wdm/wmi调用与实现


1.  文档说明

本文重点介绍了WMI的客户端实现方法和驱动程序Provider的在多路径设备相关驱动中的实现方法。

 

2.  WMI简介

WMI(Windows  Management Instrumentation)windows管理规范是WBEM模型在windows系统中的实现。通过WMI可以访问、配置、管理和监视几乎所有本地和远程的windows资源。比如用户可以在远程计算机器上启动一个进程;设定一个在特定日期和时间运行的进程;远程启动计算机;获得本地或远程计算机的已安装程序列表;查询本地或远程计算机的Windows事件日志等等。

 

应用程序程序从驱动中获取数据主要通过两种方法实现。

方案一:应用程序通过调用DeviceIOControl调用驱动接口交互

应用程序通过符号链接名打开驱动设备,调用DeviceIOControl跟驱动交互。驱动程序需要注册驱动程序符号链接名,处理应用程序发送的请求。注册符号连接名会暴露在用户模式下,安全性差。驱动程序只能被动接收应用程序的命令,不能主动发送事件给应用程序。

方案二:应用程序和驱动程序通过WMI接口交互

应用程序调用统一的COM API来读取驱动提供的数据。驱动程序可以处理IRP_MJ_SYSTEM_CONTROL数据包。也可以使用WMILIB库来处理IRP,但需要注册回调函数处理应用程序的请求,在应用程序订阅事件后,驱动程序可以主动触发事件,并通知应用程序,可以双向交互。

 

WMI客户端与WMIProvider端是通过三种方式进行交互的。包括WMI数据的查询、Provider方法的调用和对Provider事件的监测。以下调研基于MPIO DDK中gendsm的实现。

 

 

3.  WDM/WMI实现基础

3.1.创建mof文件

3.1.1 编写mof文件

用户态应用程序与驱动程序的交互是通过mof类进行交互的。

Ø 用户态应用程序所能看到是通过mof中定义的类来查询驱动程序数据。

Ø 驱动程序通过mof类结构为应用程序提供数据。

在mof文件中可以定义WMI数据,方法和事件。以下三个实例分别定义了数据、方法和事件类。当然数据和方法可以定义在同一个类中,但事件需要定义单独的类。

[WMI,

Dynamic,

 Provider("WmiProv"),

 Description("Just have a datatest."),

 Locale("MS\\0x409"),

 guid("{90A3FD34-4CDD-40c0-B24D-605DDFCFF728}")]

class GENDSM_DATA_TEST

{

    [key,read]

     stringInstanceName;

    [read]boolean Active;

   

   [WmiDataId(1),

     read,

    Description("Identifier.")

    ] uint32Id;

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("GENDSM WMI Methods") ,

 guid("{5EDEFDC3-12BB-499c-86EE-3ECA60725144}")

]

class GENDSM_METHODS_TEST

{

    [key,read]

    stringInstanceName;

    [read]boolean Active;

 

   [WmiMethodId(1),

     read,write,

    Implemented,

    Description("Clear path performance counters for the device.")

    ]

    voidGetStatus(

      [in,

      Description("in parameter")

      ]uint32unCount,

//       [in,

//       MaxLen(63)

//       Description("in parameter")

//      ]string StatusId,

            [out,

        Description("Status of the operation")

        ]uint32 Status);

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("MultiPath EventLogger"),

 guid("{EED61148-32C6-4e0a-A156-8C4564E15511}"),

 locale("MS\\0x409")

]

class GENDSM_EVENT_TEST : WMIEvent

{

        [key,read]

        stringInstanceName;

 

        [read]

       boolean Active;

 

       

 

        //

        //Current system time at time of logging.

        //

       [WmiDataId(1),

         read,

        Description("Time Stamp"),

        WmiTimeStamp

        ] uint64 TimeStamp;

 

        //

        //Indicates severity of event being logged.

        //

       [WmiDataId(2),

        read,

       Values{"Fatal Error",

              "Error",

              "Warning",

              "Information"},

 

        DefineValues{"MPIO_FATAL_ERROR",

                    "MPIO_ERROR",

                    "MPIO_WARNING",

                    "MPIO_INFORMATION"},

 

       ValueMap{"1", "2", "3", "4"}

        ]uint32 Severity;

 

       [WmiDataId(3),

        read,

        Description("ErrorCode")

        ]uint32 ErrorCode;

 

        //

        //Description of event.

        //

       [WmiDataId(4),

        read,

       MaxLen(63),

       Description("Event Description")

        ]string EventDescription;

};

编写mof文件后可以使用mofcomp.exe–check  xx.mof文件进行语法检查。

 

3.1.2 WMI类限定符

如果一个类只是作为另一个类的数据项,不输出WMI数据块,则称为嵌入类。嵌入类只需要WMI和GUID两项限定符。如果定义为嵌入类,则不能从该类的实例读取数据。其他限定符有些是需要的而有些是可选的,详细如下:

 

Dynamic: 标示数据提供者动态提供类实例的数据,而不是在mof文件中静态提供。驱动注册的wmi类必须拥有此限定符。

Static:    由mof文件静态提供类实例数据,不能用在在驱动中注册的wmi类。

Provider(“WMIProv”): (需要的)标示类的提供者是一个WMI提供者。

WMI: (需要的)标示这个类是一个wmi类

Description(“docu”): (可选的)类得描述。

Guid: (需要的)WMI数据块的唯一标示,驱动在注册时想wmi发送这个值,wmi用Guid查询驱动mof文件中的数据定义。

Locale(“MS\\locale-identifer”): (可选的)指定Description的语言。

WmiExpense(expensevalue): (可选的)指定获取数据的cpu周期间隔

 

 

3.1.3 编写mof文件注意事项

Ø 在创建类中函数时,返回值必须为void,否则编译不过。

Ø 在定义数据块或消息块时,必须包含以下两项,否则无法生成类实例。

[key, read]

string InstanceName;

[read] boolean Active;

Ø 所有类GUID在使用过程中必须保持一致。

 

 

3.2.mof文件的发布

mof文件的发布就是将mof文件类添加到CIM类库中。在应用程序查询WMI类数据时,系统WMI可以把请求发送到相应的驱动中去执行。本部分的内容在msdsm中封装实现,此部分仅作参考。

3.2.1使用mofcomp注册类

mofcomp.exe是一个mof文件汇编器,可以执行语法检查,注册等多种功能。

(1)  mofcomp*.mof 可以将*.mof文件中的类添加到类库中。

 

 

3.2.2 由驱动注册mof文件类

由驱动注册mof文件有三种实现

1、   以bmf文件形式注册

bmf文件由mofcomp.exe–WMI –B:filename.bmf  filename.mof产生,需要在驱动的资源文件(.rc)文件中包含MofResourceMOFDATAfilename.bmf字符串,当驱动收到主功能码为IRP_MJ_SYSTEM_CONTROL副功能码为IRP_MN_REGINFO或IRP_MN_REGINFO_EX,Parameters.WMI.DataPath为WMIREGISTER注册请求时,可以以下面两种方式指定mof资源名称。

Ø 如果使用wmi库函数来处理wmi请求时,需要在回调函数DpWmiQueryReginfo中(回调函数在WMILIB_CONTEXT结构体中指定)指定mof资源名称。

实例代码如下(由wmimofck.exe –cwmi.c dsm.bmf自动产生):

NTSTATUS

WmiQueryWmiRegInfo(

   IN PDEVICE_OBJECT DeviceObject,

   OUT ULONG *RegFlags,

   OUT PUNICODE_STRING InstanceName,

   OUT PUNICODE_STRING *RegistryPath,

   OUT PUNICODE_STRING MofResourceName,

   OUT PDEVICE_OBJECT *Pdo

   )

/*++

 

Routine Description:

 

   This routine is a callback into the driver to retrieve the list of

   guids or data blocks that the driver wants to register with WMI. This

   routine may not pend or block. Driver should NOT call

   WmiCompleteRequest.

 

Arguments:

 

   DeviceObject is the device whose registration info is being queried

 

   *RegFlags returns with a set of flags that describe the guids being

       registered for this device. If the device wants enable and disable

       collection callbacks before receiving queries for the registered

       guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the

       returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case

       the instance name is determined from the PDO associated with the

       device object. Note that the PDO must have an associated devnode. If

       WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique

       name for the device.

 

   InstanceName returns with the instance name for the guids if

       WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The

       caller will call ExFreePool with the buffer returned.

 

   *RegistryPath returns with the registry path of the driver. The caller

        does NOT free this buffer.

 

   *MofResourceName returns with the name of the MOF resource attached to

       the binary file. If the driver does not have a mof resource attached

       then this can be returned as NULL. The caller does NOT free this

       buffer.

 

    *Pdo returns with the device object for thePDO associated with this

       device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in

       *RegFlags.

 

Return Value:

 

   status

 

--*/

{

   struct DEVICE_EXTENSION * devExt = DeviceObject->DeviceExtension;

 

   //

   // Return the registry path for this driver. This is required so WMI

   // can find your driver image and can attribute any eventlog messages to

   // your driver.

   *RegistryPath = &WmiRegistryPath;

       

#ifndef USE_BINARY_MOF_RESOURCE

   //

   // Return the name specified in the .rc file of the resource which

   // contains the bianry mof data. By default WMI will look for this

   // resource in the driver image (.sys) file, however if the value

   // MofImagePath is specified in the driver's registry key

   // then WMI will look for the resource in the file specified there.

   RtlInitUnicodeString(MofResourceName,L"MofResourceName");

#endif

 

   //

   // Specify that the driver wants WMI to automatically generate instance

   // names for all of the data blocks based upon the device stack's

   // device instance id. Doing this is STRONGLY recommended sinceadditional

   // information about the device would then be available to callers.

   *RegFlags = WMIREG_FLAG_INSTANCE_PDO;

 

   //

   // TODO: Assign the physical device object for the device stack to *Pdo

   *Pdo = devExt->physicalDevObj;

 

   return(STATUS_SUCCESS);

}

在msdsm驱动中将MofResource填入DSM_WMILIB_CONTEXT传到下MPIO.SYS注册wmi类。

Ø 如果由driver来直接处理,则需要在驱动回传给Parameters.WMI.Buffer的WMIREGINFO结构体中指定mof资源名称。

 

2、   以动态链接库的dll的形式注册

Ø 编译mof文件

Ø 将编译过的mof问价内容包含在dll中(可以编译成dll)

Ø 在驱动的服务健下添加MofImagePath健。

 

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

   \DriverName

       MofImagePath   "\SystemRoot\System32\Drivers\DriverNameMof.dll"

也可以写在驱动安装inf文件中

       ; This is the Services section for the driver
               [Driver_service_install_section]
               AddReg=Driver_AddReg
               
               ; This is the Services AddReg section declared above.
               [Driver_AddReg]
               HKR,,MofImagePath,,DriverMof.dll 

3、   将bmf二进制内容直接包含在驱动文件中

Ø 编译mof文件

Ø 使用wmimofck.exe工具将bmf文件产生十六进制的.x文件

Ø 在驱动源文件中用#include包含.x文件中的数据。

Ø 注册为支持MSWmi_MofData_GUID,即MSWmi_MofData_GUID为数据索引。

Ø 当驱动收到IRP_MN_QUERY_ALL_DATA或IRP_MN_QUERY_SINGLE_INSTANCE请求时就mof内容以MSWmi_MofData_GUID索引传给WMI。

 

 

 

3.3.3.3mofcomp工具

mofcomp可以将mof文件生成bmf文件,在build驱动过程中生成的bmf文件使用windows\system\wbem文件夹下mofcomp.exe工具生成。命令如下:

Ø  mofcomp.exe–WMI –B:filename.bmf  filename.mof

-wmi 进行windows驱动程序模式检查

-B 只创建二进制mof文件,不添加到DB

filename.bmf生成的二进制mof文件

filename.mof编写的类文件

Ø  mofcomp.exe–check filename.mof

可以只检查mof文件语法

Ø  mofcomp.exefilename.mof

将mof文件内容添加到CIM类库中。

 

3.4.3.4wmimofck工具

在DDK bin文件夹下的x86,IA64和AMD64文件夹下有不同系统的wmimofck.exe工具。

Ø wmimofck.exe –xwmi.txt dsm.bmf

可以将dsm.bmf文件中的二进制文件内容转换为十六进制存储在wmi.txt中。

Ø wmimofck.exe –hwmi.h dsm.bmf

可以将dsm.bmf二进制文件中定义的GUID、数据结构和方法标记等存在wmi.h头文件中。在MPIO DDK中也会产生wmi.h头文件。

Ø wmimofck.exe –cwmi.c dsm.bmf

可以生成WDM中的wmi执行代码模板。如果不是用在MPIO DDK中,而是单独写自己的wmi实现会比较有用。

Ø wmimofck.exe –hwmi.h –m dsm.bmf

添加-m可以在头文件中产生方法参数列表结构体,在.c文件中实现时会比较有用。

3.5.将驱动注册为WMIProvider

一个支持WMI的驱动必须先注册才能使它的数据和消息块被WMI客户端使用。注册过程有两个阶段。

1、 调用IoWMIRegistrationControl(IN PDEVICE_OBJECT DeviceObject, IN ULONGAction) Action = WMIREG_ACTION_REGISTER,WMI会发出主功能码为IRP_MJ_SYSTEM_CONTROL副功能码为IRP_MN_REGINFO或IRP_MN_REGINFO_EX的IRP。

2、 处理WMI发送的IRP_MN_REGINFO或IRP_MN_REGINFO_EX请求。参考以bmf文件形式注册。

 

在MSDSM驱动中,在MPIO.SYS中已封装将驱动注册为WMI Provider的部分,只需要修改mof文件内容,在驱动中实现mof类定义的功能即可。

3.6.build驱动时注意事项

 

在build驱动时,最好删除mof文件和wmi头文件。如果文件夹存在dsm.bmf,而更新后的mof文件中有错误,则无法正确编译出dsm.bmf,此时编译的驱动所用bmf文件为旧bmf文件。

如build时出现没有提示dsm.bmf编译错误又无法生成bmf文件时,可以用mofcom.exe –check dsm.mof来检查mof文件的语法错误。

 

 

 

4.  WMI实现

WMI的实现包含两部分,应用程序端和驱动端的实现。在下面的三种数据实现中会分别针对应用程序端和驱动端介绍,本节所用到mof类如下。

[WMI,

Dynamic,

 Provider("WmiProv"),

 Description("Justhave a data test."),

 Locale("MS\\0x409"),

 guid("{90A3FD34-4CDD-40c0-B24D-605DDFCFF728}")]

class GENDSM_DATA_TEST

{

    [key, read]

     stringInstanceName;

    [read] booleanActive;

   

    [WmiDataId(1),

     read,

    Description("Identifier.")

    ] uint32 Id;

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("GENDSMWMI Methods") ,

 guid("{5EDEFDC3-12BB-499c-86EE-3ECA60725144}")

]

class GENDSM_METHODS_TEST

{

    [key, read]

    stringInstanceName;

    [read] booleanActive;

 

    [WmiMethodId(1),

     read, write,

     Implemented,

     Description("Clearpath performance counters for the device.")

    ]

    void GetStatus(

      [in,

      Description("in parameter")

      ]uint32 unCount,

//       [in,

//        MaxLen(63)

//       Description("in parameter")

//       ]stringStatusId,

     [out,

        Description("Status of the operation")

        ] uint32Status);

};

 

[Dynamic,

 Provider("WMIProv"),

 WMI,

 Description("MultiPath EventLogger"),

 guid("{EED61148-32C6-4e0a-A156-8C4564E15511}"),

 locale("MS\\0x409")

]

class GENDSM_EVENT_TEST : WMIEvent

{

        [key, read]

        stringInstanceName;

 

        [read]

        boolean Active;

 

       

 

        //

        // Currentsystem time at time of logging.

        //

        [WmiDataId(1),

         read,

        Description("Time Stamp"),

         WmiTimeStamp

        ] uint64TimeStamp;

 

        //

        // Indicatesseverity of event being logged.

        //

        [WmiDataId(2),

        read,

       Values{"Fatal Error",

              "Error",

              "Warning",

               "Information"},

 

       DefineValues{"MPIO_FATAL_ERROR",

                    "MPIO_ERROR",

                    "MPIO_WARNING",

                    "MPIO_INFORMATION"},

 

       ValueMap{"1", "2", "3", "4"}

        ] uint32Severity;

 

     [WmiDataId(3),

        read,

      Description("ErrorCode")

        ] uint32ErrorCode;

 

        //

        // Descriptionof event.

        //

        [WmiDataId(4),

        read,

        MaxLen(63),

       Description("Event Description")

        ] stringEventDescription;

};

 

4.1.查询WMI数据

1、 应用程序端的实现

应用程序端实现步骤如下:

Ø 建立ManagementScope对象,连接root\wmi命名空间,默认为root\cimv2命名空间。

ManagementScope scope = new ManagementScope("root\\wmi");

scope.Connect();

Ø 建立mof中数据类的ManagementClass对象,并设置Scope属性为上面的命名空间对象,为获取类实例做准备。

ManagementClass mc = new ManagementClass(@"GENDSM_DATA_TEST");

mc.Scope = scope;

Ø 获取类实例集

ManagementObjectCollection moc = mc.GetInstances();

Ø 获取类实例的属性值

foreach (ManagementObject mo in moc)

{

     Console.WriteLine(mo["Id"].ToString());

}

 

完整代码如下:

static UInt32 DSM_DATA_TEST()

        {

            UInt32 u32ErrorCode= 0;

            try

            {

                ManagementScope scope= new ManagementScope("root\\wmi");

                scope.Connect();

                ManagementClass mc =new ManagementClass(@"GENDSM_DATA_TEST");

                mc.Scope = scope;

                ManagementObjectCollection moc= mc.GetInstances();

                if (moc.Count == 0)

                {

                    Console.Write("Object Count:{0}",moc.Count);

                }

                foreach (ManagementObjectmo in moc)

                {

                    Console.WriteLine(mo["Id"].ToString());

                }

            }

            catch(Exception e)

            {

                Console.WriteLine("GENDSM_DATA_TEST:{0}", e.Message.ToString());

            }

           

            return u32ErrorCode;

        }

2、 驱动端实现

 

 

驱动端基本实现步骤如下:

Ø 在DSM_WMILIB_CONTEXT结构体中QueryWmiDataBlockEx函数指针赋值。

Ø 定义函数NTSTATUS

DsmQueryData(

    IN PVOID DsmContext,

    IN PDSM_IDS DsmIds,

    IN PIRP Irp,

    IN ULONG GuidIndex,

    IN ULONG InstanceIndex,

    IN ULONG InstanceCount,

    IN OUT PULONGInstanceLengthArray,

    IN ULONG BufferAvail,

    OUT PUCHAR Buffer,

    OUT PULONG DataLength,

    ...

)

以上两步在DSM驱动中已实现。

Ø 定义GUID变量,并赋值为wmi.h中GUID宏,该GUID与mof文件中类的GUID是一致的。

GUID GENDSM_DATA_TESTGUID = GENDSM_DATA_TESTGuid;

Ø 在DsmGuidList中添加GENDSM_DATA_TESTGUID填充的结构体WMIGUIDREGINFO。  

WMIGUIDREGINFO DsmGuidList[] = {

    {

       &GENDSM_CONFIGINFOGUID,

        1,

        0

    },

    {

       &GENDSM_PERFINFOGUID,

        1,

        0

    },

    {

       &GENDSM_WMI_METHODSGUID,

        1,

        0

    },

    {

       &GENDSM_DATA_TESTGUID,

       1,

       0

    },

    {

       &GENDSM_METHODS_TESTGUID,

        1,

        0

     },

    {

       &GENDSM_EVENT_TESTGUID,

        1,

        WMIREG_FLAG_INSTANCE_PDO|WMIREG_FLAG_EVENT_ONLY_GUID

     },

};

Ø 定义该GUID在DsmGuidList中的index宏。

#define GENDSM_DATA_TESTGuidIndex 3

Ø 在DsmQueryData函数中给类实例属性赋值。

 

 

 

实例代码如下:

switch(GuidIndex) {

case GENDSM_DATA_TESTGuidIndex:{

                dataLength =sizeof(GENDSM_DATA_TEST);

                if(dataLength > BufferAvail)

                {

                    *DataLength= dataLength;

                     status= STATUS_BUFFER_TOO_SMALL;

                }//必须的

                else

                {

                    dataTest= (PGENDSM_DATA_TEST)Buffer;

                    dataTest->Id= 10;

                     *DataLength= dataLength;

                     *InstanceLengthArray= dataLength;

                     status =STATUS_SUCCESS;

                }

         break;

        }

……..

}

GuidIndex: DsmQueryData函数传入的类GUID在DsmGuidList中的索引值。

GENDSM_DATA_TESTGuidIndex: 类在DsmGuidList中的索引值宏。

GENDSM_DATA_TEST: wmi.h头文件中由build时自动生成的类数据结构。

红色部分是必须的,为了让WMI分配足够的内存。

4.2. 方法调用

1、应用程序端的实现

应用程序端实现步骤如下:

Ø 建立ManagementScope对象,连接root\wmi命名空间,默认为root\cimv2命名空间。

ManagementScope scope = new ManagementScope("root\\wmi");

scope.Connect();

Ø 建立mof中方法类的ManagementClass对象,并设置Scope属性为上面的命名空间对象,为获取类实例做准备。

ManagementClass mc = new ManagementClass(@"GENDSM_METHODS_TEST");

mc.Scope = scope;

Ø 获取类实例集

ManagementObjectCollection moc = mc.GetInstances();

Ø 获取类单个实例后

foreach (ManagementObject mo in moc)

{

}

Ø        获取类成员函数输入参数列表

inPar = mo.GetMethodParameters(@"GetStatus");

Ø  设置输入参数值

inPar["unCount"] = Convert.ToInt32("45");

Ø  调用类成员变量

outPar = mo.InvokeMethod("GetStatus",inPar, null);

Ø  获取输出参数值

string caption = outPar["Status"].ToString();

完整代码如下:

static UInt32 DSM_METHOD_TEST()

        {

            UInt32 u32ErrorCode= 0;

            try

            {

                ManagementScope scope= new ManagementScope("root\\wmi");

                scope.Connect();

                ManagementBaseObjectinPar = null;

                ManagementBaseObject outPar= null;

                   

                mc.Scope = scope;

                ManagementObjectCollection moc= mc.GetInstances();

                foreach (ManagementObjectmo in moc)

                {

                    inPar = mo.GetMethodParameters(@"GetStatus");

                    inPar["unCount"]= Convert.ToInt32("45");

                    outPar = mo.InvokeMethod("GetStatus",inPar, null);

                    string caption = outPar["Status"].ToString();

                    Console.WriteLine(caption);

                }

            }

            catch(Exception e)

            {

                Console.WriteLine("GENDSM_METHODS_TEST:{0}", e.Message.ToString());

            }

           

            return u32ErrorCode;

        }

 

2、驱动端实现

驱动端基本实现步骤如下:

Ø 在DSM_WMILIB_CONTEXT结构体中ExecuteWmiMethodEx函数指针赋值。

Ø 定义函数实现NTSTATUS

NTSTATUS

DsmExecuteMethod (

    IN PVOID DsmContext,

    IN PDSM_IDS DsmIds,

    IN PIRP Irp,

    IN ULONG GuidIndex,

    IN ULONG InstanceIndex,

    IN ULONG MethodId,

    INULONG InBufferSize,

    IN PULONG OutBufferSize,

    IN OUT PUCHAR Buffer,

    ...

    )以上两步在DSM驱动中已实现。

Ø 定义GUID变量,并赋值为wmi.h中GUID宏,该GUID与mof文件中类的GUID是一致的。

GUID GENDSM_METHODS_TESTGUID = GENDSM_METHODS_TESTGuid;

Ø 在DsmGuidList中添加GENDSM_DATA_TESTGUID填充的结构体WMIGUIDREGINFO。  

WMIGUIDREGINFO DsmGuidList[] = {

    {

       &GENDSM_CONFIGINFOGUID,

        1,

        0

    },

    {

       &GENDSM_PERFINFOGUID,

        1,

        0

    },

    {

       &GENDSM_WMI_METHODSGUID,

        1,

        0

    },

    {

        &GENDSM_DATA_TESTGUID,

       1,

       0

    },

    {

       &GENDSM_METHODS_TESTGUID,

        1,

        0

     },

    {

       &GENDSM_EVENT_TESTGUID,

        1,

        WMIREG_FLAG_INSTANCE_PDO|WMIREG_FLAG_EVENT_ONLY_GUID

     },

};

Ø 定义该GUID在DsmGuidList中的index宏。

#define GENDSM_METHODS_TESTGuidIndex 4

Ø 在DsmQueryData函数中给类实例属性赋值。

代码类似如下格式:

if(GuidIndex== GENDSM_METHODS_TESTGuidIndex){

/*++

* InvokeMSDSM_Methods_Test

*  eric zhang 2011-08-04

--*/  if(*OutBufferSize < sizeof(ULONG))

              {

                 *OutBufferSize = sizeof(ULONG);

                 status = STATUS_BUFFER_TOO_SMALL;

              }

              else

              {

                 ulParameterIn = *((PULONG)Buffer);

                 *pulParameterOut = ulParameterIn;

                 *OutBufferSize = sizeof(ULONG);

                 status = STATUS_SUCCESS;  

}

}

GuidIndex: DsmQueryData函数传入的类GUID在DsmGuidList中的索引值。

GENDSM_METHODS_TESTGuidIndex: 方法类在DsmGuidList中的索引值宏。

输入输出都用Buffer传递,我们这里只有一个返回值,如果如果有多个返回值,最好定义返回值结构体,可以通过wmimofck.exe –hwmi.h –m –u dsm.bmf产生,然后拷贝函数参数结构体定义到实现文件中。

4.3. 事件监听与触发

1、应用程序端实现

应用程序端需要一个设置监听函数和一个监听处理函数。

设置监听函数步骤如下:

Ø 建立ManagementScope对象,连接root\wmi命名空间,默认为root\cimv2命名空间。

ManagementScope scope = new ManagementScope("root\\wmi");

scope.Connect();

Ø 创建一个WQL语句来选择监听的类

string querySQL = @"select * from GENDSM_EVENT_TEST";

Ø 创建事件观察对象并设置scope为root\wmi命名空间

ManagementEventWatcher watcher = new ManagementEventWatcher(querySQL);

watcher.Scope = scope;

Ø 设置事件处理函数

watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);

Ø 监听事件并阻塞线程等待事件发生。

watcher.Start();

Console.ReadKey();

watcher.Stop();

事件处理程序如下:

Ø 获取事件对象

Ø 获取事件属性值

实例代码如下:

static UInt32 DSM_EVENT_TEST()

        {

            UInt32 u32ErrorCode= 0;

            try

            {

                ManagementScope scope= new ManagementScope("root\\wmi");

                scope.Connect();

 

                //新建一个事件观察者对象.

                string querySQL = @"select * from GENDSM_EVENT_TEST";

                ManagementEventWatcher watcher= new ManagementEventWatcher(querySQL);

 

                watcher.Scope = scope;

                //设置要事件处理者.

                watcher.EventArrived+= new EventArrivedEventHandler(watcher_EventArrived);

                //开始监听.

                watcher.Start();

 

                //阻塞线程,等待事件激发

                Console.ReadKey();

                watcher.Stop();

            }

            catch(Exception e)

            {

                Console.WriteLine("GENDSM_EVENT_TEST:{0}",e.Message.ToString());

            }

          

            return u32ErrorCode;

        }

        static void watcher_EventArrived(objectsender, EventArrivedEventArgswmievent)

        {

            Console.WriteLine("EventArrived");

            //获取事件对象

            try

            {

                ManagementBaseObject e= (ManagementBaseObject)wmievent.NewEvent;

                Int64 TimeStamp = Convert.ToInt64(e["TimeStamp"].ToString());

                DateTime dateTime = new DateTime(TimeStamp, DateTimeKind.Local);

                Console.WriteLine("{0}-{1}-{2} {3}:{4}:{5}:{6}", dateTime.Year +1600, dateTime.Month,dateTime.Day,dateTime.Hour,dateTime.Minute,dateTime.Second,dateTime.Millisecond);

                Console.WriteLine("Severity:{0}", e["Severity"].ToString());

                Console.WriteLine("ErrorCode:{0}", e["ErrorCode"].ToString());

                Console.WriteLine(e["EventDescription"].ToString());

            }

            catch(Exception e)

            {

                Console.WriteLine(e.Message.ToString());

            }

 

        }

 

 

2、驱动端实现

驱动端基本实现步骤如下:

驱动端事件的触发不是在一个固定的函数中,而是在需要触发事件的地方触发。触发事件是通过IoWMIWriteEventL来实现。

Ø 在非分页内存中分配事件类结构体大小内存

pEventStruct = ExAllocatePool(NonPagedPool, sizeof(GENDSM_EVENT_TEST));

Ø 计算WNODE_SINGLE_INSTANCE中头WNODE_HEADER中BufferSize的大小。

BufferSize的大小包含三部分WNODE_SINGLE_INSTANCE大小、实例名长度大小和输出的DataBlock的大小。

wnodeSize = sizeof(WNODE_SINGLE_INSTANCE);

wnodeInstanceNameSize = deviceName.Length; //+ sizeof(USHORT);

wnodeDataBlockSize = sizeof(GENDSM_EVENT_TEST);// + sizeof(USHORT);

size = wnodeSize + wnodeInstanceNameSize + wnodeDataBlockSize;

Ø 在非分页内存申请size大小空间。

wnode = ExAllocatePoolWithTag(NonPagedPool, size, GEN_POOL_TAG);

Ø 给WnodeHeader各个字段赋值

RtlZeroMemory(wnode, size);

wnode->WnodeHeader.BufferSize = size;

wnode->WnodeHeader.ProviderId =IoWMIDeviceObjectToProviderId(deviceInfo->TargetObject);

wnode->WnodeHeader.Version = 1;

Ø 获取系统时间给WnodeHeader的时间戳字段赋值。

KeQuerySystemTime(&systemTime);

ExSystemTimeToLocalTime(&systemTime, &localTime);

RtlTimeToTimeFields(&localTime, &timeField);

sprintf(szTime,"%d-%02d-%02d%02d:%02d:%02d:%03d",timeField.Year, timeField.Month, timeField.Day,timeField.Hour, timeField.Minute, timeField.Second, timeField.Milliseconds);

DbgPrint(szTime);

wnode->WnodeHeader.TimeStamp.QuadPart = localTime.QuadPart;

Ø 给WnodeHeader的Guid字段赋值为事件类得GUID。

RtlCopyMemory(&wnode->WnodeHeader.Guid,&GENDSM_EVENT_TESTGUID, sizeof(GUID));

Ø 给WnodeHeader的Flags字段赋值。

wnode->WnodeHeader.Flags  =WNODE_FLAG_EVENT_ITEM | WNODE_FLAG_SINGLE_INSTANCE ;

Ø 给WNODE_SINGLE_INSTANCE三个字段赋值,这三个字段分别为实例名的偏移量、数据块的偏移量和数据块的大小。

wnode->OffsetInstanceName = wnodeSize;

wnode->DataBlockOffset = wnodeSize + wnodeInstanceNameSize;

wnode->SizeDataBlock = wnodeDataBlockSize;

Ø 填充实例名

ptmp = (PUCHAR)wnode + wnode->OffsetInstanceName;

//*((PUSHORT)ptmp) = deviceName.Length;

RtlCopyMemory(ptmp,// + sizeof(USHORT),

                           deviceName.Buffer,

                           deviceName.Length);

Ø 在事件结构体中填充数据。

//fill the GENDSM_EVENT_TEST struct

RtlZeroMemory(pEventStruct, sizeof(GENDSM_EVENT_TEST));

pEventStruct->TimeStamp = localTime.QuadPart;

pEventStruct->Severity = 4;

pEventStruct->ErrorCode = 10;

//KeQuerySystemTime(&pEventStruct->TimeStamp);

//*(PUSHORT)(pEventStruct->Component) = 16;

//RtlCopyMemory(pEventStruct->Component+1, wString,wcslen(wString) * 2);

*(PUSHORT)(pEventStruct->EventDescription) = wcslen(wString) * 2;

RtlCopyMemory(pEventStruct->EventDescription+ 1,wString,wcslen(wString)*2);

注意事项:

在填充字符串时必须在第一个USHOURT的位置填充字符串的长度,后面才能填充字符串。现在只能实现一个字符串的填充,当有多个字符串时,也只能显示第一个字符串。

Ø 将事件结构体内容拷贝到DataBlockOffset处。

ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;

RtlCopyMemory(ptmp,

pEventStruct,

sizeof(GENDSM_EVENT_TEST));

Ø 调用IoWMIWriteEvent触发事件

status = IoWMIWriteEvent(wnode);

                     if(!NT_SUCCESS(status))

                     {

                         DbgPrint("IoWMIWriteEventFail!");

                         ExFreePool(wnode);

                     }

 

结构体GENDSM_EVENT_TEST定义如下:

typedefstruct _GENDSM_EVENT_TEST

{

    // Time Stamp

    ULONGLONG TimeStamp;

    #define GENDSM_EVENT_TEST_TimeStamp_SIZEsizeof(ULONGLONG)

    #define GENDSM_EVENT_TEST_TimeStamp_ID 1

 

 

// FatalError

#defineMPIO_FATAL_ERROR 1

// Error

#defineMPIO_ERROR 2

// Warning

#defineMPIO_WARNING 3

//Information

#defineMPIO_INFORMATION 4

 

    //

    ULONG Severity;

    #define GENDSM_EVENT_TEST_Severity_SIZEsizeof(ULONG)

    #define GENDSM_EVENT_TEST_Severity_ID 2

 

    // ErrorCode

    ULONG ErrorCode;

    #define GENDSM_EVENT_TEST_ErrorCode_SIZEsizeof(ULONG)

    #define GENDSM_EVENT_TEST_ErrorCode_ID 3

 

    // Event Description

    WCHAR EventDescription[63 + 1];

    #define GENDSM_EVENT_TEST_EventDescription_ID4

 

}GENDSM_EVENT_TEST, *PGENDSM_EVENT_TEST;

 

实例代码如下:

//eric zhang 2011-09-15

             deviceInfo = DsmIds->IdList[0];

             RtlInitUnicodeString(&deviceName,L"EricZhan");

             pEventStruct = ExAllocatePool(NonPagedPool,sizeof(GENDSM_EVENT_TEST));

             // fill zero in the follow section

             //RtlZeroMemory(pEventStruct,sizeof(GENDSM_EVENT_TEST));

             wnodeSize = sizeof(WNODE_SINGLE_INSTANCE);

             wnodeInstanceNameSize = deviceName.Length;//+ sizeof(USHORT);

            wnodeDataBlockSize = sizeof(GENDSM_EVENT_TEST);// + sizeof(USHORT);

             size = wnodeSize + wnodeInstanceNameSize +wnodeDataBlockSize;

            

             wnode = ExAllocatePoolWithTag(NonPagedPool,size, GEN_POOL_TAG);

             if(NULL != wnode)

             {

                RtlZeroMemory(wnode, size);

              wnode->WnodeHeader.BufferSize= size;

              wnode->WnodeHeader.ProviderId= IoWMIDeviceObjectToProviderId(deviceInfo->TargetObject);

              wnode->WnodeHeader.Version= 1;

              KeQuerySystemTime(&systemTime);

              ExSystemTimeToLocalTime(&systemTime,&localTime);

              RtlTimeToTimeFields(&localTime,&timeField);

             sprintf(szTime,"%d-%02d-%02d%02d:%02d:%02d:%03d",timeField.Year, timeField.Month, timeField.Day,timeField.Hour, timeField.Minute, timeField.Second, timeField.Milliseconds);

              DbgPrint(szTime);

              wnode->WnodeHeader.TimeStamp.QuadPart= localTime.QuadPart;

              //KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);

              RtlCopyMemory(&wnode->WnodeHeader.Guid,&GENDSM_EVENT_TESTGUID, sizeof(GUID));

              wnode->WnodeHeader.Flags  = WNODE_FLAG_EVENT_ITEM |WNODE_FLAG_SINGLE_INSTANCE ;

              wnode->OffsetInstanceName= wnodeSize;

 

                wnode->DataBlockOffset = wnodeSize +wnodeInstanceNameSize;

              wnode->SizeDataBlock =wnodeDataBlockSize;

             

              ptmp =(PUCHAR)wnode + wnode->OffsetInstanceName;

              //*((PUSHORT)ptmp)= deviceName.Length;

              RtlCopyMemory(ptmp,//+ sizeof(USHORT),

                           deviceName.Buffer,

                           deviceName.Length);

              ptmp =(PUCHAR)wnode + wnode->DataBlockOffset;

              //*((PUSHORT)ptmp)= sizeof(GENDSM_EVENT_TEST);

             

              //fill theGENDSM_EVENT_TEST struct

              RtlZeroMemory(pEventStruct,sizeof(GENDSM_EVENT_TEST));

              pEventStruct->TimeStamp= localTime.QuadPart;

              pEventStruct->Severity= 4;

              pEventStruct->ErrorCode= 10;

              //KeQuerySystemTime(&pEventStruct->TimeStamp);

              //*(PUSHORT)(pEventStruct->Component)= 16;

              //RtlCopyMemory(pEventStruct->Component+1,wString, wcslen(wString) * 2);

              *(PUSHORT)(pEventStruct->EventDescription)= wcslen(wString) * 2;

              RtlCopyMemory(pEventStruct->EventDescription+1, wString,wcslen(wString)*2);

 

              RtlCopyMemory(ptmp,//+ sizeof(USHORT),

                       pEventStruct,

                       sizeof(GENDSM_EVENT_TEST));

 

              ptmp =(PUCHAR)wnode + wnode->DataBlockOffset;

              DbgPrint("LocationTime:%08lX",localTime.u.HighPart);

              DbgPrint("LocationTime:%08lX",localTime.u.LowPart);

              for(i = 0;i < wnodeDataBlockSize; i++)

              {

                  DbgPrint("%02X",*(ptmp + i));

              }

              status =IoWMIWriteEvent(wnode);

              if(!NT_SUCCESS(status))

              {

                  DbgPrint("IoWMIWriteEventFail!");

                  ExFreePool(wnode);

              }

             }

 

 

 

 

 

