The Road to Delphi

Delphi – Free Pascal – Oxygene


2 Comments

WMI Delphi Code Creator – New features and source code published in google code

Update : The WMI Delphi Code Creator now is hosted on Github.

In the last months I’ been working in a new version of the WMI Delphi Code Creator, porting the original code from Delphi 2007 to XE, adding new features like support for Delphi Prism and Free Pascal, and improving the source code generated by the tool. Now is time to show the results, so the new version is here with many new features,  also  the full source code is now available in the google code project hosting site under the Mozilla Public License 1.1

 

Check the list of features of the current version

  • Can generate object pascal code compatible with one of these compilers Delphi Win32, Delphi -Prism (Oxygene) , Free Pascal
  • The Delphi code generated is compatible with  Delphi 7, 2005, BDS/Turbo 2006 and RAD Studio 2007, 2009, 2010, XE.
  • The Free Pascal code generated is compatible with these versions 2.4.2, 2.4.4
  • The Delphi prism .Net  (Oxygene) generated code is compatible with all the versions up to 4.0.23.741 (in newer versions must work too)
  • Full access to metadata of any WMI Class registered in the system including qualifiers, mof definition, properties, methods, events
  • You can access directly from the application the MSDN web page related to the WMI Class which your are using.
  • Compile and run the generated code directly form the application using the selected compiler.
  • Open the the generated Delphi code in any of these  Delphi IDE’s 7, 2005, BDS/Turbo 2006 and RAD Studio 2007, 2009, 2010, XE
  • Open the the generated Free Pascal code directly in the Lazarus IDE.
  • Open the the generated Delphi Prism code directly in Visual Studio 2008, Visual Studio 2010 or MonoDevelop.
  • Runs on Windows XP, 2003, 2008, Vista and 7.
  • Themes support for Syntax highlighting (+50 themes included) compatible with the Delphi IDE Theme Editor.

For download the new version of the application and more details go to project page


16 Comments

Accesing the WMI from Delphi and Free Pascal via COM (without late binding or WbemScripting_TLB)

A fellow Delphi programmer,  ask me how they can access the WMI using the  COM API for WMI ,  so I decide write this article to show how.

First you must to know which this API was designed primarily for low level access to the WMI from C++ and for create WMI providers, compile mof files and so on.

In the past articles always I show samples to use the WMI using late binding or importing the Microsoft WMIScripting Library. in both cases you are using the same layer to access the WMI (WMIScripting).

In the next diagram you can see the layers to access the WMI, you can note how the WMIScripting finally access the WMI using the WMI COM API. In the next sample you will learn how avoid this additional layer.

The interfaces of the COM API for WMI are very similar to the Microsoft WMIScripting Library because the last is just a wrapper for the COM object.

Note : the code showed in this article was tested in Delphi 2007, Delphi XE and FPC 2.4.2 and uses the WBEM Client interface Unit for Object Pascal which is an translation of the headers of the WbemCli.h file. this unit called JwaWbemCli is part of the JEDI API Library

Accessing the WMI using the COM Interface


Initialize COM

Microsoft recommends use the CoInitializeEx function with the COINIT_MULTITHREADED flag
the code will looks like so

  if Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED)) then
  try
    //Execute your WMI code here
  finally
    CoUninitialize();
  end;

Set the general COM security level

Now In order to set the general COM security level you must perform a call to the CoInitializeSecurity function.

CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE, nil);

Create a connection to a WMI namespace.

FWbemLocator.ConnectServer(strNetworkResource, strUser, strPassword, strLocale,  WBEM_FLAG_CONNECT_USE_MAX_WAIT, strAuthority, nil, FWbemServices)

Set the security levels on the WMI connection.

By definition, WMI runs in a different process than your application. Therefore, you must create a connection between your application and WMI and you must set the impersonation and authentication levels for your application. this must be done using the CoSetProxyBlanket and CoCreateInstance functions.

 CoSetProxyBlanket(FWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nil, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE);
 CoCreateInstance(CLSID_UnsecuredApartment, nil, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, FUnsecuredApartment);

Implement your application (make the WMI query)

        Succeed := FWbemServices.ExecQuery('WQL', WQL, WBEM_FLAG_FORWARD_ONLY, nil, ppEnum);
        if Succeeded(Succeed) then
        begin
           // Get the data from the query
           while (ppEnum.Next(WBEM_INFINITE, 1, apObjects, puReturned)=0) do
           begin
             apObjects.Get('Caption', 0, pVal, pType, plFlavor);
             Writeln(pVal);
             VarClear(pVal);
           end;
        end
        else
        Writeln(Format('Error executing WQL sentence %x',[Succeed]));

Finally Cleanup and shut down your application.

After you complete your queries to WMI, you should destroy all COM pointers to shut down your application correctly. this is made setting the interface to nil to calling the varclear function.

Now a basic sample to make WMI query using the COM interface.


{$IFDEF FPC}
 {$MODE DELPHI} {$H+}
{$ENDIF}

{$APPTYPE CONSOLE}

uses
  Windows,
  Variants,
  SysUtils,
  ActiveX,
  JwaWbemCli;

const
  RPC_C_AUTHN_LEVEL_DEFAULT = 0;
  RPC_C_IMP_LEVEL_IMPERSONATE = 3;
  RPC_C_AUTHN_WINNT = 10;
  RPC_C_AUTHZ_NONE = 0;
  RPC_C_AUTHN_LEVEL_CALL = 3;
  EOAC_NONE = 0;

procedure Test_IWbemServices_ExecQuery;
const
  strLocale    = '';
  strUser      = '';
  strPassword  = '';
  strNetworkResource = 'root\cimv2';
  strAuthority       = '';
  WQL                = 'SELECT * FROM Win32_Volume';
var
  FWbemLocator         : IWbemLocator;
  FWbemServices        : IWbemServices;
  FUnsecuredApartment  : IUnsecuredApartment;
  ppEnum               : IEnumWbemClassObject;
  apObjects            : IWbemClassObject;
  puReturned           : ULONG;
  pVal                 : OleVariant;
  pType                : Integer;
  plFlavor             : Integer;
  Succeed              : HRESULT;
begin
  // Set general COM security levels --------------------------
  // Note: If you are using Windows 2000, you need to specify -
  // the default authentication credentials for a user by using
  // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
  // parameter of CoInitializeSecurity ------------------------
  if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE, nil)) then Exit;
  // Obtain the initial locator to WMI -------------------------
  if Succeeded(CoCreateInstance(CLSID_WbemLocator, nil, CLSCTX_INPROC_SERVER, IID_IWbemLocator, FWbemLocator)) then
  try
    // Connect to WMI through the IWbemLocator::ConnectServer method
    if Succeeded(FWbemLocator.ConnectServer(strNetworkResource, strUser, strPassword, strLocale,  WBEM_FLAG_CONNECT_USE_MAX_WAIT, strAuthority, nil, FWbemServices)) then
    try
      // Set security levels on the proxy -------------------------
      if Failed(CoSetProxyBlanket(FWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nil, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE)) then Exit;
      if Succeeded(CoCreateInstance(CLSID_UnsecuredApartment, nil, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, FUnsecuredApartment)) then
      try
        // Use the IWbemServices pointer to make requests of WMI
        //Succeed := FWbemServices.ExecQuery('WQL', WQL, WBEM_FLAG_FORWARD_ONLY OR WBEM_FLAG_RETURN_IMMEDIATELY, nil, ppEnum);
        Succeed := FWbemServices.ExecQuery('WQL', WQL, WBEM_FLAG_FORWARD_ONLY, nil, ppEnum);
        if Succeeded(Succeed) then
        begin
          Writeln('Running Wmi Query..Press Enter to exit');
           // Get the data from the query
           while (ppEnum.Next(WBEM_INFINITE, 1, apObjects, puReturned)=0) do
           begin
             apObjects.Get('Caption', 0, pVal, pType, plFlavor);
             Writeln(pVal);
             VarClear(pVal);
           end;
        end
        else
        Writeln(Format('Error executing WQL sentence %x',[Succeed]));
      finally
        FUnsecuredApartment := nil;
      end;
    finally
      FWbemServices := nil;
    end;
  finally
    FWbemLocator := nil;
  end;
end;

begin
  // Initialize COM. ------------------------------------------
  if Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED)) then
  try
    Test_IWbemServices_ExecQuery;
  finally
    CoUninitialize();
  end;
  Readln;
end.

And what about the Wmi events?

Ok here i leave the code to manage an async event using the COM WMI API.

Implement the Sink  definition to receive the event

Create a new class which descends from the TInterfacedObject class and the IWbemObjectSink interface, you must implement the Indicate and SetStatus functions.

type
  TWmiEventSink = class(TInterfacedObject, IWbemObjectSink)
  public
    function Indicate(lObjectCount: Longint;  var apObjArray: IWbemClassObject): HRESULT; stdcall;
    function SetStatus(lFlags: Longint; hResult: HRESULT; strParam: WideString; pObjParam: IWbemClassObject): HRESULT; stdcall;
  end;

Initilizate the Sink

Create a instance to the class TWmiEventSink which will handle the received events and use the IUnsecuredApartment.CreateObjectStub function to create a object forwarder sink.

FWmiEventSink := TWmiEventSink.Create;
FUnsecuredApartment.CreateObjectStub(FWmiEventSink, ppStub);

Execute the event

Call the ExecNotificationQueryAsync function passing the sink instance to begin listening the events.

FWbemServices.ExecNotificationQueryAsync('WQL', WQL, WBEM_FLAG_SEND_STATUS, nil, StubSink)

CleanUp

Finally use the CancelAsyncCall function to stop the Event receiver.

FWbemServices.CancelAsyncCall(StubSink);

And this is the full source code to receive the WMI async event


{$IFDEF FPC}
 {$MODE DELPHI} {$H+}
{$ENDIF}

{$APPTYPE CONSOLE}

uses
  Windows,
  Variants,
  SysUtils,
  ActiveX,
  JwaWbemCli;

const
  RPC_C_AUTHN_LEVEL_DEFAULT = 0;
  RPC_C_IMP_LEVEL_IMPERSONATE = 3;
  RPC_C_AUTHN_WINNT = 10;
  RPC_C_AUTHZ_NONE = 0;
  RPC_C_AUTHN_LEVEL_CALL = 3;
  EOAC_NONE = 0;

type
  TWmiEventSink = class(TInterfacedObject, IWbemObjectSink)
  public
    function Indicate(lObjectCount: Longint;  var apObjArray: IWbemClassObject): HRESULT; stdcall;
    function SetStatus(lFlags: Longint; hResult: HRESULT; strParam: WideString; pObjParam: IWbemClassObject): HRESULT; stdcall;
  end;

function TWmiEventSink.Indicate(lObjectCount: Longint; var apObjArray: IWbemClassObject): HRESULT; stdcall;
var
  Instance      : IWbemClassObject;
  wszName       : LPCWSTR;
  pVal          : OleVariant;
  pType         : Integer;
  plFlavor      : Integer;
  lFlags        : Longint;
  Caption, Pid  : string;
begin
  wszName:='TargetInstance';
  lFlags :=0;
  Result := WBEM_S_NO_ERROR;
  if lObjectCount > 0 then
    if Succeeded(apObjArray.Get(wszName, lFlags, pVal, pType, plFlavor)) then
    begin
      Instance := IUnknown(pVal) as IWbemClassObject;
      try
        Instance.Get('Caption', 0, pVal, pType, plFlavor);
        Caption:=pVal;
        VarClear(pVal);

        Instance.Get('ProcessId', 0, pVal, pType, plFlavor);
        Pid:=pVal;
        VarClear(pVal);

        Writeln(Format('Process %s started Pid  %s',[Caption,Pid]));

      finally
        Instance := nil;
      end;
    end;
end;

function TWmiEventSink.SetStatus(lFlags: Longint; hResult: HRESULT; strParam: WideString; pObjParam: IWbemClassObject): HRESULT; stdcall;
begin
  Result := WBEM_S_NO_ERROR;
end;

//detect when a key was pressed in the console window
function KeyPressed:Boolean;
var
  lpNumberOfEvents     : DWORD;
  lpBuffer             : TInputRecord;
  lpNumberOfEventsRead : DWORD;
  nStdHandle           : THandle;
begin
  Result:=false;
  nStdHandle := GetStdHandle(STD_INPUT_HANDLE);
  lpNumberOfEvents:=0;
  GetNumberOfConsoleInputEvents(nStdHandle,lpNumberOfEvents);
  if lpNumberOfEvents<> 0 then
  begin
    PeekConsoleInput(nStdHandle,lpBuffer,1,lpNumberOfEventsRead);
    if lpNumberOfEventsRead <> 0 then
    begin
      if lpBuffer.EventType = KEY_EVENT then
      begin
        if lpBuffer.Event.KeyEvent.bKeyDown then
          Result:=true
        else
          FlushConsoleInputBuffer(nStdHandle);
      end
      else
      FlushConsoleInputBuffer(nStdHandle);
    end;
  end;
end;

//Wmi async event
procedure Test_IWbemServices_ExecNotificationQueryAsync;
const
  strLocale    = '';
  strUser      = '';
  strPassword  = '';
  strNetworkResource = 'root\cimv2';
  strAuthority       = '';
  WQL                = 'SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Win32_Process"';
