C++调用dotnet-第一节(ICLRRuntimeInfo加载宿主方式)
C++调用dotnet-第一节(ICLRRuntimeInfo加载宿主方式)
-------C++手动加载clr调用托管代码(非com方式)
注:目前非托管C++调用.NET托管代码,主要有两种方式(1.通过CLR提供的接口CLRRuntimeInfo在c++中加载clr然后通过clr调用托管代码;2.讲dotnet托管代码封装成com的方式)本文先讲解第一张
第一种方式与第二种方式对比:
CLR Hosting宿主方式:
A劣势: 调用方法签名只能是固定的形式[static int mathName(string paramstr))];另外在测试过程中发现弹窗操作提示为非法操作(理解为不能进行弹窗等涉及安全的操作);c++方调用较 为复杂(不过形式固定,第一次封装后,后面就方便了)
B优势:托管语言开发简单,部署简单方便
COM封装托管代码方式:
A劣势:开发较第一种复杂(需要托管代码中按com的开发模式进行封装,加载到GAC中还需要强命名)、部署环境也复杂(需要注册COM)
B优势:形式多样,可以继续弹框,甚至参数可以是类,结构体等;c++调用时方便
托管语言c#开发没有特殊要求,直接像平常开发dll一样,只要方法签名满足(静态,返回值为int,输入参数为一个string类型)就可以了
如下:
1 using IMWpfLib; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace CLRHostLib 9 { 10 public class ClrClass 11 { 12 public static int ClrExcute(string paramstr) { 13 14 Console.WriteLine("调用成功"); 15 IMComInterop cc = new IMComInterop(); 16 //这句代码中有弹框操作,会报错,不能有弹框之类涉及到用户安全的操作(弹框干涉到用户界面操作了) 17 cc.ShowWindowsTest(); 18 return 1; 19 } 20 21 } 22 }
c++方面稍微复杂一点
第一步:将之前编译的dll拷贝到exe所在目录
#pragma once //#include <Windows.h> //#include <stdio.h> //#include <iostream> //#include <mscoree.h> //#include <metahost.h> //#include <assert.h> //#pragma comment(lib, "mscoree.lib") #define BUFFER_SIZE 500 //#include "stdafx.h" // // // // // using namespace std; #include <windows.h> #include <metahost.h> #pragma comment(lib, "mscoree.lib") // Import mscorlib.tlb (Microsoft Common Language Runtime Class Library). #import "mscorlib.tlb" raw_interfaces_only \ high_property_prefixes("_get","_put","_putref") \ rename("ReportEvent", "InteropServices_ReportEvent") using namespace mscorlib; class DotNetRuntimeWrap { public: DotNetRuntimeWrap(void); ~DotNetRuntimeWrap(void); public: void StartTheDotNetRuntime(LPCWSTR runtimeVersion, LPCWSTR dllPath, LPCWSTR startClass, LPCWSTR startMethod, LPCWSTR startArgument); /************************************************* 加载托管dll调用入口 *************************************************/ public: void Loader(LPCWSTR donnetVersion,LPCWSTR clrDllFullName,LPCWSTR clrClassFullName,LPCWSTR clrMathName); public: void Test(); };
1 #include "stdafx.h" 2 #include "DotNetRuntimeWrap.h" 3 4 5 DotNetRuntimeWrap::DotNetRuntimeWrap(void) 6 { 7 8 } 9 10 11 DotNetRuntimeWrap::~DotNetRuntimeWrap(void) 12 { 13 } 14 15 void DotNetRuntimeWrap::StartTheDotNetRuntime(LPCWSTR runtimeVersion, LPCWSTR dllPath, LPCWSTR startClass, LPCWSTR startMethod, LPCWSTR startArgument) 16 { 17 ICLRMetaHost *pMetaHost = NULL; 18 ICLRMetaHostPolicy *pMetaHostPolicy = NULL; 19 ICLRDebugging *pCLRDebugging = NULL; 20 CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); 21 CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy); 22 CLRCreateInstance(CLSID_CLRDebugging, IID_ICLRDebugging, (LPVOID*)&pCLRDebugging); 23 DWORD dwVersion = 0; 24 DWORD dwImageVersion = 0; 25 ICLRRuntimeInfo *pRuntimeInfo; 26 HRESULT result; 27 result = pMetaHost->GetRuntime(runtimeVersion, IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); 28 assert(SUCCEEDED(result)); 29 ICLRRuntimeHost * pRuntimeHost = NULL; 30 result = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pRuntimeHost); 31 assert(SUCCEEDED(result)); 32 result = pRuntimeHost->Start(); 33 assert(SUCCEEDED(result)); 34 DWORD dwRetCode = 0; 35 result = pRuntimeHost->ExecuteInDefaultAppDomain(dllPath, startClass, startMethod, startArgument, &dwRetCode); 36 assert(SUCCEEDED(result)); 37 pRuntimeHost->Stop(); 38 pRuntimeHost->Release(); 39 pRuntimeInfo->Release(); 40 pCLRDebugging->Release(); 41 pMetaHostPolicy->Release(); 42 pMetaHost->Release(); 43 } 44 45 46 void DotNetRuntimeWrap::Loader(LPCWSTR donnetVersion,LPCWSTR clrDllFullName,LPCWSTR clrClassFullName,LPCWSTR clrMathName) 47 { 48 wchar_t* runtimeVersionSpace = new wchar_t[BUFFER_SIZE]; 49 wchar_t* dllPathSpace = new wchar_t[BUFFER_SIZE]; 50 wchar_t* currentDir = new wchar_t[BUFFER_SIZE]; 51 GetCurrentDirectoryW(BUFFER_SIZE, currentDir); 52 StartTheDotNetRuntime(donnetVersion,clrDllFullName,clrClassFullName,clrMathName, L""); 53 //StartTheDotNetRuntime(L"v4.0.30319", L"ClassLibrary1.dll", L"ClassLibrary1.Class1", L"EntryPoint", L""); 54 free(runtimeVersionSpace); 55 free(dllPathSpace); 56 free(currentDir); 57 } 58 void DotNetRuntimeWrap::Test() 59 { 60 }
下面是调用方式
1 #include "stdafx.h" 2 #include <iostream> 3 #include "DotNetRuntimeWrap.h" 4 5 static void TestClrHost() 6 { 7 8 DotNetRuntimeWrap dotNetWrap; 9 dotNetWrap.Loader(L"v4.0.30319", L"CLRHostLib.dll", 10 L"CLRHostLib.ClrClass",L"ClrExcute"); 11 12 } 13 14 int _tmain(int argc, _TCHAR* argv[]) 15 { 16 17 TestClrHost(); 18 19 return 0; 20 }
运行结果:普通操作一切正常,不过执行弹框的时候会出错(下面截图断点这一行里面有弹框操作),规避这类操作,运行就OK了