The Road to Delphi

Delphi – Free Pascal – Oxygene

A New project – Delphi (Object Pascal) WMI class code generator

14 Comments

The lasts weeks I’ve been working in a new project, called Delphi WMI class code generator. let me tell you about it.

The WMI (Windows Management Instrumentation) is formed by many classes, this classes exposes properties and methods. Also each class, property and method have qualifiers which are something like attributes, these qualifiers include descriptions about the classes, method, parameters or properties, types and many more useful information.

Now to access the properties of a wmi class from object pascal code is a very easy task, as was shown in this post, but by the other side to access the methods is little more complicated, because you need to known if the method is static or dynamic. also you must deal in some cases with complicated parameters which must be variants arrays, objects or datetime (in UTC format). and finally some of these parameters can be optional. so if you are only an occasional user of the WMI you must figure out a lot of thinks before to use it.

Because that and to the experience gained when I wrote the WMI Delphi Code Creator application, I decided to go a couple of steps forward and create tool which facilitate the access to the properties and methods exposed by the WMI classes from Object Pascal code.

The result was a code generator which parse the very rich meta-data of the wmi classes and extract the properties and methods and convert into a Object pascal class.

Now Let me show a sample code generated by the tool for the Win32_Share Wmi class.

/// <summary>
/// Unit generated using the Delphi Wmi class generator tool, Copyright Rodrigo Ruz V. 2010
/// Application version 0.1.0.120
/// WMI version 7600.16385
/// Creation Date 24-12-2010 09:38:11
/// Namespace root\CIMV2 Class Win32_Share
/// MSDN info about this class http://msdn2.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/Win32_Share.asp
/// </summary>

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

unit uWin32_Share;

interface

uses
 Classes,
 Activex,
 Variants,
 ComObj,
 uWmiDelphiClass;

type
{$IFDEF FPC}
 Cardinal=Longint;
 Int64=Integer;
 Word=Longint;
{$ENDIF}
{$IFNDEF FPC}
 {$IF CompilerVersion <= 15}
 {$DEFINE OLD_DELPHI}
 {$IFEND}
{$ENDIF}
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Win32_Share class represents a shared resource on a Win32 system. This may be a disk drive, printer, interprocess communication, or other shareable device.
 /// Example: C:\PUBLIC.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 TWin32_Share=class(TWmiClass)
 private
 FAccessMask                         : Cardinal;
 FAllowMaximum                       : Boolean;
 FCaption                            : String;
 FDescription                        : String;
 FInstallDate                        : TDateTime;
 FMaximumAllowed                     : Cardinal;
 FName                               : String;
 FPath                               : String;
 FStatus                             : String;
 FType                               : Cardinal;
 public
 constructor Create(LoadWmiData : boolean=True); overload;
 destructor Destroy;Override;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// This property has been deprecated in favour of the GetAccessMask method of this
 /// class due to the expense of calling GetEffectiveRightsFromAcl. The value will
 /// be set to NULL
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property AccessMask : Cardinal read FAccessMask;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The AllowMaximum property indicates whether the number of concurrent users for this resource has been limited.
 /// Values: TRUE or FALSE. A value of TRUE indicates the number of concurrent users of this resource has not been limited and the value in the MaximumAllowed property is ignored.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property AllowMaximum : Boolean read FAllowMaximum;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Caption property is a short textual description (one-line string) of the
 /// object.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property Caption : String read FCaption;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Description property provides a textual description of the object.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property Description : String read FDescription;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The InstallDate property is datetime value indicating when the object was
 /// installed. A lack of a value does not indicate that the object is not installed.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property InstallDate : TDateTime read FInstallDate;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The MaximumAllowed property indicates the limit on the maximum number of users allowed to use this resource concurrently. The value is only valid if the AllowMaximum member set to FALSE
 /// Example: 10.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property MaximumAllowed : Cardinal read FMaximumAllowed;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Name property indicates the alias given to a path set up as a share on a  Win32 system.
 /// Example: public.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property Name : String read FName;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Path property indicates the local path of the Win32 share.
 /// Example: C:\Program Files
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property Path : String read FPath;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Status property is a string indicating the current status of the object.
 /// Various operational and non-operational statuses can be defined. Operational
 /// statuses are "OK", "Degraded" and "Pred Fail". "Pred Fail" indicates that an
 /// element may be functioning properly but predicting a failure in the near
 /// future. An example is a SMART-enabled hard drive. Non-operational statuses can
 /// also be specified. These are "Error", "Starting", "Stopping" and "Service". The
 /// latter, "Service", could apply during mirror-resilvering of a disk, reload of a
 /// user permissions list, or other administrative work. Not all such work is on-
 /// line, yet the managed element is neither "OK" nor in one of the other states.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property Status : String read FStatus;
 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// The Type property specifies the type of resource being shared. Types include
 /// disk drives, print queues, interprocess communications (IPC), and general
 /// devices.
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 property {$IFDEF OLD_DELPHI}_Type{$ELSE}&Type{$ENDIF} : Cardinal read FType;
 function Create(const Access : OleVariant;const Description : String;const MaximumAllowed : Cardinal;const Name : String;const Password : String;const Path : String;const {$IFDEF OLD_DELPHI}_Type{$ELSE}&Type{$ENDIF} : Cardinal): Integer;overload;
 function SetShareInfo(const Access : OleVariant;const Description : String;const MaximumAllowed : Cardinal): Integer;
 function GetAccessMask: Integer;
 function Delete: Integer;
 procedure SetCollectionIndex(Index : Integer); override;
 end;

 {$IFDEF UNDEF}{$REGION 'Documentation'}{$ENDIF}
 /// <summary>
 /// Return the description for the value of the property TWin32_Share.Type
 /// </summary>
 {$IFDEF UNDEF}{$ENDREGION}{$ENDIF}
 function GetTypeAsString(const APropValue:Cardinal) : string;

implementation

function GetTypeAsString(const APropValue:Cardinal) : string;
begin
Result:='';
 case APropValue of
 0 : Result:='Disk Drive';
 1 : Result:='Print Queue';
 2 : Result:='Device';
 3 : Result:='IPC';
 2147483648 : Result:='Disk Drive Admin';
 2147483649 : Result:='Print Queue Admin';
 2147483650 : Result:='Device Admin';
 2147483651 : Result:='IPC Admin';
 end;
end;

{TWin32_Share}

constructor TWin32_Share.Create(LoadWmiData : boolean=True);
begin
 inherited Create(LoadWmiData,'root\CIMV2','Win32_Share');
end;

destructor TWin32_Share.Destroy;
begin
 inherited;
end;

procedure TWin32_Share.SetCollectionIndex(Index : Integer);
begin
 if (Index>=0) and (Index<=FWmiCollection.Count-1) and (FWmiCollectionIndex<>Index) then
 begin
 FWmiCollectionIndex:=Index;
 FAccessMask          := VarCardinalNull(inherited Value['AccessMask']);
 FAllowMaximum        := VarBoolNull(inherited Value['AllowMaximum']);
 FCaption             := VarStrNull(inherited Value['Caption']);
 FDescription         := VarStrNull(inherited Value['Description']);
 FInstallDate         := VarDateTimeNull(inherited Value['InstallDate']);
 FMaximumAllowed      := VarCardinalNull(inherited Value['MaximumAllowed']);
 FName                := VarStrNull(inherited Value['Name']);
 FPath                := VarStrNull(inherited Value['Path']);
 FStatus              := VarStrNull(inherited Value['Status']);
 FType                := VarCardinalNull(inherited Value['Type']);
 end;
end;

//static, OutParams=1, InParams>0
function TWin32_Share.Create(const Access : OleVariant;const Description : String;const MaximumAllowed : Cardinal;const Name : String;const Password : String;const Path : String;const {$IFDEF OLD_DELPHI}_Type{$ELSE}&Type{$ENDIF} : Cardinal): Integer;
var
 objInParams                : OleVariant;
 objOutParams               : OleVariant;