var
  FWbemLocator         : IWbemLocator;
  FWbemServices        : IWbemServices;
  FUnsecuredApartment  : IUnsecuredApartment;
  ppStub               : IUnknown;
  FWmiEventSink        : TWmiEventSink;
  StubSink             : IWbemObjectSink;

begin
  // Set general COM security levels --------------------------
  // Note: If you are using Windows 2000, you need to specify -
  // the default authentication credentials for a user by using
  // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ----
  // parameter of CoInitializeSecurity ------------------------
  if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE, nil)) then Exit;
  // Obtain the initial locator to WMI -------------------------
  if Succeeded(CoCreateInstance(CLSID_WbemLocator, nil, CLSCTX_INPROC_SERVER, IID_IWbemLocator, FWbemLocator)) then
  try
    // Connect to WMI through the IWbemLocator::ConnectServer method
    if Succeeded(FWbemLocator.ConnectServer(strNetworkResource, strUser, strPassword, strLocale,  WBEM_FLAG_CONNECT_USE_MAX_WAIT, strAuthority, nil, FWbemServices)) then
    try
      // Set security levels on the proxy -------------------------
      if Failed(CoSetProxyBlanket(FWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nil, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE)) then Exit;
      if Succeeded(CoCreateInstance(CLSID_UnsecuredApartment, nil, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, FUnsecuredApartment)) then
      try
        FWmiEventSink := TWmiEventSink.Create;
        if Succeeded(FUnsecuredApartment.CreateObjectStub(FWmiEventSink, ppStub)) then
        try
          if Succeeded(ppStub.QueryInterface(IID_IWbemObjectSink, StubSink)) then
          try
            if Succeeded(FWbemServices.ExecNotificationQueryAsync('WQL', WQL, WBEM_FLAG_SEND_STATUS, nil, StubSink)) then
            begin
              Writeln('Listening events...Press any key to exit');
               while not KeyPressed do ;
              FWbemServices.CancelAsyncCall(StubSink);
            end;
          finally
            StubSink := nil;
          end;
        finally
          ppStub := nil;
        end;
      finally
        FUnsecuredApartment := nil;
      end;
    finally
      FWbemServices := nil;
    end;
  finally
    FWbemLocator := nil;
  end;
end;

begin
  // Initialize COM
  if Succeeded(CoInitializeEx(nil, COINIT_MULTITHREADED)) then
  try
    Test_IWbemServices_ExecNotificationQueryAsync;
  finally
    CoUninitialize();
  end;
  Readln;
end.

Check the source code of this article on Github.


4 Comments

Compile, Debug and Run your Pascal code online.

Do you want test a short Pascal snippet and you don’t have a compiler? try the site called ideone.

What is ideone?
Ideone is something more than a pastebin; it’s an online compiler and debugging tool which allows
to compile and run code online in more than 40 programming languages.

This site currently supports these two Pascal compilers

fpc (Free Pascal Compiler) 2.2.0 (Target OS: Linux for i386)
gpc (GNU Pascal Compiler) 20070904

for the limitations about the code submitted and others check the FAQ.


13 Comments

Accesing the WMI from Object Pascal Code (Delphi, Oxygene, FreePascal)

Due to many developers don’t know how access the WMI from Pascal code, I decided to write this entry to show a simple set of samples using Delphi Win32, Delphi.Net, Oxygene and Free-pascal.

Delphi .Net

Delphi Prism

Delphi win32 importing the Microsoft WMIScripting Library.

Delphi win32 Late-binding.

Lazarus Late-binding

UPDATE

To access the WMI using COM  you must check this article

Accesing the WMI from Delphi and FPC via COM (without late binding or WbemScripting_TLB)

All the code samples uses the Win32_BaseBoard wmi class and are console applications just for simplicity.

The code showed in this entry can be optimized a lot for experienced developers, these simple  piece of code only pretend give a basic idea which how connect to the  WMi service and retieve data using a WQL query.

This is the Managed Object Format (MOF) representation of this class.

class Win32_BaseBoard : CIM_Card
{
  string   Caption;
  string   ConfigOptions[];
  string   CreationClassName;
  real32   Depth;
  string   Description;
  real32   Height;
  boolean  HostingBoard;
  boolean  HotSwappable;
  datetime InstallDate;
  string   Manufacturer;
  string   Model;
  string   Name;
  string   OtherIdentifyingInfo;
  string   PartNumber;
  boolean  PoweredOn;
  string   Product;
  boolean  Removable;
  boolean  Replaceable;
  string   RequirementsDescription;
  boolean  RequiresDaughterBoard;
  string   SerialNumber;
  string   SKU;
  string   SlotLayout;
  boolean  SpecialRequirements;
  string   Status;
  string   Tag;
  string   Version;
  real32   Weight;
  real32   Width;
};

Using Delphi Win32 and importing the Microsoft WMIScripting Library

This must be the most used method for accessing the WMI from Delphi Win32, basically consist in import the Microsoft WMIScripting Library and then delphi will create a wrapper containing all the types, const and enumerations to access the WMI, the main objects(interfaces) are ISWbemServices (which create a connection with WMI Windows Service) , ISWbemObjectSet (Execute a WQL Query) and ISWbemPropertySet

Check the picture to see the Microsoft Wmi Scripting library organization.

The basics steps are

1) import the Microsoft WMIScripting Library

2) Establish a connection with the WMI service in a local o remote computer. using the TSWbemLocator.ConnectServer function.

    function ConnectServer(const strServer: WideString; const strNamespace: WideString;
                           const strUser: WideString; const strPassword: WideString;
                           const strLocale: WideString; const strAuthority: WideString;
                           iSecurityFlags: Integer; const objWbemNamedValueSet: IDispatch): ISWbemServices;

 

SWbemServices := CoSWbemLocator.Create.ConnectServer('.', 'root\cimv2','', '', '', '', 0, nil);

3) Execute your WQL Query using the ISWbemServices.ExecQuery function which returns a instance to the ISWbemObjectSet object.

this is the declaration of the ISWbemServices.ExecQuery

    function ExecQuery(const strQuery: WideString; const strQueryLanguage: WideString;
                       iFlags: Integer; const objWbemNamedValueSet: IDispatch): ISWbemObjectSet; safecall;

and this is a sample of calling this function

SWbemObjectSet  := SWbemServices.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL', 0, nil);

4) the next step is iterate over the returned data, to do this we can use the ISWbemObjectSet._NewEnum property wich return an enumerator to the collection returned by the SWbemObjectSet

so using a IEnumVariant (which is part of the ActiveX unit) variable we can obtain the enumerator to the collection in this way.

Enum := (SWbemObjectSet._NewEnum) as IEnumVariant;

5) finally we need access the properties of the current collection, using the SWbemObject.Properties_.Item function

    while (Enum.Next(1, TempObj, Value) = S_OK) do
    begin
       SWbemObject     := IUnknown(tempObj) as ISWBemObject;
       SWbemPropertySet:= SWbemObject.Properties_;
       SWbemPropertySet.Item('SerialNumber', 0).Get_Value;//Get the value of the SerialNumber property
    end;

Advantages of importing the Microsoft WMIScripting Library

1) Full access through the IDE (code-completion) to the types, enumerations and constants of the WMIScripting Library.
2) easy to debug syntax errors which would have been missed had you used late binding.

Drawbacks

1) Depending of the Windows version which you uses, you can get different results when you import the WMIScripting Library, check this link.

2) The final exe size is incremented when you import this library.

Check the full sample source code to get a idea how use this method.

program WmiDelphiWin32_Tlb;

{$APPTYPE CONSOLE}

uses
  ActiveX,
  Variants,
  SysUtils,
  WbemScripting_TLB in '..\..\..\Documents\RAD Studio\5.0\Imports\WbemScripting_TLB.pas';//

 function VarArrayToStr(const vArray: variant): string;

    function _VarToStr(const V: variant): string;
    var
    Vt: integer;
    begin
    Vt := VarType(V);
        case Vt of
          varSmallint,
          varInteger  : Result := IntToStr(integer(V));
          varSingle,
          varDouble,
          varCurrency : Result := FloatToStr(Double(V));
          varDate     : Result := VarToStr(V);
          varOleStr   : Result := WideString(V);
          varBoolean  : Result := VarToStr(V);
          varVariant  : Result := VarToStr(Variant(V));
          varByte     : Result := char(byte(V));
          varString   : Result := String(V);
          varArray    : Result := VarArrayToStr(Variant(V));
        end;
    end;

var
i : integer;
begin
    Result := '[';
     if (VarType(vArray) and VarArray)=0 then
       Result := _VarToStr(vArray)
    else
    for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
     if i=VarArrayLowBound(vArray, 1)  then
      Result := Result+_VarToStr(vArray[i])
     else
      Result := Result+'|'+_VarToStr(vArray[i]);

    Result:=Result+']';
end;

function VarStrNull(const V:OleVariant):string; //avoid problems with null strings
begin
  Result:='';
  if not VarIsNull(V) then
  begin
    if VarIsArray(V) then
       Result:=VarArrayToStr(V)
    else
    Result:=VarToStr(V);
  end;
end;

Procedure GetWin32_BaseBoardInfo;
var
  SWbemServices   : ISWbemServices;
  SWbemObjectSet  : ISWbemObjectSet;
  Item            : Variant;
  Enum            : IEnumVariant;
  TempObj         : OleVariant;
  Value           : Cardinal;
  SWbemObject     : ISWbemObject;
  SWbemPropertySet: ISWbemPropertySet;
begin
  SWbemServices := CoSWbemLocator.Create.ConnectServer('.', 'root\cimv2','', '', '', '', 0, nil);
  SWbemObjectSet  := SWbemServices.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL', 0, nil);
  Enum := (SWbemObjectSet._NewEnum) as IEnumVariant;

    while (Enum.Next(1, TempObj, Value) = S_OK) do
    begin
       SWbemObject     := IUnknown(tempObj) as ISWBemObject;
       SWbemPropertySet:= SWbemObject.Properties_;

        Writeln(Format('Caption                   %s',[VarStrNull(SWbemPropertySet.Item('Caption', 0).Get_Value)]));// String
        Writeln(Format('ConfigOptions             %s',[VarStrNull(SWbemPropertySet.Item('ConfigOptions', 0).Get_Value)]));// String
        Writeln(Format('CreationClassName         %s',[VarStrNull(SWbemPropertySet.Item('CreationClassName', 0).Get_Value)]));// String
        Writeln(Format('Depth                     %s',[VarStrNull(SWbemPropertySet.Item('Depth', 0).Get_Value)]));// Real32
        Writeln(Format('Description               %s',[VarStrNull(SWbemPropertySet.Item('Description', 0).Get_Value)]));// String
        Writeln(Format('Height                    %s',[VarStrNull(SWbemPropertySet.Item('Height', 0).Get_Value)]));// Real32
        Writeln(Format('HostingBoard              %s',[VarStrNull(SWbemPropertySet.Item('HostingBoard', 0).Get_Value)]));// Boolean
        Writeln(Format('HotSwappable              %s',[VarStrNull(SWbemPropertySet.Item('HotSwappable', 0).Get_Value)]));// Boolean
        Writeln(Format('InstallDate               %s',[VarStrNull(SWbemPropertySet.Item('InstallDate', 0).Get_Value)]));// Datetime
        Writeln(Format('Manufacturer              %s',[VarStrNull(SWbemPropertySet.Item('Manufacturer', 0).Get_Value)]));// String
        Writeln(Format('Model                     %s',[VarStrNull(SWbemPropertySet.Item('Model', 0).Get_Value)]));// String
        Writeln(Format('Name                      %s',[VarStrNull(SWbemPropertySet.Item('Name', 0).Get_Value)]));// String
        Writeln(Format('OtherIdentifyingInfo      %s',[VarStrNull(SWbemPropertySet.Item('OtherIdentifyingInfo', 0).Get_Value)]));// String
        Writeln(Format('PartNumber                %s',[VarStrNull(SWbemPropertySet.Item('PartNumber', 0).Get_Value)]));// String
        Writeln(Format('PoweredOn                 %s',[VarStrNull(SWbemPropertySet.Item('PoweredOn', 0).Get_Value)]));// Boolean
        Writeln(Format('Product                   %s',[VarStrNull(SWbemPropertySet.Item('Product', 0).Get_Value)]));// String
        Writeln(Format('Removable                 %s',[VarStrNull(SWbemPropertySet.Item('Removable', 0).Get_Value)]));// Boolean
        Writeln(Format('Replaceable               %s',[VarStrNull(SWbemPropertySet.Item('Replaceable', 0).Get_Value)]));// Boolean
        Writeln(Format('RequirementsDescription   %s',[VarStrNull(SWbemPropertySet.Item('RequirementsDescription', 0).Get_Value)]));// String
        Writeln(Format('RequiresDaughterBoard     %s',[VarStrNull(SWbemPropertySet.Item('RequiresDaughterBoard', 0).Get_Value)]));// Boolean
        Writeln(Format('SerialNumber              %s',[VarStrNull(SWbemPropertySet.Item('SerialNumber', 0).Get_Value)]));// String
        Writeln(Format('SKU                       %s',[VarStrNull(SWbemPropertySet.Item('SKU', 0).Get_Value)]));// String
        Writeln(Format('SlotLayout                %s',[VarStrNull(SWbemPropertySet.Item('SlotLayout', 0).Get_Value)]));// String
        Writeln(Format('SpecialRequirements       %s',[VarStrNull(SWbemPropertySet.Item('SpecialRequirements', 0).Get_Value)]));// Boolean
        Writeln(Format('Status                    %s',[VarStrNull(SWbemPropertySet.Item('Status', 0).Get_Value)]));// String
        Writeln(Format('Tag                       %s',[VarStrNull(SWbemPropertySet.Item('Tag', 0).Get_Value)]));// String
        Writeln(Format('Version                   %s',[VarStrNull(SWbemPropertySet.Item('Version', 0).Get_Value)]));// String
        Writeln(Format('Weight                    %s',[VarStrNull(SWbemPropertySet.Item('Weight', 0).Get_Value)]));// Real32
        Writeln(Format('Width                     %s',[VarStrNull(SWbemPropertySet.Item('Width', 0).Get_Value)]));// Real32
        Writeln('');
        TempObj:=Unassigned;
    end;

end;

begin
 try
    CoInitialize(nil);
    try
      GetWin32_BaseBoardInfo;
      Readln;
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
    begin
        Writeln(E.Classname, ':', E.Message);
        Readln;
    end;
  end;
end.

Using Delphi and Late-Binding

Using the CreateOleObject function

You can access the WMI using the CreateOleObject function from delphi passing the WbemScripting.SWbemLocator class name

  var
     FSWbemLocator : OLEVariant;
  begin
    FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
    //
  end;

And then to run a WQL sentence

const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  //create an instance to the WMI Scripting SWbemLocator
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //connect to the server
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
  //execute the WQL sentence
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL',wbemFlagForwardOnly);
  //get the enumerator
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  //traverse the data
  while oEnum.Next(1, FWbemObject, iValue) = 0 do
  begin
    Writeln(Format('Caption    %s',[FWbemObject.Caption]));// String
    Writeln('');
    FWbemObject:=Unassigned;
  end;
end;

Using a Moniker

Another way to access the WMI is using a Moniker, to do this we need to use the IBindCtx and IMoniker interfaces.

Check this sample to create a wmi instance using these interfaces.

  function GetWMIObject(const objectName: String): IDispatch;
  var
    chEaten: Integer;
    BindCtx: IBindCtx;//for access to a bind context
    Moniker: IMoniker;//Enables you to use a moniker object
  begin
    OleCheck(CreateBindCtx(0, bindCtx));
    OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string
    OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object
  end;

//and call in this way
GetWMIObject('winmgmts:\\localhost\root\CIMV2');

Now we can run the query an get the results

See the snippet, is very similar to the used when we import the WbemScripting_TLB unit. but the main difference is which all the variables are declarated as Variants (OLEVariant) because we don’t have available the types, enumeratios and constants of the WbemScripting_TLB unit.

var
  objWMIService : OLEVariant;
  colItems      : OLEVariant;
  colItem       : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2');
  colItems      := objWMIService.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL',0);
  oEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;

3) finally to access a particular property we can get the value directly using his name.

 while oEnum.Next(1, colItem, iValue) = 0 do
 begin
     Writeln('Serial Number : '+colItem.SerialNumber);
     colItem:=Unassigned; //avoid memory leaks caused by the oEnum.Next function
 end;

Advantages of Late Binding

1. Is a very flexible solution to access the WMI, and the code to manage the wmi objects is very close to vbscript, which is good because there are thousands of examples of vbscript on the Internet to access the WMI Data.

2. Another very important advantage is that code which uses late binding is more certain to be version-independent, because when you create a WMIObject using winmgmts you are not referencing any particular version of the WMI.

3. The final exe executable is small because you don’t import any wrapper.

Drawbacks

1. You don’t have access to the wmi types, constants and enumerations from the ide, because the code is interpreted in run-time.

2. Hard to debug syntax errors,because the compiler don’t know about the WMI types
so you can write something like this (which is wrong) and the code will be compiled anyway.

 colItems.Properties_('Prop').Qualifiers_;

the right version must be.

 colItems.Properties_.Item('Prop').Qualifiers_;

Check the code using Late Binding to access the WMI from delphi (Valid for versions 5 to XE)

program WmiDelphiWin32_LateBinding;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;//introduced in delphi 6, if you use a older version of delphi you just remove this

function VarArrayToStr(const vArray: variant): string;

    function _VarToStr(const V: variant): string;
    var
    Vt: integer;
    begin
    Vt := VarType(V);
        case Vt of
          varSmallint,
          varInteger  : Result := IntToStr(integer(V));
          varSingle,
          varDouble,
          varCurrency : Result := FloatToStr(Double(V));
          varDate     : Result := VarToStr(V);
          varOleStr   : Result := WideString(V);
          varBoolean  : Result := VarToStr(V);
          varVariant  : Result := VarToStr(Variant(V));
          varByte     : Result := char(byte(V));
          varString   : Result := String(V);
          varArray    : Result := VarArrayToStr(Variant(V));
        end;
    end;

var
i : integer;
begin
    Result := '[';
     if (VarType(vArray) and VarArray)=0 then
       Result := _VarToStr(vArray)
    else
    for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
     if i=VarArrayLowBound(vArray, 1)  then
      Result := Result+_VarToStr(vArray[i])
     else
      Result := Result+'|'+_VarToStr(vArray[i]);

    Result:=Result+']';
end;

function VarStrNull(const V:OleVariant):string; //avoid problems with null strings
begin
  Result:='';
  if not VarIsNull(V) then
  begin
    if VarIsArray(V) then
       Result:=VarArrayToStr(V)
    else
    Result:=VarToStr(V);
  end;
end;

function GetWMIObject(const objectName: String): IDispatch; //create the Wmi instance
var
  chEaten: Integer;
  BindCtx: IBindCtx;
  Moniker: IMoniker;
begin
  OleCheck(CreateBindCtx(0, bindCtx));
  OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
  OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;

//The Win32_BaseBoard class represents a base board (also known as a motherboard
//or system board).

