Note: Consider using a manifest as in the answer here for a better solution:
How to do it without a manifest
The COM registry is a service which is optional for an inproc server.
Again: You do not have to register an object in order to create it. If it is not registered, (and not in a manifest) you cannot create it with CoCreateInstance
, because the registry (or manifest) is what tells CoCreateInstance
which DLL to load.
However you can create it with LoadLibrary
, GetProcAddress
, DllGetClassObject
and IClassFactory::CreateInstance
.
(Note you will not get any COM+ services, and you cannot create out-of-process objects in this way, or objects whose threading model isn't compatible with the creating thread. If you don't ask COM to do it for you these things become your problem).
The service which CoCreateInstance
provides is to locate the correct DLL for the call to LoadLibrary, and just call the other functions for you. (And checking the threading models are compatible, creating on the appropriate thread, and using CoMarshalInterthreadInterfaceInStream/CoUnmarshalInterfaceAndReleaseStream to marshal the interface if they are not. That sounds like a lot of work but if you just have one STA therad you can pretty much ignore all the issues.)
Something like this should do the trick:
// Really you should break this up int GetClassFactoryFromDLL, then reuse the class factory.
// But this is all from memory...
// Load CLSID_MyID, from DLL pszMyDllPath
typedef HRESULT __stdcall (*_PFNDLLGETCLASSOBJECT)(
__in REFCLSID rclsid,
__in REFIID riid,
__out LPVOID *ppv
) PFNDLLGETCLASSOBJECT;
HRESULT CreateInstanceFromDll(LPCTSTR pszMyDllPath, CLSID clsidMyClass, IUknown** ppunkRet)
{
// Handle bad callers
*ppunkRet = NULL;
HANDLE hDLL = LoadLibrary(pszMyDllPath);
if(hDLL == NULL)
{
// Failed to load
return HRESULT_FROM_NTSTATUS(GetLastError());
}
PFNDLLGETCLASSOBJECT pfnDllGetClassObject = GetProcAddress(hDLL);
if(pfnDllGetClassObject == NULL)
{
// Not a COM dll
HRESULT hrRet = HRESULT_FROM_NTSTATUS(GetLastError());
FreeLibrary(hDLL);hDLL = NULL;
return hrRet;
}
IClassFactory* pClassFactory = NULL;
HRESULT hr = pfnDllGetClassObject(clsidMyClass, IID_IClassFactory, &pClassFactory);
if(FAILED(hr)){
FreeLibrary(hDLL);hDLL = NULL;
return hr;
}
hr = pClassFactory->CreateInstance(NULL, IID_IUnknown, &ppunkRet);
pClassFactory->Release();
if(FAILED(hr))
{
*ppunkRet = NULL;
FreeLibrary(hDLL);
return hr;
}
return hr;
}
Note: This will allow you to create the object. However if the object you call is itself reliant onbeing registered, it will not function correctly.
In particular, many IDispatch
implementations rely on the type library. If that's the case for a particular object, then GetIDsOfNames
and GetTypeInfo
will fail, and you will not be able to use late-bound methods with the object. This includes using dynamic
in C#, and dynamic languages such as Python.
Other methods such as dual interface methods and interfaces not inheriting from IDispatch may well work however even if the IDispatch methods do not.
Bottom line: For registration-free COM to work, the object being instantiated must not rely on its own registration.