PDA

View Full Version : Access a COM object directly through its IDispatch implementation.



eirik
20th July 2010, 22:13
Hi

I'm trying to make a Qt GUI Application communicationg with a program called Disto Online. The program provides an API. In the documentation it says: (www.elcovision.com/e_down_disto_online.html)

"The automatisation interface is made via the IDispatch interface. There a 2 object classes: The class Disto2 which is the application class and the class DistoMeasureProxy (Measure) which represents a measurement. There is also a type library Disto2.tlb. The type library is in the same folder where you installed DISTO online."

I have been able to communicate by using QAxBase::dynamicCall in the following way.



QAxObject *disto = new QAxObject("Disto2.Application");
cout << disto->dynamicCall("DistoVersion");


The problem, however is that i need to access functions that returns datatypes unsupported by QVariant. So I have to use queryInterface() (as stated in the reference http://doc.qt.nokia.com/4.0/qaxbase.html).

My question is then ... how? I've been trying to figure this out for ages, but have not succeded in finding the answer.

This is what I'm thinking: It shoul be possible to use the type library file and from that create a object which I can somehow use. It souds like a simple task but I dont know how to include the tlb-file and how to create such a object?

Any feedback will be highly appreciated.

eirik
21st July 2010, 10:50
Hi again

There has been some progress, but I'm still very confused. I have created a header file from my type library file by adding the following to my .pro file.



TYPELIBS = $$system( dumpcpp Disto2.tlb -nometaobject )


And include the generated header file where I want to use it, and it compiles. I'm using the -nometaobject because without it resulted in errors. Is this a problem? Am I just hiding errors that will occure anyway?

In my new header file there is a namespace Disto2 with two classes Disto2 and DistoMeasureProxy. Disto2 has functions that communicates with the other program and DistoMeasureProxy is the class of the object i want in return from my Disto2 function calls (I think).

I have no idea what I'm doing but hvae tried things like:



QAxObject *distoObject = new QAxObject("Disto2.Application");
QUuid IID_Disto2;
Disto2::Disto2 disto;
distoObject->queryInterface( IID_Disto2, (void**)&disto );
Disto2::DistoMeasureProxy result = disto.SingleMeasure()


That results in a Error "conversion from 'IDispatch*' to non-scalar type 'Disto2::DistoMeasureProxy' requested" (maybe not surpricing ... the smiley is not supposed to be there:)). Also, for some reason I open two instances of my other program as well.

I have no idea what to do and if anyone has any feedback I waill be very happy.

Thanks

eirik
21st July 2010, 21:47
Hmm, this was much harder than I had anticipated ...

I have gotten the code in this thread to compile: http://www.qtcentre.org/threads/231. It says that the code is "complete". But I have no idea of how to use it. How do I communicate with the API? Do I still need the type library? How?

For reference the python sample code can be written in 3 lines:


import win32com.client

disto = win32com.client.Dispatch("disto2.application")
disto.SingleMeasure()

One would think the Qt/C++ wouludn't be that hard in comparison. There is also some MFC/C++ sample code using COleDispatchDriver class.

I would like to do all in Qt/C++, but if someone has a solution using either python or MFC in some way I'm interested in hearing that as well.

Thanks

ChrisW67
22nd July 2010, 01:14
You should just be able to instantiate an object of type Disto2::Disto2 (as defined in the generated header) and use the proxy methods it provides as if they were native. Let ActiveQt worry about the COM stuff. Something like:


Disto2::Disto2 disto;
qDebug() << disto.DistoVersion();
Disto2::DistoMeasureProxy result = disto.SingleMeasure();
...

eirik
22nd July 2010, 12:45
Thanks for yor answer Chris. That is exactly how I want it to work! But I'm not quite sure how to get there.

Did you answer my second or third post? What you wrote is pretty much like i wrote in my second post in which the call to SingleMeasure() resulted in the conversion error. If it was an answer to my third post, I dont know how to use it. What is iface, what does release() and Invoke really do? (I have tried to read the documentation but it goes way over my head)

Do you (or somone else) have some more code, or hints.

ness
22nd July 2010, 15:25
did you try using "dumpcpp" tool to generate API files ?

eirik
22nd July 2010, 15:39
Yes. Just as I said in my second post.

TYPELIBS = $$system( dumpcpp Disto2.tlb -nometaobject )
Had to use the -nometaobject because I got a error if I didn't. Then I include the header files produced. That is working ok I think.

The problem as I see it (might be totally wrong) is that my functions that I need to call returns a IDispatch* which I have no idea how to use. I want it to magically convert to a class defined in my type library called DistoMeasureProxy.:confused:

ChrisW67
22nd July 2010, 23:53
I was answering the general request, not so much a specific post. Everything I know about ActiveQt as a COM client comes from the docs in Assistant, specifically http://doc.trolltech.com/4.6/activeqt-container.html and also the Qutlook (http://doc.trolltech.com/4.6/activeqt-qutlook.html) example.

Have you tried a minimal example? Something like:

trial.pro


TEMPLATE = app
TARGET = trial
CONFIG += qaxcontainer
TYPELIBS = Disto2.tlb
SOURCES += main.cpp

main.cpp:


#include "disto.h" // <<<<< adjust this to suit the file name generated by dumpcpp
#include <QApplication>
#include <QDebug>

int main(int argc, char ** argv)
{
QApplication a(argc, argv);

Disto2::Disto disto;
qDebug() << disto.DistoVersion(); // I am assuming this returns QString or an int

return a.exec();
}

eirik
23rd July 2010, 08:53
Wow! That worked. I didn't know that I didn't heve to explicitly do the connection myself. That was really helpful.

I did however have to change the the typelibs parameter from "Disto2.tlb" to "$$system(dumpcpp Disto2.tlb -nometaobject)", because your code didn't produce any header file (wierd?). If I drop the -nometaobject it causes a "reference to Disto2 is ambiguous" error (also wierd?).

But still the big problem is that I want to call a function that returns an IDispatch*. I might have said in an earlier post that it returns a Disto2:;DistoMeasureProxy, that was just a guess from my side (although it says so in the documentation as well:confused:). So my question is still how do I use a *IDispatch, which "in my opinion" should have been a Disto2:;DistoMeasureProxy class object?

Thanks.