procedure  GetWin32_BaseBoardInfo;
var
  objWMIService : OLEVariant;
  colItems      : OLEVariant;
  colItem       : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2');
  colItems      := objWMIService.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL',0);
  oEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;
  while oEnum.Next(1, colItem, iValue) = 0 do
  begin
    Writeln(Format('Caption                  %s',[VarStrNull(colItem.Caption)]));// String
    Writeln(Format('ConfigOptions            %s',[VarStrNull(colItem.ConfigOptions)]));// String
    Writeln(Format('CreationClassName        %s',[VarStrNull(colItem.CreationClassName)]));// String
    Writeln(Format('Depth                    %s',[VarStrNull(colItem.Depth)]));// Real32
    Writeln(Format('Description              %s',[VarStrNull(colItem.Description)]));// String
    Writeln(Format('Height                   %s',[VarStrNull(colItem.Height)]));// Real32
    Writeln(Format('HostingBoard             %s',[VarStrNull(colItem.HostingBoard)]));// Boolean
    Writeln(Format('HotSwappable             %s',[VarStrNull(colItem.HotSwappable)]));// Boolean
    Writeln(Format('InstallDate              %s',[VarStrNull(colItem.InstallDate)]));// Datetime
    Writeln(Format('Manufacturer             %s',[VarStrNull(colItem.Manufacturer)]));// String
    Writeln(Format('Model                    %s',[VarStrNull(colItem.Model)]));// String
    Writeln(Format('Name                     %s',[VarStrNull(colItem.Name)]));// String
    Writeln(Format('OtherIdentifyingInfo     %s',[VarStrNull(colItem.OtherIdentifyingInfo)]));// String
    Writeln(Format('PartNumber               %s',[VarStrNull(colItem.PartNumber)]));// String
    Writeln(Format('PoweredOn                %s',[VarStrNull(colItem.PoweredOn)]));// Boolean
    Writeln(Format('Product                  %s',[VarStrNull(colItem.Product)]));// String
    Writeln(Format('Removable                %s',[VarStrNull(colItem.Removable)]));// Boolean
    Writeln(Format('Replaceable              %s',[VarStrNull(colItem.Replaceable)]));// Boolean
    Writeln(Format('RequirementsDescription  %s',[VarStrNull(colItem.RequirementsDescription)]));// String
    Writeln(Format('RequiresDaughterBoard    %s',[VarStrNull(colItem.RequiresDaughterBoard)]));// Boolean
    Writeln(Format('SerialNumber             %s',[VarStrNull(colItem.SerialNumber)]));// String
    Writeln(Format('SKU                      %s',[VarStrNull(colItem.SKU)]));// String
    Writeln(Format('SlotLayout               %s',[VarStrNull(colItem.SlotLayout)]));// String
    Writeln(Format('SpecialRequirements      %s',[VarStrNull(colItem.SpecialRequirements)]));// Boolean
    Writeln(Format('Status                   %s',[VarStrNull(colItem.Status)]));// String
    Writeln(Format('Tag                      %s',[VarStrNull(colItem.Tag)]));// String
    Writeln(Format('Version                  %s',[VarStrNull(colItem.Version)]));// String
    Writeln(Format('Weight                   %s',[VarStrNull(colItem.Weight)]));// Real32
    Writeln(Format('Width                    %s',[VarStrNull(colItem.Width)]));// Real32
    Writeln('');
    colItem:=Unassigned;
  end;
end;

begin
 try
    CoInitialize(nil);
    try
      GetWin32_BaseBoardInfo;
      Readln;
    finally
    CoUninitialize;
    end;
 except
    on E:Exception do
    begin
        Writeln(E.Classname, ':', E.Message);
        Readln;
    end;
  end;
end.

Using Delphi .Net (Valid for versions 2005, 2006, 2007)

1) before to use the .net wmi objects you add the System.Management reference to your project.

2) Now we need make the connection to the WMi service, to do this you must use the System.Management namespace and the ManagementObjectSearcher class wich have several constructor to facilitate the connection with the wmi, this class is very versatile and let establish the connection and make a WQL query in a single step.

Check the constructors availables to this class

Public method ManagementObjectSearcher() 	//Initializes a new instance of the ManagementObjectSearcher class. After some properties on this object are set, the object can be used to invoke a query for management information. This is the default constructor.

 

Public method ManagementObjectSearcher(ObjectQuery) 	//Initializes a new instance of the ManagementObjectSearcher class used to invoke the specified query for management information.

 

Public method ManagementObjectSearcher(String) 	//Initializes a new instance of the ManagementObjectSearcher class used to invoke the specified query for management information.

 

Public method ManagementObjectSearcher(ManagementScope, ObjectQuery) //Initializes a new instance of the ManagementObjectSearcher class used to invoke the specified query in the specified scope.

 

Public method ManagementObjectSearcher(String, String) 	//Initializes a new instance of the ManagementObjectSearcher class used to invoke the specified query in the specified scope.

 

Public method ManagementObjectSearcher(ManagementScope, ObjectQuery, EnumerationOptions) 	//Initializes a new instance of the

 

Public method ManagementObjectSearcher class //to be used to invoke the specified query in the specified scope, with the specified options.

 

Public method ManagementObjectSearcher(String, String, EnumerationOptions) 	//Initializes a new instance of the ManagementObjectSearcher class used to invoke the specified query, in the specified scope, and with the specified options.

so to establishing the connection and make the query to the WMI you must write a code like this

Searcher  :=ManagementObjectSearcher.Create('root\cimv2','SELECT * FROM Win32_BaseBoard');

3) retrieve the data using the ManagementObjectCollection object.

4) get a enumerator to iterate over the data returned using a ManagementObjectEnumerator

    Collection:=Searcher.Get();//Get the data
    iter:=Collection.GetEnumerator;//create  a enumerator
    while(iter.MoveNext()) do//iterate over the enumerator

5) and finally to access to the value of an particular property we must use a ManagementObject object in this way

      WmiObject:=ManagementObject(iter.Current); //get the current element
      SerialNumber:=WmiObject['SerialNumber'];

This is the full source code to access the wmi from Delphi .Net from a console application

program WmiDelphi.Net;
{$APPTYPE CONSOLE}
uses
  System.Management,
  SysUtils;

