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

跨語言 COM 互操作反向實戰:Delphi 呼叫 VC 6.0 開發的 COM 元件

     編輯:關於VC++

延續上篇「VC 呼叫 Delphi COM」主題,本文詳述反向操作:在 Delphi 專案中消費 VC 6.0 (ATL) 開發的進程內 COM 伺服器。核心難點在於 IDL 到 Pascal 介面定義的手工轉換,以及 GUID/呼叫慣例的精確對應。

VC 端 COM 伺服器建立 (ATL 專案)

  1. VC 6.0 → New Project → ATL COM AppWizard → DLL 型別
  2. ClassView 右鍵 → New ATL Object → Simple Object
  3. Short Name: TestCom,介面選 Dual,執行緒模型 Apartment
  4. 介面 ITestCom 右鍵 → Add Method:ShowMsg()
  5. 實作 ShowMsg 顯示 MessageBox
  6. 編譯註冊:產生 MaAtl.dll、MaAtl.idl、MaAtl.tlb

關鍵產出:MaAtl.idl 完整內容


// MaAtl.idl : IDL source for MaAtl.dll
import "oaidl.idl";
import "ocidl.idl";

[
    object,
    uuid(78313A6E-FBA7-11D5-8094-00E04C4EA60F),
    dual,
    helpstring("ITestCom Interface"),
    pointer_default(unique)
]
interface ITestCom : IDispatch
{
    [id(1), helpstring("method ShowMsg")] HRESULT ShowMsg();
};

[
    uuid(78313A62-FBA7-11D5-8094-00E04C4EA60F),
    version(1.0),
    helpstring("MaAtl 1.0 Type Library")
]
library MAATLLib
{
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    
    [
        uuid(78313A6F-FBA7-11D5-8094-00E04C4EA60F),
        helpstring("TestCom Class")
    ]
    coclass TestCom
    {
        [default] interface ITestCom;
    };
};

IDL 手工轉換為 Pascal 介面定義

Delphi 6+ 內建 IDLtoPas.exe,舊版需手工轉換。對應規則:

IDL 元素Pascal 對應範例
interfaceinterfaceITestCom = interface(IDispatch)
uuidGUID 字串常數IID_ITestCom = '{78313A6E-FBA7-11D5-8094-00E04C4EA60F}'
coclassCoClass 工廠類別CoTestCom = class ... Create: ITestCom
methodstdcall 函數function ShowMsg: HResult; stdcall;
HRESULTHResult相容
[id(n)]DISPID 對應自動處理

完整 Pascal 介面單元 (MaAtlDll_TLB.pas)


unit MaAtlDll_TLB;

interface

uses Windows, ActiveX, Classes, ComObj;

const
  // TypeLibrary 版本
  MaAtlMajorVersion = 1;
  MaAtlMinorVersion = 0;
  
  // GUID 定義(直接從 IDL 複製)
  LIBID_MaAtl: TGUID = '{78313A62-FBA7-11D5-8094-00E04C4EA60F}';
  IID_ITestCom: TGUID = '{78313A6E-FBA7-11D5-8094-00E04C4EA60F}';
  CLASS_TestCom: TGUID = '{78313A6F-FBA7-11D5-8094-00E04C4EA60F}';

type
  // 前向宣告
  ITestCom = interface;

  // CoClass 對應介面
  TestCom = ITestCom;

  // 介面定義:繼承 IDispatch,雙重介面
  ITestCom = interface(IDispatch)
    ['{78313A6E-FBA7-11D5-8094-00E04C4EA60F}']
    function ShowMsg: HResult; stdcall;
  end;

  // 類別工廠:提供 Create/CreateRemote
  CoTestCom = class
    class function Create: ITestCom;
    class function CreateRemote(const MachineName: string): ITestCom;
  end;

implementation

uses ComObj;

class function CoTestCom.Create: ITestCom;
begin
  Result := CreateComObject(CLASS_TestCom) as ITestCom;
end;

class function CoTestCom.CreateRemote(const MachineName: string): ITestCom;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_TestCom) as ITestCom;
end;

end.

Delphi 客戶端呼叫程式碼


unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls, MaAtlDll_TLB;  // 引用轉換後的介面單元

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  pS: ITestCom;
begin
  // 1. 建立 COM 物件(自動處理 CoInitialize/CoUninitialize)
  pS := CoTestCom.Create;
  // 或跨機器:pS := CoTestCom.CreateRemote('ServerName');
  
  // 2. 呼叫方法
  pS.ShowMsg;
  
  // 3. 釋放介面(介面計數歸零自動釋放)
  pS := nil;
end;

end.

部署與註冊流程

  1. 將 VC 編譯的 MaAtl.dll 複製到目標機器
  2. 以管理員身分執行:regsvr32 MaAtl.dll
  3. Delphi 專案編譯執行,點擊按鈕驗證

常見陷阱與解決方案

問題原因解決
編譯錯誤:Undeclared identifier 'CreateComObject'未引用 ComObj 單元uses 子句加入 ComObj
執行錯誤:Class not registeredDLL 未註冊或路徑錯誤確認 regsvr32 成功,檢查註冊表 HKCR\CLSID\{GUID}
呼叫失敗:E_NOINTERFACEIID 不匹配核對 Pascal 端 GUID 與 IDL 完全一致,含大小寫與大括號
存取違規呼叫慣例不匹配確認所有方法使用 stdcall,IDL 預設即為 stdcall
參數傳遞錯誤資料型別對應錯誤參考:BSTR↔WideString, SAFEARRAY↔PSafeArray, VARIANT↔OleVariant

進階:使用類型程式庫 (.tlb) 直接匯入

Delphi 6+ 支援直接匯入 .tlb 自動產生介面單元:

  1. Component → Import Component → Import Type Library
  2. 選擇 MaAtl.tlb 或註冊後的類型程式庫
  3. 自動產生 MaAtlLib_TLB.pas,功能等同手工轉換

此法避免手工轉換錯誤,為現代 Delphi 開發推薦做法。

總結

Delphi 消費 VC COM 的核心流程:VC ATL 產出 IDL/TLB → Delphi 匯入或手工轉換為 Pascal 介面 → 以 CreateComObject 建立物件 → 介面呼叫。掌握 IDL 與 Pascal 型別系統的對應關係,配合 stdcall 呼叫慣例與 GUID 精確匹配,即可實現穩定的跨語言 COM 互操作。

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