使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
来源:互联网 发布:godaddy域名转入教程 编辑:程序博客网 时间:2024/06/06 01:39
CLR Interop简而言之是让非托管代码与托管代码之间可以相互调用的技术。这项技术可以使开发人员重用已有的托管或非托管组建,并根据自己的需要,权衡托管代码的简易性与非托管代码的灵活性,选择适合自己实际情况的编程语言,而不用过多考虑重用的组件是用哪种语言开发的。Interop中文的意思是互通性,既然是互通,代码的调用就有两种不同的方向。本文所要讲述的是使用COM Interop技术在非托管代码方如何调用托管代码。
1. 创建托管服务器
首先让我们在Visual Studio 2008创建一个C#的Class Library(类库)项目,取名为MyManagedServer,在该项目中,我们要声明并实现一个接口。
接口声明代码如下:
为了说明简单,该接口中只有一个方法,用于打印一些信息。其中的ComVisible属性至关重要,当它的值为true时,该接口才对COM可见。
using System;using System.Runtime.InteropServices;namespace MyManagedServer{ [ComVisible(true), Guid("79EDDA1C-F243-47C5-8954-5DEF01FA3D44"), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IManagedFooClass { [PreserveSig, DispId(1)] void PrintFoo(); }}
接下来是实现该接口的类:
using System;using System.Runtime.InteropServices;namespace MyManagedServer{ [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual), ProgId("MyManagedServer.ManagedFooClass") ] public class CustomCOMClient : IManagedFooClass, IManagedBarClass { public CustomCOMClient() { } #region IManagedFooClass Members [DispId(1)] public void PrintFoo() { Console.WriteLine("in MyManagedServer: CustomCOMClient.PrintFoo()"); } #endregion }}
这里我们给这个类的ProgId属性赋一个值。等会儿在注册组件的时候,注册表中将会增加一个键值,将ProgId和runtime为我们自动生成的CLSID关联起来。
2. 为COM Interop注册托管服务组件
注册组件可以用Visual Studio帮我们自动注册,也可以在命令行下手动输入命令。若要使用Visual Studio来帮我们注册组件,只需在项目属性页(鼠标右键项目名称,在下拉菜单中选择“Properties(属性)”)的Build标签页中把Register for COM Interop项打上勾,然后再build项目就可以了。如下图所示:
此外,我们也可以先build项目,然后通过命令行的方式注册组件。只需要使用regasm.exe在VS2008命令行下输入如下命令即可:
regasm assemblyname.dll /tlb /codebase
该命令会为我们注册组件,生成并注册对应的type library文件。其中assemblyname.dll是项目构建生成的程序集文件。
3. 创建非托管客户端
使用托管语言创建并注册了组建之后,我们就要使用非托管语言来尝试通过COM Interop调用组建中的方法了。首先,在Visual Studio 2008中创建一个Visual C++ Win32 Console Application,取名为MyNatvieClient,并将组建生成tlb文件拷贝至该项目的源代码目录中。然后在MyNativeClient.cpp中输入如下代码:
#include "stdafx.h"#import "mscorlib.tlb" no_namespace#import "MyManagedServer.tlb" no_namespaceint _tmain(int argc, _TCHAR* argv[]){::CoInitialize(NULL);// Get CLSID for CoCreateInstanceconst OLECHAR lpszProgID[] = OLESTR("MyManagedServer.ManagedFooClass");CLSID clsid;HRESULT hr = CLSIDFromProgID(lpszProgID, &clsid);if(SUCCEEDED(hr)){printf("CLSIDFromProgID Succeeded /n");IDispatch* ppv = 0;HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&ppv);if(SUCCEEDED(hr)){printf("CoCreateInstance Succeeded /n");// Get DispId for InvokeDISPID dispid;const LPOLESTR szMember = OLESTR("PrintFoo");HRESULT hr = ppv->GetIDsOfNames(IID_NULL, (LPOLESTR*)&szMember,1,LOCALE_SYSTEM_DEFAULT,&dispid);if(SUCCEEDED(hr)){printf("GetIDsOfNames Succeeded /n");// There's no parameter to passDISPPARAMS dispParams = {0};VARIANT vtResult;UINT dwArgErr;HRESULT hr = ppv->Invoke(dispid,IID_NULL,NULL,DISPATCH_METHOD,&dispParams,&vtResult,NULL,&dwArgErr);if(SUCCEEDED(hr)){printf("Invoke Succeeded /n");}}ppv->Release();}}return 0;}
该代码主要做了以下几件事情:
a. 调用CoInitialize进行初始化。
b. 调用CLSIDFromProgId获得对象的CLSID,因为接下来的函数将通过CLSID来创建实例。
c. 通过CoCreateInstance创建对象实例。这里创建的是一个IDispatch的对象实例。
d. 调用IDispatch::GetIDsOfNames以获得将要调用的方法的DispID,供接下来的函数使用。
e. 使用IDispatch::Invoke来调用方法。
在import type library的时候我们不仅import了组建的tlb文件,同时还import了mscorlib.tlb以避免生成的临时的tlh文件中一些类型找不到的情况。(有关此方面的问题可以参考我们团队开发人员张羿撰写的《#import从.NET DLL生成的tlb的神秘错误》)
编译通过后运行结果,可看到命令行中打印出如下信息:
CLSIDFromProgID Succeeded
CoCreateInstance Succeeded
GetIDsOfNames Succeeded
in MyManagedServer: CustomCOMClient.PrintFoo()
Invoke Succeeded
注:本文所示代码只作为实例使用。本文作者不对因代码使用不当而造成的问题负责。
- 使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
- 使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
- 自己实现IDispatch::Invoke方法
- C#中使用托管C++类,委托调用,以供托管C++类的成员函数回调的实现方式
- 在C#中调用C++Dll函数的方法
- 如何在C#中使用C++类(非托管)和C函数
- 【问题解决】在C#中使用C++编写的类 使用托管c++(managed c++)
- 在C#中使用P/Invoke调用Win32 DLL
- 在C#中使用P/Invoke调用Unmanaged Code (1)
- 在C#中使用P/Invoke调用Unmanaged Code (2)
- 在C#中使用P/Invoke调用Unmanaged Code (3)
- C# 中跨线程的调用的方法--this.invoke
- c#调用非托管函数的一个方法
- C调用c#的托管字符串传送UTF8字符集方法
- C#调用非托管C++DLL的两种方法
- 使用PInvoke实现C#调用非托管C代码DLL库
- IDispatch 接口方法的调用
- BCB(C++Builder或Embarcadero XE)中调用托管DLL的方法(C++调用C#的DLL)
- ClassLoader相关
- 只包含中英文的UTF-8与Unicode的转换(不支持其它语言)
- 备忘: DBGridEh 的过滤和排序
- 关于Treeview控件的多级显示
- 黎叔语录
- 使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法
- SQL*PLUS常用命令介绍
- 黑衣人---走出软件作坊:三五个人十来条枪 如何成为开发正规军(三十四)
- 导出Excel的方法,传入为table或html!
- 随机数产生的三种算法
- 读红马的用C#创建Acticex控件有感
- 系统分析师考试心得
- asp.net 发送邮件代码
- CrystalReports连接数据服务器函数