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

C++ 透過 COM Interop 呼叫 C# 托管類庫:IDispatch::Invoke 完整實戰

     編輯:關於C++

CLR Interop 讓非托管代碼與托管代碼雙向呼叫成為可能。本文示範非托管 C++ 客戶端如何透過 COM Interop 呼叫 C# 實現的托管類庫。

1. 建立托管伺服器

在 Visual Studio 2008 建立 C# Class Library 專案 MyManagedServer,定義介面與實作類別:

// IManagedFooClass.cs
using System;
using System.Runtime.InteropServices;

namespace MyManagedServer {
    [ComVisible(true),
     Guid("79EDDA1C-F243-47C5-8954-5DEF01FA3D44"),
     InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IManagedFooClass {
        [PreserveSig, DispId(1)]
        void PrintFoo();
    }
}

// CustomCOMClient.cs
using System;
using System.Runtime.InteropServices;

namespace MyManagedServer {
    [ComVisible(true),
     ClassInterface(ClassInterfaceType.AutoDual),
     ProgId("MyManagedServer.ManagedFooClass")]
    public class CustomCOMClient : IManagedFooClass {
        public CustomCOMClient() {}
        [DispId(1)]
        public void PrintFoo() {
            Console.WriteLine("in MyManagedServer: CustomCOMClient.PrintFoo()");
        }
    }
}
  • ComVisible(true):讓介面/類別對 COM 可見。
  • ProgId:提供人類可讀的識別碼,註冊時會關聯 CLSID。

2. 註冊組件供 COM 使用

兩種方式:

  1. 專案屬性 → Build → 勾選 Register for COM Interop,再建置。
  2. 命令列:regasm MyManagedServer.dll /tlb /codebase(產生並註冊型別庫)。

3. 建立非托管 C++ 客戶端

建立 Win32 Console Application MyNativeClient,複製產生的 MyManagedServer.tlb 到專案目錄,撰寫呼叫代碼:

#include "stdafx.h"
#import "mscorlib.tlb" no_namespace
#import "MyManagedServer.tlb" no_namespace

int _tmain(int argc, _TCHAR* argv[]) {
    ::CoInitialize(NULL);

    // 1. 由 ProgID 取得 CLSID
    const OLECHAR lpszProgID[] = OLESTR("MyManagedServer.ManagedFooClass");
    CLSID clsid;
    HRESULT hr = CLSIDFromProgID(lpszProgID, &clsid);
    if (FAILED(hr)) return -1;
    printf("CLSIDFromProgID Succeeded\n");

    // 2. 建立 IDispatch 實例
    IDispatch* ppv = nullptr;
    hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&ppv);
    if (FAILED(hr)) return -1;
    printf("CoCreateInstance Succeeded\n");

    // 3. 取得方法 DispID
    DISPID dispid;
    const LPOLESTR szMember = OLESTR("PrintFoo");
    hr = ppv->GetIDsOfNames(IID_NULL, (LPOLESTR*)&szMember, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
    if (FAILED(hr)) { ppv->Release(); return -1; }
    printf("GetIDsOfNames Succeeded\n");

    // 4. 呼叫 Invoke
    DISPPARAMS dispParams = {0};
    VARIANT vtResult;
    UINT dwArgErr;
    hr = ppv->Invoke(dispid, IID_NULL, NULL, DISPATCH_METHOD, &dispParams, &vtResult, NULL, &dwArgErr);
    if (SUCCEEDED(hr)) printf("Invoke Succeeded\n");

    ppv->Release();
    return 0;
}

關鍵步驟解析

  1. CoInitialize:初始化 COM 程式庫。
  2. CLSIDFromProgID:將人類可讀的 ProgID 解析為 CLSID。
  3. CoCreateInstance:建立 COM 物件,這裡要求 IID_IDispatch 介面(支援晚期繫結)。
  4. GetIDsOfNames:將方法名稱映射為 DISPID。
  5. Invoke:透過 DISPID 實際呼叫方法。

執行結果

CLSIDFromProgID Succeeded
CoCreateInstance Succeeded
GetIDsOfNames Succeeded
in MyManagedServer: CustomCOMClient.PrintFoo()
Invoke Succeeded

注意事項

  • 同時 #import "mscorlib.tlb" 可避免產生的 .tlh 中型別找不到的問題。
  • 本文代碼僅供教學範例,實務應用需加強錯誤處理與資源管理。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved