首页  编辑  

WMI Delphi使用指南

Tags: /超级猛料/OS.操作系统/   Date Created:

WMI Delphi使用指南

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

参考: MSDN Home >  MSDN Library >  Setup and System Administration >  Windows Management Instrumentation (WMI) >  Windows Management Instrumentation >  WMI Reference >

Copyright(C) 2004, Kingron, All rights reserved.

版权所有,严禁随意复制和传播

在Delphi中使用WMI,需要准备一些资料,以备查阅:MSDN 2003以上,或者相关的WMI资料

首先,要清楚WMI的一些基本类和框架,WMI可以连接其他的机器,因此有一个WMI的连接管理器,其类名为WbemScripting.SWbemLocator,该类有一个方法ConnectServer,可以连接指定的服务器。具体的方法和属性可以参考MSDN中SWbemLocator的部分。ConnectServer有以下参数:

 [ strServer = "" ], 计算机名字/IP

 [ strNamespace = "" ], 登录到那个NameSpace,例如\root\default,表示默认,一般使用\root\cimv2

 [ strUser = "" ], 用户名,必须有访问权限!

 [ strPassword = "" ], 密码

 [ strLocale = "" ],  语言代码,格式为MS_xxx,xxx为十六进制的LCID值,例如英语为MS_409,中文为MS_804

 [ strAuthority = "" ],

 [ iSecurityFlags = 0 ],

 [ objwbemNamedValueSet = null ]

ConnectServer返回一个SWbemServices 对象,SWbemServices 有很多方法和属性,但是我们最关心的是ExecQuery,利用SWbemServices.ExecQuery方法就可以运行WMI SQL语句了,这样,打开了一个通向系统信息的大门!SWbemServices的详细信息可以参考MSDN中Platform SDK: Windows Management Instrumentation关于SWbemServices的部分。

WMI SQL语句和SQL语句类似,这个就不详细说明了,如果不知道SQL语句,那么回去补SQL的课再来学习!

WMI SQL语句类似下面:

 SELECT * FROM WMIClass [WHERE condition]

WMIClass有许多许多许多许多~~~~~~~,分为以下几个大类:

分类目录                          说明

Computer system hardware          硬件相关

Operating system Classes          操作系统相关

Installed applications Classes    软件相关

WMI service management Classes    用于管理WMI

Performance counters Classes      系统性能监视和计数等

其中每一个大类下面有很多很多很多的小类,具体的可以参考MSDN中关于Win32 Classes的部分。因为太多了,就不一一列出来。我们最常用的有:Win32_CDROMDrive,Win32_DiskDrive,Win32_FloppyDrive,Win32_BIOS,Win32_SystemBIOS,Win32_NetworkAdapterConfiguration,Win32_NetworkAdapter,Win32_NetworkAdapterSetting,Win32_Desktop,Win32_Environment,Win32_LogicalDisk,Win32_Process………………等,因为太多了,不能全部列出来,还是自己看MSDN吧,反正是一个宝库,你几乎可以找到你需要的任何的东西!

ExecQuery返回对应的类的结果集合SWbemObjectSet,SWbemObjectSet有Count属性和Item方法,使用Item和Count可以得到其中任意一个结果,之后你可以访问其中的信息,例如Win32_Process,包含以下信息,

class Win32_Process : CIM_Process

{

 string Caption;

 string CommandLine;

 string CreationClassName;

 datetime CreationDate;

 string CSCreationClassName;

 string CSName;

 string Description;

 string ExecutablePath;

 uint16 ExecutionState;

 string Handle;

 uint32 HandleCount;

 datetime InstallDate;

 uint64 KernelModeTime;

 uint32 MaximumWorkingSetSize;

 uint32 MinimumWorkingSetSize;

 string Name;

 string OSCreationClassName;

 string OSName;

 uint64 OtherOperationCount;

 uint64 OtherTransferCount;

 uint32 PageFaults;

 uint32 PageFileUsage;

 uint32 ParentProcessId;

 uint32 PeakPageFileUsage;

 uint64 PeakVirtualSize;

 uint32 PeakWorkingSetSize;

 uint32 Priority;

 uint64 PrivatePageCount;

 uint32 ProcessId;

 uint32 QuotaNonPagedPoolUsage;

