WMI Series 6:事件预订和处理

**

事件预订和处理

WMI事件概述

对于从事 Winows 编程的开发人员来说,事件驱动的应用程序设计是再熟悉不过了,但是 WMI 中的事件又是一个什么样的概念呢?对于宝贵的内存和 CPU 资源,管理员需要不断的监视其性能;对于磁盘而言,我们需要随时知道它的使用情况,包括 I/O 性能,剩余空间等 …… 操作系统中如此之多的管理对象需要管理员一刻不停的监视其运行的状态,这样的工作负担是十分庞大的。因此,能不能当管理对象的性能数据接近某个我们事先设定的临界值时,发出警报或者 Email 通知给管理员,希望他能来处理。这种情形就是 WMI 中的事件处理机制,这种机制使得开发人员能够发布、订阅、传递事件的消息。

对于 WMI 事件处理机制来说,它必须解决三个方面的问题:

n 事件发布:能够找到事件的源;

n 事件订阅:能够订阅我感兴趣的事件;

n 事件传送:保证事件准确无误的传递到事件订阅者。

所幸的是 WMI 架构规范定义了完善的、强大的事件处理框架,使得上面的问题轻松的解决。您可以在编程时给出一个事件查询,来过滤数据,获取您感兴趣的事件。

WMI 事件分为三类:

n 内部事件:当类实例被创建、修改、删除时, WMI 响应这些内部的数据变化,这些信息来自 CIM 储存库。

n 外部事件:这类事件是用户自定义的事件。

n 计时器事件:这种事件是在特定的事件或者每个指定的事件发生的事件,它是由计时器来发布的,并且是订阅的用户自己建立的计时器。

WMI事件查询

WMI 事件查询语句与关系数据库的 SQL 查询语句很相似,下面给出一例:

SELECT *

FROM __InstanceModificationEvent

WITHIN 10

WHERE TargetInstance isa 'Win32_Service' AND

TargetInstance.StartMode = 'Manual' AND

TargetInstance.Started = FALSE AND

PreviousInstance.Started = TRUE

上面的例子查询的事件条件( WHERE 字句):事件源为 Win32_Service (即 windows 服务)中的服务,服务启动的模式为手动,而且是刚被停止的服务事件; WITHIN 字句指定事件轮询间隔为 10 秒钟; FROM 子句指定事件类型,即为实例被修改,包括服务启动、暂停、终止等。(有关更加详细的信息请参考 WMI SDK 文档)

Microsoft 公司新发布的 Visual Studio 2003 增强了服务器资源管理器的功能,对于 WMI 来说,我们可以通过服务器资源管理器查看管理类和管理事件,并且能够做事件查询,简化了编程前 WMI 查询的测试,也可以将这些管理对象做拖放到设计器,简化了编程。为了使您的服务器资源管理器能够增建 WMI 的功能,您需要到 Microsoft 公司的官方网站下载最新的 WMI Extensions for Visual Studio Windows Server 2003 Explorer ,并将其安装。

安装好了 WMI Extensions 后,展开服务器资源管理器您就可以看到 Management Classes 和 Management Events 两个节点。通过 WMI Extensions ,您可以轻松的完成下列任务:

n 查询 WMI 类的命名空间。您只需要右键单击 Management Classes ,选择 Add Classes ,在 Find class containg 文本框输入类名,然后查找就可以找到这个类所在的命名空间;

n 编译您的 WMI 查询语句,从而获取您感兴趣的事件数据。右键单击 Management Events ,选择 Add Event Query 即打开了编译 WMI 查询语句的窗口,在输入框中输入查询语句,并且选择事件源的类型,就可以执行 WMI 查询语句。这里还有一个高级选项,自动生成查询语句,查询的结果在 Visual Studio 的输出窗口中。

编程实现事件预定和处理

在这里我们将看到两个事件预定与处理的例子,一个是关于 Win32_Service 的事件预定与处理,一个是关于计时器事件的预定与处理,前者是同步的,后者是异步的。在给出例程之前,我们先看看有关事件预定与处理会涉及到的几个类,它们均位于 System.Management 命名空间下。

WqlEventQuery 类:它代表的是一个 WMI 事件查询,它的构造函数有 8 个,用户不同的情况。我们将只介绍其中的两个构造函数。

