BCB6 調用C# DLL


最近項目涉及第三方接口調用。第三方是用C#實現的WCF服務。而我們的程序是使用的BCB6開發。因此,打算將與WCF的通訊包含在C#的類庫中,給BCB6調用。BCB6 是無法直接調用C#的DLL,但可以通過C#編寫一個COM組件,然后BCB調用這個COM組件來調用。

  1. 用C#編寫COM

    大體步驟是

    1. 新建一個類庫項目

 

  1. 設置Assemblyinfo.cs

  2. 設置項目屬性

  3. 編寫代碼

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.InteropServices; //1添加Rumtime.InteropServices 程序集引用

using System.Windows.Forms; //2為了演示,所以加入了forms引用

 

namespace ComImpTest

{

[Guid("3CD116D4-18A1-4504-921B-57C053BAD618")] //3主菜單->工具->創建GUID產生

public interface IComInterface //4必須先定義接口

{

[DispId(1)] //5每一個函數或者屬性都需要指定DispID

void Hello(string name);

[DispId(2)]

int Add(int x,int y);

[DispId(3)]

string COMINFO{get;}

 

}

 

[Guid("1A8EB38C-E732-49B2-A897-B40FFD744E3D")]

public class ComImp : IComInterface //6編寫一個實現接口的類

{

public void Hello(string name)

{

Console.WriteLine("你好"+name);

MessageBox.Show("你好"+name,"C# dll 彈出界面");

}

 

public int Add(int x, int y)

{

return x + y;

}

 

public string COMINFO

{

get

{

return "com 測試";

}

}

}

}

  1. 編譯得到DLL 和 TLB

  1. BCB編寫調用
    1. 首先BCB的開發環境中需要安裝.NET FrameWork ,這里都是用的.NET FrameWork 4.0,安裝之后,

      在如圖的目錄會得到RegAsm.exe(一定要用安裝后得到的RegAsm 從其他地方復制的RegASM可能存在版本不兼容),

      這個在注冊COM的時候要用到。

    2. 建立一個BCB控制台工程
    3. 吧RegAsm.exe(我們是為了注冊方便),前面編譯得到的 ComImpTest.tlb 、ComImpTest.dll 復制到BCB工程的EXE

      輸出目錄。(這也不是必須的,本質上COM只要能注冊,然后BCB功能能找到TLB創建代理類即可)

    4. 用管理員啟動命令行,注冊ComImpTest.dll

       

      其本質是吧這個COM類注冊到了注冊表中。向系統進行了發布。

    5. 用BCB 產生代理類

      打開BCB 工程,選擇主菜單 projectàimport type library

       

       

       

      得到代理類

      包含這個頭文件,我們就可以調用了。

       

      但是這里不知道是BCB的bug,還是兼容性的問題,BCB產生的ComImp代理類的GUID是錯誤的。

      正確的GUID 應該是編寫C#dll 時產生的Guid

[Guid("1A8EB38C-E732-49B2-A897-B40FFD744E3D")]

 

我們只需要替換這個Guid即可,如果不這么做,調用時HRESULT會返回找不到實現接口。

 

 

 

 

  1. BCB 調用COM的代碼
    1. 在控制台工程中,加入代理類的頭文件 ComImpTest_tlb.h
    2. 代碼如下

//---------------------------------------------------------------------------

#pragma hdrstop

#include <iostream>

#include <vcl.h> //注意,iostream要在 vcl.h 前面定義,否則cout<<AnsiString 報錯

#include "Comimptest_tlb.h"

using namespace std;

//---------------------------------------------------------------------------

 

#pragma argsused

int main(int argc, char* argv[])

{

HRESULT hr;

//初始化COM

CoInitialize ( NULL );

//創建智能指針命名空間在頭文件Comimptest_tlb.h中可以查找到

//接口智能指針的定義也能查找到

    Comimptest_tlb::IComInterfacePtr ptr;

 

//創建實例,ComImp 的聲明,也能在頭文件中查找到。

    hr = ptr.CreateInstance(__uuidof (Comimptest_tlb::ComImp));

      

if(hr == S_OK)

{

//調用ADD方法

cout << ptr->Add (1, 2)<<endl;

//調用Hello方法,在bcbWidestring 對應 c# string

WideString name = "Zakk wylde 奧茲";

        ptr->Hello(name.c_bstr());

//調用COMINFO屬性,這里COM進行了名字改變,這些函數都可以在頭文件中查到原型定義。

BSTR outp = NULL;

ptr->get_COMINFO(&outp);

//因為是寬字符,所以要轉換為AnsiString進行輸出

cout<<AnsiString(outp)<<endl;

}

 

CoUninitialize ();

system("pause");

return 0;

}

 

 

 

 

4 用vc調用COM

用VC調用C#的COM 就沒有這么多事情。下面是VC調用的代碼,

將ComImpTest.tlb 和 ComImpTest.dll 拷貝到 VC工程的debug目錄下。然后用import指令(BCB 無法用import識別,估計是不兼容)

// testCOM3.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
#import "../debug/ComImpTest.tlb"

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr;
 //初始化COM
    CoInitialize ( NULL );   
    //創建智能指針
    ComImpTest::IComInterfacePtr ptr;

    //創建實例
    hr = ptr.CreateInstance(__uuidof (ComImpTest::ComImp));
     
    if(hr == S_OK)
    {
        cout << ptr->Add (1,2)<<endl;
        ptr->Hello(L"VC++ 調用");
        cout<<ptr->COMINFO<<endl;
    }        

    CoUninitialize (); 
    system("pause");
    return 0;
}


//---------------------------------------------------------------------------

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM