This tip describes how to use a COM DLL without registering it. You will find a small class here which you can use in your projects.
C++ developers who have heard about COM but don't know it, might think "Nuh, all the stuff I have to implement - too complicated". But when it comes to modularization, COM provides an excellent mechanism to deal with components imported from DLLs.
If you are one of these developers, you should probably read Alex Blekhman's article about how to export classes from a DLL. It leads nicely to the concept of COM - exporting interfaces.
When you reached the point where you think that using interfaces to export classes is really a good idea, you might notice that COM actually provides you with all the mechanisms you need to manage the lifetime of your objects and your modules and to create instances. You might also notice that by exporting a few functions from your DLL, you can create a COM DLL that you can easily use from your application.
One downside is there though: Normally a COM DLL has to be registered so the OS can load it when you say "create an instance of this or that class". You might not want that, maybe because you don't want your application to require any installation, maybe you don't want that your DLL can be used (easily) by other applications. So that's what this tip is about: Using components from your DLLs without registering.
Using the Code
Usually, when you want to instantiate a COM object, you would use:
COM will lookup the
CLSID in the registry, see which module provides this class, load the module (DLL) and ask the module to create that instance.
So if you want to instantiate a class that is not registered, you have to do all these steps yourself. That's what
ComLibrary is for. It has the following interface:
HRESULT Load(LPOLESTR szDllName);
HRESULT Unload(BOOL bForce = FALSE);
HRESULT GetClassObject(REFCLSID aClsid, REFIID aIid, LPVOID FAR* ppv);
template<class Iface> HRESULT CreateInstance(
IUnknown* aUnknownOuter = nullptr);
Using it is straight forward, as you might guess from the interface. For each module you are planning to use, provide an instance of
ComLibrary. It has to live as long as you are using that module:
Load the library on startup. Note that the path has to be absolute and can't be a network path to prevent security issues with loading DLLs from unexpected sources:
HRESULT hr = mMathModule.LoadModule(GetAppPath() + 'mathmodule.dll');
And then, instead of calling
IVector * pVector = nullptr;
HRESULT hr = mMathModule.CreateInstance(CLSID_Vector, &pVector);
You will still have to specify a
CLSID of course. When you create a COM DLL, you probably use MIDL to define your interfaces. If so, the MIDL compiler will create a _h.h and a _i.c file. Include them in your application, and you have everything you need to use your interfaces and
When you are done using your instances, just release them as usual. If you feel you are done using your mathmodule, you can call
UnloadModule(...). This will check if there are still outstanding references to that module (via
DllCanUnloadNow()) and unload the DLL if there are no more instances in use, or if you specify
bForce. Usually, you would do this before exiting your application.
A few notices about the module DLLs: When you create a ATL COM DLL using the assistant from VS, you end up with a DLL that can be registered. If you don't want that, you can simply remove some stuff. This also helps to keep things clean. So what you should do is:
- Remove some resources, namely the .rgs files.
- Check your
CAtlDllModule class (usually in dllmain.h) and remove the macro
- In your
CAtlDllModule implementation file, remove the
DllInstall functions. Remove them also from your .def file.
- In all your COM classes, replace the macro
The sample code uses ATL, although the
ComLibrary class doesn't, you can use it in plain COM.