首页
社区
课程
招聘
发两篇com in asm资料
发表于: 2006-4-6 22:23 6646

发两篇com in asm资料

2006-4-6 22:23
6646
这个只是用机器翻译过来的,没有修正凑合看吧!

com接收器事件在asm应用

Copyright © 2001 by Ernest Murphy ernie@surfree.com
For educational use only. All commercial use only by written license.

得到原始代码。

摘要
在COM 接口接收器事件被使用作为回call(callback)机制。一请求事件(Event)通知必须被使用, 并且这个协定不再需要时被取消。这种技术行为在二次利用被解释和被巩固。

展示一种简单测试应用。

绪论
事件(Events)也许是"sourced," 或"sinked." 这些 条件是为当前提供近似的电机工程(electrical engineering)条件, 譬如电池(battery)当前的来源, 和消耗, 譬如灯潮流接收器。

引起这次事件的对象是这个来源。接受这次事件的对象是这个接收器。接收器必须从这个来源请求事件通知,并且必须请求什么时候暂停这连接。

事件通知由一个dance请求之间在接收器对象(事件索取者)并且服务器对象(这个供应商)。要会话, 它象这样 :

客户        服务器
你源自事件吗?        是, 我来源于他们。
你来源事件连接IX吗?        是, 我来源那个接口。
为那次事件请选择我。        是, 是cookie。

当然, COM接口为这会话所使用。成功的QueryInterface 答复" 你源自事件吗?"为 IConnectionPointContainer。IConnectionPointContainer:FindConnectionPoint 答复"你来源事件接口IX吗?" 。最终, "为那次事件请选择我。"或经由IConnectionPoint:Advise实际通知请求被使用。程序执行(没有真正误差校验参量)看起来象:

      ConnectEvent PROC pIAny:DWORD,pISink:DWORD,pIID_IEvent:DWORD,
      pdwCookie:DWORD
          ;pIAny        连接我们希望连接到的指针。不是NULL。
          ;pISink       回call接口指针。不是NULL。
          ;pIID_IEvent  事件参考IID连接。不是NULL。
          ;pdwCookie    连接cookie参考。必须是NULL。
          LOCAL _pICPC:DWORD, pICP:DWORD
      coinvoke pIAny,IUnknown,QueryInterface,
      pIID_IConnectionPointContainer,
                               ADDR _pICPC
          .IF_SUCCEEDED
              ;我们的对象支持事件,得到之一!
              coinvoke _pICPC, IConnectionPointContainer,
      FindConnectionPoint,
                              pIID_IEvent, ADDR _pICP
              .IF_SUCCEEDED
                  ;建议我们这里需要事件
                  .IF_SUCCEEDED
                      coinvoke _pICP, IConnectionPoint, Advise, pISink,
      pdwCookie
                      ;有我们的事件链接, 发布中间接口
                      coinvoke _pICP, IUnknown, Release
                  .ENDIF
               .ENDIF

               ret
      ConnectEvent ENDP

做法发布接收请求相似, 除了它使用IConnectionPoint:Unadvise方法。

Visual Basic事件来源测试节目
VB 来源app是一台简单ActiveX dll服务器。它由数量提供数字特性和一个方法提高它。如果这个数字曾经超出100, 它被重新设置到100 并且事件被射击。为这些感兴趣,如果你是对这个dll. 感兴趣请看原始代码.

这个devil(魔鬼)总是在细节处。这个问题这里是怎么得到句柄在GUIDs这个VB dll用途。VB 不生产一个分开idl文件, 或h文件, 或什么的任何征兆GUIDs。实际上, 我真正地是于相当损失至于怎样VB 记住他们从构造到构造, 除非它创造他们为第一构造, 然后需要他们从最后构造为随后构造。

