Yesterday I was experimenting with WMI (Windows Management Instrumentation) using Delphi 2009. As you know, WMI maintaines a huge repository containing … well, containing almost any piece of information available in Windows. At first glance it seems impossible to find what you need in such a repository, but actually the WMI structure is very simple and logical. Usually all you have to do is:
- Connect to the WMI service
- Obtain a collection of WMI objects by name
- Enumerate the collection.
The simplest tool to explore WMI is VBScript. You must have Windows Scripting Host installed, but nowadays it seems to be installed on every Windows system. A VBScript can be executed by doubleclicking on a *.vbs file or from the command-line:
- cscript myscript.vbs
Let us start with serial port enumeration using VBScript:
strComputer = "." Set objWMIService = GetObject( _ "winmgmts:\\" & strComputer & "\root\cimv2") Set colSerialPorts = _ objWMIService.InstancesOf("Win32_SerialPort") For Each SerPort In colSerialPorts Wscript.Echo _ "Name: " & SerPort.DeviceID & vbCrLf Next
The first line of code defines local computer (“.”). I found that the empty string also works fine. Next you connect to WMI service, obtain the collection of serial ports (“Win32_SerialPort”) and enumerate the collection. That is all.
A little more work is required to do the same in Delphi. First of all you must import a type library. Click Component/Import Component from IDE main menu (I am using Delphi 2009). You will see the dialog with “Import Type Library radiobutton selected:
Click “Next” and select “Microsoft WMI Scripting V1.2 Library” from the list of registered type libraries (library version may be different on your system):
Click “Next” and “Finish” to end the wizard.
A result of the process is the file “WbemScripting_TLB.pas” that must be added to a Delphi project. We also need ActiveX unit, so normally the “uses” clause of a unit that uses WMI looks like
- uses WbemScripting_TLB, ActiveX;
We can enumerate the available Windows resources using the following scheme:
- Connect to the WMI service
- Obtain a collection of WMI objects by name
- Enumerate the collection
- For each object in the collection obtain a collection of object’s properties
- Obtain a property by name.
The serial port enumeration example in Delphi:
uses WbemScripting_TLB, ActiveX; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var Locator: ISWbemLocator; Services: ISWbemServices; ObjSet: ISWbemObjectSet; SObject: ISWbemObject; PropSet: ISWbemPropertySet; SProp: ISWbemProperty; sValue: String; Enum: IEnumVariant; Value: Cardinal; TempObj: OleVariant; begin Memo1.Lines.Clear; Locator:= CoSWbemLocator.Create; Services:= Locator.ConnectServer('.', 'root\cimv2', '', '', '','', 0, nil); ObjSet:= Services.InstancesOf('Win32_SerialPort', wbemFlagReturnWhenComplete, nil); Enum:= (ObjSet._NewEnum) as IEnumVariant; while (Enum.Next(1, tempObj, Value) = S_OK) do begin SObject:= IUnknown(tempObj) as SWBemObject; PropSet := SObject.Properties_; SProp:= PropSet.Item('DeviceID',0); sValue:= SProp.Get_Value; Memo1.Lines.Add(sValue); end; end;
Now we can enumerate any Windows resource available in WMI repository by sligtly modifying the above code. The only question is where to find the names of WMI collections such as ‘Win32_SerialPort’ or property names like ‘DeviceID’? As usual everything about WMI can be found on MSDN. Delphi help also includes WMI SDK:
ms-help://embarcadero.rs2009/WMISDK/wmi/wmi_start_page.htm