CoRegisterClassObject を使用して、com オブジェクトを含む dll をロードする方法をカスタマイズしようとしています。スレッドのアパートメント タイプが com オブジェクトのものと一致しないときに発生していた問題を解決する方法を試しています。coregisterclassobject が S_OK を返すという問題がありますが、com オブジェクトはまだ作成されるレジストリに依存しているため、何もしていないようです。これは、失敗している概念実証として私が書いたサンプルです (TestComObj はアパートメント スレッドです)。
LPSTREAM factory_stream = NULL; //GLOBAL VARIABLE FOR TEST
DWORD __stdcall FactoryThread(LPVOID param)
{
CoInitialize(NULL);
CustomClassFactory *factory = new CustomClassFactory();
factory->AddRef();
CoMarshalInterThreadInterfaceInStream(IID_IClassFactory, (IClassFactory*)factory, &factory_stream);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
factory->Release();
CoUninitialize();
return 0;
}
そして、これが私の主な機能の関連部分です。
CoInitializeEx(NULL, COINIT_MULTITHREADED);
HANDLE regThread = CreateThread(NULL, 0, FactoryThread, NULL, 0, NULL);
Sleep(5000); //ensures that the factory is registered
IClassFactory *factory = NULL;
CoGetInterfaceAndReleaseStream(factory_stream, IID_IClassFactory, (void**)&factory);
DWORD regNum = 0;
HRESULT res = CoRegisterClassObject(clsid, factory, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, ®Num);
//res == S_OK
{
TestComObjLib::ITestComObjPtr ptr;
HRESULT hr = ptr.CreateInstance(__uuidof(TestComObjLib::TestComObjCoClass), NULL);
//hr == E_NOINTERFACE HERE if not registered in the registry
}
CoRevokeClassObject(regNum);
CoUninitialize();
CoRegisterClassObject でレジストリを使用するべきではないため、現在の MTA スレッドではなく、STA でアパートメント スレッド オブジェクトを手動で作成する必要があるという考えでした。CoRegisterClassObject を使用していない場合、CoGetClassObject は新しいスレッドを生成し、そのスレッドで DllGetClassObject を呼び出すことに気付きました。そのため、クラス ファクトリを STA で作成するだけで、オブジェクトがそこに存在することがわかりました。
私が見ている問題は、上記のコードでは、ClassFactory が正常に動作しているにもかかわらず、まだレジストリを使用して TestComObj を作成していることです。今はとてもシンプルです。正しい dll に対して LoadLibrary を呼び出し、次に dllgetclassobject を呼び出し、その結果に対して createinstance を呼び出すだけです。アパートメントとスレッド化の問題を扱っていないときは、これを使用して、登録せずに com オブジェクトを作成できます。したがって、ここで何が問題なのかわかりません。