http://dev.csdn.net/article/14/14343.shtm

COM+ Events进行到底(一)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

Article last modified on 2002-7-4

----------------------------------------------------------------

The information in this article applies to:

- Microsoft Windows 2000 Advanced Server

- Microsoft Windows 2000 Server

- Microsoft Windows 2000 Professional

- Microsoft Component Service 1.0

----------------------------------------------------------------

概要

通常,我们在组件和客户程序之间实现事件通知与订阅时,会采用这两种方法:回调(Callback),和连接点(ConnectionPoint)。他们的本质其实都是,订阅者将接口传递给发布者,当有事情发生时,发布者调用接口的方法。这种类型的事件叫Tightly Coupled Event(TCE),属于Request-Reply方式。

TCE的限制在于:

1.       订阅者必须知道它所请求的通知来自于哪一个发布者。发布者和订阅者紧紧绑定在一起,双方程序代码依赖于接口的定义,我们必须在编译时刻知道对方的信息(CLSID,或ProgID);

2.       要求订阅者和发布者必须同时在线。也就是说,在生存周期上必须重叠(overlap);

3.       不包含过滤或截取机制。

COM+提供了一种全新的服务:COM+ Events或者Loosely Coupled Events(LCE)。不过此事件非彼事件。用微软的话说就是“COM+ 事件不与传统 ConnectionPoints 事件关联,并且在完全不同的方案中使用。

它的思路是,发布者亲自维护一个外部数据库(我们管它叫EventList),其中存储了订阅的所有事件的列表。发布者通过这个表知道该如何发送事件通知。订阅者也可以读入此列表,并选择它感兴趣的事件。发布者再维护另一个数据库(我们管它叫SubscribtionList),其中存储了订阅者的CLSID。从概念上讲,这个数据库相当于一个邮件列表。订阅者可以向这个库中添加自己的CLSID。发布者想要激发事件时,会检查这个数据库,找到所有订阅这个事件的订阅者的CLSID,创建每一个相关类的新对象,并调用对象的方法。

这个属于Publisher-Subscriber方式。

