Примечание: Рассмотрите возможность использования манифеста, как в ответе здесь, для лучшего решения:
Как это сделать без манифеста
Реестр COM - это служба , которая необязательна для сервера inproc.
Еще раз: Вам не нужно регистрировать объект для его создания. Если он не зарегистрирован, (и не в манифесте) вы не можете создать его с помощью CoCreateInstance
, поскольку реестр (или манифест) - это то, что CoCreateInstance
сообщает, какую DLL загрузить.
Однако вы можете создать его с помощью LoadLibrary
, GetProcAddress
, DllGetClassObject
и IClassFactory::CreateInstance
.
(Обратите внимание, что вы не получите никаких сервисов COM + и не сможете таким образом создавать объекты вне процесса или объекты, чья модель потоков не совместима с создаваемым потоком. Если вы не попросите COM сделать это для тебя эти вещи становятся твоей проблемой).
Служба, предоставляемая CoCreateInstance
, заключается в том, чтобы найти правильную DLL для вызова LoadLibrary и просто вызвать другие функции для вас. (И проверка совместимости моделей потоков, создание в соответствующем потоке и использование CoMarshalInterthreadInterfaceInStream / CoUnmarshalInterfaceAndReleaseStream для маршалинга интерфейса, если они не являются. Это звучит как большая работа, но если у вас есть только один STA therad, вы можете в значительной степени игнорировать все вопросы.)
Нечто подобное должно сработать:
// 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;
}
Примечание: Это позволит вам создать объект. Однако, если вызываемый вами объект сам по себе зависит от регистрации, он не будет работать правильно.
В частности, многие реализации IDispatch
полагаются на библиотеку типов. Если это относится к конкретному объекту, то GetIDsOfNames
и GetTypeInfo
завершатся ошибкой, и вы не сможете использовать методы с поздним связыванием с объектом. Это включает использование dynamic
в C # и динамические языки, такие как Python.
Другие методы, такие как методы двойного интерфейса и интерфейсы, не наследуемые от IDispatch, могут хорошо работать, даже если методы IDispatch не работают.
Итог: чтобы без регистрации COM работал, объект, который создается, не должен полагаться на свою собственную регистрацию.