程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 文件系統驅動編程基礎篇之4——Wmi管理規范

文件系統驅動編程基礎篇之4——Wmi管理規范

編輯:關於C++

二、WMI簡介

一)基於Web的企業管理(Web-Based Enterprise Management (WBEM))的提出是為了解決企業在快速發展的過程中,總成本(Total cost of ownership(TCO)) 也隨之快速增長的矛盾,它作為一項業界倡議,起始於1996年,規范了企業網絡中受管資源的描述與使用。WBEM建立在通用信息模型(Common Information Model (CIM, 由Desktop Management Task Force,即DMTF推動的工業化標准))規劃(schema)的基礎上。WBEM提出了一個標准化的的方法用於建立統一的框架,不同技術和平台上產生的管理信息均以相同的形式供管理程序訪問,這樣就減少了維護費用和企業網絡的壽命周期成本(life cycle costs)。(注:Common除了譯為“通用”,也可譯為“公共”)

從根本上說,WBEM提供了數據定義的信息標准和組件交互的處理標准。

二)CIM是一種機制,用於為受管資源建模並以受管對象格式(Managed Object Format (MOF))表現這些模型。使用 CIM 和 MOF,組成受管資源或資源網絡的組件可以象在面向對象設計過程中使用的組件一樣被建模和看待。

CIM由一個核心模型,許多通用模型以及擴展模型組成。核心模型是一系列類、連接和屬性的集合,該對象組提供了所有管理域公用的基本信息模型;通用模型提供特定管理域的通用信息模型,這些特定的管理域,如系統、應用程序、設備、用戶和網絡等;擴展模型代表通用模型的特定技術擴展。

A core model—incorporates classes applicable to all management domains.

Common models—incorporate classes common to specific management domains, independent of particular technologies or implementations. Common domains include systems, applications, devices, users, and networks. These models provide a basis for the development of management applications and include a set of base classes for extension into technology-specific areas.

Extension models—these represent technology-specific extensions of the common models. These models are specific to environments, such as operating systems (for example, UNIX, or Microsoft Windows).

三)Windows Management Instrumentation——通常譯為WMI管理規范,是微軟提出的,與WBEM兼容的技術,同樣也兼容於CIM2.0或2.5。WMI是Windows管理服務的主要組件,它提供的功能如下(從資料2節選,重點記憶紅字即可mcieels):

A rich and consistent model of Windows 98 and Windows 2000 operation, configuration, and status. 是一個模型

A COM API that supplies a single point of access to all management information. 可COM訪問

Interoperability with other Windows 2000 management services, which will simplify vendors' efforts to create well-integrated management applications. 可協作

A flexible architecture that allows vendors to extend the information model to cover new devices, applications, and other enhancements by writing code modules (WMI providers). 可擴展

A powerful event architecture that allows changes in management information to be identified, aggregated, compared to and associated with other management information, and forwarded to local or remote management applications. 有事件機制

A rich query language(WQL) that enables detailed queries of the information model. 可查詢

A scriptable API, which enables management application developers to use Visual Basic? or Windows Script Host (WSH). 可腳本訪問

圖10-2是上圖架構的簡化,在WMI模型中,數據和事件被分成了消費者(Consumers)和生產者(Providers)兩類。數據塊就是抽象類的實例,其概念與C++中的類概念一致。如同C++中的類,WMI類也有數據成員和實現對象行為的方法。數據塊中的內容並不是由WMI指定,而是由數據生產者和數據的使用目的決定的。送往驅動程序的數據最有可能來自管理者本身的操作。而驅動程序發出的數據通常是某種性能的統計數據,這些數據的消費者可能是某個性能監視程序。

WMI類允許同時存在全球化和本地化的數據,詳看資料3。

WMI類又可稱為主類(master class),由基類(basic class)和amendment(修正,糾正之意,用於本地化,難以揣摩合適的譯文^_^)類組成。主類包含所有的屬性集和限定(qualifiers)。基類是主類的子集,包含所有的屬性集和部分限定,不包含本地限定(localizable qualifiers)。amendment和主類具有相同的名字,是一個抽象類,包含了關於本地限定的屬性子集(includes a subset of properties with localizable qualifiers),不包含主類的其他屬性。

