silverlightshanghaiID:SilverlightShanghai
49446次访问,排名2110好友2人,关注者8
SilverlightShanghai的文章
原创 27 篇
翻译 1 篇
转载 0 篇
评论 73 篇
CLR & Silverlight Shanghai的公告
如果你对CLR或Silverlight有什么意见或建议,欢迎通过导航条中的EMAIL给我们留言。有技术问题欢迎访问MSDN中文论坛进行提问(请参阅链接)。 贴子以"现状"提供且没有任何担保也没有授予任何权利。如果需要转载、录用文章,必须点击“联系作者”与博客管理员书面联系取得许可。
最近评论
Yashmak:fuadam

对,我之前的理解确实有问题. 当实现一个接口方法时,如果没有使用virtual关键字, 编译出的IL会将该方法标记为vitrual+final. 这就导致了在此实现类的子类中不能再次override此方法(我据此认定了 "abstract method" 不一定是 "virtual method").
如果在实现时使用了virtual关键字, ……
fuadam:想请教下博主
.net1.1以后接口方法的调用是通过
call dword ptr ds:[00750010h] 这种方式来进行调用的

我想知道全局接口表地址和在表的偏移是怎么得到的
fuadam:Yashmak
请先研究下CLR的基本概念
Yashmak:首先, 请博主使用 "虚方法" 而不是 "虚函数" 这个概念, 以便不引起不必要的误解.

博主似乎误解了 "虚方法(virtual method)" 和 "抽象方法(abstract method)" 的概念吧??

接口中定义的方法是 "抽象方法", 而非 "虚方法". C#中的"抽象方法"不等同于"虚函数".
"所有的interface……
ASP_lover:

推荐给Web程序员,

学习网络赚钱 www.888RMB.Com.cn 为中国赚钱网站,

提供赚钱教程、赚钱经验、赚钱 秘籍、赚钱项目、赚钱产品, 为想赚钱的人群提供一个赚钱的网络平台






文章分类
收藏
    相册
    个人博客
    CLR & Silverlight上海开发团队MSDN上的家(RSS)
    微软STBC服务器与开发工具事业部(中国)的博客(RSS)
    走近我们的开发人员:ATField的专栏(RSS)
    技术论坛
    Silverlight技术MSDN中文技术论坛(RSS)
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 使用IDispatch::Invoke函数在C++中调用C#实现的托管类库方法收藏

    新一篇: 在COM应用中使用.NET组件  | 旧一篇: 现在就下载开源工具P/Invoke Interop Assistant -- 使用P/Invoke中进行签名转换的好帮手

    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_namespace
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	::CoInitialize(NULL);
    
    	// Get CLSID for CoCreateInstance
    	const 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 Invoke
    			DISPID 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 pass
    				DISPPARAMS 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

    注:本文所示代码只作为实例使用。本文作者不对因代码使用不当而造成的问题负责。

    发表于 @ 2008年07月15日 16:07:00|评论(loading...)|收藏

    新一篇: 在COM应用中使用.NET组件  | 旧一篇: 现在就下载开源工具P/Invoke Interop Assistant -- 使用P/Invoke中进行签名转换的好帮手

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © CLR & Silverlight Shanghai