我正在实施我的第一个进程外COM服务器(我的第一个COM服务器,就此而言)。我已按照步骤编写IDL文件,生成代理/存根DLL的代码,编译DLL并注册它。
当我检查注册表项时,我有
HKEY_CLASSES_ROOT/Interface/<GUID>
的密钥,其值为(例如)IMyApp
和HKEY_CLASSES_ROOT/Interface/<GUID>/ProxyStubClsid32
的密钥,其值为<GUID>
,即与密钥名称相同的值 我不明白第二个键的值如何与键名中的<GUID>
值相同,因为我目前的理解是
HKEY_CLASSES_ROOT/Interface/<GUID>
中,GUID是界面 ID ProxyStubClsid32
的值不是接口ID,而是指向实现上述接口的组件的类 ID HKEY_CLASSES_ROOT/CLSID/<GUID>/InprocServer32
(其中GUID是上述类 ID)的值指向代理DLL 如果一个是接口ID而另一个是类ID,HKEY_CLASSES_ROOT/Interface/<GUID>/ProxyStubClsid32
的值如何保持相同的值GUID?
答案 0 :(得分:6)
您对COM中使用Guids的方式的基本理解是正确的。值得注意的是,具有相同guid的接口和coclass不是问题。它们存在于不同的注册表项HKCR \ Interface vs HKCR \ CLSID中,无论您是在查找IID还是CLSID,它都会在COM中清晰显示。
其次是你写的IDL。请注意,没有地方可以指定代理的CLSID,只能在那里声明代理和存根支持的IID。
接下来,您需要通过自动生成代理/存根的方式进行疯狂追逐。核心Windows SDK标头是RpcProxy.h,在文本编辑器中打开它看看。宏汤很重,但它确实有一些不错的评论描述了正在发生的事情。重要的RPC辅助函数是NdrDllRegisterProxy(),它注册代理并在使用Regsvr32.exe时调用。它的第3个参数指定代理的CLSID。我会让你读取并引用.h文件中的重要位:
编译器开关:
-DPROXY_CLSID=clsid Specifies a class ID to be used by the proxy DLL.
您使用Project + Properties,C / C ++,Preprocessor,Preprocessor Definitions设置指定的那个。请注意,您的项目将不指定它。
追逐汤然后把你放在这个:
// if the user specified an override for the class id, it is
// PROXY_CLSID at this point
#ifndef PROXY_CLSID
#define GET_DLL_CLSID \
( aProxyFileList[0]->pStubVtblList[0] != 0 ? \
aProxyFileList[0]->pStubVtblList[0]->header.piid : 0)
#else //PROXY_CLSID
#define GET_DLL_CLSID &PROXY_CLSID
#endif //PROXY_CLSID
换句话说,如果你没有自己指定CLSID(你没有),那么它使用存根表中的第一个 IID 。
这使得ProxyStubClsid32 guid与第一个接口的IID相同。功能,而不是错误。
答案 1 :(得分:0)
初学者混乱(tm)的案例。通过致电regsrv32
注册的课程不是我的 CLSID。它是专门为代理/存根DLL生成的(友好名称PSFactory也表示这一点)。因为罗曼R.怀疑,有两个班级,我认为只有一个班级。当我使用/Embedding
开关调用时,EXE服务器会注册我自己的CLSID。
答案 2 :(得分:0)
据我所知,MIDL现在管理所有代理/存根混乱(继承自IDispatch而不是IUnknown,您可能已经这样做,因为您拥有ProxyStubClsid32注册表项)。
唯一需要的是正确注册服务器(只是构建它或者/ RegServer没有为我们正确注册它......以及其他许多人),这样做只需要调用LoadTypeLibEx(构建之后)服务器或安装它。)
所以只需使用此代码创建一个小exe,并在构建和安装后调用它:
String^ l_TLB = l_Path + "\\MyServer.tlb";
IntPtr l_TLBP = System::Runtime::InteropServices::Marshal::StringToBSTR(l_TLB);
ITypeLib *pTypeLib;
HRESULT hr = LoadTypeLibEx(static_cast<LPCOLESTR>(l_TLBP.ToPointer()), REGKIND_REGISTER, &pTypeLib);
if(SUCCEEDED(hr))
pTypeLib->Release();