5.  参考资料

http://msdn.microsoft.com/en-us/library/ff547139(v=VS.85).aspx   Implementing WMI

http://msdn.microsoft.com/en-us/library/aa394558(VS.85).aspx  WMI C++ sample

http://msdn.microsoft.com/en-us/library/aa394559(VS.85).aspx  WMI Errors Contents

http://msdn.microsoft.com/en-us/library/ms186120.aspx C# WMI

http://msdn.microsoft.com/en-us/library/ff563733%28v=VS.85%29.aspx send event

应用程序代码如下:


using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace wmitest
{
    class Program
    {
        static void Main(string[] args)
        {
           if(args[0].Equals("-method"))
           {
               DSM_METHOD_TEST();
           }
           else if(args[0].Equals("-data"))
           {
               DSM_DATA_TEST();
           }
           else if(args[0].Equals("-event"))
           {
               DSM_EVENT_TEST();
           }
        }
        static UInt32 DSM_DATA_TEST()
        {
            UInt32 u32ErrorCode = 0;
            try
            {
                ManagementScope scope = new ManagementScope("root\\wmi");
                scope.Connect();
                ManagementClass mc = new ManagementClass(@"GENDSM_DATA_TEST");
                mc.Scope = scope;
                ManagementObjectCollection moc = mc.GetInstances();
                if (moc.Count == 0)
                {
                    Console.Write("Object Count:{0}",moc.Count);
                }
                foreach (ManagementObject mo in moc)
                {
                    Console.WriteLine(mo["Id"].ToString());
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("GENDSM_DATA_TEST:{0}", e.Message.ToString());
            }
            
            return u32ErrorCode;
        }
        static UInt32 DSM_METHOD_TEST()
        {
            UInt32 u32ErrorCode = 0;
            try
            {
                ManagementScope scope = new ManagementScope("root\\wmi");
                scope.Connect();
                ManagementBaseObject inPar = null;
                ManagementBaseObject outPar = null;
                ManagementClass mc = new ManagementClass(@"GENDSM_METHODS_TEST");
                mc.Scope = scope;
                ManagementObjectCollection moc = mc.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    inPar = mo.GetMethodParameters(@"GetStatus");
                    inPar["unCount"] = Convert.ToInt32("45");
                    outPar = mo.InvokeMethod("GetStatus", inPar, null);
                    string caption = outPar["Status"].ToString();
                    Console.WriteLine(caption);
                }
            }
            catch(Exception e)
            {
                Console.WriteLine("GENDSM_METHODS_TEST:{0}", e.Message.ToString());
            }
            
            return u32ErrorCode;
        }
        static UInt32 DSM_EVENT_TEST()
        {
            UInt32 u32ErrorCode = 0;
            try
            {
                ManagementScope scope = new ManagementScope("root\\wmi");
                scope.Connect();

                //新建一个事件观察者对象.
                string querySQL = @"select * from GENDSM_EVENT_TEST";
                ManagementEventWatcher watcher = new ManagementEventWatcher(querySQL);

                watcher.Scope = scope;
                //设置要事件处理者.
                watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
                //开始监听.
                watcher.Start();

                //阻塞线程,等待事件激发
                Console.ReadKey();
                watcher.Stop();
            }
            catch(Exception e)
            {
                Console.WriteLine("GENDSM_EVENT_TEST:{0}",e.Message.ToString());
            }
           
            return u32ErrorCode;
        }
        static void watcher_EventArrived(object sender, EventArrivedEventArgs wmievent)
        {
            Console.WriteLine("EventArrived");
            //获取事件对象
            try
            {
                ManagementBaseObject e = (ManagementBaseObject)wmievent.NewEvent;
                Int64 TimeStamp = Convert.ToInt64(e["TimeStamp"].ToString());
                DateTime dateTime = new DateTime(TimeStamp, DateTimeKind.Local);
                Console.WriteLine("{0}-{1}-{2} {3}:{4}:{5}:{6}", dateTime.Year + 1600, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
                Console.WriteLine("Severity:{0}", e["Severity"].ToString());
                Console.WriteLine("ErrorCode:{0}", e["ErrorCode"].ToString());
                Console.WriteLine(e["EventDescription"].ToString());
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message.ToString());
            }
 
        }
    }
}



 

驱动中部分代码如下:

NTSTATUS
DsmQueryData(
    IN PVOID DsmContext,
    IN PDSM_IDS DsmIds,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG InstanceCount,
    IN OUT PULONG InstanceLengthArray,
    IN ULONG BufferAvail,
    OUT PUCHAR Buffer,
    OUT PULONG DataLength,
    ...
    )
/*++

Routine Description:

    This is the main WMI query entry point. The index into the GUID array is found
    and assuming the buffer is large enough, the data will be copied over.

Arguments:

    DsmContext - Global context
    DsmIds - Pointer to DSM_IDS structure for this request.
    Irp - The WMI Irp
    GuidIndex - Index into the WMIGUIDINFO array
    InstanceIndex - Index value indicating for which instance data should be returned.
    InstanceCount - The number of instances for which to return the data.
    InstanceLengthArray - Array of ULONGs that indicate per-instance data lengths.
    BufferAvail - Buffer size in bytes.
    Buffer - Buffer to which the data is written.
    DataLength - Storage for the actual data length written.

Return Value:

    BUFFER_TOO_SMALL - If BufferAvail isn't large enough.
    GUID_NOT_FOUND - If GuidIndex doesn't correspond to an actual entry in the reginfo array.
    SUCCESS;

--*/
{
    PDSM_CONTEXT context = DsmContext;
    PGENDSM_CONFIGINFO configInfo;
    PGENDSM_PERFINFO perfInfo;
    PGENDSM_DEVICEPERF devicePerf;
    PLIST_ENTRY entry;
    PDEVICE_INFO deviceInfo;
    ULONG dataLength;
    ULONG i;
/*++
* eric zhang 2010-08-09
*
--*/
    PGENDSM_DATA_TEST dataTest;
    ULONG devices = context->NumberDevices;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    DbgPrint("eric++++");
    DbgPrint("DsmQueryData");
    DbgPrint("eric----");
    //
    // Check the GuidIndex - the index into the DsmGuildList array - to see whether
    // this is actually supported.
    //
    switch(GuidIndex) {
        case GENDSM_WMI_METHODSGuidIndex: {
            //
            // This is for a method. Setting lengths to zero and status of success
            // are necessary.
            //
            *DataLength = 0;
            status = STATUS_SUCCESS;
            *InstanceLengthArray = 0;
            break;

        }
        case GENDSM_CONFIGINFOGuidIndex: {

            //
            // Ensure that the buffer is large enough. WMI will send down 0 or small-length
            // buffers to get back the actual size needed.
            //
            dataLength = sizeof(GENDSM_CONFIGINFO);
            if (dataLength > BufferAvail) {

                //
                // Buffer is too small. Indicate this back
                // to the mpio driver (and to WMI).
                //
                *DataLength = dataLength;
                status = STATUS_BUFFER_TOO_SMALL;
            } else {

                //
                // Get the buffer.
                //
                configInfo = (PGENDSM_CONFIGINFO)Buffer;

                //
                // Set-up the necessary info.
                //
                configInfo->NumberFOGroups = context->NumberFOGroups;
                configInfo->NumberMPGroups = context->NumberGroups;
                configInfo->LoadBalancePolicy = DSM_LB_STATIC;

                //
                // Indicate the size of returned data to
                // WMI and MPIO.
                //
                *DataLength = dataLength;
                *InstanceLengthArray = dataLength;
                status = STATUS_SUCCESS;
            }
            break;
        }
        case GENDSM_PERFINFOGuidIndex: {

            //
            // Calculate the necessary buffer requirement.
            // Start with the encapsulating struct.
            //
            dataLength = sizeof(GENDSM_PERFINFO);

            //
            // Add enough for each of the devices. The array is defined as
            // having one element in the structure already.
            //
            dataLength += (devices - 1) * sizeof(GENDSM_DEVICEPERF);

            //
            // If the buffer passed in is too small, tell wmi the correct
            // size.
            //
            if (dataLength > BufferAvail) {

                *DataLength = dataLength;
                status = STATUS_BUFFER_TOO_SMALL;
            } else {

                perfInfo = (PGENDSM_PERFINFO)Buffer;

                //
                // Indicate the number of array entries that will follow.
                //
                perfInfo->NumberDevices = devices;

                //
                // for each device, get it's cached perf. info and jam
                // it into the user buffer.
                //
                entry = context->DeviceList.Flink;
                for (i = 0; i < devices; i++) {

                    //
                    // Get the correct array entry.
                    //
                    devicePerf = &perfInfo->PerfInfo[i];

                    //
                    // Get the matching deviceInfo structure.
                    //
                    deviceInfo = CONTAINING_RECORD(entry, DEVICE_INFO, ListEntry);

                    //
                    // Copy over the perf. info.
                    //
                    devicePerf->NumberReads = deviceInfo->Stats.NumberReads;
                    devicePerf->NumberWrites = deviceInfo->Stats.NumberWrites;
                    devicePerf->BytesRead = deviceInfo->Stats.BytesRead;
                    devicePerf->BytesWritten = deviceInfo->Stats.BytesWritten;

                    //
                    // Move to the next deviceInfo
                    //
                    entry = entry->Flink;
                }

                //
                // Let mpio and wmi know the actual data length.
                //
                *DataLength = dataLength;
                *InstanceLengthArray = dataLength;

                status = STATUS_SUCCESS;
            }

            break;
        }
    /*++
    *  Query Data
    *    eric zhang 2011-08-04
    --*/
    
    case GENDSM_DATA_TESTGuidIndex:{
          dataLength = sizeof(GENDSM_DATA_TEST);
          if(dataLength > BufferAvail)
          {
              *DataLength = dataLength;
            status = STATUS_BUFFER_TOO_SMALL;
          }
          else
          {
              dataTest = (PGENDSM_DATA_TEST)Buffer;
              dataTest->Id = 10;
            *DataLength = dataLength;
            *InstanceLengthArray = dataLength;
            status = STATUS_SUCCESS;
          }
          DbgPrint("eric++++");
          DbgPrint("Data Test Finish in DsmQueryData\n");
          DbgPrint("eric----");
             break;
     }
    /*++
    *  Query Data
    *    eric zhang 2011-08-04
    --*/
    case GENDSM_METHODS_TESTGuidIndex:{
        dataLength = sizeof(ULONG) * 2;
        if(dataLength > BufferAvail)
        {
              *DataLength = dataLength;
            status = STATUS_BUFFER_TOO_SMALL;
        }    
        else
        {
             *DataLength = dataLength;
                   status = STATUS_SUCCESS;
                   *InstanceLengthArray = dataLength;
        }
        DbgPrint("eric++++");
        DbgPrint("Methods Test Finish in DsmQueryData\n");
        DbgPrint("Buffer Context: %ld",*((PULONG)Buffer));
        DbgPrint("BufferAvail %d\n",BufferAvail);
        DbgPrint("DataLength %d\n",*DataLength);
        DbgPrint("eric----");
         break;
     }
     case GENDSM_EVENT_TESTGuidIndex:{
         dataLength = sizeof(GENDSM_EVENT_TEST);
        if(dataLength < BufferAvail)
        {
        *DataLength = dataLength;
        status = STATUS_BUFFER_TOO_SMALL;
        }
        DbgPrint("eric++++");
        DbgPrint("Event Test Finish in DsmQueryData\n");
        DbgPrint("Buffer Context: %ld",*((PULONG)Buffer));
        DbgPrint("BufferAvail %d\n",BufferAvail);
        DbgPrint("DataLength %d\n",*DataLength);
        DbgPrint("eric----");
        break;
     }
        default:
            status = STATUS_WMI_GUID_NOT_FOUND;
            break;
    }

    return status;
}



NTSTATUS
DsmExecuteMethod (
    IN PVOID DsmContext,
    IN PDSM_IDS DsmIds,
    IN PIRP Irp,
    IN ULONG GuidIndex,
    IN ULONG InstanceIndex,
    IN ULONG MethodId,
    IN ULONG InBufferSize,
    IN PULONG OutBufferSize,
    IN OUT PUCHAR Buffer,
    ...
    )
/*++

Routine Description:

    This routine handles the invocation of WMI methods defined in the DSM mof.

Arguments:

    DsmContext - Global context
    DsmIds - Pointer to DSM_IDS structure for this request.
    Irp - The WMI Irp
    GuidIndex - Index into the WMIGUIDINFO array
    InstanceIndex - Index value indicating for which instance data should be returned.
    MethodId - Specifies which method to invoke.
    InBufferSize - Buffer size, in bytes, of input parameter data.
    OutBufferSize - Buffer size, in bytes, of output data.
    Buffer - Buffer to which the data is read/written.

Return Value:

    Status of the method, or STATUS_WMI_ITEMID_NOT_FOUND

--*/
{
    PDSM_CONTEXT context = DsmContext;
    //PDEVICE_INFO deviceInfo;
    PGROUP_ENTRY group;
    PLIST_ENTRY entry;
    NTSTATUS status;
    ULONG dataLength;
    ULONG i;
    KIRQL irql;
    ULONG loadBalanceType = 0;
    ULONG ulParameterIn;
    ULONG *pulParameterOut = (PULONG)Buffer;
    //PGENDSM_EVENT_TEST pEventStruct = NULL;
    //eric zhang 2011-09-15
    PWNODE_SINGLE_INSTANCE  wnode;
    ULONG                   wnodeSize = 0;
    ULONG                   wnodeDataBlockSize = 0;
    ULONG                   wnodeInstanceNameSize = 0;
    PUCHAR                  ptmp;
    ULONG                   size;
    UNICODE_STRING          deviceName;
    #define GEN_POOL_TAG (ULONG)'eric'
    PDEVICE_INFO deviceInfo = NULL;
    GUID GENDSM_EVENT_TESTGUID = GENDSM_EVENT_TESTGuid;
    PGENDSM_EVENT_TEST pEventStruct = NULL;
    LARGE_INTEGER systemTime, localTime;
    WCHAR wString[63] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234";
    //eric zhang 2011-09-15
    //eric zhang 2011-09-16
    TIME_FIELDS timeField;
    CHAR szTime[128];
    //eric zhang 2011-09-16
    DbgPrint("eric++++");
    DbgPrint("DsmExecuteMethod");
    DbgPrint("eric----");
    //
    // Preload status with failure.
    //
    status = STATUS_WMI_ITEMID_NOT_FOUND;


    //
    // This should be the 'METHODS' Index.
    //
    if (GuidIndex == GENDSM_WMI_METHODSGuidIndex) {

        //
        // Check the MethodID to determine which one should
        // be invoked.
        //
        if (MethodId == GenDsmClearCounters) {

            //
            // Clear all of the devices' counters.
            //
            status = DsmClearCounters(context);

        } else if (MethodId == GenDsmSetLBPolicy) {

            //
            // Data In should be a ULONG.
            //
            dataLength = sizeof(ULONG);

            //
            // Ensure this is correct.
            //
            if (InBufferSize >= dataLength) {

                //
                // Get the policy.
                //
                loadBalanceType = *((PULONG)Buffer);

                //
                // Set-up the new load-balancing policy.
                //
                status = DsmUpdateLBPolicy(context,
                                           loadBalanceType);
            }  else {

                //
                // Indicate that the buffer is incorrect.
                //
                status = STATUS_INVALID_PARAMETER;
            }
        }
    }
    else if(GuidIndex == GENDSM_METHODS_TESTGuidIndex){
/*++
* Invoke MSDSM_Methods_Test
*  eric zhang 2011-08-04
*  
--*/    if(*OutBufferSize < sizeof(ULONG))
        {
            *OutBufferSize = sizeof(ULONG);
            status = STATUS_BUFFER_TOO_SMALL;
        }
        else
        {
            ulParameterIn = *((PULONG)Buffer);
            *pulParameterOut = ulParameterIn;
            *OutBufferSize = sizeof(ULONG);
            status = STATUS_SUCCESS;    
               
            //status = ulParameterIn;

            //eric zhang 2011-09-15
            deviceInfo = DsmIds->IdList[0];
            RtlInitUnicodeString(&deviceName, L"EricZhan");
            pEventStruct = ExAllocatePool(NonPagedPool, sizeof(GENDSM_EVENT_TEST));
            // fill zero in the follow section
            //RtlZeroMemory(pEventStruct, sizeof(GENDSM_EVENT_TEST));
            wnodeSize = sizeof(WNODE_SINGLE_INSTANCE);
            wnodeInstanceNameSize = deviceName.Length; //+ sizeof(USHORT);
            wnodeDataBlockSize = sizeof(GENDSM_EVENT_TEST);// + sizeof(USHORT);
            size = wnodeSize + wnodeInstanceNameSize + wnodeDataBlockSize;
            
            wnode = ExAllocatePoolWithTag(NonPagedPool, size, GEN_POOL_TAG);
            if(NULL != wnode)
            {
               RtlZeroMemory(wnode, size);
            wnode->WnodeHeader.BufferSize = size;
            wnode->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(deviceInfo->TargetObject);
            wnode->WnodeHeader.Version = 1;
            KeQuerySystemTime(&systemTime);
            ExSystemTimeToLocalTime(&systemTime, &localTime);
            RtlTimeToTimeFields(&localTime, &timeField);
            sprintf(szTime,"%d-%02d-%02d %02d:%02d:%02d:%03d",timeField.Year, timeField.Month, timeField.Day, timeField.Hour, timeField.Minute, timeField.Second, timeField.Milliseconds);
            DbgPrint(szTime);
            wnode->WnodeHeader.TimeStamp.QuadPart = localTime.QuadPart;
            //KeQuerySystemTime(&wnode->WnodeHeader.TimeStamp);
            RtlCopyMemory(&wnode->WnodeHeader.Guid, &GENDSM_EVENT_TESTGUID, sizeof(GUID));
            wnode->WnodeHeader.Flags  = WNODE_FLAG_EVENT_ITEM | WNODE_FLAG_SINGLE_INSTANCE ;
            wnode->OffsetInstanceName = wnodeSize;

               wnode->DataBlockOffset = wnodeSize + wnodeInstanceNameSize;
                wnode->SizeDataBlock = wnodeDataBlockSize;
            
            ptmp = (PUCHAR)wnode + wnode->OffsetInstanceName;
            //*((PUSHORT)ptmp) = deviceName.Length;
            RtlCopyMemory(ptmp,// + sizeof(USHORT),
                            deviceName.Buffer,
                            deviceName.Length);
            ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
            //*((PUSHORT)ptmp) = sizeof(GENDSM_EVENT_TEST);
            
            //fill the GENDSM_EVENT_TEST struct
            RtlZeroMemory(pEventStruct, sizeof(GENDSM_EVENT_TEST));
            pEventStruct->TimeStamp = localTime.QuadPart;
            pEventStruct->Severity = 4;
            pEventStruct->ErrorCode = 10;
            //KeQuerySystemTime(&pEventStruct->TimeStamp);
            //*(PUSHORT)(pEventStruct->Component) = 16;
            //RtlCopyMemory(pEventStruct->Component+1, wString, wcslen(wString) * 2);
            *(PUSHORT)(pEventStruct->EventDescription) = wcslen(wString) * 2;
            RtlCopyMemory(pEventStruct->EventDescription+ 1, wString,wcslen(wString)*2);

            RtlCopyMemory(ptmp,// + sizeof(USHORT),
                        pEventStruct,
                        sizeof(GENDSM_EVENT_TEST));

            ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
            DbgPrint("LocationTime:%08lX",localTime.u.HighPart);
            DbgPrint("LocationTime:%08lX",localTime.u.LowPart);
            for(i = 0; i < wnodeDataBlockSize; i++)
            {
                DbgPrint("%02X",*(ptmp + i));
            }
            status = IoWMIWriteEvent(wnode);
            if(!NT_SUCCESS(status))
            {
                DbgPrint("IoWMIWriteEvent Fail!");
                ExFreePool(wnode);
            }
            }
            //eric zhang 2011-09-15

            /*
            pEventStruct = (PGENDSM_EVENT_TEST)ExAllocatePool(NonPagedPool,sizeof(GENDSM_EVENT_TEST));
               if(pEventStruct)
               {
                   pEventStruct->Severity = 4;
                status = WmiFireEvent(NULL, (LPGUID)&GENDSM_EVENT_TESTGUID,0,sizeof(GENDSM_EVENT_TEST),pEventStruct);
                   if(!NT_SUCCESS(status))
                   {
                       DbgPrint("WmiFireEvent Fail!");
                    }
                    else
                    {
                        DbgPrint("Firing GENDSM_EVENT_TEST!");
                    }
                 }
             */
        }
        DbgPrint("eric++++");
        DbgPrint("Method Test Finish in DsmExecuteMethod\n");
        DbgPrint("eric----");

    }
    return status;
}


 


你可能感兴趣的:(buffer,methods,exception,string,null,object,WMI)