amendment總是位於包含基類定義的命名空間下的子命名空間。每一個子命名空間包含著特別本地化(particular locale)的amendment類,這樣設計的結果是多種語言的子命名空間可以被加入到儲存庫(repository,見架構圖)中,因此可同時存在多種語言的類定義:

ROOT\CIMV2

ROOT\CIMV2\MS_409

ROOT\CIMV2\MS_407

WMI允許存在多重命名空間,每個命名空間中包含的類屬於一個或多個用戶模式生產者。生產者使用平台SDK中公開的COM接口來注冊Windows管理服務(Windows Management Service)。操作系統(包括所有設備驅動程序)支持一個名為root\cimv2的命名空間,裡面包含了CIM版本2。

四)WDM驅動程序可以作為WMI類實例的生產者。一個描述了驅動程序支持的各種類(驅動程序可以為這些類提供數據)的腳本稱為驅動程序規劃(schema)。我們可以使用MOF(Managed Object Format)語言定義規劃。系統則維護一個稱為儲存庫(repository)的數據字典,它包含了所有已知的規劃定義。如果驅動程序做得正確,系統將在初始化驅動程序時自動把規劃放到儲存庫中。

WDM生產者是WMI生產者的一個組成部分,它可以訪問WDM硬件驅動的類、實例、方法和事件。硬件驅動的類位於root\wmi命名空間,Wmi.mof和Wmicore.mof定義了主要的WDM類。WDM生產者允許管理程序從滿足WMI-for-WDM的設備驅動訪問數據和事件,生產者主要以IWbemServices接口的形式提供這些服務。

為了查看命名空間,可到微軟站點下載安裝WMITools軟件。WMI CIM Studio以樹視圖的形式展現了分層的命名空間。

三、MOF與WQL語言

MOF是一種基於接口定義語言 (IDL) 的語言,用於描述管理信息,即用於描述CIM。MOF 語法是以文本形式描述對象定義的方法。MOF 匯編器(如mofcomp.exe)處理 MOF 文件,並向 CIM 儲存庫添加必需的對象定義。C++Builder類型庫(Type Library)也使用了IDL。

MOF語法類似於C++,但遠比C++簡單,如果在學習過程中遇到困難,可以聯想兩者的相似處。如MOF類的實例化可以想象成C++的構造函數,引用也可以聯想成C++的&。

一個簡單的MOF文件master.mof如下:

點擊看大圖

MOF和C++類定義有相似之處,也使用#pragma預處理。#pragma amendment指示編譯器輸出語言中性和語言特定的兩個版本,“MS_409”表示本地標識符(LCID),類似還有“MS_408”等。

MOF的數據類型見資料10。

MOF包含了豐富的限定(Qualifier ,[ ]裡以逗號分隔的標識符),用於描述類、實例、屬性、方法和方法的參數。限定名不區分大小寫,除此之外,它還遵守類似於C++命名的一些約束。限定可分為三大類:標准限定(Standard qualifier),CIM限定(CIM qualifier),特殊限定(Unique qualifier),你還可以為自己的生產者創建自定義的限定。

限定可以被稱為“限定風格”(Qualifier Flavor)的標志來修飾,語法為:

[qualifier1 : flavor1 flavor2 flavor3, qualifier2 : flavor1]

因此,綜合了限定以及限定風格的分類後也可進行如下的劃分(*為WDM裡常見):

Qualifier Type Description 注釋 Meta Refines the definition of meta-constructs by clarifying the actual usage of a class or property declaration. 通過MOF語法闡明類或屬性聲明的實際用途,元限定完善了CIM模式元結構的定義。 Standard* Supports the descriptions that all CIM-compliant implementations must handle.   Optional Addresses situations not common to all CIM-compliant implementations.   WMI-specific* Describes qualifiers specific to WMI, such as performance counter class qualifiers.   Qualifier Flavors Provides additional information about a qualifier, such as whether a derived class or instance can override the qualifier's original value.  

一些限定與風格:

Qualifier 分類 注釋 示例 Amended Flavor 基類不用該限定,amendment類用於本地化 DisplayName("User Name") : Amended Amendment WMI-specific – Standard 指明類裡包含被本地化的amended限定 Amendment Description Standard 描述了被命名的元素,默認為NULL Description("This property shows when the object was created") DisplayName Standard 代替真實的元素名而顯示在UI的名字 DisplayName("Time Stamp") Dynamic WMI-specific – Standard 指明類的實例被動態創建 Dynamic Guid 自定義 必須,驅動程序用來辨別生產者 見wmi42.mof Key* Standard 鍵屬性用來標識和區分每一個實例 Key Locale WMI-specific – Standard 為類或實例指定語言 Locale(0x409) Provider WMI-specific – Standard 限定的值是動態生產者的名字,生產者創建類實例和更新實例數據 Provider("WMIProv") WMI 自定義 表示生產者類型 見wmi42.mof WmiDataId WMI-specific – WDM Index in the WNODE of the data for the property. The WDM provider uses this qualifier to determine how the data is formatted while extracting data from the WNODE and generating WMI classes. The starting value is 1. (除了InstanceName和Active屬性,其他屬性都必須帶有該Id) WmiDataId(1)

* Key:Msdn上存在矛盾的說明。錯誤的說明是認為僅InstanceName能被聲明為Key,但實際上可由多個屬性組成復合鍵。

對於難以理解的限定,可通過CIM Studio來查看實際的效果。如屬於Meta類別的Association是一個難以琢磨的限定,請看下面的mof文件:

<// 本文轉自 C++Builder研究 - http://www.ccrun.com/article.asp?i=1057&d=d1f203

/p>

#pragma namespace("\\\\.\\root") instance of __Namespace
{
Name = "WMI" ;
} ;
#pragma namespace("\\\\.\\root\\WMI")
Class A{
[key] string aKey;
};
Class C{
[key] string cKey;
};
Class D{
[key] string dKey;
};
Class E{
[key] string eKey;
};
// The following class creates an association between the "A", "C", "D", "E" class
[Association] Class B{
[key] A ref aRef;
[Key, Min(1)] C ref cRef;
[key] D ref dRef;
[key] E ref eRef;
};

它在命名空間root\wmi下創建了A、B、C、D、E五個類,它們的Association關系分別為:

MOF匯編器常用的三種操作:

檢查MOF文件語法:mofcomp –check master.mof

創建語言中性和語言特定的MOF文件:mofcomp -MOF:g.mof -MFL:l.mof master.mof

編譯成二進制的BMF文件,該文件可以自定義資源的方式加入C++工程的資源文件中:mofcomp –B: bin.bmf l.mof

// g.mof,0x409 = 1033
[LOCALE(1033)]
class myclass
{
[key] string Name;
uint64 Value;
uint64 Timestamp;
};

// l.mof
#pragma namespace("\\\\.\\root\\default")
instance of __namespace{ name="ms_409";};
#pragma namespace("\\\\.\\root\\default\\ms_409")
[Description("Localized version of MyClass for American English") : Amended,AMENDMENT, LOCALE(0x409)]
class myclass
{
[DisplayName("User Name") : Amended,Description("The Name property contains the name of the user") : Amended,key] string Name;
[DisplayName("Time Stamp") : Amended,Description("This property shows when the object was created") : Amended] uint64 Timestamp;
};

注釋// 或 /* */並非可隨處添加,如匯編器提示“…文件域意外的符號…”時要特別注意注釋是否放於錯誤的位置上。

instance of __namespace一行實例化了ms_409命名空間(即root\DEFAULT\ms_409),下一行則在這個命名空間加載myclass類。

通過語法檢查的mof文件可以加入WMI命名空間(N表示默認加載的空間):

mofcomp -N:root\default g.mof

使用CIM Studio查看儲存庫裡的g.mof,對於l.mof,Value不會出現在屬性表中:

通過CIM Studio裡的MOF Generator工具還可以生成你感興趣的節點的MOF文件。

請閱讀如下toaster.mof,理解包含的語法,並在WMI命名空間下驗證自己的理解:

[Dynamic, Provider("WMIProv"),
WMI,
Description("Toaster driver information"),
guid("{BBA21300-6DD3-11d2-B844-00C04FAD5171}"),
locale("MS\\0x409")]
class ToasterDeviceInformation
{
[key, read]
string InstanceName;
[read] boolean Active;

[WmiDataId(1),
read,
WmiEnum{"0=I8042 Connector"
"1=Serial Connector",
"2=Parallel Connector",
"3=USB Connector" },
Description("How the toaster is connected to the computer")]
uint32 ConnectorType;

[WmiDataId(2),
read,
Description("This indicates the capacity in Kilo Watts of the toaster device.")]
uint32 Capacity;

[WmiDataId(3),
read,
Description("Number of errors that occurred on this device")]
uint32 ErrorCount;

[WmiDataId(4),
read,
Description("Indicates the number of controls on the toaster device.")]
uint32 Controls;

[WmiDataId(5),
read,
write,
Description("The DebugPrintLevel property indicates the debug output level of toaster device.")]
uint32 DebugPrintLevel;

[WmiDataId(6),
read,
Description("ModelName")]
string ModelName;
};
[WMI, Dynamic, Provider("WMIProv"),
guid("{01CDAFF1-C901-45b4-B359-B5542725E29C}"),
locale("MS\\0x409"),
WmiExpense(1),
Description("Notify Toaster Arrival")]
class ToasterNotifyDeviceArrival : WMIEvent
{
[key, read]
string InstanceName;

[read]
boolean Active;

[read,
Description("Device Model Name"),
WmiDataId(1)] string ModelName;
};

為了解系統默認生成的命名空間,可閱讀system32\wbem路徑下的MOF文件。為了掌握MOF的語法,可閱讀DDK源代碼目錄下的MOF文件。

WQL是Ansi-SQL的簡化版本,它可以用來查詢命名空間下的類,如select * from wmi42,對此不再詳述。

四、WMI與驅動程序

請先閱讀資料1第二節,以及wmi42示例的SYS部分。

驅動程序對WMI的支持,體現在對系統控制IRP,即IRP_MJ_SYSTEM_CONTROL的支持上。除了以Ioctl類似的方式實現該IRP(AltWmi.cpp),更簡單的方式是委托WMILIB來支持WMI(Wmi.cpp),這涉及到一個數據結構:

// This structure supplies context information for WMILIB to process the
// WMI irps. Memory for this structure may be paged.
typedef struct _WMILIB_CONTEXT
{
// WMI data block guid registration info
ULONG GuidCount;
PWMIGUIDREGINFO GuidList;

// WMI functionality callbacks
PWMI_QUERY_REGINFO QueryWmiRegInfo;
PWMI_QUERY_DATABLOCK QueryWmiDataBlock;
PWMI_SET_DATABLOCK SetWmiDataBlock;
PWMI_SET_DATAITEM SetWmiDataItem;
PWMI_EXECUTE_METHOD ExecuteWmiMethod;
PWMI_FUNCTION_CONTROL WmiFunctionControl;
} WMILIB_CONTEXT, *PWMILIB_CONTEXT;

Wmi.cpp是如何處理WMI請求的?針對系統控制IRP裡的幾個副功能碼,我們定義了相應的回調函數,WMILIB_CONTEXT結構裡的回調函數指針指向我們的函數。當WMI派遣例程DispatchWmi調用WmiSystemControl來處理IRP時,就會自動調用這些函數。AddDevice和RemoveDevice例程調用IoWMIRegistrationControl為設備對象注冊或注銷作為WMI數據生產者(WMI data provider)的驅動程序。注冊之後,第一個被處理的系統控制IRP的副功能碼是IRP_MN_REGINFO,派遣函數QueryRegInfo被調用以處理該功能碼。在QueryRegInfo裡,返回了系統用於創建數據塊的MOF資源的名字。其他派遣函數就此略過,Msdn裡對每個函數都有詳細的敘述。

Wmi42正確啟動後應該符合下圖的情形(如果在安裝上碰到問題,可暫時跳過,下篇將對安裝問題作進一步的說明):

留有余力的讀者,可進一步研究WMI的事件機制,在此略過。

五、WMI、COM與用戶程序

請閱讀資料1第三節,以及Chap10\WMI42示例的TEST部分。

本篇是初次涉及COM編程,今後我們還將陸續接觸COM在各領域的應用。COM既是一種技術,也是一種組件,這種組件對外公開了一些稱為“接口”的抽象類,除此以外都是不透明的。假如我們剖開外殼可以看到內部的實體,即不是接口的那些類,由被稱為“類廠”的類來創建(即用類來創建類)。實體通過接口對外提供了COM的所有服務。接口、實體、類廠可看成COM組件的基本元素。

