這個主題在《c#高級編程》中有提到,可以下本電子書來看看。一下我也列出自己的學習筆記。
根據網上的說法,C#調用C++至少有以下幾種方法:
1通過COM組件調用
2通過MC++轉接
3利用Intptr
由於我只能成功使用COM組件的方法,所以下面只談一下這個方法。
一.通過ALT建立COM組件
1、創建ATL Project
步驟1:建立一個解決方案。 步驟2:在 該解決方案中,新建一個 vc++ 的 ATL 項目。見下圖
選擇Dynamic-link library(DLL)
2、向工程中添加ATL對象
選擇ATL Simple Object
名字為FunTest
Interface選擇Custom
3、在接口中添加方法.(在類視圖中)
方法名為Sum,參數如下圖,有三個參數
接口方法的實現, 這個太簡單了
STDMETHODIMP CFunTest::Sum(LONG num1, LONG num2, LONG* pVal) { // TODO: Add your implementation code here *pVal = num1 + num2; return S_OK; }
二.在C#中調用COM組件
1、新建一個C# console項目,比如叫Test(winform的也是一樣道理,只是Console調試更方便而已。第一次在C#中調用COM組件時,建議先用Console試試,否則會搞得一頭煙)
2、添加引用:
在彈出的對話框中選COM子頁,找到ATLProjectTest 1.0類型庫(或類似的東西)
就會發現在Test->引用下多了ATLProjectTestLib
3在主函數(program.cs)中調用組件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using ATLProjectTestLib; namespace Test { class Program { static void Main(string[] args) { ATLProjectTestLib.FunTestClass f1 = new FunTestClass(); Console.Write (f1.Sum(3,4)); } } }
三.很多的細節及注意事項
僅按上面一步步地操作下來發現還會出錯,會說找不到XX COM組件,或是COM組件沒注冊。實際上很多不當操作都會導致上面這個錯誤。只有當你生成的文件中有Interop.ATLProjectTestLib.dll時,你才算成功了。
1、所有修改都要重新編譯。如修改了ATL項目,首先要重新編譯ATL,再重新編譯C# project。當把項目移到另一台計算機,有時編譯器由於ATL項目沒有被修改,而不會重新編譯,這就無法寫注冊表。這時可以把ATL項目的Debug文件夾刪除,再重新編譯。
2、在創建ATL project時,由於一個選Dual或Custom的地方,我認為應該選Dual,但網上較多文章選Custom。
以下是選了Custom后應做的補救,
回到ATLProjectTest,在ATLProjectTest.idl中(或雙擊 類視圖->IFunTest)
import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(90477521-7218-4CA1-AADC-EAF3C42AB24B), dual, //--------按原做法不設這個屬性,只有設了這個屬性才不會錯 helpstring("IFunTest 接口"), pointer_default(unique) ]
3、ATL默認按32位編譯,而C#中一般是按any CPU形式,像我是64位機的就要小心了。要改一下C#項目中的生成規則。
點擊項目的屬性頁:
設置目標平台為x86
4、做完上面這3點,大概Test應該能運行了。可以先跳到第四大點看完后再倒回來。
在實際的工程中,一般有很多個項目,假設以C#項目為主,還有一個ATL項目ATLProjectTest。而這個ATLProjectTest被Business項目(邏輯層)調用,而Business又被Form項目(用戶層)調用,這都是很常見的。
在“編譯”時就不能直接啟動調試,要按ATLProjectTest->Business->Form的順序一個個地生成項目。
5、有時會因為找不到Interop.ATLProjectTestLib.dll而出錯,可以試着把各個項目的輸出路徑都改到同一個文件夾(如用戶層工程的文件夾)。
四.更具體的編程
ATL與C#類型對應
ATL |
C# |
LONG |
int |
DOUBLE |
double |
CHAR |
sbyte |
VARIANT_BOOL |
bool |
BSTR |
string |
* |
ref |
在C++中更多用STL string來寫
BSTR與STL string的轉化方法
#include <iostream> #include <string> #include<comutil.h> #pragma comment(lib,"comsuppw") using namespace std; string str; //STL string BSTR bs; bs = _com_util::ConvertStringToBSTR(str.c_str()); str = _com_util::ConvertBSTRToString(bs);
解決了字符串的問題數組和對象都好辦,因為可以序列化。
有關構造函數和析構函數我還不太會怎么做,但可以自定義Init()和ToEnd()來應付一下。
就寫到這里了,還有很多不懂得,請多多指正!