(图1可参看http://www.microsoft.com/CHINA/msdn/library/techart/com+agvb4.gif)

具体执行的顺序,图2说得非常明白:

(图2可参看http://www.idevresource.com/images/articles/com+eventsintro1.gif)

Fig 2 shows a typical COM+ events life cycle.

LCE的优点就在于:

n       订阅者不必知道上层事件处理的细节;

n       发布者不在运行时,订阅者也可以发出订阅请求;发布者不用理会订阅者是否在家,就可以发布通知;

n       过滤或者截取。订阅者可以选择订阅事件中哪些他更感兴趣,比如,一个订户订阅了出版社的新书通知,但是他还可以告诉出版社只有当国外作家的新书到达时才给他通知,或者只有当价格低于50元的新书到达时候才通知他。

更多细节

发布者的事件方法执行情况:

当一个事件的方法最终返回时,

非QC的订阅者中:

临时订阅者的情况:订阅者对象已经被调用,而且方法已经返回!

永久订阅者的情况:订阅者对象已经被创建、调用、返回,而且已经被释放!

QC订阅者的情况:

所有对QC订阅者的调用已经被记录下来;

对于永久订阅者,这些记录已经被送到队列准备传送出去。

所以非QC订阅者的执行情况会影响到发布者,而QC不会。比如非QC的订阅者中如果在接收到事件通知的方法中Sleep个一分钟,那发布者的事件方法就必须老老实实等1分钟,然后再调用下一个订阅者对象。

订阅者的疑问一:

如果我的订阅者程序已经在处理一个事件了,这时候又来了一个事件通知,那么这第二个事件会被谁接收呢?

是新创建一个订阅者对象呢?还是等着当前这个事件处理完?

我认为是后者。

发布者的疑问一:

发布者可不可以位于不同的机器?

发布者分布到远程服务器上,但是事件通知仍然在中心服务器上。这种情况可以通过下面两种方法做到:

u      将EventClass所在的COM+应用导出为应用程序代理。在远程服务器上安装这个代理。

u      在远程服务器上调用该EventClass发布事件时,调用代码改为:CreateObject(“%YourEventClassProgID%”, “\\%YourCenterServerName%”)。

这样,在远程服务器上的事件发布行为,都会被转到中心服务器上的EventClass应用。

订阅者的疑问二:

订阅者是否可以位于不同的机器呢?

下面的文字是引用MSDN的《COM+ Events Architecture》:

Note   This version of COM+ Events does not support a distributed event store. A subscriber must subscribe to an event on each computer from which it wants to receive notification. As an alternative, you can register the EventClass and subscriptions on a central computer and instantiate this EventClass from the remote computers on which you will publish events. Delivery of events is provided either by DCOM or queued components. For more information on using queued components, see Composing Events with Queued Components.

曾经有人做过下面的步骤试图远程订阅:

ü        远程订阅者创建一个“COMAdmin.COMAdminCatalog”的实例;

ü        远程订阅者调用COMAdmin.COMAdminCatalog的Connect方法连结至中心服务器;

ü        远程订阅者通过向中心服务器的临时订阅数据库中添加一条记录来订阅;

但是,结果是中心服务器的其他本地订阅者都接收到了事件通知,而远程订阅者却没有。

建议如果真的想远程订阅的话,可以自己实现DCOM,或者用QC。

EventClass组件的调试:
如果在VC IDE或者VB IDE中设断点调试EventClass组件,那么当事件发布时,订阅者将接收不到事件通知。
这是由于在COM+应用中EventClass组件的注册地址已经被更改为:
D:\Program Files\Microsoft Visual Studio\VB98\VB6DEBUG.DLL了!
虽然,EventCalss组件的CLSID没有变,但是不是和订阅数据库中记录的不一样了呢,所以没有通知订阅者。
 
制作实录:
第一步,先做一个EventClass组件:
新建一个VB DLL,Project Name为TomoTrace,Class Module Name为Trace。
代码极其简单,为:
Public Function Publish(ByVal strAuthor As String, _
                        ByVal strTraceType As String, _
                        ByVal strEventCategory As String, _
                        ByVal nEventID As Integer, _
                        ByVal nOther As Integer, _
                        ByVal strTraceContent As String) As Integer
                       
    ' Do Nothing
                       
End Function
在组件服务中新建一个COM+应用,在该应用下新建组件TomoTrace.Trace,注意要选择安装为新的事件类。
记录下这个接口的CLSID。
第二步,做一个订阅者:
新建一个VB EXE,Project Name为Trace2File。
首先要引用TomoTrace组件,并实现它的Trace接口:
Implements Trace
 
声明一些全局变量:
‘  g_oAdmin将是COMAdmin.COMAdminCatalog的实例对象:
Dim g_oAdmin As Object
 
‘  使用ICatalogObject接口将允许读写COM+ Catalog中的对象暴露出来的属性:
Dim SubObj As ICatalogObject
 
Const TransientSubscription = "Transient Subscription"
 
‘ 这是TomoTrace.Trace事件接口的ClassID:
Const EVENTCLSID = "{8EDBE260-A7C7-4000-BF95-CA4CC8FCA6C2}"
 
Dim g_CascadeApp, g_TransID
 
‘  你可以用ICatalogCollection接口枚举、添加、删除和获得Collection中的条目:
Dim Subcoll As ICatalogCollection
 
在Form初始化时,提交订阅请求:
Private Sub Form_Load()
' Create COMAdmin object
    Set g_oAdmin = CreateObject("COMAdmin.COMAdminCatalog.1")
   
    ' Get the TRANSIENTSUBSCRIPTIONS collection
    Set Subcoll = g_oAdmin.GetCollection("TransientSubscriptions")
   
    ' Add a new subscription
    Set SubObj = Subcoll.Add
    ‘ 将我们的EventClass的CLSID加进去
    SubObj.Value("EventCLSID") = EVENTCLSID
    ‘ 临时订阅时,这个Name条目的值一定是“Transient Subscription”
    SubObj.Value("Name") = TransientSubscription
    SubObj.Value("SubscriberInterface") = Me
 
       ‘ 将所做的改变存入COM+ Catalog Data Store中:
    Subcoll.SaveChanges
 
       ‘ 实际计算中g_TransID的值将为
’ {ADA4AFA1-6B54-4C4B-A74A-9EFFF4F7DC3F},这就是这次订阅的唯一标识
‘ 我们将在取消订阅时用到这个标识
    g_TransID = SubObj.Value("ID")
End Sub
 
Form退出时,取消临时订阅:
Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
 
‘ 对于Collection中的所有对象,读取数据
    Subcoll.Populate
 
    ' Remove the subscription
    Dim k
    For k = 0 To Subcoll.Count - 1
        Dim oObject
        Set oObject = Subcoll.Item(k)
       
               ‘ 如果Collection中的条目的ID和我们先前保存的ID一样,则删除
        If oObject.Value("ID") = g_TransID Then
            Subcoll.Remove (k)
            Subcoll.SaveChanges
        End If
    Next
    On Error GoTo 0
   
End Sub
 
实现事件的方法:
Private Function Trace_Publish(ByVal strAuthor As String, _
                                ByVal strTraceType As String, _
                                ByVal strEventCategory As String, _
                                ByVal nEventID As Integer, _
                                ByVal nOther As Integer, _
                                ByVal strTraceContent As String) As Integer
    ‘ 将Trace的内容添加到listbox中:
    Dim lCount As Long
    listTrace.AddItem Now & " :: " & strTraceType
   
    If (Len(strTraceContent) < 60) Then
        listTrace.AddItem "--------" & strTraceContent
    Else
        listTrace.AddItem "--------" & Left(strTraceContent, 60) & "..."
    End If
   
    lCount = listTrace.ListCount - 1
    listTrace.ListIndex = lCount
    If lCount > 20 Then
        listTrace.RemoveItem 0
    End If
                       
End Function
第三步,做一个发布者:
新建一个VBScript脚本,它将调用EventClass组件TomoTrace.Trace:
Dim obj
Set obj = CreateObject("TomoTrace.Trace")
strAuthor = "TomoEvent"
strTraceType= "Information"
strEventCategory = "Application"
nEventID = 0
nOther = 0
strTraceContent = "这里我们的例子中,EventClass就是TomoTrace.DLL组件,订阅者是Trace2File.EXE。发布者就是本脚本。"
obj.Publish strAuthor, strTraceType, strEventCategory, nEventID, nOther, strTraceContent
PublisheràDistributoràSubscriber:
先启动几个Trace2File.EXE,然后运行VBScript脚本。你就会看到这几个Trace2File上显示出发布的Trace内容。
然后将这个脚本放置在远程机器上,修改一下脚本:CreateObject(“TomoTrace.Trace”) àCreateObject(“TomoTrace.Trace”,”\\zhengyun”)。这样就可以在其他机器上向中心服务器发布事件通知了。
 
Written by zhengyun (at) tomosoft.com

转载于:https://www.cnblogs.com/vboy/articles/172677.html

将COM+ Events进行到底[转]相关推荐

  1. MySQL里Wating for Slave workers to free pending events到底在等什么

    作者:八怪(高鹏) 中亦科技数据库专家 一.问题来源 这是一位朋友给我的一个截图,说show slave status一直处于Wating for Slave workers to free pend ...

  2. 把鼠标、触摸屏、触控笔统一起来,Pointer Events介绍

    跨设备的问题 平时我们在电脑上访问的网页,大部分情况下是用鼠标来控制的.比如说链接跳转,就是鼠标指针移动到链接文字或图片的位置,然后点击一下.又比如说滚动屏幕,滑动一下鼠标滚轮就可以. 如果是供手机访 ...

  3. 成功解决win10下dos中运行tensorboard --logdir=logs和调用events.out.tfevents一闪而过的问题

    成功解决win10下dos中运行tensorboard --logdir=logs和调用events.out.tfevents一闪而过的问题 目录 解决问题 解决思路 解决方法 解决问题 在dos中运 ...

  4. 那一年,我考入了西北师范大学GIS专业,然而我很迷茫,GISer的职业规划到底是怎样的?

    那一年,我考入了西北师范大学,录取专业为地理信息系统,也就是常说的GIS,本科毕业后又考取了GIS专业的研究生,顺利毕业,进入了高校从事GIS教育工作.作为一个GISer,我相信有很多人跟我一样很迷茫 ...

  5. Celery 源码解析六:Events 的实现

    序列文章: Celery 源码解析一:Worker 启动流程概述 Celery 源码解析二:Worker 的执行引擎 Celery 源码解析三: Task 对象的实现 Celery 源码解析四: 定时 ...

  6. Kubernetes学习总结(11)—— Kubernetes Pod 到底是什么?

    前言 [译]What are Kubernetes Pods Anyway?最近看到了一条关于Kubernetes Pods的推特,来自了不起的Amy Codes(我真的希望这是她的真名): 虽然不是 ...

  7. Linux perf 1.4、hardware events

    可以通过perf list命令来查看系统中的hardware event: # simpleperf list hw List of hardware events:cpu-cyclesinstruc ...

  8. Kubernetes(K8s)Events介绍(上)

    Kubernetes Events虽不常被提起,却意义非凡.它存储在Etcd里,记录了集群运行所遇到的各种大事件.本系列文章将一步一步地揭开Kubernetes Events的神秘面纱. 师出有名 前 ...

  9. [源码解读]一文彻底搞懂Events模块

    前言 为什么写这篇文章? 清楚的记得刚找node工作和面试官聊到了事件循环,然后面试官问事件是如何产生的?什么情况下产生事件... Events 在哪些场景应用到了? 之前封装了一个 RxJava 的 ...

最新文章

  1. CROC-MBTU 2012, Elimination Round (ACM-ICPC) 总结
  2. linux 内核rt,实时操作系统kernel rt
  3. 家用电器用户行为分析与事件识别_8个步骤,教你如何开始用户行为分析
  4. matlab 基本变量和函数
  5. 数据结构思维 第十章 哈希
  6. 基于Geoserver配置多图层地图以及利用uDig来进行样式配置
  7. error C2871: #39;std#39; : does not exist or is not a namespace
  8. iOS利用Speech Kit实现语音识别
  9. windows服务器性能监控工具、方法及关键指标
  10. Java 垃圾回收机制原理
  11. 拓扑图是用什么软件画的?
  12. linux 音频处理软件推荐,Linux 上的优秀音频编辑工具推荐
  13. NodeJS集成Redis实战
  14. 【基本办公软件】万彩办公大师教程丨彩色转化PDF为黑白PDF
  15. html audio解决浏览器无法播放问题
  16. html怎么美化输入框,css 美化input输入框-美化按钮
  17. 笑话:如果你在河边等待得足够久,你会看到你的敌人的尸体漂过,是怎么翻译出来的?
  18. 金山的 wifi共享android手机怎莫共享台式机3g无线网络,巧妙开启笔记本WiFi共享 手机上网有神助...
  19. 【Unity】在Unity中实现扫描二维码 生成二维码功能
  20. 利用Python提取ABAQUS的计算结果(ODB)信息

热门文章

  1. spring 事务笔记(四)
  2. 零拷贝和java NIO
  3. android应用资源可以分为两大类,Android 应用资源(一)
  4. 下面不是python合法标识符_哪个不是python合法标识符
  5. c语言程序设计章节作业网上,C语言程序设计第17章在线测试
  6. 14K Star,「程序员做饭指南」冲上热榜
  7. mysql 取出全部数据库_php取出mysql数据库中所有数据
  8. bitnamigitlab_Bitnami Gitlab 安装配置 step by step
  9. linux 系统lv扩展_Linux增加LV(逻辑卷)容量
  10. python数据库操作sqlite_Python操作mysql和sqlite