你的位置:首页 > ASP.net教程

[ASP.net教程]C++调用C#dll类库中的方法(非显性COM)


        一般在网上搜C++如何调用C#的函数,出来的结果都是做成COM组件,但是这种方法dll安装麻烦,需要注册COM组件,需要管理员权限,调试麻烦,经常需要重启机器,反正有诸多不便。

        然后在看《CLR via C#》时看到一种方法,可以免去这种苦恼。少废话,先上代码。

C#类库的:

namespace ClassLibrary1{  public class Class1  {    public static int pwzMethodName(String pwzArgument)    {      //Thread.Sleep(10000);      Console.WriteLine(pwzArgument);      Console.WriteLine(Thread.GetDomain().FriendlyName);    }  }}

C++调用代码:

#include <metahost.h>#include <fstream>using namespace std;#pragma comment(lib, "mscoree.lib")int _tmain(int argc, _TCHAR* argv[]){  ICLRMetaHost *pMetaHost = nullptr;  ICLRMetaHostPolicy *pMetaHostPolicy = nullptr;   ICLRRuntimeHost *pRuntimeHost = nullptr;   ICLRRuntimeInfo *pRuntimeInfo = nullptr;   HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);   hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));   if(FAILED(hr)) {     MessageBox(0,L"启动出错",L"Error",MB_OK|MB_ICONERROR);    goto cleanup;   }   hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost));   hr = pRuntimeHost->Start();   DWORD dwRet = 0;   hr = pRuntimeHost->ExecuteInDefaultAppDomain(L"ClassLibrary1.dll", //不会产生新的进程    L"ClassLibrary1.Class1",     L"pwzMethodName",     L"nimei",     &dwRet);   hr = pRuntimeHost->Stop(); cleanup:   if(pRuntimeInfo != nullptr) {     pRuntimeInfo->Release();     pRuntimeInfo = nullptr;   }   if(pRuntimeHost != nullptr) {     pRuntimeHost->Release();     pRuntimeHost = nullptr;   }   if(pMetaHost != nullptr) {     pMetaHost->Release();     pMetaHost = nullptr;   } }

C#的代码就不解释了,就是提供一个int ClassLibrary1.Class1.pwzMethodName(String)的这样一个方法。

重点看一下C++,它的思路就是通过metahost.h中的函数来操作clr环境。

第一句,CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost) 来初始化CLR环境,得到返回值pMetaHost。

第二句,pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)) 来指定运行时,第一个参数.NET版本号,必须和你的C#dll的版本号兼容,而且 此参数必须与显示在 C:\Windows\Microsoft.NET\Framework 或 C:\Windows\Microsoft.NET\Framework64 下的 .NET Framework 版本目录名称相匹配。比如,你的dll是用4.0编译的,而你的Framework目录有一下文件夹:v2.0.50727   v3.0   v3.5   v4.0.30319 ,所以这里的参数就是“v4.0.30319”,而且v是必须的。

第三句,pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost)) 将 CLR 加载到当前进程中,并返回运行时接口指针pRuntimeHost。

第四句,pRuntimeHost->Start() 将公共语言运行时 (CLR) 初始化到进程中。

第五句,pRuntimeHost->ExecuteInDefaultAppDomain

HRESULT ExecuteInDefaultAppDomain (  [in] LPCWSTR pwzAssemblyPath,  [in] LPCWSTR pwzTypeName,   [in] LPCWSTR pwzMethodName,  [in] LPCWSTR pwzArgument,  [out] DWORD *pReturnValue);

pwzAssemblyPath是C#类库的路径和文件名,pwzTypeName是命名空间和类名,pwzMethodName是要调用的方法名称,pwzArgument是要传入的参数名称,pReturnValue是函数返回值。

后面的都是释放语句。

一般看来,这种方法只能调用int function(String para)这样的函数,但是实际上LPCWSTR 是WCHAR *,既然是指针就可以传递对象,同样返回值也可以是结构体或者数组。

本例地址:http://files.cnblogs.com/files/chihirosan/CPPCS%E4%BA%A4%E4%BA%92.rar