begin
 objInParams                 := GetInstanceOf.Methods_.Item('Create').InParameters.SpawnInstance_();
 objInParams.Properties_.Item('Access').Value  := Access;
 objInParams.Properties_.Item('Description').Value  := Description;
 objInParams.Properties_.Item('MaximumAllowed').Value  := MaximumAllowed;
 objInParams.Properties_.Item('Name').Value  := Name;
 objInParams.Properties_.Item('Password').Value  := Password;
 objInParams.Properties_.Item('Path').Value  := Path;
 objInParams.Properties_.Item('Type').Value  := {$IFDEF OLD_DELPHI}_Type{$ELSE}&Type{$ENDIF};
 objOutParams                := WMIService.ExecMethod(WmiClass, 'Create', objInParams, 0, GetNullValue);
 Result := VarIntegerNull(objOutParams.ReturnValue);
end;

//not static, OutParams=1, InParams>0
function TWin32_Share.SetShareInfo(const Access : OleVariant;const Description : String;const MaximumAllowed : Cardinal): Integer;
var
 ReturnValue : OleVariant;
begin
 ReturnValue := GetInstanceOf.SetShareInfo(Access,Description,MaximumAllowed);
 Result      := VarIntegerNull(ReturnValue);
end;

//not static, OutParams=1, InParams=0
function TWin32_Share.GetAccessMask: integer;
var
 ReturnValue : OleVariant;
begin
 ReturnValue := GetInstanceOf.GetAccessMask;
 Result      := VarIntegerNull(ReturnValue);
end;

//not static, OutParams=1, InParams=0
function TWin32_Share.Delete: integer;
var
 ReturnValue : OleVariant;
begin
 ReturnValue := GetInstanceOf.Delete;
 Result      := VarIntegerNull(ReturnValue);
end;
end.

as you can see the generated code is a full documented class compatible with the delphi help insight feature, available since Delphi 2005.

check this screen-shot which show the help insight for the Getowner method of the Win32_Process class.

This tool not only facilitate the access to the wmi, also give you information about every single WMI class, method and property.

here some features of the application

  • The code generated is compatible Delphi 7, 2005, BDS/Turbo 2006 and RAD Studio 2007, 2009, 2010, XE and the Free Pascal Compiler 2.2.4 (win32)
  • Create full documented classes compatible with the help insight feature, available since Delphi 2005.
    Note : the language of the description of the methods, parameters and properties depends on of the language of the windows where you generate the units.
  • Create additional helper functions to retrieve the description of the returned values for the properties and functions.
  • Support access to the WMI of the remote computers.

Now see this sample application which uses a class generated by the tool to access the BIOS information of a Remote PC.

program TestRemote;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  uWmiDelphiClass in '..\..\uWmiDelphiClass.pas', //the base class must be always included
  uWin32_BIOS in '..\..\root_CIMV2\uWin32_BIOS.pas'; //the class with the BIOs information

var
  RemoteBiosInfo : TWin32_BIOS;
  i              : integer;