我发现为这最有用的工具是TlbToInc.exe, 类型库对inc文件由Maurice Montgenie翻译。我有版本1.0,做了一个非常可靠工作翻译, 虽有唯一的例外我必须增加下划线方法名字在他们的声明。我相信这被确定在比较最新的版本。

并且, 我必须为接收器接口手工插入关于LIBID, IID, 和 CLSID事件信息。我能够简单获得这些数字从Sean  Baxter's 得到fast型Lib浏览器, 可得到于http://ript.net/~spec/typeinf3/t_browse.exe 。

某些原因, Microsoft's OLEView拒绝打开VB dll, 没有提供给我有用的信息。

关于接口名的一些笔记

当我创造VB 测试app, 我建立类名" MyEventClass " 。VB 创造一个接口为它命名"_ MyEventClass, "注意这个唯一底线。

为输出XMax方法, VB 创造其它接口 "__MyEventClass," 注意这有二个底线。VB没有为这个接口创造CLSID-LIBID, 这些我建立在我自己当它来时刻实施他们。其它app 也许并且实施这同样接口机智它自己的CLSID 和 LIBID 没有冲突。

与Windows混合的COM

同样对scripter app, 我们需要出口接口从我们的exe ( 事件接收器本身) 。事件接收器测试app Sink.exe 是一个简单对话主窗口app, 意味大多数窗口代码这里自Iczelion's 讲解来直接#10.请参见他对这个app.的完美的窗口部份的解释.

这个app的主要步骤如下:

1.初始化: 在WM_CREATE, 我们从VB创造我们的对象,然后建议它我们想要的事件通知。

2.整理: 在WM_DESTROY,我们整理所有, 首先分开我们的事件与未建议(Unadvise)的call, 那么宣布接口从VB 卸载这个dll.

3.射击(Firing)事件: 为这次实证, 所有这些事件是建立信息框告诉我们这次事件发生了。一个严谨的app在同样地方能移动(put)某一严谨的代码。

另外, typelib(类型连接)为接收器接口必须被注册在注册表。为简单,这个app注册如果需要被注册这个lib没有检查。

实施类方法

事件接受器程序没有能比较简单:

     MyEvent_XMax PROC
         invoke MessageBox, NULL, ADDR sEvent, ADDR DlgName, MB_OK
         ret
     MyEvent_XMax ENDP

事件接受器是dispinterface,i.e., 它使用IDispatch作为基地址。有些suprisely, VB射击事件与调用方法, 与射击XMax直接相对。这是一个比较慢的call的惯例, 但最安全, 象所有接受器将支持它。如果表现出问题仅仅保留这在意见里。

如果你浏览VB接口,你看见它期望__MyEventClass接口 顶端是一个抽象的IDispatch 接口。然而,CoLib不支持抽象的IDispatch, 因为它总把IDispatch作为一个双重接口。然而, VB 不介意我们怎么实施我们的接口。这将被期望,当COM唯一强加约束在接口, 不是执行。

建立Sink.exe例子

试样应用也许是建立在使用MASM32包(最新版6)与Service Pack 2安装。SP是需要为COM引伸。

新COM不包括文件要求为这个样品。

Sink.asm 意志适当地建立造从快速编辑使用建立所有设置。

结论

事件接收器简单实施和可扩展可再用组成部分的有用性, 那一些是什么COM是所有关于无论如何。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 308
活跃值: (362)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
2
源COM事件在asm应用(2)

Copyright © 2001 by Ernest Murphy ernie@surfree.com
For educational use only. All commercial use only by written license.

Get the source code.

摘要
即然我们知道怎么接收COM事件(events),它产生时我们学会怎么引用他们。当basic方法(methods)是在标准库预编译程序这个恶魔(devil)是在细节(details),在应用(application), 事件(events)实施相当简单。

一些理论谈到怎样论述库工作。给出实际应用方法。如果你曾经使用Visual Basic做基本事件, 一个相似的" RaiseEvent"宏指令被定义。

射击事件(fires events)为VB 应用的简单测试应用将被示范。

