最近,做产品开发,需要在非托管的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);
按照以上操作,就完成了整个过程。以上,是我的学习过程遇到的问题和解决办法,记录下来防止自己忘记,同时也与大家分享,免走弯路。