天天看點

c++ 非托管程式調用c#托管程式l的實作操作方式

        最近,做産品開發,需要在非托管的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);

   按照以上操作,就完成了整個過程。以上,是我的學習過程遇到的問題和解決辦法,記錄下來防止自己忘記,同時也與大家分享,免走彎路。

繼續閱讀