介绍

事件(Events)也许是"sourced,"或"sinked." 这些术语为当前提供近似对电机工程(electrical engineering)术语,譬如电池当前的来源(battery current source),和消费者(consumers),譬如灯潮流接收器(lamp current sink)。

我们将建立引起这次事件的对象,或事件来源。对象来源 事件给这个行为提供IConnectionPointContainer接口做广告(advertise)。对象为这个接口寻找事件通知QueryInterrface。

IConnectionPointContainer有二个方法:

IConnectionPointContainer:EnumConnectionPoints
Not used in our library (returns E_NOTIMPL)
              没使用我们的库(返回 E_NOTIMPL)

IConnectionPointContainer:FindConnectionPoint
Returns an manager object supporting an IConnectionPoint interface for a specific event interface.
             返回管理对象支持IConnectionPoint接口为一个具体事件接口。

在我们的例子, 我们使用全局变量的Event_Map可得到 我们的库。这Map有指向这次事件IID的二名成员, 并且 并且指向对应的IConnectionPoint管理对象:

EventItem STRUCT
    pIID_IEvent     DWORD   0
    pObjIEventMgr   DWORD   0
EventItem ENDS

PObjIEventMgr refs 初始化为NULL, 并且 IConnectionPointContainer:FindConnectionPoint 方法依照必要建立管理对象满足pObjIEventMgr references(参考)(更多的在"坏习性(Bad Habits)的Visual Basic").

事件管理对象简单地支持IConnectionPoint 接口。 IConnectionPoint 有这些方法:

IConnectionPoint_GetConnectionInterface
             Returns the IID of the outgoing interface managed by this connection point.
            由这连接点指针返回这个外接口的IID。

IConnectionPoint_GetConnectionPointContainer
Returns the parent object's IConnectionPointContainer interface pointer.
              返回父object的IConnectionPointContainer 接口指针。

IConnectionPoint_Advise
Creates a connection between a connection point and a client's sink, where the sink implements the outgoing interface supported by this connection point.
建立连接在连接指针和 客户的接收器之间, 这个接收器由这连接指针支持实施这个外接口。

IConnectionPoint_Unadvise
                Terminates a notification previously set up with Advise.
              终止一个通知早先设定与警告。

IConnectionPoint_EnumConnections
                Not supported, returns E_NOTIMPL.
              不支持,返回E_NOTIMPL 。

注意没有界定多少个事件接口被放置, 多少连接被建立。警告方法保留增加type指针逐个call各事件。有一个严格的(serious)极限, 这是在以后"将来想法"讨论.

代码为这二个接口相当直接了当的被安置在连接点管理库cpmgr.lib。你需要在你的应用包含这些。

射击你的事件
Firing Up your Event

我们需要的最后诀窍(这的确是诀窍)是方式获得事件fire。由fire, 为每一警告我们出示事件接口的连接预定call IEventSink 接口。

这是把戏因为火方法叫从顶面服务器目标代码, 但电话的目的地被拿着在从容的经理对象之内。 宁可然后进入一个solipsistic 论据在遏制, 或提供其它接口, 我简单地欺诈了。

真正地欺诈。 我打破了代码遏制。

它是好, 甚而MSVC 可能做那以"朋友" 定义。 "朋友" 手段"打破遏制在这种材料这里。"我打破遏制由安置对象在图书馆包括文件经理的细节, 因而他们泄漏对顶面目标代码。

如果我让CPManagerObjData 结构漏对主要对象, 我能采取我的经理对象尖并且走它同样方式经理分类符号, 并且得到尖对劝告名单。 并且与CPManagerListItem 结构并且泄漏了, 我能走名单和得到需要叫的所有事件水槽尖。

因而用经理对象的秘密实施细节武装, FireEvents 宏指令可能做它是事。 FireEvents 有以下proto:

FireEvents MACRO IEventSink:REQ, MethodName:REQ, Params:vararg

因为这个宏指令被执行在顶面对象, 它已经知道何处Event_Map 是, 并且可能走那发现匹配的事件IID, 并且然后对象经理对象(若有) 。 为没有对象, 我们没有联系, 并且没什么做。 为一个匹配的对象, 每个劝告对象叫反过来。 一旦比赛被发现, 宏观出口, 如同它当比赛在整体名单不被发现。

宏指令装配正确事件电话从您通过它的参量。 IEventSink 被使用几个方式, 首先定义接口GUID 由附有"pIID _" 它喜欢如此:

pIEvent CATSTR <pIID_&IEventSink&>

然后其它参量被做做适当的接口和方法塑像:

    istatement CATSTR <invoke [edx].&IEventSink&.&IEventSink&_&MethodName&, ecx>
    IFNB <Params>     ;; add the list of parameter arguments if any
        istatement CATSTR istatement, <, >, <&Params>
    ENDIF

注意我们" invoke " 宁可然后"coinvoke" 因为我们做"coinvoke" 样式操作在同样宏指令。 进行的代码将安置IEvent 水槽在ecx, 如此我们得到一祈求譬如这:

        mov edx, [ecx]
        invoke [edx].ISomeEvent.ISomeEvent_SomeMethod, ecx, Param1, Param2, ... ParamN

因为我们使用祈求宏指令, MASM 将做它是proto 检查对于我们, 确定我们至少得到适当的参量计数在堆打电话。

MyCom3, or MyCom2 Revisited(MyCom3, 或MyCom2 再访)

MyCom 节目样品应该现在是熟悉对您。 我使用它第三时候是事件来源。 我们的事件将叫当价值超出100. 这所有变动做对MyCom2 。asm 做它事件来源:

1) include 各项:
include     \masm32\COM\Callback\cpmgr.inc
include     IMyCom3.inc
includelib  \masm32\COM\Callback\cpmgr.lib

2) 定义Event_Map public:
PUBLIC EventMap

3) 定义你的 events 在Event_Map:
EventMap    EventItem   DeclareEvent (__MyEventClass)
            END_EVENT_MAP

note __MyEventClass is the outgoing IEvent we source

4) 加 IConnectionPointContainer 到你的 interface map:
MyCom2IMap  InterfaceItem { pIID_IMyCom2,  OFFSET vtableIMyCom2 }
            InterfaceItem { pIID_IConnectionPointContainer, OFFSET vtIConnectionPointContainer}
            END_INTERFACE_MAP

5) 确定在哪里射击事件。 为MyCom, 我们做这在SetValue 和RaiseValue 方法:

    .IF eax > 100
        FireEvents this_, __MyEventClass, XMax
    .ENDIF

6) 有一个其它细节改变, 我留下那直到"Visual.basic 坏习性" 部分。

坚硬部份进来得到。idl 文件正确。 我承认我从我做在MSVC 与ATL 图书馆的一个相似的对象借用了我的。 我改变了GUIDS, 类, 图书馆和接口名字从巫术师引起了代码。

您并且将需要匹配的IMyCom3 。公司文件描述__ MyEventClass 和MyCom2 接口。 终于, 不要忘记管理员剧本, 这与MyCom2 是相似, 除了新类和新库。

The Visual Basic Event Source Test Program(Visual.basic 事件来源测试程序)

VB 被选择测试我们的事件, 照原样大概广泛被应用的自动化程序设计工具全世界。 正I 拥有拷贝的它。

在我们的MyCom3 以后。dll 登记(通过regsvr32 。exe), 一个标准EXE 项目被开始。 首先是开掘入项目| 参考和检查"MyCom3 1.0 型图书馆。"这告诉我们希望使用我们的新dll 的VB 。

然后, 在形式的一般声明部分, 增加线:

Private WithEvents MC3 As MyCom3

