2012-10-19 72 views
0

我正在執行我的第一個進程外COM服務器(我的第一個COM服務器就是這個問題)。我已按照步驟編寫IDL文件,生成代理/存根DLL的代碼,編譯DLL並註冊它。用於進程外COM服務器的註冊表項

當我檢查的註冊表項,我有

  • 名爲HKEY_CLASSES_ROOT/Interface/<GUID>的關鍵,其vaue是(說)IMyApp
  • 名爲HKEY_CLASSES_ROOT/Interface/<GUID>/ProxyStubClsid32的關鍵,它的值是<GUID>,即相同的值作爲鍵名

我不明白的第二個關鍵的價值如何能同<GUID>值我n個鍵的名字,因爲我目前的理解是,

  • 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?

編輯:我仍然希望爲這個答案。簡而言之:由於一個組件和一個接口是兩個不同的東西,同一個ID如何用於兩者?

+0

你爲什麼不找'ProxyStubClsid32'在註冊表中找到現有的COM類,以便該值看到佈局的細節?更不用說[MSDN解釋佈局](http://msdn.microsoft.com/en-us/library/windows/desktop/ms688573%28v=vs.85%29.aspx)。 –

+0

因爲微軟這樣設計的。 – Wug

+0

@Roman R:COM類是我要寫的服務器,所以它甚至沒有註冊 – Dabbler

回答

5

您對COM中使用GUID的方式的基本理解是正確的。值得注意的是,具有相同GUID的接口和coclass不是問題。他們生活在不同的註冊表項中,HKCR \ Interface與HKCR \ CLSID,並且在COM中始終清楚您是查找IID還是CLSID。

其次是你寫的IDL。請注意,沒有地方可以指定代理的CLSID,只有代理和存根支持的IID可以在那裏聲明。

接下來,您需要通過代理/存根自動生成的方式進行雁行。核心的Windows SDK頭是RpcProxy.h,在文本編輯器中打開它看看。宏湯非常重,但它有一些體面的評論,描述了正在發生的事情。重要的RPC幫助器函數是NdrDllRegisterProxy(),它註冊代理並在您使用Regsvr32.exe時被調用。它的第三個參數指定代理的CLSID。我讓你做閱讀,只是引述了重要位.h文件:

編譯器開關:

-DPROXY_CLSID=clsid 
    Specifies a class ID to be used by the proxy DLL. 

這是你和項目+屬性,C/C++指定,預處理器,預處理器定義設置。請注意,您的項目將而不是指定它。

經湯追逐土地,然後你就這一個:

// 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相同。功能,而不是一個錯誤。

+0

這非常有益,謝謝!有趣的是,雖然GUID是「全局唯一的」,但它引用的內容仍然可能不明確,並取決於外部上下文(組件或接口)。我不明白這是因爲我認爲它們就像XML名稱空間中的URI(URI的唯一值唯一確定了所討論的名稱空間),但事實並非如此。 – Dabbler

+0

第二個想法...如果CLSID不在IDL文件中,代理/存根DLL永遠不會知道它,那麼它是如何獲得註冊的?它需要註冊,對吧? – Dabbler

+0

不知道如何更好地解釋它,那麼我已經做到了。 NdrDllRegisterProxy()消耗CLSID,第三個參數,並寫入註冊表項。 GET_DLL_CLSID提供它。 –

0

初學者的困惑(tm)。通過調用regsrv32註冊的課程不是我的 CLSID。它是專門爲代理/存根DLL生成的(友好名稱PSFactory也表示這一點)。正如Roman R.所懷疑的那樣,我認爲有兩個班只有一個班。使用/Embedding開關調用時,我自己的CLSID由EXE服務器註冊。

0

對於我所知道的,所有的代理/存根破壞現在由MIDL管理(從IDispatch繼承而不是IUnknown,您可能已經這樣做了,因爲您擁有ProxyStubClsid32註冊表項)。

唯一需要的是註冊服務器正確(只是建立它或做/註冊服務器沒有註冊它適合我們和其他許多人),這樣做只需要調用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(); 
相關問題