C++调用dotnet-第二节(COM方式)
-------托管代码封装成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++调用时方便
这种方式托管代码放比较麻烦,需要强命名(不加载到GAC可以不签名)
第一步允许与com互操作,项目右键属性勾选或者AssemblyInfo添加代码[assembly: ComVisible(true)]
下面是AssemblyInfo.cs代码内容:
1 using System.Reflection; 2 using System.Runtime.CompilerServices; 3 using System.Runtime.InteropServices; 4 using System.Windows; 5 using System.EnterpriseServices; 6 7 // 有关程序集的常规信息通过以下 8 // 特性集控制。更改这些特性值可修改 9 // 与程序集关联的信息。 10 [assembly: AssemblyTitle("IMWpfLib")] 11 [assembly: AssemblyDescription("")] 12 [assembly: AssemblyConfiguration("")] 13 [assembly: AssemblyCompany("")] 14 [assembly: AssemblyProduct("IMWpfLib")] 15 [assembly: AssemblyCopyright("Copyright © 2016")] 16 [assembly: AssemblyTrademark("")] 17 [assembly: AssemblyCulture("")] 18 [assembly: AssemblyKeyFileAttribute(@"IMWpfLib.snk")] 19 20 // 将 ComVisible 设置为 false 使此程序集中的类型 21 // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 22 // 则将该类型上的 ComVisible 特性设置为 true。 23 [assembly: ComVisible(true)] 24 25 // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 26 [assembly: Guid("69423b07-6bfb-473c-8a1f-443596dbf209")] 27 28 // 程序集的版本信息由下面四个值组成: 29 // 30 // 主版本 31 // 次版本 32 // 生成号 33 // 修订号 34 // 35 // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 36 // 方法是按如下所示使用“*”: 37 // [assembly: AssemblyVersion("1.0.*")] 38 [assembly: AssemblyVersion("1.0.0.0")] 39 [assembly: AssemblyFileVersion("1.0.0.0")]
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 7 using System.Runtime.InteropServices; 8 using System.Windows; 9 using System.EnterpriseServices; 10 namespace IMWpfLib 11 {//sn -k IMWpfLib.snk 12 //gacutil -i IMWpfLib.dll 13 //tlbexp IMWpfLib.dll /out:IMWpfLib.tlb 14 15 // gacutil -i G:TestVSworkSpaceRichTxtboxTestIMWpfLibinDebugIMWpfLib.dll 16 //TlbExp G:TestVSworkSpaceRichTxtboxTestIMWpfLibinDebugIMWpfLib.dll /out:IMWpfLib.tlb 17 18 //regasm G:TestVSworkSpaceRichTxtboxTestIMWpfLibinDebugIMWpfLib.dll 19 [Guid("087195E0-DA0D-40E2-AF4C-0C9EDE95D425")] 20 public interface IMLibInterface 21 { 22 [DispId(1)] 23 MainWindow NewImWindow(); 24 25 [DispId(2)] 26 void ShowWindows(Window showWindow); 27 28 [DispId(3)] 29 IMCtrl NewContro(); 30 31 [DispId(4)] 32 void ShowWindowsTest(); 33 34 [DispId(5)] 35 void ShowWindowsTest2(); 36 37 } 38 [Guid("C099A746-4733-4523-B324-683A9E9F3416")] 39 [ClassInterface(ClassInterfaceType.None)] 40 public class IMComInterop : ServicedComponent, IMLibInterface 41 { 42 public IMComInterop() 43 { 44 45 } 46 47 48 public MainWindow NewImWindow() 49 { 50 return new MainWindow(); 51 } 52 53 public void ShowWindows(Window showWindow) 54 { 55 showWindow.Show(); 56 } 57 58 public IMCtrl NewContro() 59 { 60 return new IMCtrl(); 61 } 62 public void ShowWindowsTest() 63 { 64 MainWindow a = new MainWindow(); 65 a.ShowDialog(); 66 } 67 public void ShowWindowsTest2() 68 { 69 Console.Write(1 + 1); 70 } 71 } 72 }
执行上述代码后通过C:Program Files (x86)Microsoft SDKs 下面的工具(根据.NET版本选择不同版本的工具)生成tlb com接口定义库给c++用
A.生成强命名秘钥:sn -k IMWpfLib.snk
B.在AssemblyInfo.cs中添加代码[assembly: AssemblyKeyFileAttribute(@"IMWpfLib.snk")]
C.重新编译dll,将其copy到c++的exe所在目录或者注册到GAC中(gacutil -i IMWpfLib.dll)
D.regasm注册com组件:regasm G:TestVSworkSpaceRichTxtboxTestIMWpfLibinDebugIMWpfLib.dll(开发环境中这一步vs会帮你自动完成,不要奇怪为什么不注册也可以用)
regasm.exe所在目录C:WindowsMicrosoft.NETFramework64v4.0.30319
检验方式可以在.NET项目中添加引用里面选择com,查看有没有对于dll名字的com项
E.生成tlb:tlbexp IMWpfLib.dll /out:IMWpfLib.tlb
非托管C++代码
1 // ImportCsharp.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 #include "DotNetRuntimeWrap.h" 7 8 #import "G:TestVSworkSpaceRichTxtboxTestIMWpfLibinDebugIMWpfLib.tlb" raw_interfaces_only 9 10 11 //static void TestClrHost() 12 // { 13 // 14 // DotNetRuntimeWrap dotNetWrap; 15 // dotNetWrap.Loader(L"v4.0.30319", L"CLRHostLib.dll", 16 // L"CLRHostLib.ClrClass",L"ClrExcute"); 17 // 18 // } 19 static void TestCom() 20 { 21 22 CoInitialize(NULL);//一定要初始化 23 IMWpfLib::IMLibInterfacePtr ptr; //生成的 24 ptr.CreateInstance(__uuidof(IMWpfLib::IMComInterop));//创建智能指针 25 26 //IMWpfLib::_MainWindow **ptrMP=NULL; 27 ptr->ShowWindowsTest2(); 28 29 ptr->ShowWindowsTest(); 30 31 } 32 33 34 35 int _tmain(int argc, _TCHAR* argv[]) 36 { 37 38 //TestClrHost(); 39 TestCom(); 40 return 0; 41 }
执行结果如下:正常调用,托管dll中可以弹框,返回结构体等等,比前文的方法功能更强大,不过开发和部署都要稍微麻烦一些,各位可根据自己情况选择