C++如何調用C#開發的dll

來源:互聯網
上載者:User

標籤:方法調用   描述   產生   win32   步驟   char   訪問   使用   cad   

轉載  http://www.cnblogs.com/huangmianwu/p/6145044.html

前言C++編寫的程式為Unmanaged 程式碼,C#編寫的程式為Managed 程式碼。Managed 程式碼雖然提供了其他開發平台沒有的許多優勢,但由於前期系統及曆史版本很多使用的是Unmanaged 程式碼編寫的程式,所以CLR提供了一些機制,允許在應用程式中同時包含託管和Unmanaged 程式碼。具體說分為以下三種:Managed 程式碼能調用DLL中的非託管函數。通過P/Invoke(Platform Invoke)機制調用DLL中的函數,如Kernel32.dll等。Managed 程式碼可以使用現有COM組件(伺服器)。許多公司都已經實現了大量非託管COM組件。利用來自這些組件的類型庫,可建立一個託管程式集來描述COM組件。Managed 程式碼可像訪問其他任何類型一樣訪問託管程式集中的類型。Unmanaged 程式碼可以使用託管類型(伺服器)。許多現有的Unmanaged 程式碼要求提供COM組件來確保代碼正確工作。使用Managed 程式碼可以更簡單地實現這些組件,避免所有代碼都不得不和引用計數和介面打交道。比如C++調用C#開發的dll。以上部分文字摘自《CLR via C#》,會比較難懂點。剛好工作中有通過C++調用C#開發的dll的經驗,也就是上述第3點。所以想藉此文記錄下開發的步驟和思路。後續有時間再把上述的1、2點補上,形成一個系列文章。本文1、用C#編寫dll該dll只簡單實現兩個功能:字串拼接和兩個數相加。先建立方法介面:Add和Join。代碼如下: 複製代碼 [Guid("254D1FBC-416B-422F-AE39-C923E8803396")] public interface ICalc { [DispId(1)] bool Add(string a, string b, out int c); [DispId(2)] void Join(string a, string b, out string c); }複製代碼為了更全面地介紹調用的方法類型,在這裡專門把Add方法傳回值定義為bool類型,結果通過輸出參數輸出,為int類型;Join方法無傳回值(void類型),結果通過輸出參數輸出,為string類型。其中DispId特性和GUID特性是必須的。DispId按順序編號即可。GUID的建立步驟為工具-->建立GUID-->選擇第5項,複製(針對VS2013)如所示:接下來建立繼承ICalc介面的Calc類,實現Add和Join方法,代碼如下。也需要建立GUID,步驟同上。複製代碼[Guid("F963B111-39FA-499D-9172-6102C79BB6E5")][ClassInterface(ClassInterfaceType.None)] public class Calc : ICalc { public bool Add(string a, string b, out int c) { int int_a; int int_b; if (!Int32.TryParse(a, out int_a)) { c = 0; return false; } if (!Int32.TryParse(b, out int_b)) { c = 0; return false; } c = int_a + int_b; return true; } public void Join(string a, string b, out string c) { c = a + b; return ; } }複製代碼 此外還需要設定“使程式集COM可見”和“為COM互操作註冊”“使程式集COM可見”步驟為:項目屬性-->“應用程式”項-->"程式集資訊"-->勾選“使程式集COM可見”,如所示:“為COM互操作註冊”設定步驟為:項目屬性-->“產生”項-->勾選“為COM互操作註冊”,如所示:注意:此項操作需要提供系統管理員許可權,啟動VS時請以“管理員身份運行”,否則產生解決方案時會出現對登錄機碼XXX的訪問被拒絕的錯誤。產生解決方案後,會產生dll和tlb兩個檔案。到此則已經完成C#端的工作了。接下來介紹通過regasm.exe產生註冊表檔案供使用者將dll註冊為COM組件。2、註冊dll為COM組件在本機開發時因為勾選了勾選“為COM互操作註冊”選項,所以產生解決方案時已經在本機將該dll註冊為COM組件,所以運行時不需再註冊,但如果是在其他機器上運行時,需要將dll註冊為COM組件後才可使用。在這裡我們通過regasm.exe產生註冊表檔案供使用者將dll註冊為COM組件(其實就是把GUID匯入註冊表)。指令檔如下:regasm E:\部落格園\UnmanagecodeCallManagecode\CalcClass\CalcClass\bin\Debug\CalcClass.dllregasm E:\部落格園\UnmanagecodeCallManagecode\CalcClass\CalcClass\bin\Debug\CalcClass.dll /tlb: CalcClass.tlbregasm E:\部落格園\UnmanagecodeCallManagecode\CalcClass\CalcClass\bin\Debug\CalcClass.dll /regfile: CalcClass.reg注意使用的regasm.exe版本與開發dll所使用的.NET Framework版本最好保持一致。運行該指令碼產生CalcClass.reg檔案。在其他機器上運行該檔案,即可註冊該COM組件,才能正常使用。接下來是如何將其封裝成COM組件的問題了。3、將dll封裝成COM組件建立工作空間,選擇Win32 Dynamic-Link Library,類型為簡單DLL工程。將上述產生的dll和tlb兩個檔案拷貝至工作空間檔案路徑下。在StdAfx.h標頭檔下增加以下兩行代碼匯入dll:(內容需要根據tlb檔案名稱和命名空間做更改)#import "CalcClass.tlb"using namespace CalcClass;在cpp檔案中添加以下方法聲明(聲明為C編譯串連方式的外部函數),也可建立標頭檔後包含進來。extern "C"_declspec(dllexport)BOOL Add(char* a,char* b,long* c);extern "C"_declspec(dllexport)void Join(char* a,char* b,char* c);實現聲明的兩個方法:複製代碼BOOL Add (char* a,char* b,long* c){ CoInitialize(NULL); CalcClass::ICalcPtr CalcPtr(__uuidof(Calc));//擷取Calc所關聯的GUID VARIANT_BOOL ret = CalcPtr->Add(_bstr_t(a),_bstr_t(b),c); CalcPtr->Release(); CoUninitialize(); if( ret == -1 ) return 1; else return ret;}void Join (char* a,char* b,char* c){ CoInitialize(NULL); CalcClass::ICalcPtr CalcPtr(__uuidof(Calc));//擷取Calc所關聯的GUID BSTR temp; CalcPtr->Join(_bstr_t(a),_bstr_t(b),&temp); strcpy(c , _com_util::ConvertBSTRToString(temp)); CalcPtr->Release(); CoUninitialize(); }複製代碼這裡做兩點說明:1、對於VARIANT_BOOL類型做個簡單介紹:-1表示true,0表示false。(這點確實顛覆了我們對bool值的常規理解)2、C#的out參數轉換為C++時必須傳指標變數,也就是說傳參時須對變數進行取指操作,這也是輸出參數的本質。(可以通過tlb檔案參考調用,或者產生後參考查看tli或tlh檔案)編譯成功後則完成了dll封裝為COM組件的任務。至此,C++即可調用C#編寫的dll了。下面將展示一個調用的DEMO樣本。4、調用DEMO樣本建立工作空間,選擇Win32 exe,類型為對話方塊。設計介面如下所示,添加按鈕事件OnAddbtn和OnJoinbtn聲明方法,代碼如下:typedef BOOL (* Add)(char* a,char* b,long* c);typedef void (* Join)(char* a,char* b,char* c);OnAddbtn事件響應代碼如下:複製代碼void CCalcComDemoDlg::OnAddbtn() { // TODO: Add your control notification handler code here BOOL ret; long result; char A[255]; char B[255]; CString str_A; CString str_B; GetDlgItem(IDC_EDIT1)->GetWindowText(str_A); GetDlgItem(IDC_EDIT2)->GetWindowText(str_B); strcpy(A,str_A); strcpy(B,str_B); HINSTANCE calc; calc = LoadLibrary(TEXT("CalcCom.dll")); if (NULL == calc) { MessageBox("cant‘t find dll"); return; } Add _Add=(Add)::GetProcAddress(calc,"Add"); if (NULL == _Add) { MessageBox("cant‘t find function"); return; } else { ret = _Add(A,B,&result); CString boxMsg; boxMsg.Format("Reslut: %d\nMessage:%ld\n",ret,result); MessageBox(boxMsg); }}複製代碼OnJoinbtn事件響應代碼如下:複製代碼void CCalcComDemoDlg::OnJoinbtn() { // TODO: Add your control notification handler code here char A[255]; char B[255]; CString str_A; CString str_B; GetDlgItem(IDC_EDIT1)->GetWindowText(str_A); GetDlgItem(IDC_EDIT2)->GetWindowText(str_B); strcpy(A,str_A); strcpy(B,str_B); char result[255]; HINSTANCE calc; calc = LoadLibrary(TEXT("CalcCom.dll")); if (NULL == calc) { MessageBox("cant‘t find dll"); return; } Join _Join=(Join)::GetProcAddress(calc,"Join"); if (NULL == _Join) { MessageBox("cant‘t find function"); return; } else { _Join(A,B,result); CString boxMsg; boxMsg.Format("Message:%s\n",result); MessageBox(boxMsg); }}複製代碼這裡用的是LoadLibrary(TEXT("CalcCom.dll")),預設為exe執行路徑下的dll。所以編譯完成後將上述產生的COM組件dll拷貝到exe執行路徑下。當然也可直接指定dll的路徑。運行程式即可驗證是否成功調用C#編寫的dll。如所示。Add方法調用結果Join方法調用結果附件為程式原始碼。僅供參考。 http://files.cnblogs.com/files/huangmianwu/UnmanagecodeCallManagecode.rar

 

C++如何調用C#開發的dll

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.