public WqlEventQuery(string) :输入参数为 WMI 的 SQL 查询语句,如给出的查询语句:

SELECT *

FROM __InstanceModificationEvent

WITHIN 10

WHERE TargetInstance isa 'Win32_Service'

public WqlEventQuery(string, TimeSpan, string):输入参数依次为事件类型,轮询间隔,过滤条件。对应上面的WMI查询语句,三个输入参数分别为:”__InstanceModificationEvent”、 new TimeSpan(0,0,10)、” TargetInstance isa 'Win32_Service'”。上述的两种方式使用构造函数得到的实例是一样的。


ManagementEventWatcher类:根据指定的事件查询预订临时事件通知,指定的事件指的是WqlEventQuery类的实例。ManagementEventWatcher的构造函数常使用的是带一个WqlEventQuery对象的输入参数。它还有另外一个重要的方法WaitForNextEvent()方法,用于等待下一个与指定查询匹配的事件,然后返回该事件。Start()方法用于启动查询并等待事件通知(发生),Stop()方法停止预定事件通知。


有了这些准备后,我们可以看看程序了。

//同步的事件预定和处理

public static void syncEvent()

{

//创建事件查询,每隔一秒轮询一次

string Query="SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance isa 'Win32_Service' AND TargetInstance.StartMode = 'Manual' AND TargetInstance.Started = FALSE AND PreviousInstance.Started = TRUE";

WqlEventQuery query=new WqlEventQuery(Query);

ManagementEventWatcher watcher=new ManagementEventWatcher(query);

// 直到下一次事件发生

ManagementBaseObject e = watcher.WaitForNextEvent();

//显示返回事件的信息

Console.WriteLine(

"服务{0}刚被停止, 现在的状态为: {1},服务描述为: {2}",

((ManagementBaseObject)e["TargetInstance"])["Name"], ((ManagementBaseObject)e["TargetInstance"])["State"],((ManagementBaseObject)e["TargetInstance"])["Description"]);

//退出事件预定

watcher.Stop();

}


应该说来上面的程序是比较简单的,为了测试结果,您可以将你的服务管理器中的任何一个手动启动的服务(或将其中一个服务改为手动启动)从启动状态改为停止,上面的程序就会有输出结果了。如果您选定的服务不是手动启动的,后者服务不是从启动状态改为停止,上面的事件查询将不会有任何结果,一直等待一个符合WQL查询条件的事件发生。


下面要讲的一个例子是计时器对象的事件预定和处理,有关计时器的知识,您可以阅读本书的计数器技术章节获取更为详细的信息。这个程序依照下列步骤:


1)        创建计时器事件的管理类对象;


2)        获取计时器的实例;


3)        设定计时器的参数;


4)        计时器开始定时;


5)        创建计时器事件查询的WqlEventQuery类型实例,并预定事件;


6)        挂接计时器事件处理方法;


7)        开始侦听计时器事件;


8)        停止预定计时器事件。


首先我们定义计时器事件的处理方法:

//定义事件处理方法

public class EventHandler

{

public void HandleEvent(object sender, EventArrivedEventArgs e)

{

Console.WriteLine("Event arrived !");

}

}


接下来的代码为计时器事件预定与处理的全部代码:


 


 


 

//计时器事件预定与处理

public static void asyncEvent()

{

ManagementClass timerClass =

new ManagementClass("__IntervalTimerInstruction");

ManagementObject timer = timerClass.CreateInstance();

timer["TimerId"] = "Timer1";

timer["IntervalBetweenEvents"] = 1000;

timer.Put();

// 预定计时器事件

// 创建计时器事件查询

WqlEventQuery query =

new WqlEventQuery("__TimerEvent", "TimerId="Timer1"");

// 初始化watcher,并预定query定义的事件

ManagementEventWatcher watcher = new ManagementEventWatcher(query);

// 挂接事件的处理方法

watcher.EventArrived +=

new EventArrivedEventHandler((new EventHandler()).HandleEvent);

// 开始侦停事件

watcher.Start();

<SPAN lang=EN-US

**

Published At
Categories with Web编程
Tagged with
comments powered by Disqus