首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

COM 智能指標實戰條款 11:型別安全的資源建立與介面查詢——綁定 IID 與介面的編譯期保障

     編輯:關於C語言

條款 11:以型別安全方式建立資源與查詢介面

手動 CoCreateInstance 的型別不安全陷阱


void func() {
    IX* pIX = NULL;
    hr = CoCreateInstance(CLSID_MYCOMPONENT, NULL, CLSCTX_INPROC_SERVER,
                          IID_IX, (void**)pIX); // 錯誤:缺 & 運算子
    assert(hr);
    pIX->IxFunction(); // 行為未定義,多數情況錯誤
}

原因:建立組件/查詢介面函數非型別安全,void** 參數接受任意型別指標。

智能指標也救不了手動調用


void func() {
    CComPtr spIX = NULL;
    hr = CoCreateInstance(CLSID_MYCOMPONENT, NULL, CLSCTX_INPROC_SERVER,
                          IID_IY, (void**)&pIX); // IID_IY 配 IX* → 錯誤
    assert(hr);
    pIX->IxFunction();
}

斷言能捕獲,但為何不從源頭杜絕?

最佳解法:使用智能指標內建功能函數


void func() {
    CComPtr spIX = NULL; // IID 在建構時綁定
    spIX.CoCreateInstance(CLSID_MYCOMPONENT); // 無 IID、無 void**
    assert(spIX);
    spIX->IxFunction();
}

程式碼簡潔且型別安全。_com_ptr_t 更進一步:


_COM_SMARTPTR_TYPEDEF(ICalculator, IID_ICALCULATOR);
ICalculatorPtr spCalculator(CLSID_CALCULATOR); // 建構函數建立組件
spCalculator->Add(1, 2, &nSum);

IID 與介面綁定的兩種機制

_com_ptr_t:特化時指定 IID(_COM_SMARTPTR_TYPEDEF(ICalculator, IID_ICALCULATOR)),靈活但易錯配。
CComPtr:要求介面宣告時用 __declspec(uuid) 綁定 IID:


interface __declspec(uuid("994D80AC-A5B1-430a-A3E9-2533100B87CE")) ICalculator : IUnknown {
    virtual HRESULT STDMETHODCALLTYPE Add(const int nNum1, const int nNum2, int* pnSum) const = 0;
    virtual HRESULT STDMETHODCALLTYPE Sub(const int nMinuend, const int nSubtrahend, int* pnQuotient) const = 0;
};

否則 CComPtr 編譯失敗:no GUID has been associated with this object。

相容兩者的最佳實踐

介面宣告統一採用 __declspec(uuid),兼容 CComPtr 編譯期檢查與 _com_ptr_t 靈活特化。雖犧牲些許可移植性,換來編譯期型別安全——先考慮程式正確執行,再談相容性。

IDL 定義介面並綁定 IID 更合理,但為示例清晰此處採用 C++ 語法。

—— 作者:liuchang5 的專欄

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved