Click to See Complete Forum and Search --> : Question about COM QueryInterface


scicatur
May 16th, 2005, 10:41 AM
Before my question I explain my situation.

Situation:
I have a microsoft dll that I wish to use from my mingw C++ project. The dll is a microsoft COM creature. Means the following:

1) I have an IDL (Interface Description Language) file which is a text file describing all the interfaces found inside the dll.
2) All the interfaces are inherited from IUnknown.
3) The IDL file tells me the IID (some identification) of every interface and also the names and parameters of all the functions found inside the dll

Here is how I try to make use of the dll:

1. I initialize the COM with "hr = CoInitialize();" So far so good.
2. I load the dll with "hdll = LoadLibrary("litgen.dll"); No problem.
3. Now to some real work:

typedef HRESULT (*CreateWriterFType)(IUnknown**);
CreateWriterFType CreateWriter;
CreateWriter = (CreateWriterFType)GetProcAddress( hdll, "CreateWriter" );
hr = CreateWriter( &pUnkLitWriter );

which also compiles and executes nicely.
4. In order to eventually use the functions in the dll I should load some interface with QueryInterface... like this :

hr = pUnkLitWriter->QueryInterface( IID_ILITWriter, &pLitWriter );

but here is the trouble. In my code the IID_ILITWriter is just placeholder without real value. It's type is REFIID, but this tells me nothing. I can see that it defines the COM interface that I wish to load but how can I initialize it?

So the QUESTION:
How do I get valid REFIID parameter for QueryInterface function??

NMTop40
May 16th, 2005, 10:58 AM
It's a long time since I had to use COM and I didn't really like it back then (although it is still used extensively, and is at least better than MFC), but I don't think you are supposed to load COM DLLs that way.

Normally the GUID, i.e. that funny looking reference id, is stored in the registry when you register your COM component (DLL) and then when you wish to load it, you use the COM method to create a component (can't remember what it is) with your GUID and it uses the DLL to create it.

When you've done it this way, you can call QueryInterface on your component giving another interface GUID to see if your component implements it. This is, in reality, a type of dynamic_cast.

If you do use COM you should probably use ATL with it. And if you have visual components, use WTL.

By the way, this is probably also in the wrong forum.

scicatur
May 16th, 2005, 11:25 AM
Ok About the loading of the dll I followed the instructions in MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncnt/html/sdkdevguide_understandinginterfaces.asp

They explain there that for litgen.dll there is no need to load litgen to register or anything like that. But I admit that they mention i should generate litgen.h for my project with their "midl.exe" program... but anyways i have no "midl.exe" in my harddrive and no way to get it from internet.

But if I knew how to generate a valid REFIID to give for the QueryInterface my problem should be solved. Besides I think that the missing midl.exe just creates the REFIID constants from the IDL file and puts this info into the header.

About the ATL and WTL I think it requires me to use Visual C++. Remember that I am doing my project with mingw which is a gcc variant. And that is also why I posted my question here in the C++ (Non-Visual C++ Issues) forum.

Yves M
May 16th, 2005, 12:49 PM
There are three ways you can go about this. You can try to get .h files compiled by midl (there may be other IDL compilers, not sure though), you could try to use IDispatch or you could write the headers by hand.

I guess the IDispatch route would be OK for a start (it's slightly slower and has more overhead than calling the objects directly, but you don't even need an idl for it).

Here is some code that uses IDispatch to get a handle to Word's Application object.

CLSID w;

memset(&w, 0, sizeof(w));

// You may want to use CoInitializeEx instead
CoInitialize(0);

HRESULT hr = CLSIDFromProgID(L"Word.Application", &w);

IUnknown *p = 0;
hr = CoCreateInstance(w, 0, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **) &p);

IDispatch *pD = 0;
hr = p->QueryInterface(IID_IDispatch, (void **) &pD);
// Now pD points to a Word.Application object (in case nothing went wrong)

scicatur
May 16th, 2005, 02:07 PM
How about writing the headers by hand. I think my DLL doesn't have that IDispatch interface, meaning perhaps it's not a full featured COM.

I think I can manage writing the interfaces... Nothing too difficult there.
but I think I should write to the header something like following:


REFIID IID_ILITCallback = ??????????????????;


where the ?????????????????? part is the problem .. I don't know what to write here.

I assume that the answer comes from the .idl file: where

[object, uuid(6BC62165-B91C-4993-8002-5BC30B2D1196)]
interface ILITCallback : IUnknown
{


but how to convert this uuid(6BC62165-B91C-4993-8002-5BC30B2D1196) into type REFIID ????

Arjay
May 16th, 2005, 03:24 PM
I downloaded the content sdk, took a look through the samples and it seems pretty straightforward if you are using Visual C++, although it's really quite strange to have to use LoadLibrary. There's also appears to be a memory leak in the line:


ILITCallbackPtr pCallback(new ErrHandler);


How is the 'new' released? Is the com object suppose to do it? Pretty non-standard.

Anyway, I've attached the midl output of litgen.idl (litgen.h, litgen_i.c, and ligen_p.c).

Hopefully this helps.

Arjay

scicatur
May 16th, 2005, 09:47 PM
Many Thanks for your answer and trouble.. I think this helps me to get on with my project.