📄 8.2 windows management instrumentation.htm
字号:
size=3><B style="LINE-HEIGHT: 25px">Win32_SystemAccount<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>Win32_SystemAccount类别描述了本机帐户。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7
size=3><B style="LINE-HEIGHT: 25px">Win32_LoadOrderGroup<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>Win32_LoadOrderGroup类别确认可取决于服务的载入顺序群组。Win32_LoadOrderGroup的二个重要的关联类别是描述基础类别服务与一个载入顺序群组关系的Win32_LoadOrderGroupServiceMembers类别,以及描述基础服务和取决于开始执行之载入顺序群组间依存关系的Win32_LoadOrderGroup
ServiceDependencies类别。以下的方法可以表示这二个类别之间的差异:元件关联类别说明「服务或驱动程序为此群组的一个成员」,然而依存关系之相关类别则说明「此服务或驱动程序隶属于此群组」。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">软件安装类别<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>图8-5说明了有关软件安装的主要类别。这些类别直接反映了用来控制Microsoft Windows
Installer技术的资讯。如果您使用Windows
Installer安装您的服务,这些安装类别会被自动地加入,而您就可以使用WMI来安装、移除以及修复您的安装资讯。</FONT></P>
<P><BR style="LINE-HEIGHT: 25px"> </P>
<CENTER style="LINE-HEIGHT: 25px">
<P><INPUT id=5 style="LINE-HEIGHT: 25px" type=image height=388
width=550 src="8.2 Windows Management Instrumentation.files/8-5.gif"
border=0 onclick="imgclick"></P></CENTER>
<CENTER style="LINE-HEIGHT: 25px">
<TABLE style="LINE-HEIGHT: 25px" border=0>
<TBODY style="LINE-HEIGHT: 25px">
<TR style="LINE-HEIGHT: 25px">
<TD style="LINE-HEIGHT: 25px" align=middle><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2><FONT style="LINE-HEIGHT: 25px" face=arial
color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 图8-5 </B></FONT>与软件安装有关的类别</FONT></TD></TR></TBODY></TABLE></CENTER>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>Win32_Product是具体的类别,是经由一个消费者单元取得的实体元件、软件特性以及其他产品的集合。这个类别的实例描述了被Windows
Installer安装的产品。一个产品通常与单一的安装套件有关。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>CIM_SoftwareElement类别为特定平台而将CIM_SoftwareFeature物件个别分解到一组可管理或可部署的元件中。由它的硬体架构以及作业系统可以唯一的确定软件元件平台(例如,Microsoft
Win98或Windows 2000)。</FONT></P></A><A style="LINE-HEIGHT: 25px"
name=208005>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">事件<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>每个有用的管理应用程序必然是经由事件驱动。这是为了一个回应管理应用程序(在它们中断后,元件是固定不变的)以及预防管理应用程序(在它们中断前,元件是固定不变的)。WMI有一个要求尽量使您使用的部份最小化的事件相关特性的一个广泛设备。在本节中,将会看到WMI提供的部份,接着会描述如何使您的服务从一个大且复杂的环境下转移至一个可管理的企业类别应用程序中,或者能正常的使用于远端服务的情形。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>每个事件结构至少必须解决叁个问题:</FONT></P><FONT style="LINE-HEIGHT: 25px"
face=arial color=#000000 size=2>
<UL style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 发行(Publication) </B></FONT>我该如何查明有什么事件?<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 订阅(Subscription) </B></FONT>我该如何将想知道事件告诉系统?<BR
style="LINE-HEIGHT: 25px">
<LI style="LINE-HEIGHT: 25px"><FONT style="LINE-HEIGHT: 25px"
face=arial color=#3e80d7 size=2><B
style="LINE-HEIGHT: 25px"> 传送(Delivery) </B></FONT>事件如何传送到我这里?<BR
style="LINE-HEIGHT: 25px"> </LI></UL></FONT>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">事件的发行<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>WMI中的事件透过一个事件类别被发行。一个事件的产生被类别的实例所描述。所有的事件类别皆从
__Event系统类别取得。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>您可以在CIM Studio的 __SystemClass\__IndicationRelated下找到
__Event类别。用于系统类别前面的双底线是用来区分其他类别名称与保留的系统类别名称。WMI不允许您定义一个前面加底线的类别名称。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>WMI定义的最重要事件类别为
__InstanceOperationEvent以及取得它的类别。实际上它们是非常简单的,如同您可在下列之MOF程序代码中看到的:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">class __InstanceOperationEvent :__Event { <BR> object TargetInstance; <BR>}; <BR>class __InstanceCreationEvent :__InstanceOperationEvent { <BR>}; <BR>class __InstanceDeletionEvent :__InstanceOperationEvent { <BR>}; <BR>class __InstanceModificationEvent :__InstanceOperationEvent { <BR> object PreviousInstance; <BR>};</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>其中二个object定义了嵌入的物件,这些物件会触发事件。例如,当一个新的处理程序成立时,如透过新的Win32_Process类别描述的一样,以它包含嵌入物件之新实例的TargetInstance属性产生一个
__InstanceCreat类别的新实例。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>透过这个方法,WMI提供一个描述每个命名空间之建立、修改或删除动作的事件。当然,这些事件只有在要求时才会被接收—在最简单的电脑系统中,如果您询问所有可能的__InstanceOperationEvents时,则您每秒钟就会接收到成千的事件。基本上您可以监控每一个线程、处理程序、文件、服务或其他改变系统状态之元件的实例。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">事件的订阅<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>在WMI中,事件的订阅透过一个客户端应用程序完成。询问是与一个类别相互作用的一个自然方法。您可以呼叫一个API并传递一个物件定义的询问,将您有兴趣的物件告诉WMI。例如,当一个新的处理程序被启动时,以下的Microsoft
Visual Basic程序代码会侦测到它并显示处理程序的名称。</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">Dim wbemService As SWbemServices <BR>Dim events As SWbemEventSource <BR>Dim singleEvent As SWbemObject <BR>Dim sQuery As String <BR>Set wbemServices = GetObject("winmgmts:{impersonationLevel=impersonate}") <BR>sQuery = "select * from __instancecreationevent within 10" & _ <BR> "where targetinstance isa ’Win32_Process’" <BR>Set events = wbemServices.ExecNotificationQuery(sQuery) <BR>Do <BR> Set singleEvent = events.NextEvent <BR> MsgBox singleEvent.TargetInstance.Name <BR>Loop</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>程序代码的第一个陈述式透过WinMgmt服务取得一个handle,以开启WMI。第二个陈述式则提供订阅的请求。第叁个陈述式透过服务而引用了ExecNotificationQuery函数,以执行该请求。经由ExecNotificationQuery呼叫而回传的event物件有一个如事件发生时,允许您等待事件的NextEvent方法。当我们讨论到事件的传递时,您将会看到这个请求事件的范例程序。WMI支援非常复杂的事件订阅和传递机制,以适用各式各样的管理应用程序。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=Arial color=#3e77d7 size=3
Black><B style="LINE-HEIGHT: 25px">说明</B></FONT> </P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>您应该也要注意一些与先前所列之范例程序代码有关的特性。它利用WMI指令码的惯例,假设root\CIMV2为预设的命名空间。同样的,它没有包括任何错误处理或终止程序代码。</FONT></P>
<HR style="LINE-HEIGHT: 25px">
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">事件的传递<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>现在我们将注意力转移到事件的传递上。您曾经看过一个透过允许您编写捕捉与处理事件的简单指令码介面支援的基本事件传递机制。事实上,如果将事件当成管理应用程序的一部份使用,您将会需要以一个非同步的方式处理它们。您也需要过滤事件以使您只察看有兴趣的事件。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>WMI允许您控制事件被传递的二个方法,即哪个事件已被传递以及取得与事件一起传递的资料。利用要求来陈述订阅请求的事实,以负担这个控制。我们已经看过每次得到一个处理程序已启动事件之简单的订阅请求。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>考虑一个稍微复杂的范例。假设您只想取得已停止之以手动方式启动的服务名称,您的第一个步骤是找出一个定义服务启动方式的属性。在CIM
Studio中察看Win32_Service类别的定义,您应该会看到一个名称为StartMode的属性。在属性上按下滑鼠右键,选择Property
Qualifiers以察看它的修饰语。ValueMap修饰语包含了有关启动模式的资讯,而且可以为以下之一的值:Boot、System、Auto、Manual以及Disabled。如果它为「Manual」,则我们可以检查并察看StartMode的属性。服务的名称是经由Name属性而给定的,所以您的订阅要求可能会是以下的内容:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">Select TargetInstance.Name <BR>From __InstanceModificationEvent <BR>Within 10 <BR>Where TargetInstance isa ’Win32_Service’ and <BR> TargetInstance.StartMode = ’Manual’ and <BR> TargetInstance.Started = FALSE and <BR> PreviousInstance.Started = TRUE</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>注意到这个要求使用了PreviousInstance值,以确定服务的启动状态是否已经从True被改变到False。服务有许多可以改变的外观,但是在这个情况下我们只对服务是否已停止的事实感到兴趣。使用Within类别的请求定义一个透过CIM
Object Manager在侦测事件发生时使用的轮询间隔。基本上物件管理员每十秒就会重新评估该物件。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>您可以编写一个用WMI登录之固定的事件订阅者,其方法是每个事件发生时,这个订阅者被要求采取一些动作。我们刚才已在范例中看过,您可以确定每次服务被停止时,操作员会被通知。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>WMI有许多标准的订阅者,您可以用它来建构复杂的事件控制者。例如,WMI可以利用Microsoft Message
Queue(MSMQ)来保证事件的传递。WMI有一个可以发布命令列呼叫的标准订阅者,例如,当一个物件发生时,允许您传送一个e-mail讯息。</FONT></P></A><A
style="LINE-HEIGHT: 25px" name=208006>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e70d7
size=5><B style="LINE-HEIGHT: 25px">TimeServiceProvider的WMI提供者范例<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>TimeServiceProvider的WMI提供者范例(「08
TimeServiceProvider.dll」)如 </FONT></A><FONT
style="LINE-HEIGHT: 25px" face=arial color=#000000 size=2><A
style="LINE-HEIGHT: 25px"
href="http://www.acejoy.com/doc/serverside/8.htm#369_1"
target=_new>列表8-1</A> 所示,说明了如何为第叁章所描述之TimeService建立一个WMI提供者之DLL。TimeServiceProvider使WMI可以看见TimeService服务的属性。透过对WMI的使用,一个客户端可以取回此属性。不像本书中的另一个范例,WMI
SDK工具为此范例建立了原始程序代码。本节中,您将会学习到如何使用这些工具建立一个动态的扩展WMI的Win32_Service类别。这个范例的原始程序代码文件存放在附赠光碟的08-TimeServiceProvider目录中。现在我将透过一个简单的动态提供者来说明它的步骤。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">选择提供的资讯<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>建立提供者的第一个步骤是决定服务之可用资讯。TimeService服务使用一个匿名管道给Client/Server连结—这个匿名管道的名称即是一个可利用的资讯。在TimeService.cpp文件中(第叁章),可以看到管道名称为「\\.\pipe\TimeService」。我们将会建立一个提供管理员或客户端使用WMI来要求匿名管道的动态提供者。您可以考虑修订这个WMI提供者,因此它也允许管理员透过使用WMI而改变匿名管道的名称。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e72d7
size=4><B style="LINE-HEIGHT: 25px">使用MOF取回一个类别<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>下一个步骤是用Win32_Service取回一个类别,并且增加一个匿名管道的属性至取回的类别中。以下的程序代码说明被用来建立此类别的MOF程序代码,存放在附赠光碟上的TimeServiceStart.mof文件中:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">#pragma namespace("\\\\.\\root\\cimv2") <BR>class Richter_TimeServiceProvider :Win32_Service { <BR> string PipeName; <BR>};</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7
size=3><B style="LINE-HEIGHT: 25px">使用MOF编译器<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>一旦建立了
.mof档后,您需要使用MOF编译器去编译它(MOFComp.exe),它是WMI的一部份。MOF编译器将会增加新的Richter_TimeServiceProvider类别至系统中。以下说明了您可以使用的编译命令:</FONT></P>
<DIV style="LINE-HEIGHT: 25px; BACKGROUND-COLOR: #d7d7d7"><FONT
style="LINE-HEIGHT: 25px" face=Arial size=3><PRE style="LINE-HEIGHT: 25px">C:\WINNT\system32\wbem\mofcomp.exe -class:forceupdate <BR> "<filepath>\TimeServiceStart.mof"</PRE></FONT></DIV>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>请注意「-class:forceupdate」选项以及标记在MOF文件路径前后引号的使用。当类别发生冲突时,「-class:forceupdate」选项可以强迫更新类别,而引号则允许您使用包含空白字元的名称。请察看《WMI
SDK以及Platform SDK》文件的「MOF
Compiler」主题,以取得更多有关MOF编译器之可用选项资讯。</FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#3e74d7
size=3><B style="LINE-HEIGHT: 25px">结合MOF编译器至Visual Studio<BR
style="LINE-HEIGHT: 25px"> </B></FONT></P>
<P><FONT style="LINE-HEIGHT: 25px" face=arial color=#000000
size=2>如果您时常使用MOF编译器,您会发现可以很方便的将它新增至Microsoft Visual
Studio之Tools功能表,开启Visual
Studio并从Tools功能表中选择Customize选项即可完成这件事。在Customize对话方块中,选择Tools页签,卷动清单至底部,增加一个新的工具,名称为MOF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -