`
hgfghwq19
  • 浏览: 47672 次
  • 性别: Icon_minigender_2
  • 来自: 青岛
社区版块
存档分类
最新评论

alt 进程外com组件的连接事件

 
阅读更多

  1. 问题的提出
  类似于设计模式中Observer模式,在COM编程中,希望实现一种机制,使得对数据变化感兴趣的若干部分能够接受到数据的变化通知。一个典型的应用:计算机监控程序在计算机状态数据发生变化时通知系统管理员、系统日志程序、发送电子邮件等等,在com编程中连接点为我们方便的做到了这一点,在进程内com组件中我参考http://www.vckbase.com/document/viewdoc/?id=1538杨老师的文章很容易就参实现连接点的挂接,可是在进程外组件中去挂接失败,如下面代码所示: CSink sink; int _tmain(int argc, _TCHAR* argv[]) { ::CoInitialize( NULL ); IClassFactory *pCF=NULL; HRESULT hr = ::CoGetClassObject(__uuidof( FetionMsg),CLSCTX_LOCAL_SERVER, NULL, IID_IClassFactory, (void**)&pCF); if( SUCCEEDED( hr )){ IFetionMsg * sp = NULL; pCF->CreateInstance(NULL,__uuidof(IFetionMsg),(void **)&sp); if(sp){ _bstr_t bstrVar("test"); //CComBSTR bstrVar("test"); BSTR bstrValue = ::SysAllocString(L"进程外组件测试代码。。。。"); // BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib sp->sendMsg(bstrVar); getchar(); sp->Release(); SysFreeString(bstrValue); } IConnectionPointContainerPtr spContainer; sp->QueryInterface(__uuidof(IConnectionPointContain er),(void**)&spContainer); CComQIPtr m_spCP; // 得到连接点接口 spContainer->FindConnectionPoint(__uuidof(_IFetionM sgEvents),&m_spCP ); if( !m_spCP ){ return 0; } DWORD m_dwCookie = 0; HRESULT hr = m_spCP->Advise(&sink, &m_dwCookie ); if( FAILED( hr ) ){ } pCF->Release(); } ::CoUninitialize(); return 0; } 这个问题我重试了很多次,开始以为是代理存根没有注册,后来注册了也一样,在网上搜索了一下,原来也有很多人碰到了和我一样的问题并且没有找到很好的解决办法,我纳闷了好久,后来在微软的管网上找到了相关介绍,网址:http://support.microsoft.com/kb/194179/zh-cn示例演示如何使用 ATL IDispEventImpl 和 IDispEventSimpleImpl 类来创建 ATL 接收器,但上面是在进程内组件中实现的,今天我这个例子是在进程外组件中实现,终于成功实现了进程外组件连接点事件的挂接,下面我们来看自己实现的进程外组件和接收器。
  2.实现部分
  一、进程外com组件实例
  用vs2008 atl 工程生成向导生成一个com组件工程
  组件类型选择"可执行文件EXE"
  创建一个atl简单对象接口,注意要技术连接点
  
  添加一个OnMsg接口函数,在CProxy_ISrcObjEvents类中添加连接点的实现代码  HRESULT Fire_OnMsg(BSTR p) { CComVariant varResult; T* pT = static_cast(this); int nConnectionIndex; CComVariant* pvars = new CComVariant[1]; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex Lock(); CComPtr sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); IDispatch* pDispatch = reinterpret_cast(sp.p); if (pDispatch != NULL) { VariantClear(&varResult); pvars[0] = p; DISPPARAMS disp = { pvars, NULL, 1, 0 }; pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL); } } delete[] pvars; return varResult.scode; }  生成sys1.idl代码如下: import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(92AE347B-3623-4A3F-896E-DCE4C087CC92), dual, nonextensible, helpstring("ISrcObj 接口"), pointer_default(unique) ] interface ISrcObj : IDispatch{ [id(1), helpstring("方法test1")] HRESULT test1([in] BSTR p1, [in] BSTR p2); }; [ uuid(F43ABC61-454C-4EA3-B6D2-06C4C5584F9D), version(1.0), helpstring("sys1 1.0 类型库") ] library sys1Lib { importlib("stdole2.tlb"); [ uuid(4AEE7640-CB24-419D-AA48-34DFB446548F), helpstring("_ISrcObjEvents 接口") ] dispinterface _ISrcObjEvents { properties: methods: [id(1), helpstring("方法OnMsg")] HRESULT OnMsg([in] BSTR p1); }; [ uuid(AF32FB41-38B7-42E7-85AA-6A447D755409), helpstring("SrcObj Class") ] coclass SrcObj { [default] interface ISrcObj; [default, source] dispinterface _ISrcObjEvents; }; };  OnMsg接口函数的实现 STDMETHODIMP CSrcObj::test1(BSTR p1, BSTR p2) { // TODO: 在此添加实现代码 /**执行回调*/ Fire_OnMsg(p1); return S_OK; }  这样,进程内组件工程的实现就完成了,下面我们要实现在另一个进程里调用OnMsg接口函数,并且能在接收器里接收到事件。
  二、进程外组件事件连接
  创建一个win32工程,记得支持alt,加上头文件
  #include 
  #include 
  1、接收器的实现代码 #pragma once #define IDC_SRCOBJ 103 #import "../sys1/Debug/sys1.tlb" no_namespace named_guids ////////////////////////////////////////////////// /////////////////////////// // This file contains 4 different sink object all of which handle the 'Tick' // which is fired by the 'EventSrc' object // A COM object also acting as a sink. This class uses IDispEventImpl, with the // type library specified as a parameter. It use SINK_ENTRY_EX() to specify each // event form each source interface being handled. class CSinkObj1 :public IDispEventImpl { public: CSinkObj1() { } BEGIN_SINK_MAP(CSinkObj1) //Make sure the Event Handlers have __stdcall calling convention SINK_ENTRY_EX(IDC_SRCOBJ, DIID__ISrcObjEvents, 1, OnTick) END_SINK_MAP() // Event handler for 'Tick' - [id(1)] HRESULT Tick([in] long tckcnt); HRESULT __stdcall OnTick(long tickcnt) { // output string to list box printf( "Sink1 : Tick Event Received - %d\n", tickcnt); return S_OK; } }; // CSinkObj2 implements a sink object by deriving from IDispEventImpl but // not specifying the type library as a template argument. Instead the type // library and default source interface for the object are determined using // AtlGetObjectSourceInterface(). A SINK_ENTRY() macro is used for each // event from each source interface which is to be handled. class CSinkObj2 : public IDispEventImpl { public: CSinkObj2() { } BEGIN_SINK_MAP(CSinkObj2) //Make sure the Event Handlers have __stdcall calling convention SINK_ENTRY(IDC_SRCOBJ, 1, OnTick) END_SINK_MAP() // Event handler for 'Tick' - [id(1)] HRESULT Tick([in] long tckcnt); HRESULT __stdcall OnTick(BSTR p1) { // output string to list box char* lpszText2 = _com_util::ConvertBSTRToString(p1); printf( "Sink2 : Tick Event Received - %s\n", lpszText2); delete[] lpszText2; return S_OK; } }; // CSinkObj3 implements a sink object by deriving from IDispEventSimpleImpl. In // this case the type library is either not available or its more efficient not // to load the type library. The source interface ID is specified as an template // argument. A SINK_ENTRY_INFO() macro is used for each event from each source // interface which is to be handled. The last parameter to the macro is the // _ATL_FUNC_INFO structure which provides information about the event (source // interface method) since the type library is not available. static _ATL_FUNC_INFO OnTikcInfo = {CC_STDCALL, VT_BSTR, 1, {VT_BSTR}}; class CSinkObj3 : public IDispEventSimpleImpl { public: CSinkObj3() { } BEGIN_SINK_MAP(CSinkObj3) //Make sure the Event Handlers have __stdcall calling convention SINK_ENTRY_INFO(IDC_SRCOBJ, DIID__ISrcObjEvents, 1, OnTick, &OnTikcInfo) END_SINK_MAP() // Event handler for 'Tick' - [id(1)] HRESULT Tick([in] long tckcnt); HRESULT __stdcall OnTick(BSTR p1) { // output string to list box char* lpszText2 = _com_util::ConvertBSTRToString(p1); printf( "Sink3 : Tick Event Received - %s\n", lpszText2); delete[] lpszText2; return S_OK; } }; // CSinkObj4 is essentially same as CSinkObj3 except instead of providing the // _ATL_FUNC_INFO structure statically we can fill in the structure at run time. // This offers a little more flexibility and is a trade off of speed over size. class CSinkObj4 : public IDispEventSimpleImpl { public: CSinkObj4() { } BEGIN_SINK_MAP(CSinkObj4) //Make sure the Event Handlers have __stdcall calling convention SINK_ENTRY_EX(IDC_SRCOBJ, DIID__ISrcObjEvents, 1, OnMsg1) // equivalent to // SINK_ENTRY_INFO(IDC_SRCOBJ, DIID__EventSink, 1, OnTick, NULL) END_SINK_MAP() // fill in the _ATL_FUNC_INFO structured depending on DISPID HRESULT GetFuncInfoFromId(const IID& iid, DISPID dispidMember, LCID lcid, _ATL_FUNC_INFO& info) { if (InlineIsEqualGUID(iid, DIID__ISrcObjEvents)) { // fill in _ATL_FUNC_INFO with attributes of 'Tick' event info.cc = CC_STDCALL; switch(dispidMember) { case 1: info.vtReturn = VT_BSTR; info.nParams = 1; info.pVarTypes[0] = VT_BSTR; return S_OK; default: return E_FAIL; } } return E_FAIL; } // Event handler for 'Tick' - [id(1)] HRESULT Tick([in] long tckcnt); HRESULT __stdcall OnMsg1(BSTR p1) { // output string to list box char* lpszText2 = _com_util::ConvertBSTRToString(p1); printf( "Sink4 : OnMsg Event Received - %s\n", lpszText2); delete[] lpszText2; return S_OK; } }; 添加一个CSinkTest类,代码如下: #pragma once #include "SinkObj.h" class CSinkTest { public: CSinkTest(void); ~CSinkTest(void); public: CComQIPtr m_spSrcObj; CSinkObj1* m_pSinkObj1; CSinkObj2* m_pSinkObj2; CSinkObj3* m_pSinkObj3; CSinkObj4* m_pSinkObj4; bool init(); LRESULT OnClickedSink1(); LRESULT OnClickedSink2(); LRESULT OnClickedSink3(); LRESULT OnClickedSink4(); }; #include "StdAfx.h" #include "SinkTest.h" CSinkTest::CSinkTest(void) { m_pSinkObj1 = NULL; m_pSinkObj2 = NULL; m_pSinkObj3 = NULL; m_pSinkObj4 = NULL; } CSinkTest::~CSinkTest(void) { if (m_pSinkObj1) { // disconnect from source if connected if (m_pSinkObj1->m_dwEventCookie != 0xFEFEFEFE) m_pSinkObj1->DispEventUnadvise(m_spSrcObj, &m_pSinkObj2->m_iid); delete m_pSinkObj1; } if (m_pSinkObj2) { // disconnect from source if connected if (m_pSinkObj2->m_dwEventCookie != 0xFEFEFEFE) m_pSinkObj2->DispEventUnadvise(m_spSrcObj, &m_pSinkObj2->m_iid); delete m_pSinkObj2; } if (m_pSinkObj3) { // disconnect from source if connected if (m_pSinkObj3->m_dwEventCookie != 0xFEFEFEFE) m_pSinkObj3->DispEventUnadvise(m_spSrcObj); delete m_pSinkObj3; } if (m_pSinkObj4) { // disconnect from source if connected if (m_pSinkObj4->m_dwEventCookie != 0xFEFEFEFE) m_pSinkObj4->DispEventUnadvise(m_spSrcObj); delete m_pSinkObj4; } } LRESULT CSinkTest::OnClickedSink1() { // Construct the sink object CSinkObj defined in SinkObj.h. // In this case the sink object is also another COM object // HRESULT hr = CComObject::CreateInstance(m_pSinkObj); // m_pSinkObj->AddRef(); // _ASSERTE(SUCCEEDED(hr)); // // // connect the sink and source, m_spSrcObj is the source COM object // hr = m_pSinkObj->DispEventAdvise(m_spSrcObj); // // // Error handling // if (FAILED(hr)) // { // TCHAR buf[1024]; // wsprintf(buf, "Connect Err-%x", hr); // } return 0; } LRESULT CSinkTest::OnClickedSink2() { // Make sure the COM object corresponding to pUnk implements IProvideClassInfo2 or // IPersist*. Call this method to extract info about source type library if you // specified only 2 parameters to IDispEventImpl m_pSinkObj2 = new CSinkObj2(); //m_pSinkObj2->AddRef(); HRESULT hr = AtlGetObjectSourceInterface(m_spSrcObj, &m_pSinkObj2->m_libid, &m_pSinkObj2->m_iid, &m_pSinkObj2->m_wMajorVerNum, &m_pSinkObj2->m_wMinorVerNum); _ASSERTE(SUCCEEDED(hr)); // connect the sink and source, m_spSrcObj is the source COM object hr = m_pSinkObj2->DispEventAdvise(m_spSrcObj, &m_pSinkObj2->m_iid); // Error handling if (FAILED(hr)) { TCHAR buf[1024]; wsprintf(buf, "Connect Err-%x", hr); } if(m_spSrcObj)m_spSrcObj->test1(_bstr_t("OnClickedS ink2_p1"),_bstr_t("OnClickedSink2_p2")); return 0; } LRESULT CSinkTest::OnClickedSink3() { m_pSinkObj3 = new CSinkObj3(); //m_pSinkObj3->AddRef(); // connect the sink and source, m_spSrcObj is the source COM object HRESULT hr = m_pSinkObj3->DispEventAdvise(m_spSrcObj); // Error handling if (FAILED(hr)) { TCHAR buf[1024]; wsprintf(buf, "Connect Err-%x", hr); } if(m_spSrcObj)m_spSrcObj->test1(_bstr_t("OnClickedS ink3_p1"),_bstr_t("OnClickedSink3_p2")); return 0; } LRESULT CSinkTest::OnClickedSink4() { m_pSinkObj4 = new CSinkObj4(); //m_pSinkObj4->AddRef(); // connect the sink and source, m_spSrcObj is the source COM object HRESULT hr = m_pSinkObj4->DispEventAdvise(m_spSrcObj); // Error handling if (FAILED(hr)) { TCHAR buf[1024]; wsprintf(buf, "Connect Err-%x", hr); } if(m_spSrcObj)m_spSrcObj->test1(_bstr_t("OnClickedS ink4_p1"),_bstr_t("OnClickedSink4_p2")); return 0; } bool CSinkTest::init() { ::CoInitialize( NULL ); IClassFactory *pCF=NULL; HRESULT hr = ::CoGetClassObject(__uuidof( SrcObj),CLSCTX_LOCAL_SERVER, NULL, IID_IClassFactory, (void**)&pCF); if( SUCCEEDED( hr )) { HRESULT hr1= pCF->CreateInstance(NULL,__uuidof(ISrcObj),(void**) &m_spSrcObj); if(m_spSrcObj){ return TRUE; } } return FALSE; }  调用部分代码 #include "stdafx.h" #include "SinkTest.h" CSinkTest sink; int _tmain(int argc, _TCHAR* argv[]) { if(!sink.init()){ return 0; } //sink.OnClickedSink1(); //sink.OnClickedSink2(); sink.OnClickedSink3(); sink.OnClickedSink4(); getchar(); return 0; }   执行结果:
  
分享到:
评论

相关推荐

    Windows系统进程详解

    )(附:Svchost.exe文件对那些从动态连接库中运行的服务来说是一个普通的主机进程名。Svhost.exe文件定位在系统的 %systemroot%\system32文件夹下。在启动的时候,Svchost.exe检查注册表中的位置来构建需要加载的服务...

    Delphi 5编程实例与技巧

    5.3.1 检测Shift、Alt和Ctrl键是否 按下 122 5.3.2 屏蔽系统功能键 123 5.3.3 模拟按下键盘上的某个键 124 5.3.4 限制鼠标移动的范围 124 5.3.5 自定义鼠标 125 5.3.6 设置光标闪烁的速度 126 5.3.7 不同程序间的...

    DELPHI 5编程实例与技巧

    5.3.1 检测Shift、Alt和Ctrl键是否 按下 122 5.3.2 屏蔽系统功能键 123 5.3.3 模拟按下键盘上的某个键 124 5.3.4 限制鼠标移动的范围 124 5.3.5 自定义鼠标 125 5.3.6 设置光标闪烁的速度 126 5.3.7 不同程序间的...

    易语言 茶凉专用模块

    参数 定时器事件处理, 子程序指针, , 定时器触发事件 .子程序 创建多级目录, 逻辑型, 公开, 成功返回真,失败返回假 .参数 目录路径, 文本型 .子程序 创建进程, 整数型, 公开, 创建一个程序进程(成功返回进程ID,...

    Altium Designer Beta 19.0.10完整版安装包+安装教程+和谐文件

    添加首选项选项以在移动组件功能后启用/禁用重新连接。 25975 修复了在特定电路板设计中启动交互式路由器时存在很长延迟的问题。 25982 为焊盘和过孔添加并集成了新的热释放选项。 26034 修复了“PCB列表”面板...

    易语言程序免安装版下载

     静态编译后的易语言EXE/DLL之间不能再共享譬如窗口、窗口组件等类似资源,对于已经静态连接到一个EXE/DLL中的支持库,该支持库中的数据或资源将不能再被其它EXE/DLL中所使用的同名支持库访问。这是因为代码被分别...

    iubi:该应用程序允许通过浏览器中的javascript操作使用数字角色SDK的生物识别读取器

    该应用程序显示一个后台进程,使您可以通过javascript监听事件和动作。 #如何安装 安装角色数字SDK。 执行iubi.exe文件(它将安装必要的组件以初始化应用程序)。 如何使用JavaScript连接iubi.exe。 当后台运行...

    网络端口查询

    3.ctrl+alt+del打开任务管理器,选进程,这里有很多正在运行的程序怎么找? 查看--选择列--在PID(进程标示符)前面打钩。好了,下面的进程前面都有了PID号码。这时上一步找到的PID就有用了,找到1484,比如PEER....

    暗组远控2010脱壳版

    6.进程管理:可以查看对方进程,并可以终止进程。 7.插件管理:可以加载自定义插件扩展功能。 服务端体积:44.5 KB(压缩) 97.5 KB(无压缩) 启动方式简要说明 1.Active启动 第一次安装:360安全卫士无提示,即时上线 ...

    C#开发经验技巧宝典

    0828 将组件放到COM+服务器上去 496 0829 调用非托管的DLL文件 497 0830 如何将GridView控件数据导入Word 497 0831 如何将GridView控件数据导入Excel 497 0832 单片机如何实现在线调试 498 0833 单片机...

    windowsnt 技术内幕

    规划并实现审核策略 打开文件、文件夹及打印机的审核功能 使用事件查看器检查审核事件 安全性日志(Securty Log)的归档 使用服务器管理器查看正在使用的资源 断开用户与服务器的连接 调协系统管理告警(Administrative...

    C#编程经验技巧宝典

    C#编程经验技巧宝典源代码,目录如下: 第1章 开发环境 1 <br>1.1 Visual Studio开发环境安装与配置 2 <br>0001 安装Visual Studio 2005开发环境须知 2 <br>0002 配置合适的Visual Studio 2005...

    Visual C++编程技巧精选500例.pdf

    180 如何使用事件对象同步进程? 181 如何在两个执行程序间进行数据通信? 182 如何使用工作线程? 183 如何正常终止线程? 184 如何异常终止线程? 185 如何获取线程退出码? 186 如何使用线程优先级? 187 如何使用用户...

    C#微软培训资料

    第十三章 事件和索引指示器 .148 13.1 事 件 .148 13.2 索引指示器 .151 13.3 小 结 .154 第十四章 继 承 .155 14.1 C#的继承机制.155 <<page 3>> page begin==================== 14.2 多 态 性 ....

    电脑高手必备 Windows系统35招实用技巧

     (2)网络安全模式:和安全模式类似,但是增加了对网络连接的支持。在 局域网环境中解决Windows XP的启动故障,此选项很有用。  (3)命令提示符的安全模式:也和安全模式类似,只使用基本的文件和驱 动程序启动...

Global site tag (gtag.js) - Google Analytics