procedure  GetWin32_BaseBoardInfo;
var
Searcher   : ManagementObjectSearcher ;
Collection : ManagementObjectCollection;
iter       : ManagementObjectCollection.ManagementObjectEnumerator;
WmiObject  : ManagementObject;
begin
  try
    Searcher  :=ManagementObjectSearcher.Create('SELECT * FROM Win32_BaseBoard'); //make the WMi query
    Collection:=Searcher.Get();//Get the data
    iter:=Collection.GetEnumerator;//create  a enumerator
    while(iter.MoveNext()) do//iterate over the enumerator
    begin
      WmiObject:=ManagementObject(iter.Current); //get the current element
         Writeln(Format('Caption                 %s',[WmiObject['Caption']]));
         Writeln(Format('ConfigOptions           %s',[WmiObject['ConfigOptions']]));
         Writeln(Format('CreationClassName       %s',[WmiObject['CreationClassName']]));
         Writeln(Format('Depth                   %s',[WmiObject['Depth']]));
         Writeln(Format('Description             %s',[WmiObject['Description']]));
         Writeln(Format('Height                  %s',[WmiObject['Height']]));
         Writeln(Format('HostingBoard            %s',[WmiObject['HostingBoard']]));
         Writeln(Format('HotSwappable            %s',[WmiObject['HotSwappable']]));
         Writeln(Format('InstallDate             %s',[WmiObject['InstallDate']]));
         Writeln(Format('Manufacturer            %s',[WmiObject['Manufacturer']]));
         Writeln(Format('Model                   %s',[WmiObject['Model']]));
         Writeln(Format('Name                    %s',[WmiObject['Name']]));
         Writeln(Format('OtherIdentifyingInfo    %s',[WmiObject['OtherIdentifyingInfo']]));
         Writeln(Format('PartNumber              %s',[WmiObject['PartNumber']]));
         Writeln(Format('PoweredOn               %s',[WmiObject['PoweredOn']]));
         Writeln(Format('Product                 %s',[WmiObject['Product']]));
         Writeln(Format('Removable               %s',[WmiObject['Removable']]));
         Writeln(Format('Replaceable             %s',[WmiObject['Replaceable']]));
         Writeln(Format('RequirementsDescription %s',[WmiObject['RequirementsDescription']]));
         Writeln(Format('RequiresDaughterBoard   %s',[WmiObject['RequiresDaughterBoard']]));
         Writeln(Format('SerialNumber            %s',[WmiObject['SerialNumber']]));
         Writeln(Format('SKU                     %s',[WmiObject['SKU']]));
         Writeln(Format('SlotLayout              %s',[WmiObject['SlotLayout']]));
         Writeln(Format('SpecialRequirements     %s',[WmiObject['SpecialRequirements']]));
         Writeln(Format('Status                  %s',[WmiObject['Status']]));
         Writeln(Format('Tag                     %s',[WmiObject['Tag']]));
         Writeln(Format('Version                 %s',[WmiObject['Version']]));
         Writeln(Format('Weight                  %s',[WmiObject['Weight']]));
         Writeln(Format('Width                   %s',[WmiObject['Width']]));
    end;
    Readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end;

begin
  try
    GetWin32_BaseBoardInfo;
    Readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

Using Delphi Prism

By far using .Net and delphi prism must be the easy way to access the WMI, because you don’t need to implement enumerators or helper functions to avoid nulls. therefore exists many resources of the WMI and .Net in the MSDN site.

1) to access the WMI from .Net you add the System.Management namespace which give you full access to the WMI.

2) Now using the ManagementObjectSearcher class in a single step you can establish a connection to the wmi service and make a WQL query.

Searcher := new ManagementObjectSearcher('root\cimv2','select * from Win32_BaseBoard');

3) for iterate over the WMI data you can use the great features of dephi-prism, how create a local variable in a for loop

for WmiObject : ManagementObject  in searcher.Get() do //in this single line you are creating a WmiObject to get access to the properties,and searcher.Get() return a enumerator that iterates through the ManagementObjectCollection.

Finally the Source code of a Delphi Prism console application to access the WMI.

namespace WmiDelphiPrism;

interface
uses
System,
System.Management,
System.Text;

type
    ConsoleApp = class
    private
        class method GetWin32_BaseBoardInfo;
    public
        class method Main;
    end;

implementation

class method ConsoleApp.Main;
begin
 try
    GetWin32_BaseBoardInfo;
    Console.Read();
 except on E: Exception do
  Console.WriteLine(E.ToString()+' Trace '+E.StackTrace );
 end;
end;

class method ConsoleApp.GetWin32_BaseBoardInfo;
var
Searcher : ManagementObjectSearcher;
begin
     Searcher := new ManagementObjectSearcher('root\cimv2','select * from Win32_BaseBoard');
        for WmiObject : ManagementObject  in searcher.Get() do
        begin
             Console.WriteLine('{0,-35} {1,-40}','Caption',WmiObject['Caption']);
             Console.WriteLine('{0,-35} {1,-40}','ConfigOptions',WmiObject['ConfigOptions']);
             Console.WriteLine('{0,-35} {1,-40}','CreationClassName',WmiObject['CreationClassName']);
             Console.WriteLine('{0,-35} {1,-40}','Depth',WmiObject['Depth']);
             Console.WriteLine('{0,-35} {1,-40}','Description',WmiObject['Description']);
             Console.WriteLine('{0,-35} {1,-40}','Height',WmiObject['Height']);
             Console.WriteLine('{0,-35} {1,-40}','HostingBoard',WmiObject['HostingBoard']);
             Console.WriteLine('{0,-35} {1,-40}','HotSwappable',WmiObject['HotSwappable']);
             Console.WriteLine('{0,-35} {1,-40}','InstallDate',WmiObject['InstallDate']);
             Console.WriteLine('{0,-35} {1,-40}','Manufacturer',WmiObject['Manufacturer']);
             Console.WriteLine('{0,-35} {1,-40}','Model',WmiObject['Model']);
             Console.WriteLine('{0,-35} {1,-40}','Name',WmiObject['Name']);
             Console.WriteLine('{0,-35} {1,-40}','OtherIdentifyingInfo',WmiObject['OtherIdentifyingInfo']);
             Console.WriteLine('{0,-35} {1,-40}','PartNumber',WmiObject['PartNumber']);
             Console.WriteLine('{0,-35} {1,-40}','PoweredOn',WmiObject['PoweredOn']);
             Console.WriteLine('{0,-35} {1,-40}','Product',WmiObject['Product']);
             Console.WriteLine('{0,-35} {1,-40}','Removable',WmiObject['Removable']);
             Console.WriteLine('{0,-35} {1,-40}','Replaceable',WmiObject['Replaceable']);
             Console.WriteLine('{0,-35} {1,-40}','RequirementsDescription',WmiObject['RequirementsDescription']);
             Console.WriteLine('{0,-35} {1,-40}','RequiresDaughterBoard',WmiObject['RequiresDaughterBoard']);
             Console.WriteLine('{0,-35} {1,-40}','SerialNumber',WmiObject['SerialNumber']);
             Console.WriteLine('{0,-35} {1,-40}','SKU',WmiObject['SKU']);
             Console.WriteLine('{0,-35} {1,-40}','SlotLayout',WmiObject['SlotLayout']);
             Console.WriteLine('{0,-35} {1,-40}','SpecialRequirements',WmiObject['SpecialRequirements']);
             Console.WriteLine('{0,-35} {1,-40}','Status',WmiObject['Status']);
             Console.WriteLine('{0,-35} {1,-40}','Tag',WmiObject['Tag']);
             Console.WriteLine('{0,-35} {1,-40}','Version',WmiObject['Version']);
             Console.WriteLine('{0,-35} {1,-40}','Weight',WmiObject['Weight']);
             Console.WriteLine('{0,-35} {1,-40}','Width',WmiObject['Width']);
        end;
end;
end.

Using Lazarus

The code necessary to access the WMI from Free-pascal using lazarus is very similar to the used in the Delphi win32 Late-binding., so i will show the differences only because the general idea is the same.