 uint32 QuotaPagedPoolUsage;

 uint32 QuotaPeakNonPagedPoolUsage;

 uint32 QuotaPeakPagedPoolUsage;

 uint64 ReadOperationCount;

 uint64 ReadTransferCount;

 uint32 SessionId;

 string Status;

 datetime TerminationDate;

 uint32 ThreadCount;

 uint64 UserModeTime;

 uint64 VirtualSize;

 string WindowsVersion;

 uint64 WorkingSetSize;

 uint64 WriteOperationCount;

 uint64 WriteTransferCount;

};

那么我们就可以用Obj.Caption,Obj.CommandLine等来访问其中的数据!下面以访问某一台机器的进程列表为例给出一个演示性的代码:

procedure TForm1 . Button1Click ( Sender : TObject );

var

 Locator : ISWbemLocator ;

 Service : ISWbemServices ;

 ObjectSet : ISWbemObjectSet ;

 SObject : OleVariant ;

 Enum : IEnumVariant ;

 Item : OleVariant ;

 Value : Cardinal ;

 i : integer ;

begin

 Locator := CreateOleObject ( 'WbemScripting.SWbemLocator' ) as ISWbemLocator ;

 Service := Locator . ConnectServer ( '' , 'root\CIMV2' , '' , '' , '' , '' , wbemConnectFlagUseMaxWait , nil );

 ObjectSet := Service . ExecQuery ( 'Select * From Win32_Process' , 'WQL' , wbemFlagReturnImmediately , nil );

 Enum := ( ObjectSet . _NewEnum ) as IEnumVariant ;

  while ( Enum . Next ( 1 , SObject , Value )) = S_OK do

  begin

    //    SObject:= IUnknown(SObject) as SWBemObject;

    /// Can access any properites of Win32_Process class object

   Memo1 . Lines . Add ( SObject . Caption );

    /// ....

   Memo1 . Lines . Add ( SObject . VirtualSize );

  end ;

end ;

下面是OLE的写法,不需要Import TypeLib,使用也方便一些的:

procedure TForm1 . Button1Click ( Sender : TObject );

var

 Locator : OleVariant ;

 Service : OleVariant ;

 ObjectSet : OleVariant ;

 SObject : OleVariant ;

 Enum : IEnumVariant ;

 Value : Cardinal ;

begin

 Locator := CreateOleObject ( 'WbemScripting.SWbemLocator' );

 Service := Locator . ConnectServer ();

 ObjectSet := Service . ExecQuery ( 'Select * From Win32_Process' );

 Enum := IUnknown ( ObjectSet . _NewEnum ) as IEnumVariant ;

  while ( Enum . Next ( 1 , SObject , Value )) = S_OK do

  begin

    /// Can access any properites of Win32_Process class object

   Memo1 . Lines . Add ( SObject . Caption );

    /// ....

   Memo1 . Lines . Add ( SObject . VirtualSize );

  end ;

end ;

同样,如果要获取某个SObject的所有的属性和方法列表,可以采取类似下面的代码:

function WMIQuery ( const WQL : string ; const Computer : string = '' ; const User : string = '' ; const Password : string = '' ): IEnumVariant ;

{

 ·µ »Ø WQLÓï ¾ä µÄ ¼¯ ºÏ ¶Ô Ïó £¬ Óà ·¨ Èç Ï £º

 var

   Enum : IEnumVariant;

   Obj : OleVariant;

   V : Cardinal;

 ...

   Enum := WMIQuery('select * from win32_process');

   while Enum.Next(1,Obj, V) = S_OK do

   begin

     /// Obj.Name

     /// Obj.Value

     /// ...

   end;

}

var

 Locator , Service , ObjectSet : OleVariant ;

