native C++ 动态调用.NET DLL

时间:2022-09-01 12:52:49

关于这个问题找了好多地方,都只有第二种解决办法,可是我要返回一个字符串,没办法,继续找,最后还是在http://blogs.msdn.com/b/msdnforum/archive/2010/07/09/use-clr4-hosting-api-to-invoke-net-assembly-from-native-c.aspx找到了解决的办法,这里记下来备忘。

转发下范例包:http://files.cnblogs.com/files/maintell/Cpp_app_hosts_CLR_4_and_invokes_.NET_assembly_%28CppHostCLR%29.zip

第一种可以返回一个任意变量或者对象,第二种简单点,只能返回整型,具体看代码:

  1 //
  2 //   FUNCTION: RuntimeHostV4Demo1(PCWSTR, PCWSTR)
  3 //
  4 //   PURPOSE: The function demonstrates using .NET Framework 4.0 Hosting 
  5 //   Interfaces to host a .NET runtime, and use the ICorRuntimeHost interface
  6 //   that was provided in .NET v1.x to load a .NET assembly and invoke its 
  7 //   type. 
  8 //   
  9 //   If the .NET runtime specified by the pszVersion parameter cannot be 
 10 //   loaded into the current process, the function prints ".NET runtime <the 
 11 //   runtime version> cannot be loaded", and return.
 12 //   
 13 //   If the .NET runtime is successfully loaded, the function loads the 
 14 //   assembly identified by the pszAssemblyName parameter. Next, the function 
 15 //   instantiates the class (pszClassName) in the assembly, calls its 
 16 //   ToString() member method, and print the result. Last, the demo invokes 
 17 //   the public static function 'int GetStringLength(string str)' of the class 
 18 //   and print the result too.
 19 //
 20 //   PARAMETERS:
 21 //   * pszVersion - The desired DOTNETFX version, in the format “vX.X.XXXXX”. 
 22 //     The parameter must not be NULL. It’s important to note that this 
 23 //     parameter should match exactly the directory names for each version of
 24 //     the framework, under C:\Windows\Microsoft.NET\Framework[64]. The 
 25 //     current possible values are "v1.0.3705", "v1.1.4322", "v2.0.50727" and 
 26 //     "v4.0.30319". Also, note that the “v” prefix is mandatory.
 27 //   * pszAssemblyName - The display name of the assembly to be loaded, such 
 28 //     as "CSClassLibrary". The ".DLL" file extension is not appended.
 29 //   * pszClassName - The name of the Type that defines the method to invoke.
 30 //
 31 //   RETURN VALUE: HRESULT of the demo.
 32 //
 33 HRESULT RuntimeHostV4Demo1(PCWSTR pszVersion, PCWSTR pszAssemblyName, 
 34     PCWSTR pszClassName)
 35 {
 36     HRESULT hr;
 37 
 38     ICLRMetaHost *pMetaHost = NULL;
 39     ICLRRuntimeInfo *pRuntimeInfo = NULL;
 40 
 41     // ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting interfaces
 42     // supported by CLR 4.0. Here we demo the ICorRuntimeHost interface that 
 43     // was provided in .NET v1.x, and is compatible with all .NET Frameworks. 
 44     ICorRuntimeHost *pCorRuntimeHost = NULL;
 45 
 46     IUnknownPtr spAppDomainThunk = NULL;
 47     _AppDomainPtr spDefaultAppDomain = NULL;
 48 
 49     // The .NET assembly to load.
 50     bstr_t bstrAssemblyName(pszAssemblyName);
 51     _AssemblyPtr spAssembly = NULL;
 52 
 53     // The .NET class to instantiate.
 54     bstr_t bstrClassName(pszClassName);
 55     _TypePtr spType = NULL;
 56     variant_t vtObject;
 57     variant_t vtEmpty;
 58 
 59     // The static method in the .NET class to invoke.
 60     bstr_t bstrStaticMethodName(L"GetStringLength");
 61     SAFEARRAY *psaStaticMethodArgs = NULL;
 62     variant_t vtStringArg(L"HelloWorld");
 63     variant_t vtLengthRet;
 64 
 65     // The instance method in the .NET class to invoke.
 66     bstr_t bstrMethodName(L"ToString");
 67     SAFEARRAY *psaMethodArgs = NULL;
 68     variant_t vtStringRet;
 69 
 70     // 
 71     // Load and start the .NET runtime.
 72     // 
 73 
 74     wprintf(L"Load and start the .NET runtime %s \n", pszVersion);
 75 
 76     hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
 77     if (FAILED(hr))
 78     {
 79         wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr);
 80         goto Cleanup;
 81     }
 82 
 83     // Get the ICLRRuntimeInfo corresponding to a particular CLR version. It 
 84     // supersedes CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE.
 85     hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
 86     if (FAILED(hr))
 87     {
 88         wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
 89         goto Cleanup;
 90     }
 91 
 92     // Check if the specified runtime can be loaded into the process. This 
 93     // method will take into account other runtimes that may already be 
 94     // loaded into the process and set pbLoadable to TRUE if this runtime can 
 95     // be loaded in an in-process side-by-side fashion. 
 96     BOOL fLoadable;
 97     hr = pRuntimeInfo->IsLoadable(&fLoadable);
 98     if (FAILED(hr))
 99     {
100         wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
101         goto Cleanup;
102     }
103 
104     if (!fLoadable)
105     {
106         wprintf(L".NET runtime %s cannot be loaded\n", pszVersion);
107         goto Cleanup;
108     }
109 
110     // Load the CLR into the current process and return a runtime interface 
111     // pointer. ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting  
112     // interfaces supported by CLR 4.0. Here we demo the ICorRuntimeHost 
113     // interface that was provided in .NET v1.x, and is compatible with all 
114     // .NET Frameworks. 
115     hr = pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, 
116         IID_PPV_ARGS(&pCorRuntimeHost));
117     if (FAILED(hr))
118     {
119         wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
120         goto Cleanup;
121     }
122 
123     // Start the CLR.
124     hr = pCorRuntimeHost->Start();
125     if (FAILED(hr))
126     {
127         wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
128         goto Cleanup;
129     }
130 
131     // 
132     // Load the NET assembly. Call the static method GetStringLength of the 
133     // class CSSimpleObject. Instantiate the class CSSimpleObject and call 
134     // its instance method ToString.
135     // 
136 
137     // The following C++ code does the same thing as this C# code:
138     // 
139     //   Assembly assembly = AppDomain.CurrentDomain.Load(pszAssemblyName);
140     //   object length = type.InvokeMember("GetStringLength", 
141     //       BindingFlags.InvokeMethod | BindingFlags.Static | 
142     //       BindingFlags.Public, null, null, new object[] { "HelloWorld" });
143     //   object obj = assembly.CreateInstance("CSClassLibrary.CSSimpleObject");
144     //   object str = type.InvokeMember("ToString", 
145     //       BindingFlags.InvokeMethod | BindingFlags.Instance | 
146     //       BindingFlags.Public, null, obj, new object[] { });
147 
148     // Get a pointer to the default AppDomain in the CLR.
149     hr = pCorRuntimeHost->GetDefaultDomain(&spAppDomainThunk);
150     if (FAILED(hr))
151     {
152         wprintf(L"ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr);
153         goto Cleanup;
154     }
155 
156     hr = spAppDomainThunk->QueryInterface(IID_PPV_ARGS(&spDefaultAppDomain));
157     if (FAILED(hr))
158     {
159         wprintf(L"Failed to get default AppDomain w/hr 0x%08lx\n", hr);
160         goto Cleanup;
161     }
162 
163     // Load the .NET assembly.
164     wprintf(L"Load the assembly %s\n", pszAssemblyName);
165     hr = spDefaultAppDomain->Load_2(bstrAssemblyName, &spAssembly);
166     if (FAILED(hr))
167     {
168         wprintf(L"Failed to load the assembly w/hr 0x%08lx\n", hr);
169         goto Cleanup;
170     }
171 
172     // Get the Type of CSSimpleObject.
173     hr = spAssembly->GetType_2(bstrClassName, &spType);
174     if (FAILED(hr))
175     {
176         wprintf(L"Failed to get the Type interface w/hr 0x%08lx\n", hr);
177         goto Cleanup;
178     }
179 
180     // Call the static method of the class: 
181     //   public static int GetStringLength(string str);
182 
183     // Create a safe array to contain the arguments of the method. The safe 
184     // array must be created with vt = VT_VARIANT because .NET reflection 
185     // expects an array of Object - VT_VARIANT. There is only one argument, 
186     // so cElements = 1.
187     psaStaticMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 1);
188     LONG index = 0;
189     hr = SafeArrayPutElement(psaStaticMethodArgs, &index, &vtStringArg);
190     if (FAILED(hr))
191     {
192         wprintf(L"SafeArrayPutElement failed w/hr 0x%08lx\n", hr);
193         goto Cleanup;
194     }
195 
196     // Invoke the "GetStringLength" method from the Type interface.
197     hr = spType->InvokeMember_3(bstrStaticMethodName, static_cast<BindingFlags>(
198         BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public), 
199         NULL, vtEmpty, psaStaticMethodArgs, &vtLengthRet);
200     if (FAILED(hr))
201     {
202         wprintf(L"Failed to invoke GetStringLength w/hr 0x%08lx\n", hr);
203         goto Cleanup;
204     }
205 
206     // Print the call result of the static method.
207     wprintf(L"Call %s.%s(\"%s\") => %s\n", 
208         static_cast<PCWSTR>(bstrClassName), 
209         static_cast<PCWSTR>(bstrStaticMethodName), 
210         static_cast<PCWSTR>(vtStringArg.bstrVal), 
211         vtLengthRet.lVal);
212 
213     // Instantiate the class.
214     hr = spAssembly->CreateInstance(bstrClassName, &vtObject);
215     if (FAILED(hr))
216     {
217         wprintf(L"Assembly::CreateInstance failed w/hr 0x%08lx\n", hr);
218         goto Cleanup;
219     }
220 
221     // Call the instance method of the class.
222     //   public string ToString();
223 
224     // Create a safe array to contain the arguments of the method.
225     psaMethodArgs = SafeArrayCreateVector(VT_VARIANT, 0, 0);
226 
227     // Invoke the "ToString" method from the Type interface.
228     hr = spType->InvokeMember_3(bstrMethodName, static_cast<BindingFlags>(
229         BindingFlags_InvokeMethod | BindingFlags_Instance | BindingFlags_Public),
230         NULL, vtObject, psaMethodArgs, &vtStringRet);
231     if (FAILED(hr))
232     {
233         wprintf(L"Failed to invoke ToString w/hr 0x%08lx\n", hr);
234         goto Cleanup;
235     }
236 
237     // Print the call result of the method.
238     wprintf(L"Call %s.%s() => %s\n", 
239         static_cast<PCWSTR>(bstrClassName), 
240         static_cast<PCWSTR>(bstrMethodName), 
241         static_cast<PCWSTR>(vtStringRet.bstrVal));
242 
243 Cleanup:
244 
245     if (pMetaHost)
246     {
247         pMetaHost->Release();
248         pMetaHost = NULL;
249     }
250     if (pRuntimeInfo)
251     {
252         pRuntimeInfo->Release();
253         pRuntimeInfo = NULL;
254     }
255     if (pCorRuntimeHost)
256     {
257         // Please note that after a call to Stop, the CLR cannot be 
258         // reinitialized into the same process. This step is usually not 
259         // necessary. You can leave the .NET runtime loaded in your process.
260         //wprintf(L"Stop the .NET runtime\n");
261         //pCorRuntimeHost->Stop();
262 
263         pCorRuntimeHost->Release();
264         pCorRuntimeHost = NULL;
265     }
266 
267     if (psaStaticMethodArgs)
268     {
269         SafeArrayDestroy(psaStaticMethodArgs);
270         psaStaticMethodArgs = NULL;
271     }
272     if (psaMethodArgs)
273     {
274         SafeArrayDestroy(psaMethodArgs);
275         psaMethodArgs = NULL;
276     }
277 
278     return hr;
279 }

第二种比较简单:

native C++ 动态调用.NET DLLnative C++ 动态调用.NET DLL
  1 //
  2 //   FUNCTION: RuntimeHostV4Demo2(PCWSTR, PCWSTR)
  3 //
  4 //   PURPOSE: The function demonstrates using .NET Framework 4.0 Hosting 
  5 //   Interfaces to host a .NET runtime, and use the ICLRRuntimeHost interface
  6 //   that was provided in .NET v2.0 to load a .NET assembly and invoke its 
  7 //   type. Because ICLRRuntimeHost is not compatible with .NET runtime v1.x, 
  8 //   the requested runtime must not be v1.x.
  9 //   
 10 //   If the .NET runtime specified by the pszVersion parameter cannot be 
 11 //   loaded into the current process, the function prints ".NET runtime <the 
 12 //   runtime version> cannot be loaded", and return.
 13 //   
 14 //   If the .NET runtime is successfully loaded, the function loads the 
 15 //   assembly identified by the pszAssemblyName parameter. Next, the function 
 16 //   invokes the public static function 'int GetStringLength(string str)' of 
 17 //   the class and print the result.
 18 //
 19 //   PARAMETERS:
 20 //   * pszVersion - The desired DOTNETFX version, in the format “vX.X.XXXXX”. 
 21 //     The parameter must not be NULL. It’s important to note that this 
 22 //     parameter should match exactly the directory names for each version of
 23 //     the framework, under C:\Windows\Microsoft.NET\Framework[64]. Because 
 24 //     the ICLRRuntimeHost interface does not support the .NET v1.x runtimes, 
 25 //     the current possible values of the parameter are "v2.0.50727" and 
 26 //     "v4.0.30319". Also, note that the “v” prefix is mandatory.
 27 //   * pszAssemblyPath - The path to the Assembly to be loaded.
 28 //   * pszClassName - The name of the Type that defines the method to invoke.
 29 //
 30 //   RETURN VALUE: HRESULT of the demo.
 31 //
 32 HRESULT RuntimeHostV4Demo2(PCWSTR pszVersion, PCWSTR pszAssemblyPath, 
 33     PCWSTR pszClassName)
 34 {
 35     HRESULT hr;
 36 
 37     ICLRMetaHost *pMetaHost = NULL;
 38     ICLRRuntimeInfo *pRuntimeInfo = NULL;
 39 
 40     // ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting interfaces
 41     // supported by CLR 4.0. Here we demo the ICLRRuntimeHost interface that 
 42     // was provided in .NET v2.0 to support CLR 2.0 new features. 
 43     // ICLRRuntimeHost does not support loading the .NET v1.x runtimes.
 44     ICLRRuntimeHost *pClrRuntimeHost = NULL;
 45 
 46     // The static method in the .NET class to invoke.
 47     PCWSTR pszStaticMethodName = L"GetStringLength";
 48     PCWSTR pszStringArg = L"HelloWorld";
 49     DWORD dwLengthRet;
 50 
 51     // 
 52     // Load and start the .NET runtime.
 53     // 
 54 
 55     wprintf(L"Load and start the .NET runtime %s \n", pszVersion);
 56 
 57     hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost));
 58     if (FAILED(hr))
 59     {
 60         wprintf(L"CLRCreateInstance failed w/hr 0x%08lx\n", hr);
 61         goto Cleanup;
 62     }
 63 
 64     // Get the ICLRRuntimeInfo corresponding to a particular CLR version. It 
 65     // supersedes CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE.
 66     hr = pMetaHost->GetRuntime(pszVersion, IID_PPV_ARGS(&pRuntimeInfo));
 67     if (FAILED(hr))
 68     {
 69         wprintf(L"ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr);
 70         goto Cleanup;
 71     }
 72 
 73     // Check if the specified runtime can be loaded into the process. This 
 74     // method will take into account other runtimes that may already be 
 75     // loaded into the process and set pbLoadable to TRUE if this runtime can 
 76     // be loaded in an in-process side-by-side fashion. 
 77     BOOL fLoadable;
 78     hr = pRuntimeInfo->IsLoadable(&fLoadable);
 79     if (FAILED(hr))
 80     {
 81         wprintf(L"ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr);
 82         goto Cleanup;
 83     }
 84 
 85     if (!fLoadable)
 86     {
 87         wprintf(L".NET runtime %s cannot be loaded\n", pszVersion);
 88         goto Cleanup;
 89     }
 90 
 91     // Load the CLR into the current process and return a runtime interface 
 92     // pointer. ICorRuntimeHost and ICLRRuntimeHost are the two CLR hosting  
 93     // interfaces supported by CLR 4.0. Here we demo the ICLRRuntimeHost 
 94     // interface that was provided in .NET v2.0 to support CLR 2.0 new 
 95     // features. ICLRRuntimeHost does not support loading the .NET v1.x 
 96     // runtimes.
 97     hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, 
 98         IID_PPV_ARGS(&pClrRuntimeHost));
 99     if (FAILED(hr))
100     {
101         wprintf(L"ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr);
102         goto Cleanup;
103     }
104 
105     // Start the CLR.
106     hr = pClrRuntimeHost->Start();
107     if (FAILED(hr))
108     {
109         wprintf(L"CLR failed to start w/hr 0x%08lx\n", hr);
110         goto Cleanup;
111     }
112 
113     // 
114     // Load the NET assembly and call the static method GetStringLength of 
115     // the type CSSimpleObject in the assembly.
116     // 
117 
118     wprintf(L"Load the assembly %s\n", pszAssemblyPath);
119 
120     // The invoked method of ExecuteInDefaultAppDomain must have the 
121     // following signature: static int pwzMethodName (String pwzArgument)
122     // where pwzMethodName represents the name of the invoked method, and 
123     // pwzArgument represents the string value passed as a parameter to that 
124     // method. If the HRESULT return value of ExecuteInDefaultAppDomain is 
125     // set to S_OK, pReturnValue is set to the integer value returned by the 
126     // invoked method. Otherwise, pReturnValue is not set.
127     hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath, 
128         pszClassName, pszStaticMethodName, pszStringArg, &dwLengthRet);
129     if (FAILED(hr))
130     {
131         wprintf(L"Failed to call GetStringLength w/hr 0x%08lx\n", hr);
132         goto Cleanup;
133     }
134 
135     // Print the call result of the static method.
136     wprintf(L"Call %s.%s(\"%s\") => %d\n", pszClassName, pszStaticMethodName, 
137         pszStringArg, dwLengthRet);
138 
139 Cleanup:
140 
141     if (pMetaHost)
142     {
143         pMetaHost->Release();
144         pMetaHost = NULL;
145     }
146     if (pRuntimeInfo)
147     {
148         pRuntimeInfo->Release();
149         pRuntimeInfo = NULL;
150     }
151     if (pClrRuntimeHost)
152     {
153         // Please note that after a call to Stop, the CLR cannot be 
154         // reinitialized into the same process. This step is usually not 
155         // necessary. You can leave the .NET runtime loaded in your process.
156         //wprintf(L"Stop the .NET runtime\n");
157         //pClrRuntimeHost->Stop();
158 
159         pClrRuntimeHost->Release();
160         pClrRuntimeHost = NULL;
161     }
162 
163     return hr;
164 }
View Code