"WithEvents" 通知VB 寻找外出的事件接口。 VB 应该发现我们的, 并且如果您搜寻在对象下拉下代码窗口, 您将看见MC3 潜伏那里。 点击它并且您得到残余部分代码为XMax 事件。 这里我们显示信息框证明我们得到了事件。

代码的剩余与那是相似在MyCom2

Bad Habits of Visual Basic(Visual.basic 坏习性)

当第一调试这种应用, 我注意一切是公正美好的第一次我运行了测试程序。 如果我跑了它第二次从VB IDE, 讨厌的GPF 崩溃收效了。 但是, 编写对。这每次有效得优良的exe 。

感兴趣。 这为什么:

VB 不保留什么事件一张非常好名单它连接。 如同VB app 被终止, 它寻找IConnectionPoint:EnumConnections 告诉什么它连接了。 当VB 没有得到这张名单(记住我们不支持方法) VBB 投掷了它的手和终止了。

不那么坏在exe, 因为整个过程被扯下, 并且资源被发布。 但在IDE VB 保留举行dll 的它装载了。

您能看问题吗?

因为dll 不是被装载的新鲜的□运行时间, 。数据区包含价值最后终止。 他们不得到重新设置对初值。 并且因为VB 没有这是连接的Unadvise, Event_Map 仍然包含在不再存在的对象的参考。

叫一个死的对象是一个肯定的火方式对GPF 。

"work-around" 固定为这将安排我们的dll 使这些尖无效照原样被创造。 不幸地, 唯一的地方做这是在MyCom_Create 方法里面, 象如此:

    ; 使EventMap pObjIEventMgr 尖无效
    ; 保留淘气客户(譬如VB) 从虐待我们。
    ; NULL the EventMap pObjIEventMgr pointers
    ; to keep naughty clients (such as VB) from abusing us.
    mov ecx, OFFSET EventMap
    mov eax, [ecx]
    .WHILE eax
        mov [ecx].EventItem.pObjIEventMgr, NULL
        add ecx, SIZEOF EventItem
        mov eax, [ecx]
    .ENDW

Building the Sink.exe Sample(修造Sink.exe 样品)

试样应用也许是修造使用MASM32 包裹(最新版6) 以服务叠板2 安装了。 SP 是需要的为COM 引伸。

亲自, 我使用windows.inc版本1.19 。

MyCom3.asm意志适当地然后建立从快的编辑使用修造所有设置。

小心保存道路因为文件期待他们。 这些文件意欲拉开拉链入您\masm32 \com \例子\ 文件夹。 如果您安置他们其他地方您必须更换道路编码到新cpmgr 公司和解放。

Thoughts for the Future(想法为将来)

它是太久使CoLib 真正地演变。 几件事对此打扰我, 并且麻烦我足够强烈值得将破解所有现有的代码的再设计。

即然我们有连接点下来, 我们有一个新问题: Event_Map 被定义的方法只允许一个唯一对象在项目对出口事件。 更加一般事是需要的, 并且明显的地方是ClassMap 。 增加其它成员会允许每个它使用的类定义(的地方若有) Event_Map 居住。

至于长期因为我将破解代码为这, 我不妨并且滑倒在ClassMap 的重新解释, 并且安排它是尖名单对各ClassItem, 宁可然后一一些许多ClassItem 结构。

终于, 我将得到那些唠叨的电子邮件关于怎样代码CoLib 引起不工作在调试器。 不是我曾经会注意, 我从未使用调试器。 但一些, 并且他们有好案件为赞成那包括而辩论。

现在如果某人会重写我的buggy 管理员剧本分析器为我...   <hint> <wink>

Conclusion(结论)

事件来源简单实施和可能扩展可再用的组分的有用性, 哪些是是什么COM 所有关于无论如何。

里面是原文:
上传的附件:
2006-4-6 22:25
0
游客
登录 | 注册 方可回帖
返回
//