2009-11-12 19 views
6

當我得到它是有三種方式來實現在COM編組:COM如何選擇如何編組接口?

  • 類型庫編組
  • 代理/存根編組
  • 由對象實現IMarshal

現在怎麼做的組件消費者(用戶)選擇將使用哪一個?它是自己決定並使用首選方式,還是它調用一些內置函數並解決了它的問題?

我目前遇到以下情況:我的組件實現了自定義接口ICustomInterface也由從另一家公司的一個組件來。我的組件沒有typelib,也沒有實現IMarshal。系統註冊表包含具有代理/存根的GUID的HKCR \ Interface {uuidof(ICustomInterface)} \ ProxyStubClsid32密鑰,該代理/存根可以跟蹤到該另一個公司提供的庫。

現在,當我的組件消費初始化我的組件從我的組件調用QueryInterface()請求IMarshal,當返回E_NOINTERFACE它只是什麼都不做。這是爲什麼 - 爲什麼不從其他公司的代理/存根庫啓動?

回答

0

我在這個有點生疏,但你有沒有在你的項目名爲blindquery功能? (如果你創建了一個C++ ATL項目,它通常由嚮導聲明)。函數內的斷點。該向導生成的函數通常在查詢界面由於錯誤代碼返回E_NOINTERFACE時遇到問題。

從我的舊項目 _

編輯(找到示例代碼)blindquery

class ATL_NO_VTABLE CChildEvents : 
    public CComObjectRootEx <CComSingleThreadModel>, 
    public CComCoClass<CChildEvents, &CLSID_ChildEvents>, 
    public IDispatchImpl<IChildEvents, &IID_IChildEvents, &LIBID_XXX> 
{ 
public: 
    CChildEvents(void) : 
    m_pItfMgr(0) 
    { 
    } 

    /* called from internalQI to tear off a new blind interface */ 
    static HRESULT WINAPI _BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD dw); 

    DECLARE_REGISTRY_RESOURCEID(IDR_CHILDEVENTS) 
    DECLARE_PROTECT_FINAL_CONSTRUCT() 

    BEGIN_COM_MAP(CChildEvents) 
     COM_INTERFACE_ENTRY(IChildEvents) 
     COM_INTERFACE_ENTRY(IDispatch) 
     COM_INTERFACE_ENTRY_FUNC_BLIND(0, _BlindQuery) 
    END_COM_MAP() 
}; 


HRESULT WINAPI CChildEvents::_BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD /* dw */) 
{ 
    HRESULT hr = E_NOINTERFACE; 
    USES_CONVERSION; 

    try 
    { 
     if(pvThis == NULL) 
     { 
      ATLASSERT(FALSE); 
     } 
     else 
     { 
      /* 
      * cast the pvThis pointer to the actual class £ 
      * so we can use it here £ 
      * reinterpret_cast should be safe since we're calling ourself 
      */ 
      CChildEvents *pThis = reinterpret_cast < CChildEvents * > (pvThis); 
      if(pThis == NULL) 
      { 
       ATLASSERT(FALSE); 
      } 
      else 
      { 

        /* check to see if it matches on of our children's DIID */ 
            if(memcmp(&riid,&l_someotherguid,sizeof(GUID)) == 0) { 

         /* if so cast to a IDispatch -- the standard for event interfaces */ 
         *ppv = reinterpret_cast < IDispatch * > (pvThis); 

         /* addref */ 
         pThis->AddRef(); 

         /* reply */ 
         hr = S_OK; 

       } 
      } 
     } 
    } 
    catch(...) 
    { 
     ATLASSERT(FALSE); 
    } 

    /* must not be in our map - tell them to GO FISH */ 
    return(hr); 
} 
+0

不,我沒有。我嘗試了所有合理設置的嚮導,但沒有聲明這樣的功能。我也爲這個名字谷歌搜索 - 沒有合理的匹配。可能是你拼錯了這個名字? – sharptooth 2009-11-12 09:05:41

+0

我挖入我的舊代碼,發現盲查詢實際上是我自己的功能。 LOL ..使用這個宏http://msdn.microsoft.com/en-us/library/5b6w5bwx(VS.80).aspx – 2009-11-12 09:22:46

+0

那麼,這是鉤住QI的一個很好的方式()。但這就是全部 - 這個函數被稱爲包含IMarshal的一組itersfaces,沒有明顯的原因。 – sharptooth 2009-11-12 09:43:49

5

的COM運行時將使用類型庫(了oleautomation)編組,如果你加入了CLSID {00020424-0000-0000-C000-000000000046}標記您的接口使用標準的封送在HKCR\Interfaces\{iid}\ProxyStubClsid(其中{iid}是您的界面的GUID)。您還需要註冊一個類型庫,以便運行時提取參數信息,並且只能使用某些類型的子集。還有一些(舊)信息herehere

如果您想使用MIDL編譯器從您的IDL生成的自定義代理/存根,那麼您需要將接口註冊表項更改爲該代理對象的CLSID。這使您可以使用更廣泛的類型,例如「原始」陣列。

如果你支持IMarshal那麼這就是將在優先使用這兩種機制。這意味着你可以改變你的對象來聚合自由線程封送拆分器(使用其實現IMarshal),而不必在註冊表中改變任何東西。這將避免創建任何代理。

希望這會有所幫助。

+0

但是爲什麼我會看到奇怪的行爲 - 特別是運行時首先QIs IMarshal的組件,並且它何時獲取E_NOINTERFACE它只是保留,不試圖查找HKCR \ Interface \ {InterfaceId}鍵? – sharptooth 2009-11-16 12:46:04

+0

你見過這裏的文檔http://msdn.microsoft.com/en-us/library/ms678428%28VS.85%29.aspx?也許你可以組合一個調用CoMarshalInterface的小測試用例(它最終是COM運行時所要做的),然後通過追蹤來看看會發生什麼。我嘗試了它,並與regmon,我可以看到它擊中註冊表。 – voyce 2009-11-16 15:27:05