begin

 Locator := CreateOleObject ( 'WbemScripting.SWbemLocator' );

  if IsLocalComputer ( Computer ) then

   Service := Locator . ConnectServer ()

  else

   Service := Locator . ConnectServer ( Computer , 'root\cimv2' , Computer + '\' + User , Password );

 ObjectSet := Service . ExecQuery ( WQL );

 Result := IUnknown ( ObjectSet . _NewEnum ) as IEnumVariant ;

end ;

function WMIDumpProperties ( WQLObj : OleVariant ; Properites : TStrings ): Boolean ;

var

 Enum : IEnumVariant ;

 Obj : OleVariant ;

 V : Cardinal ;

begin

 Enum := IUnknown ( WQLObj . Properties_ . _NewEnum ) as IEnumVariant ;

  while Enum . Next ( 1 , Obj , V ) = S_OK do

  try

    //VType := VarTypeAsText(VarType(Prop));

   Properites . Add ( Format ( '%s=%s' ,[ Obj . Name , VariantToString ( Obj . Value )]));

  except

   Properites . Add ( Format ( '%s=(Error Get Property Value)' ,[ Obj . Name ]));

  end ;

end ;

procedure TForm1.Button1Click(Sender: TObject);

 var

   Enum : IEnumVariant;

   Obj : OleVariant;

   T : OleVariant;

   WQL: ISWBemObject;

   V : Cardinal;

begin

 Memo1.Clear;

   Enum := WMIQuery(Edit1.Text);

   while Enum.Next(1, Obj, V) = S_OK do

   begin

     Memo1.Lines.Add(Obj.Name);

     WMIDumpProperties(Obj, Memo1.Lines);

     Memo1.Lines.Add('-----------');

     /// Obj.Name

     /// Obj.Value

     /// ...

   end;

 //WMIGetBIOSInfo(Memo1.Lines);

end;

属性对象包含一些基本的属性:

Property         Description

CIMType          Type of this property.

IsArray          Boolean value that indicates if this property has an array type.

IsLocal          Boolean value that indicates if this is a local property.

Name             Name of this property.

Origin           Contains the originating class of this property.

Qualifiers_      An SWbemQualifierSet object, which is the collection of qualifiers for this property.

Value            Actual value of this property. This is the default automation property of this object.

同样,获取方法列表代码类似。

var

 EnumProp: IEnumVariant;

 Value: Cardinal;

 SMethod: OleVariant;

 ...

 EnumProp := IUnknown(SObject.Methods_._NewEnum) as IEnumVariant;

 while EnumProp.Next(1, SMethod, Value) = S_OK do

 begin

   /// SMethod.Name;

   /// SMethod.

   /// ...

 end;

方法对象有以下一些基本属性:

Property             Description

InParameters         An SWbemObject object whose properties define the input parameters for this method.

Name                 Name of the method.

Origin               Originating class of the method.

OutParameters        An SWbemObject object whose properties define the out parameters and return type of this method.

Qualifiers_          An SWbemQualifierSet object that contains the qualifiers for this method.

如果要调用某些Classes的方法,可以这样:

1:创建WbemScripting对象

2:调用ConnectServer,得到SWbemServices对象

3:调用Service对象的Get方法,Get需要一个ClassesName作为参数

4:调用该Class的对应的方法。

MSDN中可以找到每个Classes的所有的属性和方法及其参数的列表信息。

下面以创建一个计算器进程为例,进行演示:

procedure TForm1 . Button2Click ( Sender : TObject );

var

 Locator , Win32Process : OleVariant ;

begin

 Locator := CreateOleObject ( 'WbemScripting.SWbemLocator' );

 Win32Process := Locator . ConnectServer (). Get ( 'Win32_Process' );

 Win32Process . Create ( 'Calc.exe' );

end ;

使用接口的话,可以这样:

CoCreateInstance(CLSID_WbemLocator, 0,

       CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc) as ISWbemLocator;

然后调用ISWbemLocator接口的属性和方法即可。

WMI所有的接口及其参考,请查阅MSDN中的相关内容。

另外,我们也可以使用WMI TypeLib来达到我们的目的。

可以 使用 "Project|Import type library" 导入 <Windows System32>\wbem\wbemdisp.tlb 文件,导入后我们会看到若干个组件,使用他们就可以了。

以后Uses WbemScripting_TLB 就可以。

例如下面的代码演示如何关闭一个远程计算机。

uses WbemScripting_TLB, ActiveX;

procedure Shutdown(const ComputerName, UserName, Password: WideString);

const

 ClassName = 'Win32_OperatingSystem';

var

 Locator: ISWbemLocator;

 Services: ISWbemServices;

 tmpObjSet: ISWbemObjectSet;

 tmpEnum: IEnumVariant;

 tmpRet: LongWord;

 tmpClass: OleVariant;

begin

 Locator := CreateOleObject('WbemScripting.SWbemLocator') as ISWbemLocator;

 Services := Locator.ConnectServer(ComputerName, 'root\cimv2', UserName, Password);

 tmpObjSet := Services.InstancesOf(ClassName);

 tmpEnum:= tmpObjSet._NewEnum as IEnumVariant;

 while tmpEnum.Next(1, tmpClass, tmpRet) = S_OK do

 tmpClass.Win32Shutdown(8, 0);

end;

注意:如果要访问远程计算机,必须在本机启用DCOM,启动方法为:控制面板--〉管理工具--〉组件服务--〉,展开"组件服务|计算机|我的电脑",右击"我的电脑",选择属性,打开默认属性页面,选择"在此计算机上启用分布式COM",确定关闭对话框,重新启动计算机。在完成上述操作前,必须启动"Distributed Transaction Coordinator "服务,否则操作不能正常进行!如果不能正常启动Distributed Transaction Coordinator 服务,请运行msdtc -resetlog ,然后再启动Distributed Transaction Coordinator 服务,如果还是不能正常启动,请检查事件查看器中的相关信息。

下面的代码演示如何列举所有的进程及其相关信息:

uses

 ActiveX, WbemScripting_TLB;

function ADsEnumerateNext(pEnumVariant: IEnumVARIANT; cElements: ULONG;

 var pvar: OleVARIANT; var pcElementsFetched: ULONG): HRESULT; safecall; external 'activeds.dll';

procedure DumpWMI_Process(Process: SWBemObject);

var

 Enum: IEnumVARIANT;

 varArr: OleVariant;

 lNumElements: ULong;

 SProp: ISWbemProperty;

 Prop: OleVariant;

 PropName: string;

 PropType: string;

 PropValue: string;

begin

 Form1.Memo1.Lines.Add('+ WMI Path: ' + Process.Path_.Path);

 Enum := Process.Properties_._NewEnum as IEnumVariant;

 while (Succeeded(ADsEnumerateNext(Enum, 1, VarArr, lNumElements))) and

   (lNumElements > 0) do

 begin

   if Succeeded(IDispatch(varArr).QueryInterface(SWBemProperty, SProp)) and

     Assigned(SProp) then

   begin

     try

       PropName  := SProp.Name;

       Prop := SProp.Get_Value;

       PropType := VarTypeAsText(VarType(Prop));

       PropValue := VarToStr(Prop);

       Form1.Memo1.Lines.Add('  + ' + PropName + '[' + PropType + '] = ' + PropValue);

     except

       on E: Exception do

       begin

         // WriteLn(ErrOutput, PropName, ': ', E.Message);

       end;

     end;

   end;

 end;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

 Server: string;

 Enum: IEnumVARIANT;

 varArr: OleVariant;

 lNumElements: ULong;

 AName: array[0..255] of Char;

 ASize: DWORD;

begin

 if (ParamCount = 0) then

 begin

   Server := '';

   ASize  := SizeOf(AName) - 1;

   if GetComputerName(@AName, ASize) then Server := AName;

 end

 else

 begin

   Server := ParamStr(1);

 end;

 try

   Memo1.Lines.BeginUpdate;

   Enum := CoSWbemLocator.Create.ConnectServer(Server, 'root\cimv2', '',

     '', '', '', 0, nil).ExecQuery('Select * from Win32_Process', 'WQL',

     wbemFlagBidirectional, nil)._NewEnum as IEnumVariant;

   while (Succeeded(ADsEnumerateNext(Enum, 1, varArr, lNumElements))) and

     (lNumElements > 0) do

   begin

     DumpWMI_Process(IUnknown(varArr) as SWBemObject);

   end;

 finally

   Memo1.Lines.EndUpdate;

 end;

end;

{

You need the WbemScripting_TLB unit, which you can create by installing the type library

<Windows System32>\wbem\wbemdisp.tlb type library using the "Project|Import type library" menu option.

}

下面是一些方法调用的代码:

var

 Form1: TForm1;

 Service: ISWbemServices;

 InParam, OutParam, SObject, Process:    ISWbemObject;

 Method:   ISWbemMethod;

 SProp1, SProp2, MyProperty: ISWbemProperty;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

var

 PropValue: OleVariant;

begin

 Service:= SWbemLocator1.ConnectServer('.', 'root\cimv2', '', '', '',   '', 0, nil);

 // см. Примечание 1

 Service.Security_.Set_ImpersonationLevel(wbemImpersonationLevelImpersonate);

 Process:= Service.Get('Win32_Process', 0, nil);

 // см. Примечание 2  

 Method:= Process.Methods_.Item('Create', 0);

 // см. Примечание 3    

 InParam:= Method.InParameters.SpawnInstance_(0);

 // см. Примечание 4      

 MyProperty:= InParam.Properties_.Add('CommandLine', wbemCimtypeString, False, 0);  

{

 С помощью метода Set_Value объекта ISWbemProperty присваеваем свойству CommandLine

 значение Notepad.exe

}

 PropValue:= 'Notepad.exe';

 MyProperty.Set_Value(PropValue);

 // После того, как все входные свойства определены, запускаем приложение.

 // OutParam - объект, возвращаемый методом ExecMethod_

 OutParam:= Process.ExecMethod_('Create', InParam, 0, nil);

 //  Получения выходных параметров из возвращённого объекта OutParam типа SWbemObject

 SProp1:= outParam.Properties_.Item('ReturnValue', 0);

 

 // Проверяю, удалось ли запустить приложение. Если свойство ReturnValue не равно 0,

 // то произошла ошибка.

 if SProp1.Get_Value = 0 then

 begin

   SProp2:= outParam.Properties_.Item('ProcessID', 0);

   Button2.Enabled:= True;

   Button1.Enabled:= False;

   sleep(300);

   SetForegroundWindow(Form1.Handle);

 end

 else

   MessageBox(0, PChar('Не удалось запустить приложение.'), PChar(Form1.Caption), MB_OK);

end;

procedure TForm1.Button2Click(Sender: TObject);

var

 PropValue: OleVariant;

begin

   SObject:= Service.Get('Win32_Process.Handle="' +  WideString(SProp2.Get_Value) + '"', 0, nil);

   Method:= SOBject.Methods_.Item('Terminate', 0);

   InParam:= Method.InParameters.SpawnInstance_(0);

   MyProperty:= InParam.Properties_.Add('Reason', wbemCimtypeUint32, False, 0);

   PropValue:= 0;

   MyProperty.Set_Value(PropValue);

   OutParam:= SObject.ExecMethod_('Terminate', InParam, 0, nil);

   SProp1:= outParam.Properties_.Item('ReturnValue', 0);

   if SProp1.Get_Value = 0 then

   begin

     Button1.Enabled:= True;

     Button2.Enabled:= False;

   end

   else

     MessageBox(0, PChar('Не удалось закрыть приложение.'), PChar(Form1.Caption), MB_OK);

end;

procedure TForm1.Button3Click(Sender: TObject);

var

 ObjectSet: ISWbemObjectSet;

 Enum:      IEnumVariant;

 TempObj:   OleVariant;

 Value:     Cardinal;

begin

// Выключение компьютера - использование Shutdown без свойств.

 if MessageBox(0, PChar('Если вы выберете ''Да'', ваш компьютер выключится!'),

   PChar(Form1.Caption), MB_YESNO or MB_ICONEXCLAMATION or MB_DEFBUTTON2) = mrYes then

 begin

   Service:= SWbemLocator1.ConnectServer('.', 'root\cimv2', '', '', '',

     '', 0, nil);

   Service.Security_.Privileges.Add(wbemPrivilegeShutdown, True);

 // см. Примечание 5    

//  SObject:= Service.Get('Win32_OperatingSystem', wbemFlagUseAmendedQualifiers, nil);

//  ObjectSet:= SObject.Instances_(0, nil);

   ObjectSet:= Service.ExecQuery('SELECT * FROM Win32_OperatingSystem WHERE Primary=True',

     'WQL', wbemFlagReturnImmediately, nil);

   Enum:= (ObjectSet._NewEnum) as IEnumVariant;

   while (Enum.Next(1, TempObj, Value) = S_OK) do

   begin

     SObject:= IUnknown(tempObj) as SWBemObject;

     SObject.ExecMethod_('Shutdown', nil, 0, nil);

   end;

 end; { if MessageBox }

end;

end.

wmi.zip (41.4KB)