接口的使用有一個很重要的約定——凡是查詢/獲取一次接口,都要用AddRef()增加一次計數,接口使用後都要用Release()釋放本次計數。有時候我們使用API函數後沒有調用AddRef(),卻需要Release(),原因是這些函數內部已有調用代碼。這樣的常用API並沒有幾個,我們可以通過實踐很快的掌握,一些不確定是否需要釋放計數,以及如何釋放計數的API可以查閱Msdn。

COM出現後不久,一些“懶人”寫出了自動維護約定的智能指針,隨後ATL出現了。客觀的說,微軟在技術上的創新貢獻是有目共睹的,但是ATL?它把所有看到的東西一律封裝成模板,這樣你可以僅用ATL就可以完成一個實用的Windows程序了,它的技術書籍重得甚至可拿來壓艙底。相比大多數人的敬而遠之,微軟雖然也在逐漸淡化COM,但即便如此,今天很多的新生技術外表下都隱藏著COM。

WMI也是通過COM接口提供服務,詳見資料11。

TEST示例首先初始化COM和為進程設置了默認的安全值,接著打開root\wmi命名空間,設置接口權限,最後報告Wmi42類屬性的信息。

在此例的基礎上,可深入學習各類接口函數,弄清MOF語法如何以COM接口方式調用。

代碼《let_us_try_wmi_samples》,《WMI C++ Application Examples》演示了如何使用WMI訪問常見硬件,後篇系統的總結了用戶模式下調用WMI的基本步驟。另可閱讀Msdn上關於Vista下使用WMI的論述。

六、IClientSecurity接口與安全

vs2005的Msdn裡並沒有IClientSecurity接口的說明(官方站點有此說明的),既然微軟似乎有意忘記了,筆者也實在不願花費時間陷入細節中去,我們可在在實踐中來體會該接口的功能。

IClientSecurity

Gives the client control over the security settings for each individual interface proxy of an object. The methods of IClientSecurity can be used to set or query the security settings of a specific interface proxy or to copy an interface proxy.

Every object has one proxy manager, and every proxy manager exposes the IClientSecurity interface automatically. Therefore, the client can query the proxy manager of an object for IClientSecurity, using any interface pointer on the object. If the QueryInterface call succeeds, the IClientSecurity pointer can be used to call an IClientSecurity method, passing a pointer to the interface proxy that the client is interested in. If a call to QueryInterface for IClientSecurity fails, either the object is implemented in-process or it is remoted by a custom marshaler that does not support security. (A custom marshaler can support security by offering the IClientSecurity interface to the client.)

The interface proxies passed as parameters to IClientSecurity methods must be from the same object as the IClientSecurity interface. That is, each object has a distinct IClientSecurity interface: calling IClientSecurity on one object and passing a proxy to another object will not work. Also, you cannot pass an interface to an IClientSecurity method if the interface does not use a proxy. This means that interfaces implemented locally by the proxy manager cannot be passed to IClientSecurity methods, except for IUnknown, which is the exception to this rule.

For more information about proxies, see IMarshal - Default Implementation.

When to Implement

The proxy manager for each object provides an implementation of IClientSecurity, so you would typically not implement this interface. If, however, you are defining objects that support custom marshaling, you may choose to implement IClientSecurity on the objects' custom proxies to maintain a consistent programming model for the objects' client applications. You may also choose to support this interface on in-process objects. 

When to Use

Call the methods of this interface to examine or modify the security settings of a particular connection to an out-of-process object. For example, you might temporarily establish a higher security level — one with complex encryption — only for the period when sensitive information or data is being sent to the object. Alternately, you might establish different proxies to the same object with different security levels. You could use these security levels to support different clients that are calling your object or to support different operations within your application.

Methods in Vtable Order

IClientSecurity Methods Description QueryBlanket Retrieves authentication information. SetBlanket Sets the authentication information that will be used to make calls on the specified proxy. CopyProxy Makes a copy of the specified proxy.

七、結語

除了Ioctl,現在我們又掌握了一個了解系統的重要手段,讀者在關注WMI細節的同時,也請留意一下系統性的事物如何把各個分系統進行整合。

本篇作為選讀內容,不設參考完成時間。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved