欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    课件18 使用MFC进行COM编程.pdf

    • 资源ID:70344383       资源大小:297.80KB        全文页数:11页
    • 资源格式: PDF        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    课件18 使用MFC进行COM编程.pdf

    Windows 程序设计程序设计 版权所有(C),户现锋,2004 年 课件 18 使用 MFC 进行 COM 编程 基本目标:掌握使用 MFC 进行 COM 组件的开发 许多人认为 MFC 是一个主要用于创建图形用户界面的类库,这一点当然无可辩驳。然而在 MFC 中还有大量的 OLE 代码,可以方便 COM 客户和服务器的创建。创建 COM 组件可以使用 ATL 和 MFC,那种方法更好呢?实际上,它们都是选择。一个比较好的原则是,如果 COM 对象对 GUI 有大的需求,那么使用 MFC 可能更好。如果COM 组件的大小和速度是直观重要的,可以采用 ATL。MFC 对 COM 组件的支持依赖于 MFC 对多重接口的支持。多重接口、多重继承和嵌套类多重接口、多重继承和嵌套类 多重继承是实现多重接口的很好的选择。使用多重继承可以很容易地把这两个接口绑定到一个组件类。但是使用多重继承容易导致符号冲突的问题。最简单的情形是每一个接口都从 IUnknown 继承,所以多重继承在 IUnknown 的三个方法上都存在冲突。一般来说,这并没有什么大的问题。但是一个复杂的组件可能接口级别进行引用计数,而不是在对象级别进行引用计数,多重继承在这种情况下几乎是不可能的,因为只有一套实现 IUnknown 的方案,代码不能很好地区分调用是从那个接口进来的,即使可以,也是比较复杂的。在 MFC 中,没有使用多重继承来支持多重接口,而是使用嵌套类的方法来支持多重接口。CCmdTarget 类中的类中的 IUnknown 实现实现 MFC 组件不直接从 IUnknown 继承,MFC 的 COM 类从 CCmdTarget 继承。我们可以把CCmdTarget类想象为MFC的IUnknown,CCmdTarget不仅包含了一些重要而且基本的COM功能,它还提供了在 MFC 中每个窗口类都必须的关键框架。考虑到对自动化和消息处理的支持,我们应该知道对于 COM 和用户接口类等来说,CCmdTarget 是一个非常重要的类。对于 COM,CCmdTarget 给 COM 对象提供了一个现成的 IUnknown 实现的基类。下面的代码是从 MFC 的头文件中摘录的代码:class CCmdTarget:public CObject public:/these versions do not delegate to m_pOuterUnknown DWORD InternalQueryInterface(const void*,LPVOID*ppvObj);DWORD InternalAddRef();DWORD InternalRelease();/these versions delegate to m_pOuterUnknown DWORD ExternalQueryInterface(const void*,LPVOID*ppvObj);DWORD ExternalAddRef();DWORD ExternalRelease();在 CCmdTarget 中,有两组使用 Internal 或者 External 前缀的方法。只有在你的 COM 对象是聚合关系的一部分时,内部和外部 IUnknown 方法之间的区别才变得重要起来。在我们实现接口时,我们需要调用外部的 IUnknown 实现。声明嵌套类 在使用 MFC 创建 COM 组件时,你实际上是在创建一个外部封装类,该类为每一个组件 支 持 的 接 口 维 护 一 个 嵌 套 类。为 了 帮 助 声 明 嵌 套 类,MFC提 供 了BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 两个宏。下面是 BEGIN_INTERFACE_PART 的定义,该宏有两个参数,给嵌套类指定的名称和派生嵌套类的接口类:#define BEGIN_INTERFACE_PART(localClass,baseClass)class X#localClass:public baseClass public:STDMETHOD_(ULONG,AddRef)();STDMETHOD_(ULONG,Release)();STDMETHOD(QueryInterface)(REFIID iid,LPVOID*ppvObj);下面是 END_INTERFACE_PART 宏的定义,该宏结束类的声明,声明了该类的一个实例,并且将嵌套类声明为外部类的友类,这使得任何内部类都可以自由地存取外部的数据成员和方法:#define END_INTERFACE_PART(localClass)m_x#localClass;friend class X#localClass;在 BEGIN_INTERFACE_PART 和 END_INTERFACE_PART 之间,我们需要放置接口类的除了 IUnknown 的三个方法之外的所有方法。实现实现 QueryInterface 的方法的方法 MFC COM 类的 QueryInterface 实现象消息映射一样,依赖于映射表格。MFC 中存在许多不同的映射,有连接映射、调度映射、事件接收器映射、消息映射和接口映射等等。一般来说,不管是那种类型的映射,都可以把映射看作是 MFC 基于某种唯一标识符来查找某块执行代码的方法。比如在消息映射中,MFC 使用消息 ID 来查找属于某个 MFC 子类的处理函 数。这 个 表 格 主 要 由 以 下 几 个 宏 构 成:DECLARE_INTERFACE_MAP、BEGIN_INTERFACE_MAP、END_INTERFACE_MAP和INTERFACE_PART。MFC IUnknown接口是接口表格的第一个接口进行类型转换得到的。宏 INTERFACE_PART 主要用来填充表格,说明 COM 类支持的接口,该宏有三个参数,组件类的名称、接口 IID 和负责实现该接口的嵌套类的名字。定义如下:#define INTERFACE_PART(theClass,iid,localClass)&iid,offsetof(theClass,m_x#localClass),MFC COM 类工厂类工厂 MFC 使用宏 DECLARE_DYNCREATE 和 IMPLEMENT_DYNCREATE 给 COM 提供了动态创建的能力。这个宏并不是专门为 COM 或者 OLE 提供的,MFC 中的很多功能都依赖于类的动态创建的特性。MFC使用宏DECLARE_OLECREATE和IMPLEMENT_OLECREATE宏为COM提供了类工厂的实现,但是这两个宏依赖上面提到的提供动态创建能力的宏。这两个宏的定义如下:/Macros for creating creatable automation classes.#define DECLARE_OLECREATE(class_name)public:static AFX_DATA COleObjectFactory factory;static AFX_DATA const GUID guid;#define IMPLEMENT_OLECREATE(class_name,external_name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)AFX_DATADEF COleObjectFactory class_name:factory(class_name:guid,RUNTIME_CLASS(class_name),FALSE,_T(external_name);AFX_COMDAT const AFX_DATADEF GUID class_name:guid=l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8 ;进行组件生命期的管理进行组件生命期的管理 为了对组件的生命期进行管理,需要对组件中的 COM 对象进行计数。MFC 是通过两个函数 AfxOleLockApp()和 AfxOleUnlockApp()来完成计数工作的。一般在 COM 的构造函数中调用 AfxOleLockApp()增加组件的全局对象的引用计数,在析构函数中减少组件的全局对象的引用计数。MFC将全局对象的引用计数和服务器所计数合二为一,也就是说对于类厂的LockServer调用,也是简单地调用上述两个函数。为嵌套类实现为嵌套类实现 IUnknown 接口接口 每个嵌套类都从一个接口类继承,而该接口类从 IUnknown 继承,我们必须实现嵌套类中的所有的函数,包括 IUnknown 的方法,否则无法实例化类。在实现的时刻,我们必须把嵌套类的IUnknown接口重定向到外部类所支持的IUnknown接口上。下面是一个嵌套类的实现:STDMETHODIMP_(ULONG)COuterCls:XCInterCls:AddRef()METHOD_PROLOGUE(COuterCls,CInterCls)return pThis-ExternalAddRef();STDMETHODIMP_(ULONG)COuterCls:XCInterCls:Release()METHOD_PROLOGUE(COuterCls,CInterCls)return pThis-ExternalRelease();STDMETHODIMP COuterCls:XCInterCls:QueryInterface(REFIID riid,void*ppv)METHOD_PROLOGUE(COuterCls,CInterCls)return pThis-ExternalQueryInterface(&riid,ppv);仔细看以下我们可以发现,每个方法的第一行都使用一个宏 METHOD_PROLOGUE,下一行把对 IUnknown 方法的调用转发到 pThis 变量,pThis 从那而来呢?pThis 变量是 COuterCls 对象的指针,该指针是根据 this 指针计算出来的,this 指针是COuterCls 内部的类 XCInterCls 的变量 m_xCInterCls 的指针,而不是指向 COuterCls 实例本身。而 pThis 变量是 COuterCls 对象的指针,有了该指针,把方法调用重定向到 COuterCls从 CCmdTarget 继承而来的 IUnknown 方法就很简单了。pThis 的声明和计算是宏 METHOD_PROLOGUE 的结果。其定义如下:#define METHOD_PROLOGUE(theClass,localClass)theClass*pThis=(theClass*)(BYTE*)this-offsetof(theClass,m_x#localClass);AFX_MANAGE_STATE(pThis-m_pModuleState)pThis;/avoid warning from compiler 我们可以看出,从当前的 this 指针的值减去减去嵌套类的成员在外部类中的偏移地址即可得到 pThis,就可以得到 COuterCls 对象的指针。因此,有了 pThis 指针,可以自由地存取外部类的方法和数据。其余的事情其余的事情 MFC 为 组 件 的 注 册 和 解 除 注 册 提 供 了 相 应 的 实 现,主 要 是 通 过 调 用 函 数COleObjectFactory:UpdateRegistryAll()来完成函数 DllRegisterServer(),该函数在内部查询组件内部的每个类工厂的 CLSID 并创建合适的注册表入口,没有比这更简单的了。解除组件的注册可以使用 COleObjectFactory:UnregisterAll()函数来轻松实现 DllUnregisterServer。MFC 还通过函数 AfxDllGetClassObject()轻松实现了 DllGetClassObject 入口,利用AfxDllCanUnloadNow()函数实现了 DllCanUnloadNow 入口。利用利用 MFC 创建创建 COM 组件例子组件例子 下面我利用 MFC 创建一个 COM 组件,该组件支持两个接口,IDispatch 和 IPlus,IPlus接口如下所示:DECLARE_INTERFACE_(IPlus,IUnknown)STDMETHOD(Plus)(long,long,long*)PURE;其中 Plus 函数完成两个数值相加,同时我们利用 IDispatch 也实现该方法。(1)首先创建一个 MFC 动态链接库工程,工程名称是 ComByMfc,如下所示:(2)在向导的给出个选项中,注意选中 Automation 复选框,如下所示:(3)按 Finish 完成工程的创建,生成的主要代码如下所示 BOOL CComByMfcApp:InitInstance()/Register all OLE server(factories)as running.This enables the /OLE libraries to create objects from other applications.COleObjectFactory:RegisterAll();return TRUE;/Special entry points required for inproc servers STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID*ppv)AFX_MANAGE_STATE(AfxGetStaticModuleState();return AfxDllGetClassObject(rclsid,riid,ppv);STDAPI DllCanUnloadNow(void)AFX_MANAGE_STATE(AfxGetStaticModuleState();return AfxDllCanUnloadNow();/by exporting DllRegisterServer,you can use regsvr.exe STDAPI DllRegisterServer(void)AFX_MANAGE_STATE(AfxGetStaticModuleState();COleObjectFactory:UpdateRegistryAll();return S_OK;(4)利用 ClassWizard 增加一个类 CPlusServer,该类从 CCmdTarget 继承,如下所示:这一步生成的类实现了 IDispatch 接口,并且生成了一个类厂具备了一个强大的基础。代码如下:/PlusServer.h:header file/CPlusServer command target class CPlusServer:public CCmdTarget DECLARE_DYNCREATE(CPlusServer)CPlusServer();/protected constructor used by dynamic creation /Attributes public:/Operations public:/Overrides /ClassWizard generated virtual function overrides /AFX_VIRTUAL(CPlusServer)public:virtual void OnFinalRelease();/AFX_VIRTUAL /Implementation protected:virtual CPlusServer();/Generated message map functions /AFX_MSG(CPlusServer)/NOTE-the ClassWizard will add and remove member functions here./AFX_MSG DECLARE_MESSAGE_MAP()DECLARE_OLECREATE(CPlusServer)/Generated OLE dispatch map functions /AFX_DISPATCH(CPlusServer)/NOTE-the ClassWizard will add and remove member functions here./AFX_DISPATCH DECLARE_DISPATCH_MAP()DECLARE_INTERFACE_MAP();/PlusServer.cpp:implementation file/#include stdafx.h#include ComByMfc.h#include PlusServer.h#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILE static char THIS_FILE=_FILE_;#endif /CPlusServer IMPLEMENT_DYNCREATE(CPlusServer,CCmdTarget)CPlusServer:CPlusServer()EnableAutomation();/To keep the application running as long as an OLE automation /object is active,the constructor calls AfxOleLockApp.AfxOleLockApp();CPlusServer:CPlusServer()/To terminate the application when all objects created with /with OLE automation,the destructor calls AfxOleUnlockApp.AfxOleUnlockApp();void CPlusServer:OnFinalRelease()/When the last reference for an automation object is released /OnFinalRelease is called.The base class will automatically /deletes the object.Add additional cleanup required for your /object before calling the base class.CCmdTarget:OnFinalRelease();BEGIN_MESSAGE_MAP(CPlusServer,CCmdTarget)/AFX_MSG_MAP(CPlusServer)/NOTE-the ClassWizard will add and remove mapping macros here./AFX_MSG_MAP END_MESSAGE_MAP()BEGIN_DISPATCH_MAP(CPlusServer,CCmdTarget)/AFX_DISPATCH_MAP(CPlusServer)/NOTE-the ClassWizard will add and remove mapping macros here./AFX_DISPATCH_MAP END_DISPATCH_MAP()/Note:we add support for IID_IPlusServer to support typesafe binding/from VBA.This IID must match the GUID that is attached to the /dispinterface in the.ODL file./228C6810-DF12-4BC6-9B53-6058551B6225 static const IID IID_IPlusServer=0 x228c6810,0 xdf12,0 x4bc6,0 x9b,0 x53,0 x60,0 x58,0 x55,0 x1b,0 x62,0 x25 ;BEGIN_INTERFACE_MAP(CPlusServer,CCmdTarget)INTERFACE_PART(CPlusServer,IID_IPlusServer,Dispatch)END_INTERFACE_MAP()/54A404F4-5B23-40B3-9ABF-99E1025CC931 IMPLEMENT_OLECREATE(CPlusServer,ComByMfc.PlusServer,0 x54a404f4,0 x5b23,0 x40b3,0 x9a,0 xbf,0 x99,0 xe1,0 x2,0 x5c,0 xc9,0 x31)/CPlusServer message handlers (5)利用 ClassWizard 为类的 IDispatch 增加一个 Plus 方法,完成两个数值相加并且返回结果,如下图所示:(6)在上图中,点击 Add Method 按钮,出现下面的对话框,结果如下所示:(7)实现 Plus 方法如下所示:long CPlusServer:Plus(long nParam1,long nParam2)/TODO:Add your dispatch handler code here return nParam1+nParam2;(8)在 PlusServer.h 文件中增加接口 IPlus 的定义:DECLARE_INTERFACE_(IPlus,IUnknown)STDMETHOD(Plus)(long,long,long*)PURE;(9)在类 CPlusServer 内声明内嵌类 CInnerPlus 如下所示:public:BEGIN_INTERFACE_PART(CInnerPlus,IPlus)STDMETHOD(Plus)(long,long,long*);END_INTERFACE_PART(CInnerPlus)(10)实现 IPlus 接口如下:STDMETHODIMP_(ULONG)CPlusServer:XCInnerPlus:AddRef()METHOD_PROLOGUE(CPlusServer,CInnerPlus)return pThis-ExternalAddRef();STDMETHODIMP_(ULONG)CPlusServer:XCInnerPlus:Release()METHOD_PROLOGUE(CPlusServer,CInnerPlus)return pThis-ExternalRelease();STDMETHODIMP CPlusServer:XCInnerPlus:QueryInterface(REFIID riid,void*ppv)METHOD_PROLOGUE(CPlusServer,CInnerPlus)return pThis-ExternalQueryInterface(&riid,ppv);STDMETHODIMP CPlusServer:XCInnerPlus:Plus(long nParam1,long nParam2,long*pResult)METHOD_PROLOGUE(CPlusServer,CInnerPlus)*pResult=pThis-Plus(nParam1,nParam2);return S_OK;(11)利用 guidgen.exe 为接口 IPlus 生成接口 IID,如下所示:(12)按 Copy 按钮,然后在 PlusServer.cpp 文件的 BEGIN_INTERFACE_MAP 之前粘贴,并修改名字,然后在接口映射表格中加入接口映射,结果如下所示:/9847ABFB-AF1C-4fbc-AF22-08252E9C8808 static const IID IID_IPlus=0 x9847abfb,0 xaf1c,0 x4fbc,0 xaf,0 x22,0 x8,0 x25,0 x2e,0 x9c,0 x88,0 x8 ;BEGIN_INTERFACE_MAP(CPlusServer,CCmdTarget)INTERFACE_PART(CPlusServer,IID_IPlusServer,Dispatch)INTERFACE_PART(CPlusServer,IID_IPlus,CInnerPlus)END_INTERFACE_MAP()(13)编译链接该 DLL,我们生成了 COM 组件。

    注意事项

    本文(课件18 使用MFC进行COM编程.pdf)为本站会员(asd****56)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开