1) you must add the Windows unit to the uses clause because this unit contan the PULONG type which is required in some functions.

2) you don’t need call CoInitialize and CoUninitialize functions because both are initializated by the comobj unit

3) the helper function GetWMIObject must be modified to fit with the new types of parameteres required by the MkParseDisplayName function.

which is declarated like this (see the _para3 param which is of PULONG (^cardinal) type)

 function MkParseDisplayName(_para1:IBindCtx; _para2:POLESTR; out _para3:PULONG; out _para4:IMoniker):HRESULT;stdcall; external  'ole32.dll' name 'MkParseDisplayName';

and the modified helper function now look like this.

function GetWMIObject(const objectName: String): IDispatch; //create the Wmi instance
var
  chEaten: PULONG;
  BindCtx: IBindCtx;
  Moniker: IMoniker;
begin
  OleCheck(CreateBindCtx(0, bindCtx));
  OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
  OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;

4) the function IEnumVARIANT.Next requires a Variant param

Function  Next(celt: ULONG; OUT rgVar: VARIANT;  pCeltFetched: pULONG=nil):HResult;StdCall;

so you must use it in this way

var
colItem : Variant;
//
//
//
while oEnum.Next(1, colItem, nil) = 0 do

5) finally if you wanna use the format function, you must aware which has some problems with variant values. so you must rewrite the code to show the info in this way.

    SDummy:=VarStrNull(colItem.Caption); //SDummy is a string
    Writeln(Format('Caption                  %s',[SDummy]));

Lazarus source code of console aplication to access the WMI

program WmiLazarus_LateBinding;

{$mode objfpc}

uses
   SysUtils,
   Variants,
   comobj,//required for the OleCheck and CoInitialize functions
   ActiveX,
   Windows;//required for the PULONG type

function VarArrayToStr(const vArray: variant): string;

    function _VarToStr(const V: variant): string;
    var
    Vt: integer;
    begin
    Vt := VarType(V);
        case Vt of
          varSmallint,
          varInteger  : Result := IntToStr(integer(V));
          varSingle,
          varDouble,
          varCurrency : Result := FloatToStr(Double(V));
          varDate     : Result := VarToStr(V);
          varOleStr   : Result := WideString(V);
          varBoolean  : Result := VarToStr(V);
          varVariant  : Result := VarToStr(Variant(V));
          varByte     : Result := char(byte(V));
          varString   : Result := String(V);
          varArray    : Result := VarArrayToStr(Variant(V));
        end;
    end;

var
i : integer;
begin
    Result := '[';
     if (VarType(vArray) and VarArray)=0 then
       Result := _VarToStr(vArray)
    else
    for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
     if i=VarArrayLowBound(vArray, 1)  then
      Result := Result+_VarToStr(vArray[i])
     else
      Result := Result+'|'+_VarToStr(vArray[i]);

    Result:=Result+']';
end;

function VarStrNull(const V:OleVariant):string; //avoid problems with null strings
begin
  Result:='';
  if not VarIsNull(V) then
  begin
    if VarIsArray(V) then
       Result:=VarArrayToStr(V)
    else
    Result:=VarToStr(V);
  end;
end;

function GetWMIObject(const objectName: String): IDispatch; //create the Wmi instance
var
  chEaten: PULONG;
  BindCtx: IBindCtx;
  Moniker: IMoniker;
begin
  OleCheck(CreateBindCtx(0, bindCtx));
  OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
  OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;

//The Win32_BaseBoard class represents a base board (also known as a motherboard
//or system board).

procedure  GetWin32_BaseBoardInfo;
var
  objWMIService : OleVariant;
  colItems      : OleVariant;
  colItem       : Variant;
  oEnum         : IEnumvariant;
  SDummy        : string;
begin;
  objWMIService := GetWMIObject('winmgmts:\\localhost\root\CIMV2');
  colItems      := objWMIService.ExecQuery('SELECT * FROM Win32_BaseBoard','WQL',0);
  oEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;
  while oEnum.Next(1, colItem, nil) = 0 do
  begin
    SDummy:=VarStrNull(colItem.Caption);
    Writeln(Format('Caption                  %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.ConfigOptions);
    Writeln(Format('ConfigOptions            %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.CreationClassName);
    Writeln(Format('CreationClassName        %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Depth);
    Writeln(Format('Depth                    %s',[SDummy]));// Real32
    SDummy:=VarStrNull(colItem.Description);
    Writeln(Format('Description              %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Height);
    Writeln(Format('Height                   %s',[SDummy]));// Real32
    SDummy:=VarStrNull(colItem.HostingBoard);
    Writeln(Format('HostingBoard             %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.HotSwappable);
    Writeln(Format('HotSwappable             %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.InstallDate);
    Writeln(Format('InstallDate              %s',[SDummy]));// Datetime
    SDummy:=VarStrNull(colItem.Manufacturer);
    Writeln(Format('Manufacturer             %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Model);
    Writeln(Format('Model                    %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Name);
    Writeln(Format('Name                     %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.OtherIdentifyingInfo);
    Writeln(Format('OtherIdentifyingInfo     %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.PartNumber);
    Writeln(Format('PartNumber               %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.PoweredOn);
    Writeln(Format('PoweredOn                %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.Product);
    Writeln(Format('Product                  %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Removable);
    Writeln(Format('Removable                %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.Replaceable);
    Writeln(Format('Replaceable              %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.RequirementsDescription);
    Writeln(Format('RequirementsDescription  %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.RequiresDaughterBoard);
    Writeln(Format('RequiresDaughterBoard    %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.SerialNumber);
    Writeln(Format('SerialNumber             %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.SKU);
    Writeln(Format('SKU                      %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.SlotLayout);
    Writeln(Format('SlotLayout               %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.SpecialRequirements);
    Writeln(Format('SpecialRequirements      %s',[SDummy]));// Boolean
    SDummy:=VarStrNull(colItem.Status);
    Writeln(Format('Status                   %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Tag);
    Writeln(Format('Tag                      %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Version);
    Writeln(Format('Version                  %s',[SDummy]));// String
    SDummy:=VarStrNull(colItem.Weight);
    Writeln(Format('Weight                   %s',[SDummy]));// Real32
    SDummy:=VarStrNull(colItem.Width);
    Writeln(Format('Width                    %s',[SDummy]));// Real32
  end;

end;

begin
 try
   //CoInitialize(nil);   you don't need call this because is initializated by the comobj unit
    try
      GetWin32_BaseBoardInfo;
      Readln;
    finally
    //CoUninitialize;
    end;
 except
    on E:Exception do
    begin
        Writeln(E.Classname, ':', E.Message);
        Readln;
    end;
  end;
end.

So now you don’t have excuses to don’t use the WMI for pascal code. And remember which you have the WMI Delphi Code creator to help you.;)