First, COM is like black magic for me. But I need to use COM dll in one project I'm working on.
So, I have a DLL I am developing and I need some functionalities that are available in a separate COM DLL. When I look to the COM DLL with Depends.exe I see methods like DllGetClassObject() and other functions but none of the functions I'm interested in.
I have access to the COM DLL (legacy) source code but it's a mess and I'd rather like to use the COM DLL in binary like a big black box not knowing what's going on inside.
So, how can I call the COM DLL functions from my code using LoadLibrary? Is it possible? If, yes, could you give me an example of how to do it?
I'm using Visual Studio 6 for this project.
Thanks a lot!
Typically you would use
CoCreateInstance()
to instantiate an object from a COM DLL. When you do this, there's no need to load the DLL first and get proc addresses like you would need to do with a normal DLL. This is because Windows "knows" about the types that a COM DLL implements, what DLL they are implemented in, and how to instantiate them. (Assuming of course that the COM DLL is registered, which it typically is).Suppose you have a COM DLL with the IDog interface you want to use. In that case,
dog.idl
myCode.cpp
All this memory management stuff can get pretty grungy, though, and the ATL provides smart pointers that make the task of instantiating & managing these objects a little easier:
EDIT:
When I said above that:
...I really glossed over exactly how Windows knows this. It's not magic, although it might seem a little occult-ish at first.
COM libraries come with Type Libraries, which list the Interfaces and CoClasses that the library provides. This Type Library is in the form of a file on your hard drive -- very often it is embedded directly in the same DLL or EXE as the library itself. Windows knows where to find the Type Library and the COM Library itself by looking in the Windows Registry. Entries in the Registry tell Windows where on the hard drive the DLL is located.
When you call
CoCreateInstance
, Windows looks the clsid up in the Windows Registry, finds the corresponding DLL, loads it, and executes the proper code in the DLL that implements the COM object.How does this information get in to the Windows Registry? When a COM DLL is installed, it is registered. This is typically done by running regsvr32.exe, which in turn loads your DLL in to memory and calls a function named
DllRegisterServer
. That function, implemented in your COM server, adds the necesarry information to the Registry. If you are using ATL or another COM framework, this is probably being done under the hood so that you don't have to interface with the Registry directly.DllRegisterServer
only needs to be called once, at install-time.If you try to call
CoCreateInstance
for a COM object that has not yet been registered via theregsvr32
/DllRegisterServer
process, thenCoCreateInstance
will fail with an error that says:Fortunately, the fix for this is to simply call
regsvr32
on your COM server, and then try again.In general, you should prefer
CoCreateInstance
orCoGetClassObject
rather than accessingDllGetClassObject
directly. But if you're dealing with a DLL that you can't, or don't want to, register, then the below describes (part of) what these function do behind the scenes.Given a CLSID,
DllGetClassObject
allows you to get the class object, from which you can create instances (via theIClassFactory
interface, if I remember correctly).Summary of steps (it's been a while since I've last touched COM, so pardon any obvious errors):
DllGetClassObject(clsid, IID_IClassFactory, &cf)
, whereclsid
is the CLSID you want to get the class object for, andcf
is of course the class factory.cf->CreateInstance(0, iid, &obj)
, whereiid
is the IID of the interface you'd like to use, andobj
is of course the object.(
CoCreateInstance
performs steps 1 and 2.CoGetClassObject
performs step 1. You would useCoGetClassObject
if you need to create many instances of the same class, so that step 1 doesn't need to be repeated each time.)If it's a COM DLL, all you need do is add it as a reference to your project, and then you can call the functions that are within the DLL.
Yes, you can use the low level COM functions like DLLGetClassObject, but why would you?
Here's a bit of code showing how to get the class factory and use it to create a COM object. It uses a struct to keep track of the module handle and DllGetClassObject function pointer. You should hold on to the module handle until you are done with the COM object.
To use this function, you need to allocate an instance of the ComModuleInfo struct and set the szDLL to the DLL filename or full path name. Then call the function with the class id and interface Id of the COM object you want to get from that DLL.
You do not directly use LoadLibrary() with a COM library. CoCreateInstance() will call this function if it's not already, and then new an instance of the class you implemented in the library onto the heap and finally return to you a raw pointer to that object. Of course, it could fail during the process, and thus some mechanism for you to check the status like HRESULT.
For simplicity of using it, you can think of a COM library as a common DLL with 1) some predefined entry(main) function, 2) you have to call some predefined function like CoCreateInstance() to enter it, and accept that it's like that because it has to.
If the type library is embedded in the DLL you can import it into your project:
This will auto-generate header files that get included in your project and allow you to use the exported objects.