最近,做産品開發,需要在非托管的c++程式調用c#的托管程式。經過試驗,整理了一種簡便方法,但該方法局限比較多,後面會推薦另外一個方式。現在先介紹該方法的操作步驟如下:
1.建立c#的dll中接口的定義參看下面的示例。注意接口中的函數必須為靜态的函數,輸入參數隻能有一個字元串類型,傳回值必須為int,具體參看下面說明。
using System.IO;
using System.Xml;
using System.Data;
namespace CLRLib
{
/// <summary>
/// 此類為和c++互動的接口類,成員函數均為靜态函數
/// </summary>
class cgCLRLibAccessAdapter
{
/// <summary>
/// 測試
/// </summary>
/// <param name="szParam">标志參數</param>
/// <returns>傳回值</returns>
// 備注:接口函數隻能為靜态函數,傳回值隻能為Int,輸入參數隻能有一個字元串
public static Int32 IsTest(String szParam)
{
int i= 2;
return i;
}
}
}
2.定義了類cgCLRAccess用來操作通路c#類的函數。具體類的定義參看附件檔案cgCLRAcess.h和cgCLRAcess.cpp。
檔案cgCLRAcess.h:
#pragma once
#include "stdafx.h"
#include <MSCorEE.h>
//=========================================================================
//通路CLRDll的相關類
class cgCLRAccess
{
private:
CString m_szFileName; //動态庫檔案全名
CString m_szClassName; //c#類名稱
ICLRRuntimeHost *m_pClrHost; //CLR運作時态宿主
CString m_szNetFrameVersion; //dll的目标FrameWork版本
public:
cgCLRAccess(CString fileName,CString className,CString netFrameVersion);
~cgCLRAccess();
//運作方法
int RunMethod(CString szMethodName,CString szParamString);
};
檔案cgCLRAcess.cpp:
#include "StdAfx.h"
#include "cgCLRAccess.h"
#include <Windows.h>
#include <assert.h>
#include <Windows.h>
#include <MSCorEE.h>
using namespace std;
#pragma comment(lib,"mscoree.lib")
// ---------------------------------------------------------------
// 名稱: cgCLRAccess
// 功能: 構造函數
// 變量: [in] fileName -- dll檔案名
// [in] className -- 類名,包含命名空間
// [in] netFrameVersion -- NetFrame版本号
// 傳回: 傳回值int表示結果,-1,表示運作方法失敗
// 編寫: 張偉強,20170725
// ---------------------------------------------------------------
cgCLRAccess::cgCLRAccess(CString fileName,CString className,CString netFrameVersion)
{
m_szFileName=fileName;
m_szClassName=className;
m_szNetFrameVersion=netFrameVersion;
m_pClrHost =NULL;
//注意隻能調用一次,第一個需要傳遞c#dll的.net framework版本号,預設空為2.0
HRESULT hr = CorBindToRuntimeEx(m_szNetFrameVersion,
NULL,0,
CLSID_CLRRuntimeHost,
IID_ICLRRuntimeHost,
(PVOID*)&m_pClrHost);
if(hr != S_OK||hr != S_FAILED)
{
m_pClrHost = NULL;
return;
}
if(m_pClrHost)
{
hr=m_pClrHost->Start();
}
}
cgCLRAccess::~cgCLRAccess()
{
if(m_pClrHost != NULL)--隻能加載一次
{
m_pClrHost->Stop();
m_pClrHost->Release();
}
}
// ---------------------------------------------------------------
// 名稱: RunMethod
// 功能: 運作方法
// 變量: [in] szMethodName -- 方法名稱
// [in] szParamString -- 方法參數
// 傳回: 傳回值int表示結果,-1,表示運作方法失敗
// 編寫: 張偉強,20170725
// ---------------------------------------------------------------
int cgCLRAccess::RunMethod(CString szMethodName,CString szParamString)
{
DWORD retVal=0;
//将dll加載到預設應用程式域中,并調用其中的方法
HRESULT hr = m_pClrHost->ExecuteInDefaultAppDomain(m_szFileName,m_szClassName,szMethodName,
szParamString,&retVal);
//後面增加錯誤處理
if(hr!=S_OK)
{
retVal = -1;
}
return retVal;
}
3.c++調用的代碼如下:
CString szParam=_T("test");
// 需要注意,這個類隻能定義一次。_T("v4.0.30319")為c#依賴的.NetFrame版本号,如果傳遞錯誤,則會導緻後面運作ExecuteInDefaultAppDomain出錯,錯誤代碼-2146234341或者FFFFFFFF8013101B。CLRLib.dll 為dll庫的檔案名,需要時要帶路徑
cgCLRAccess clrAccess(_T("CLRLib.dll"),_T("CLRLib.cgCLRLibAccessAdapter"),_T("v4.0.30319"));
int nRet =clrAccess.RunMethod(_T("IsTest"),szParam);
按照以上操作,就完成了整個過程。以上,是我的學習過程遇到的問題和解決辦法,記錄下來防止自己忘記,同時也與大家分享,免走彎路。