begin
   try
     RemoteBiosInfo:=TWin32_BIOS.Create(False); //Create a instance of the TWin32_BIOS, the false value indicate which not load the Values when calls the constructor.
     try

       RemoteBiosInfo.WmiServer:='192.168.217.128'; //the remote pc name or IP
       RemoteBiosInfo.WmiUser  :='Administrator'; //the user used to establish the connection
       RemoteBiosInfo.WmiPass  :='password'; //the password
       RemoteBiosInfo.LoadWmiData; //now load the the data of the class

       if RemoteBiosInfo.WmiConnected then  //check if the connection was established
       begin
         Writeln('Serial Number       '+RemoteBiosInfo.SerialNumber);
         Writeln('BuildNumber         '+RemoteBiosInfo.BuildNumber);
         if RemoteBiosInfo.BIOSVersion.Count>0 then
         Writeln('Version             '+RemoteBiosInfo.BIOSVersion[0]);
         Writeln('Identification Code '+RemoteBiosInfo.IdentificationCode);
         Writeln('Manufacturer        '+RemoteBiosInfo.Manufacturer);
         Writeln('SoftwareElementID   '+RemoteBiosInfo.SoftwareElementID);
         Writeln('Release Date        '+DateToStr(RemoteBiosInfo.ReleaseDate));
         Writeln('Install Date        '+DateToStr(RemoteBiosInfo.InstallDate));
         Writeln('Target S.O          '+GetTargetOperatingSystemAsString(RemoteBiosInfo.TargetOperatingSystem));
         Writeln('Soft. element state '+GetSoftwareElementStateAsString(RemoteBiosInfo.SoftwareElementState));

         Writeln('');
         Writeln('Bios Characteristics');
         Writeln('--------------------');
         for i:=Low(RemoteBiosInfo.BiosCharacteristics)  to High(RemoteBiosInfo.BiosCharacteristics) do
          Writeln(GetBiosCharacteristicsAsString(RemoteBiosInfo.BiosCharacteristics[i]));
       end
       else
       Writeln('No connected');
     finally
      RemoteBiosInfo.Free;
     end;
   except
    on E:Exception do
     Writeln(E.Classname, ': ', E.Message);
   end;

 Readln;
end.

You can found more information about the internals, the full source code, demos and samples of this tool in the google code project page.

See you, and happy new year.

Author: Rodrigo

Just another Delphi guy.

14 thoughts on “A New project – Delphi (Object Pascal) WMI class code generator

  1. That’s a great tool. Thank you!
    Wasn’t it better to integrate this with your WMI Delphi Code Creator? That way all WMI related stuff would be inside a single tool.

    Anyways, this really simplifies dealing with WMI classes in an OOP manner.

    Thanks again, and Merry Christmas.

    • Hi thanks for your words, about integrate both tools, i want to keep it as separate projects for the moment because are very different, one generate quick snippets to access a particular wmi method, event or property and the another generate a wrapper for a wmi class with all the properties and methods.

  2. Why do redeclare int64, cardinal and word for FPC?

  3. Excelente, un muy buen trabajo. Aunque algo distinto comparado con tu trabajo anterior (Wmi Delphi Code Creator).

    Te felicito, pero más que nada te lo agradezco. Tienes muy buenos temas.

  4. hi
    i want to contact with you but i dont have any way to do.

    i want to implement simple app to work with bluetooth in delphi.
    but all component for this is not free.
    do you know any component?
    or any windows api?
    i have problem to auto detect device and send file to devices. my app needs to automatically finding devices and sending file aoutomating too. but nrCommon component is not any benefit to doing this operation.
    plz help me
    thanks

  5. Thanks a lot Rodrigo , very Very grateful.

  6. Excelente trabajo! muchas gracias, y feliz año

  7. What color scheme you use? It looks nice. Where can I download it?

  8. Hi, do you think you can provide source for CIM_LogicalFile Class (http://msdn.microsoft.com/en-us/library/aa387893(VS.85).aspx) because i can not find it on my computer with your program. I think this class can access a remote file.
    I need to make a program in Lazarus witch lists folder contents and permissions from shares in witch the user doesn’t have access (not even read). I will hardcode in source file my AD user credentials.
    Do you have other idea how i can accomplish this?
    Thank you very much.

    • mdalacu, the CIM_LogicalFile wmi class is a abstract class, which is not implemented directly for the WMI, instead try using the CIM_DataFile class, if you check the download section http://code.google.com/p/delphi-wmi-class-generator/downloads/list, you can find the root_CIMV2.rar file which contains the source for the CIM_DataFile. N ote that depending on the size of the disk to scan the execution of the clas might take several minutes to complete. try using the Wmi Code creator to tweak the WQL and optimize the access time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s