//**************************************************************************************************
//                                                                                                  
// Unit uWmiDelphiClass                                                                             
// Base class  for the classes generated by the Delphi Wmi Class generator                          
// https://github.com/RRUZ/delphi-wmi-class-generator                                               
//                                                                                                  
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the    
// License at http://www.mozilla.org/MPL/                                                           
//                                                                                                  
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF   
// ANY KIND, either express or implied. See the License for the specific language governing rights  
// and limitations under the License.                                                               
//                                                                                                  
// The Original Code is uWmiDelphiClass.pas.                                                        
//                                                                                                  
// The Initial Developer of the Original Code is Rodrigo Ruz V.                                     
// Portions created by Rodrigo Ruz V. are Copyright (C) 2010-2015 Rodrigo Ruz V.                    
// All Rights Reserved.                                                                             
//                                                                                                  
//**************************************************************************************************

unit uWmiDelphiClass;

interface
{$IFNDEF MSWINDOWS}
     Sorry Only Windows
{$ENDIF}


{todo}
// remove latebinding dependence in methods invoke
// remove old_delphi conditional
// add option to create code optimized by version  (enumerators, generics)
   // add generics support?
{end todo}



{.$DEFINE _DEBUG}

{.$DEFINE WMI_COM_API}
{$DEFINE WbemScripting_TLB}
{.$DEFINE WMI_LateBinding}


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

{$IFNDEF FPC}
  {$IF CompilerVersion < 17}
    {$DEFINE OLD_DELPHI}
  {$IFEND}
{$ENDIF}


{$IFDEF WMI_COM_API}
  {$MESSAGE 'Using WMI_COM_API'}

  {$IF CompilerVersion >=24}
    {$DEFINE Winapi_Wbem}
  {$IFEND}

{$ENDIF}

{$IFDEF WbemScripting_TLB}
  {$MESSAGE 'Using WbemScripting_TLB'}
{$ENDIF}

{$IFDEF WMI_LateBinding}
  {$MESSAGE 'Using WMI_LateBinding'}
{$ENDIF}


uses
{$IFDEF WMI_COM_API}
 {$IFDEF Winapi_Wbem}
  Winapi.Wbem,
 {$ELSE}
  JwaActiveX,
  JwaWbemCli,
 {$ENDIF}
{$ENDIF}
{$IFDEF WbemScripting_TLB}
  WbemScripting_TLB,
{$ENDIF}
  Windows,
  Classes;



type
  TWordArray      = Array of Word;
  TShortIntArray  = Array of ShortInt;
  TByteArray      = Array of Byte;
  TSmallIntArray  = Array of SmallInt;
  TIntegerArray   = Array of Integer;
  TCardinalArray  = Array of Cardinal;
  TInt64Array     = Array of Int64;
  TDoubleArray    = Array of Double;
  TBooleanArray   = Array of Boolean;
  TTDateTimeArray = Array of TDateTime;
  TOleVariantArray= Array of OleVariant;
  TWideStringArray= Array of WideString;

{$IFDEF WMI_COM_API}
    PCOAUTHIDENTITY    = ^TCOAUTHIDENTITY;
    _COAUTHIDENTITY    = Record
                          User           : PChar;
                          UserLength     : ULONG;
                          Domain         : PChar;
                          DomainLength   : ULONG;
                          Password       : PChar;
                          PassWordLength : ULONG;
                          Flags          : ULONG;
                          End;

   COAUTHIDENTITY      = _COAUTHIDENTITY;
   TCOAUTHIDENTITY     = _COAUTHIDENTITY;
{$ENDIF}




  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The TWmiConection class represents the base class to connect to the WMI Services.
  /// </summary>
  {$IFDEF UNDEF}{$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}{$ENDIF}
  TWmiConnection=class
  private
    {$IFDEF WbemScripting_TLB}
    FSWbemLocator   : ISWbemLocator;
    FWMIService     : ISWbemServices;
    {$ENDIF}

    {$IFDEF WMI_LateBinding}
    FSWbemLocator   : OleVariant;
    FWMIService     : OleVariant;
    {$ENDIF}

    {$IFDEF WMI_COM_API}
    FSWbemLocator   : IWbemLocator;
    FWMIService     : IWbemServices;
    AuthInfo        : TCOAUTHIDENTITY;
    {$ENDIF}

    {$IFDEF FPC}
    FWmiServer      : WideString;
    FWmiUser        : WideString;
    FWmiPass        : WideString;
    FWmiNameSpace   : WideString;
    {$ELSE}
    FWmiServer      : string;
    FWmiUser        : string;
    FWmiPass        : string;
    FWmiNameSpace   : string;
    {$ENDIF}
    FWmiConnected   : Boolean;
    FWmiIsLocal     : Boolean;
   {$IFDEF FPC}
    procedure SetWmiServer(const Value: WideString);
    procedure SetWmiUser(const Value: WideString);
    procedure SetWmiPass(const Value: WideString);
   {$ELSE}

    procedure SetWmiServer(const Value: string);
    procedure SetWmiUser(const Value: string);
    procedure SetWmiPass(const Value: string);
   {$ENDIF}
  public
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiConnect procedure establish a connection with the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
    procedure WmiConnect(ForceConnection:Boolean);
   {$IFDEF FPC}
   {$REGION 'Documentation'}
   /// <summary>
   /// The WmiNameSpace property return the current WMI namespace
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiNameSpace  : WideString read FWmiNameSpace write FWmiNameSpace;
   {$REGION 'Documentation'}
   /// <summary>
   /// The WmiServer property return or set the current server name or ip where the WMi service is connected
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiServer : WideString read FWmiServer write SetWmiServer;
   {$REGION 'Documentation'}
   /// <summary>
   /// The WmiUser property return or set the user name used to connect to the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiUser : WideString read FWmiUser write SetWmiUser;
   {$REGION 'Documentation'}
   /// <summary>
   /// The WmiPass property return or set the password used to connect to the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiPass: WideString read FWmiPass write SetWmiPass;
   {$ELSE}
   //*****************************************************
   //Delphi mode
   //*****************************************************
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiNameSpace property return the current WMI namespace
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiNameSpace  : string read FWmiNameSpace write FWmiNameSpace;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiServer property return or set the current server name or ip where the WMi service is connected
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiServer : string read FWmiServer write SetWmiServer;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiUser property return or set the user name used to connect to the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiUser : string read FWmiUser write SetWmiUser;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiPass property return or set the password used to connect to the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiPass: string read FWmiPass write SetWmiPass;
   {$ENDIF}
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiPass property return True or False if the current instance is connected to the WMI service
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiConnected  : boolean read FWmiConnected;

   {$IFDEF WMI_LateBinding}
   property  SWbemLocator  : OleVariant read FSWbemLocator;
   property  WMIService    : OleVariant read FWMIService;
   {$ENDIF}

   {$IFDEF WbemScripting_TLB}
   property  SWbemLocator  : ISWbemLocator  read FSWbemLocator;
   property  WMIService    : ISWbemServices read FWMIService;
   {$ENDIF}

   {$IFDEF WMI_COM_API}
   property  SWbemLocator  : IWbemLocator  read FSWbemLocator;
   property  WMIService    : IWbemServices read FWMIService;
   {$ENDIF}

  protected
  public
    constructor Create; overload;
    Destructor Destroy; override;
  end;

  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The TWmiClass class represents the base class to access the WMI info.
  /// </summary>
  {$IFDEF UNDEF}{$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}{$ENDIF}
  TWmiClass=class//(TObject)
  private
    FOwnedConnection: Boolean;
    FWmiConnection  : TWmiConnection;
    {$IFDEF FPC}
    FWmiClass       : WideString;
    {$ELSE}
    FWmiClass       : string;
    {$ENDIF}


    {$IFDEF WMI_COM_API}
    FStaticInstance : IWbemClassObject;
    {$ELSE}
    FStaticInstance : OleVariant;
    {$ENDIF}


    FWMiDataLoaded  : Boolean;
    FWmiPropsNames  : TStrings;
    procedure DisposeCollection;
    function  GetPropValue(const PropName: string): OleVariant;
    procedure SetWmiConnection(const Value: TWmiConnection);
   {$IFDEF WMI_LateBinding}
    function GetWMIService: OleVariant;
   {$ENDIF}
   {$IFDEF WbemScripting_TLB}
    function GetWMIService: ISWbemServices;
   {$ENDIF}
   {$IFDEF WMI_COM_API}
    function GetWMIService: IWbemServices;
   {$ENDIF}
  protected
    FWmiCollection      : TList;
    FWmiCollectionIndex : Integer;
    function    _LoadWmiData: boolean;
    constructor Create(LoadData:boolean;const _WmiNamespace,_WmiClass:string); overload;
  public

   {$IFDEF WbemScripting_TLB}
    function ExecMethod(const strObjectPath: WideString; const strMethodName: WideString;
                        const objWbemInParameters: IDispatch; iFlags: Integer;
                        const objWbemNamedValueSet: IDispatch): IDispatch;
   {$ENDIF}

   {$IFDEF WMI_LateBinding}
    function ExecMethod(const strObjectPath: WideString; const strMethodName: WideString;
                        const objWbemInParameters: OleVariant; iFlags: Integer;
                        const objWbemNamedValueSet: OleVariant): OleVariant;
   {$ENDIF}

   {$IFDEF WMI_LateBinding}
   function  GetNullValue  : OleVariant;
   {$ENDIF}
   {$IFDEF WbemScripting_TLB}
   function  GetNullValue  : IDispatch;
   {$ENDIF}
   {$IFDEF WMI_COM_API}
   function  GetNullValue  : IDispatch;
   {$ENDIF}
   property  Value[const PropName : string] : OleVariant read GetPropValue; default;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiProperties property return the list of the properties of the current class
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiProperties : TStrings read FWmiPropsNames;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiCollectionIndex property return the current index to the collection which store the WMI Data
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiCollectionIndex : integer read FWmiCollectionIndex  write FWmiCollectionIndex;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetCollectionCount function return the number of items of the collection which store the WMI Data
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   function  GetCollectionCount:Integer;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The SetCollectionIndex procedure set the  index of the collection which store the WMI Data
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   procedure SetCollectionIndex(Index: Integer);virtual;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetCollectionIndexByPropertyValue function get the index of the coolection based in the Property name and value
   /// if the value is not found return a -1
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   function  GetCollectionIndexByPropertyValue(const PropertyName:string; AValue:OleVariant):integer;virtual;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetPropertyValue function return the value of an property
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   function  GetPropertyValue(const PropName: string): OleVariant;
   function  GetPropertyValueByIndex(const PropName: string;Index:Integer): OleVariant;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetInstanceOf function return an instance to the current wmi class returned by the ExecQuery method
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}


   {$IFDEF WMI_LateBinding}
   function  GetInstanceOf: OleVariant;
   {$ENDIF}

   {$IFDEF WMI_COM_API}
   function  GetInstanceOf: IWbemClassObject;
   {$ENDIF}

   {$IFDEF WbemScripting_TLB}
   function  GetInstanceOf: OleVariant;
   {$ENDIF}


   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetStaticInstance function return an instance to the current wmi class
   /// is equivalent to call WMIService.Get(WmiClass,0,GetNullValue);
   /// MSDN : Retrieves an object, that is either a class definition or an instance, based on the object path.
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   function  GetStaticInstance : OleVariant;
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The GetWmiData procedure fill the collection with the data returbes by the ExecQuery method
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   procedure GetWmiData;
   Destructor Destroy; override;
   property  WmiConnection : TWmiConnection read FWmiConnection write SetWmiConnection;
   {$IFDEF FPC}
   {$REGION 'Documentation'}
   /// <summary>
   /// The WmiClass property return the current WMI class
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiClass  : WideString read FWmiClass;
   {$ELSE}
   {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
   /// <summary>
   /// The WmiClass property return the current WMI class
   /// </summary>
   {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
   property  WmiClass  : string read FWmiClass;
   {$ENDIF}

   {$IFDEF WMI_LateBinding}
   property  WMIService    : OleVariant read GetWMIService;
   {$ENDIF}
   {$IFDEF WbemScripting_TLB}
   property  WMIService    :  ISWbemServices read GetWMIService;
   {$ENDIF}
   {$IFDEF WMI_COM_API}
   property  WMIService    :  IWbemServices read GetWMIService;
   {$ENDIF}
  end;


{
  TWmiError=class
  private
    FOperation: string;
    FProviderName: string;
    FParameterInfo: string;
  public
    property Operation : string read FOperation;
    property ParameterInfo : string read FParameterInfo;
    property ProviderName : string read FProviderName;
    constructor Create; overload;
    Destructor  Destroy; override;
  end;
}

  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarStrNull function convert a OleVariant value to an string in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarStrNull(const V:OleVariant):string;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarWideStringNull function convert a OleVariant value to an WideString in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarWideStringNull(const V:OleVariant):WideString;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarByteNull function convert a OleVariant value to a Byte value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarByteNull(const V:OleVariant):Byte;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarShortIntNull function convert a OleVariant value to a ShortInt value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarShortIntNull(const V:OleVariant):ShortInt;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarWordNull function convert a OleVariant value to a Word value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarWordNull(const V:OleVariant):Word;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarSmallIntNull function convert a OleVariant value to a SmallInt value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarSmallIntNull(const V:OleVariant):SmallInt;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarIntegerNull function convert a OleVariant value to a Integer value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarIntegerNull(const V:OleVariant):Integer;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarInt64Null function convert a OleVariant value to a Int64 value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarInt64Null(const V:OleVariant):Int64;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarLongNull function convert a OleVariant value to a Longint value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarLongNull(const V:OleVariant):Longint;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarCardinalNull function convert a OleVariant value to a Cardinal value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarCardinalNull(const V:OleVariant):Cardinal;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarBoolNull function convert a OleVariant value to a Boolean value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarBoolNull(const V:OleVariant):Boolean;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarDoubleNull function convert a OleVariant value to a Double value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarDoubleNull(const V:OleVariant):Double;
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The VarDateTimeNull function convert a OleVariant value in UTC format to a TDateTime value in a safe way to avoid problems with null values
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function VarDateTimeNull(const V : OleVariant): TDateTime; //UTC
  {$IFNDEF OLD_DELPHI}{$REGION 'Documentation'}{$ENDIF}
  /// <summary>
  /// The DateTimeToUTC function convert a TDateTime Value to the UTC format
  /// </summary>
  {$IFNDEF OLD_DELPHI}{$ENDREGION}{$ENDIF}
  function DateTimeToUTC(const DateTimeValue:TDateTime):string;

  function ArrayToVarArray(Arr : Array Of string):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Word):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Integer):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Byte):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Cardinal):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Int64):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of Boolean):OleVariant; overload;
  function ArrayToVarArray(Arr : Array Of OleVariant):OleVariant; overload;


  procedure  VarArrayToArray(Arr : OleVariant;OutArr : TStrings); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TWordArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TShortIntArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TByteArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TSmallIntArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TIntegerArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TCardinalArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TInt64Array); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TDoubleArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TBooleanArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TTDateTimeArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TOleVariantArray); overload;
  procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TWideStringArray); overload;



implementation

uses
 ComObj,
 Variants,
 Activex,
 SysUtils;

type
  TVariantValueClass=class
  {$IFDEF WMI_LateBinding}
   Value      : OleVariant;
  {$ENDIF}

  {$IFDEF WbemScripting_TLB}
   Value      : OleVariant;
  {$ENDIF}

  {$IFDEF WMI_COM_API}
   Value      : IWbemClassObject;
  {$ENDIF}
  end;

  TDataWmiClass=class
   PropsValues : Array of OleVariant;
   //PropsValues : TStringList;
   InstanceOf  : TVariantValueClass;
  end;



Const
{$IFDEF WMI_LateBinding}
SWbemScripting_SWbemLocator {$IFDEF FPC}:WideString{$ENDIF}  = 'WbemScripting.SWbemLocator';

wbemImpersonationLevelAnonymous   = $00000001;  //Anonymous 	Hides the credentials of the caller.
                                                //Calls to WMI may fail with this impersonation level.
wbemImpersonationLevelIdentify 	  = $00000002;  //Identify 	Allows objects to query the credentials of the caller.
                                                //Calls to WMI may fail with this impersonation level.
wbemImpersonationLevelImpersonate = $00000003;  //Impersonate 	Allows objects to use the credentials of the caller.
                                                //This is the recommended impersonation level for WMI Scripting API calls.
wbemImpersonationLevelDelegate 	  = $00000004;  //Delegate 	Allows objects to permit other objects to use the credentials of the caller.
                                                //This impersonation, which will work with WMI Scripting API calls but may constitute an unnecessary security risk, is supported only under Windows 2000.

wbemFlagForwardOnly               = $00000020; //Causes a forward-only enumerator to be returned. Forward-only enumerators are generally much faster and use less memory than conventional enumerators, but they do not allow calls to SWbemObject.Clone_.
wbemFlagBidirectional             = $00000000; //Causes WMI to retain pointers to objects of the enumeration until the client releases the enumerator.
wbemFlagReturnImmediately         = $00000010; //Causes the call to return immediately.
wbemFlagReturnWhenComplete        = $00000000; //Causes this call to block until the query is complete. This flag calls the method in the synchronous mode.
wbemQueryFlagPrototype            = $00000002; //Used for prototyping. It stops the query from happening and returns an object that looks like a typical result object.
wbemFlagUseAmendedQualifiers      = $00020000; //Causes WMI to return class amendment data with the base class definition. For more information, see Localizing WMI Class Information.
{$ENDIF}

{$IFDEF WMI_COM_API}
  //Impersonation Level Constants
  //http://msdn.microsoft.com/en-us/library/ms693790%28v=vs.85%29.aspx
  RPC_C_AUTHN_LEVEL_DEFAULT   = 0;
  RPC_C_IMP_LEVEL_ANONYMOUS   = 1;
  RPC_C_IMP_LEVEL_IDENTIFY    = 2;
  RPC_C_IMP_LEVEL_IMPERSONATE = 3;
  RPC_C_IMP_LEVEL_DELEGATE    = 4;

  //Authentication Service Constants
  //http://msdn.microsoft.com/en-us/library/ms692656%28v=vs.85%29.aspx
  RPC_C_AUTHN_WINNT      = 10;
  RPC_C_AUTHN_LEVEL_CALL = 3;
  RPC_C_AUTHN_DEFAULT    = Integer($FFFFFFFF);
  EOAC_NONE              = 0;

  //Authorization Constants
  //http://msdn.microsoft.com/en-us/library/ms690276%28v=vs.85%29.aspx
  RPC_C_AUTHZ_NONE       = 0;
  RPC_C_AUTHZ_NAME       = 1;
  RPC_C_AUTHZ_DCE        = 2;
  RPC_C_AUTHZ_DEFAULT    = Integer($FFFFFFFF);

  //Authentication-Level Constants
  //http://msdn.microsoft.com/en-us/library/aa373553%28v=vs.85%29.aspx
  RPC_C_AUTHN_LEVEL_PKT_PRIVACY   = 6;

  SEC_WINNT_AUTH_IDENTITY_ANSI    = 1;
  SEC_WINNT_AUTH_IDENTITY_UNICODE = 2;

 //COAUTHIDENTITY Structure
 //http://msdn.microsoft.com/en-us/library/ms693358%28v=vs.85%29.aspx
{$ENDIF}

 MaxNumProps             =256;
 DefaultDoubleNullValue  :Double=0.0;
 //DefaultDateTimeNullValue=0;
 DefaultByteNullValue    :Byte=0;
 DefaultShorIntNullValue :ShortInt=0;
 DefaultWordNullValue    :Word=0;
 DefaultSmallIntNullValue:Smallint=0;
 DefaultIntegerNullValue :Integer=0;
 DefaultInt64NullValue   :Int64=0;
 DefaultLongNullValue    :Longint=0;
 DefaultCardinalNullValue    :Cardinal=0;
 DefaultBoolNullValue    :Boolean=False;


procedure  VarArrayToArray(Arr : OleVariant;OutArr : TStrings); overload;
var
  i : integer;
begin
   OutArr.Clear;
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr.Add(VarStrNull(Arr[i]));
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TWordArray); overload;
var
  i    : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarWordNull(Arr[i]);
   end;
end;


procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TShortIntArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1));
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarShortIntNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TByteArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarByteNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TSmallIntArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarSmallIntNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TIntegerArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarIntegerNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TCardinalArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarCardinalNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TInt64Array); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarInt64Null(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TDoubleArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarShortIntNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TBooleanArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarBoolNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TTDateTimeArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarDateTimeNull(Arr[i]);
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TOleVariantArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=Arr[i];
   end;
end;

procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TWideStringArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarWideStringNull(Arr[i]);
   end;
end;


{
procedure  VarArrayToArray(Arr : OleVariant;var OutArr : TStringArray); overload;
var
  i : integer;
begin
   SetLength(OutArr,0);
   if not VarIsNull(Arr) and VarIsArray(Arr) then
   begin
     SetLength(OutArr,VarArrayHighBound(Arr, 1)+1);
     for i := VarArrayLowBound(Arr, 1) to VarArrayHighBound(Arr, 1) do
      OutArr[i]:=VarStrNull(Arr[i]);
   end;
end;
 }
function ArrayToVarArray(Arr : Array Of string):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Word):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Integer):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Byte):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Cardinal):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Int64):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of Boolean):OleVariant;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function ArrayToVarArray(Arr : Array Of OleVariant):OleVariant; overload;
var
 i : integer;
begin
    Result   :=VarArrayCreate([0, High(Arr)], varVariant);
    for i:=Low(Arr) to High(Arr) do
     Result[i]:=Arr[i];
end;

function CreateInstanceDataWmiClass: TDataWmiClass;
begin
  Result           :=TDataWmiClass.Create;
  Result.InstanceOf:=TVariantValueClass.Create;
  SetLength(Result.PropsValues,MaxNumProps);
end;

procedure DisposeDataWmiClass(DataWmiClass: TDataWmiClass);
var
 i : integer;
begin
  for i := 0 to MaxNumProps-1 do
   DataWmiClass.PropsValues[i]:=Unassigned;

  SetLength(DataWmiClass.PropsValues, 0);

  {$IFDEF WMI_LateBinding}
  DataWmiClass.InstanceOf.Value:=Unassigned;
  {$ENDIF}

  {$IFDEF WMI_COM_API}
  DataWmiClass.InstanceOf.Value:=nil;
  {$ENDIF}

  {$IFDEF WbemScripting_TLB}
  DataWmiClass.InstanceOf.Value:=Unassigned;
  {$ENDIF}

  DataWmiClass.InstanceOf.Free;
  DataWmiClass.Free;
end;


function VarDoubleNull(const V:OleVariant):Double;
begin
  Result:=DefaultDoubleNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarStrNull(const V:OleVariant):string;
begin
  Result:='';
  if not VarIsNull(V) then
    Result:=V;//VarToStr(V);
end;

function VarWideStringNull(const V:OleVariant):WideString;
begin
  Result:='';
  if not VarIsNull(V) then
    Result:=V;//VarToStr(V);
end;

function VarByteNull(const V:OleVariant):Byte;
begin
  Result:=DefaultByteNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarShortIntNull(const V:OleVariant):ShortInt;
begin
  Result:=DefaultShorIntNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;


function VarWordNull(const V:OleVariant):Word;
begin
  Result:=DefaultWordNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarSmallIntNull(const V:OleVariant):SmallInt;
begin
  Result:=DefaultSmallIntNullValue;
  if not VarIsNull(V) then
    Result:=  V;
end;

function VarIntegerNull(const V:OleVariant):Integer;
begin
  Result:=DefaultIntegerNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarInt64Null(const V:OleVariant):Int64;
begin
  Result:=DefaultInt64NullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarLongNull(const V:OleVariant):Longint;
begin
  Result:=DefaultLongNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

function VarCardinalNull(const V:OleVariant):Cardinal;
begin
  Result:=DefaultCardinalNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;


function VarBoolNull(const V:OleVariant):Boolean;
begin
  Result:=DefaultBoolNullValue;
  if not VarIsNull(V) then
    Result:=V;
end;

//Universal Time (UTC) format of YYYYMMDDHHMMSS.MMMMMM(+-)OOO.
function DateTimeToUTC(const DateTimeValue:TDateTime):string;
var Year, Month, Day: Word;
var Hour, Min, Sec, MSec: Word;
begin
  DecodeDate(DateTimeValue, Year, Month, Day);
  DecodeTime(DateTimeValue,Hour, Min, Sec, MSec);
  Result:=Format('%.4d%.2d%.2d%.2d%.2d%.2d.000000+000',[Year, Month, Day, Hour, Min, Sec]);
end;


//Universal Time (UTC) format of YYYYMMDDHHMMSS.MMMMMM(+-)OOO.
//20091231000000.000000+000

{$IFDEF WMI_LateBinding}
function VarDateTimeNull(const V : OleVariant): TDateTime;
var
  Dt : OleVariant;
begin
  Result:=0;
  if VarIsNull(V) then exit;
  Dt:=CreateOleObject('WbemScripting.SWbemDateTime');
  Dt.Value := V;
  Result:=Dt.GetVarDate;
end;
{
var
 Year, Month, Day    : Word;
 Hour, Min, Sec, MSec: Word;
 UtcStr              : string;
begin
  Result:=0;
  UtcStr:=VarStrNull(V);
  if Length(UtcStr)>=15 then
  begin
     Year  :=StrToInt(Copy(UtcStr,1,4));
     Month :=StrToInt(Copy(UtcStr,5,2));
     Day   :=StrToInt(Copy(UtcStr,7,2));

     Hour  :=StrToInt(Copy(UtcStr,9,2));
     Min   :=StrToInt(Copy(UtcStr,11,2));
     Sec   :=StrToInt(Copy(UtcStr,13,2));
     MSec  :=0;
     Result:=EncodeDate(Year, Month, Day)+EncodeTime(Hour, Min, Sec, MSec);
  end;
end;
}
{$ENDIF}


{$IFDEF WbemScripting_TLB}
function VarDateTimeNull(const V : OleVariant): TDateTime;
var
  Dt : TSWbemDateTime;
begin
  Result:=0;
  if VarIsNull(V) then exit;
  Dt:=TSWbemDateTime.Create(nil);
  try
    Dt.Value:=V;
    Result:=Dt.GetVarDate(True);
  finally
    Dt.Free;
  end;
end;

{$ENDIF}

{$IFDEF WMI_COM_API}
function VarDateTimeNull(const V : OleVariant): TDateTime;
var
 Year, Month, Day    : Word;
 Hour, Min, Sec, MSec: Word;
 UtcStr              : string;
begin
  Result:=0;
  UtcStr:=VarStrNull(V);
  if Length(UtcStr)>=15 then
  begin
     Year  :=StrToInt(Copy(UtcStr,1,4));
     Month :=StrToInt(Copy(UtcStr,5,2));
     Day   :=StrToInt(Copy(UtcStr,7,2));

     Hour  :=StrToInt(Copy(UtcStr,9,2));
     Min   :=StrToInt(Copy(UtcStr,11,2));
     Sec   :=StrToInt(Copy(UtcStr,13,2));
     MSec  :=0;
     Result:=EncodeDate(Year, Month, Day)+EncodeTime(Hour, Min, Sec, MSec);
  end;
end;
{$ENDIF}

{
function VarDateTimeNull(const V:OleVariant):TDateTime;
begin
  Result:=DefaultDateTimeNullValue;
  if VarIsArray(V) and not VarIsNull(V) then
    Result:= V[0]
  else
  if not VarIsNull(V) then
    Result:=V;
end;
}

{ TWmiConnection }

constructor TWmiConnection.Create;
begin
  inherited Create;
  FWmiConnected       := False;
  FWmiIsLocal         := True;
  FWmiServer          := 'localhost';
  FWmiUser            := '';
  FWmiPass            := '';
end;

destructor TWmiConnection.Destroy;
begin
  {$IFDEF WMI_LateBinding}
  FSWbemLocator:=Unassigned;
  FWMIService  :=Unassigned;
  {$ENDIF}

  {$IFDEF WMI_COM_API}
  FSWbemLocator:=nil;
  FWMIService  :=nil;
  {$ENDIF}

  inherited;
end;

{$IFDEF FPC}
procedure TWmiConnection.SetWmiServer(const Value: WideString);
begin
  FWmiServer  := Value;
  FWmiIsLocal := false;
end;

procedure TWmiConnection.SetWmiUser(const Value: WideString);
begin
  FWmiUser    := Value;
  FWmiIsLocal := false;
end;

procedure TWmiConnection.SetWmiPass(const Value: WideString);
begin
  FWmiPass := Value;
  FWmiIsLocal := false;
end;
{$ELSE}
procedure TWmiConnection.SetWmiServer(const Value: string);
begin
  FWmiServer  := Value;
  FWmiIsLocal := false;
end;

procedure TWmiConnection.SetWmiUser(const Value: string);
begin
  FWmiUser    := Value;
  FWmiIsLocal := false;
end;

procedure TWmiConnection.SetWmiPass(const Value: string);
begin
  FWmiPass := Value;
  FWmiIsLocal := false;
end;
{$ENDIF}

//http://www.computerperformance.co.uk/Logon/code/code_80070005.htm#Local_Security_and_Policies_and_DCOM
procedure TWmiConnection.WmiConnect(ForceConnection:boolean);
{$IFDEF WMI_COM_API}
var
  OpResult  : HRESULT;
{$ENDIF}
begin
   if not FWmiConnected or ForceConnection then
   begin
     {$IFDEF WMI_LateBinding}
       {$IFDEF FPC}
        FSWbemLocator := CreateOleObject(SWbemScripting_SWbemLocator);
        FWMIService   := FSWbemLocator.ConnectServer(WmiServer, WmiNameSpace, WmiUser, WmiPass);
       {$ELSE}
        FSWbemLocator := CreateOleObject(SWbemScripting_SWbemLocator);
        FWMIService   := FSWbemLocator.ConnectServer(WmiServer, WmiNameSpace, WmiUser, WmiPass);
       {$ENDIF}
        if not FWmiIsLocal then
          FWMIService.Security_.ImpersonationLevel := wbemImpersonationLevelImpersonate;
     {$ENDIF}

     {$IFDEF WbemScripting_TLB}
       FSWbemLocator  := CoSWbemLocator.Create;
       FWMIService    := FSWbemLocator.ConnectServer(WmiServer, WmiNameSpace,WmiUser, WmiPass, '', '', 0, nil);
      if not FWmiIsLocal then
        FWMIService.Security_.ImpersonationLevel := wbemImpersonationLevelImpersonate;
     {$ENDIF}

     {$IFDEF WMI_COM_API}

      if FWmiIsLocal then
       if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE, nil)) then Exit
       else
      else
       if Failed(CoInitializeSecurity(nil, -1, nil, nil, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IDENTIFY, nil, EOAC_NONE, nil)) then Exit;

      OpResult:=CoCreateInstance(CLSID_WbemLocator, nil, CLSCTX_INPROC_SERVER, IID_IWbemLocator, FSWbemLocator);

      if Succeeded(OpResult) then
      begin
        if FWmiIsLocal then
          OpResult:=FSWbemLocator.ConnectServer(Format('\\%s\%s',[WmiServer,WmiNameSpace]), WmiUser, WmiPass, '',  WBEM_FLAG_CONNECT_USE_MAX_WAIT, '', nil, FWMIService)
        else
          OpResult:=FSWbemLocator.ConnectServer(Format('\\%s\%s',[WmiServer,WmiNameSpace]), WmiUser, WmiPass, '',  WBEM_FLAG_CONNECT_USE_MAX_WAIT, '', nil, FWMIService);

        if Succeeded(OpResult) then
        begin
          // Set security levels on a WMI connection
          if FWmiIsLocal then
            if Failed(CoSetProxyBlanket(FWMIService, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nil, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nil, EOAC_NONE)) then Exit
             else
          else
            if Failed(CoSetProxyBlanket(FWMIService,  RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, PWideChar(Format('\\%s',[WmiServer])), RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, @AuthInfo, EOAC_NONE)) then Exit;

          //avoid using CLSID_UnsecuredApartment for the moment ;)
          //if Succeeded(CoCreateInstance(CLSID_UnsecuredApartment, nil, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, FUnsecuredApartment)) then

        end;

      end;
      {$ENDIF}
   end;



      FWmiConnected   := True;

end;


{ TWmiClass }
constructor TWmiClass.Create(LoadData:boolean;const _WmiNamespace,_WmiClass:string);
begin
  inherited Create;
  FWmiConnection      := TWmiConnection.Create;
  FOwnedConnection    := True;
  FWMiDataLoaded      := False;
  FWmiCollectionIndex := -1;
  FWmiCollection      := TList.Create;
  FWmiConnection.FWmiNameSpace       := _WmiNamespace;
  FWmiClass           := _WmiClass;
  FWmiPropsNames      := TStringList.Create;

  if LoadData then
    FWMiDataLoaded:=_LoadWmiData;
end;


destructor TWmiClass.Destroy;
begin
  FWmiPropsNames.Free;
  DisposeCollection;
  if FOwnedConnection and  (FWmiConnection<>nil) then
  FreeAndNil(FWmiConnection);
  FWmiCollection.Free;
  inherited;
end;

{$IFDEF FPC}
function GetWMIObject(const objectName: WideString): IDispatch;
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;
{$ENDIF}



function TWmiClass.GetCollectionCount: Integer;
begin
  if FWMiDataLoaded then
   Result:=FWmiCollection.Count
  else
   Result:=-1;
end;

function TWmiClass.GetCollectionIndexByPropertyValue(const PropertyName: string; AValue: OleVariant): integer;
var
  i : Integer;
  V : OleVariant;
begin
  Result:=-1;
  if FWMiDataLoaded then
    for i:=0 to FWmiCollection.Count-1 do
    begin
      V:=GetPropertyValueByIndex(PropertyName,i);
      if V=AValue then
      begin
        Result:=i;
        VarClear(V);
        Break;
      end
      else
      VarClear(V);
    end;
end;


{$IFDEF WMI_LateBinding}
function TWmiClass.GetInstanceOf: OleVariant;
begin
  if FWMiDataLoaded then
    Result:=TDataWmiClass(FWmiCollection[FWmiCollectionIndex]).InstanceOf.Value
  else
    raise Exception.Create('WMI Data not loaded');
end;
{$ENDIF}

{$IFDEF WbemScripting_TLB}
function TWmiClass.GetInstanceOf: OleVariant;
begin
  if FWMiDataLoaded then
    Result:=TDataWmiClass(FWmiCollection[FWmiCollectionIndex]).InstanceOf.Value
  else
    raise Exception.Create('WMI Data not loaded');
end;
{$ENDIF}

{$IFDEF WMI_COM_API}
function TWmiClass.GetInstanceOf: IWbemClassObject;
begin
  if FWMiDataLoaded then
    Result:=TDataWmiClass(FWmiCollection[FWmiCollectionIndex]).InstanceOf.Value
  else
    raise Exception.Create('WMI Data not loaded');
end;

{$ENDIF}

{$IFDEF WMI_COM_API}
function TWmiClass.GetNullValue: IDispatch;
begin
  Result:=nil;
end;
{$ENDIF}

{$IFDEF WMI_LateBinding}
function TWmiClass.GetNullValue: OleVariant;
begin
  Result:=Null;
end;
{$ENDIF}

{$IFDEF WbemScripting_TLB}
function TWmiClass.GetNullValue: IDispatch;
begin
  Result:=nil;
end;
{$ENDIF}

function TWmiClass.GetPropertyValue(const PropName: string): OleVariant;
var
 i  : integer;
begin
  i     :=FWmiPropsNames.IndexOf(PropName);
  if i<>-1 then
    Result:=TDataWmiClass(FWmiCollection[FWmiCollectionIndex]).PropsValues[i]
  else
    Result:=varNull;
end;

function TWmiClass.GetPropertyValueByIndex(const PropName: string; Index: Integer): OleVariant;
var
 i  : integer;
begin
  i     :=FWmiPropsNames.IndexOf(PropName);
  if i<>-1 then
    Result:=TDataWmiClass(FWmiCollection[Index]).PropsValues[i]
  else
    Result:=varNull;
end;

function TWmiClass.GetPropValue(const PropName: string): OleVariant;
begin
  Result:=GetPropertyValue(PropName);
end;


function TWmiClass.GetStaticInstance: OleVariant;
begin
  Result:=FStaticInstance;
end;


{$IFDEF WMI_COM_API}
function TWmiClass.GetWMIService: IWbemServices;
begin
   Result:=FWmiConnection.WMIService;
end;
{$ENDIF}


{$IFDEF WMI_LateBinding}
function TWmiClass.GetWMIService: OleVariant;
begin
   Result:=FWmiConnection.WMIService;
end;
{$ENDIF}

{$IFDEF WbemScripting_TLB}
function TWmiClass.GetWMIService: ISWbemServices;
begin
   Result:=FWmiConnection.WMIService;
end;
{$ENDIF}



//Improving Enumeration Performance  http://msdn.microsoft.com/en-us/library/aa390880%28VS.85%29.aspx
function TWmiClass._LoadWmiData: boolean;
var
  {$IFDEF WMI_LateBinding}
  objWbemObjectSet: OLEVariant;
  WmiProperties   : OLEVariant;
  {$ENDIF}

  {$IFDEF WbemScripting_TLB}
  objWbemObjectSet: ISWbemObjectSet;
  SWbemObject     : ISWbemObject;
  WmiProperties   : ISWbemPropertySet;
  {$ENDIF}

  {$IFNDEF WMI_COM_API}
  oEnum           : IEnumvariant;
  {$ENDIF}

  {$IFDEF FPC}
  //iValue          : PULONG;

  {$IFDEF WMI_COM_API}
  oWmiObject      : IWbemClassObject;
  {$ELSE}
  oWmiObject      : Variant;
  {$ENDIF}

  PropItem        : Variant;
  WQL             : WideString;
  sValue          : WideString;
  oEnumProps      : IEnumVARIANT;

  {$ELSE}

  {$IFDEF WMI_COM_API}
  oWmiObject      : IWbemClassObject;
  {$ELSE}
  oWmiObject      : OLEVariant;
  iValue          : Cardinal;
  PropItem        : OLEVariant;
  oEnumProps      : IEnumVARIANT;
  {$ENDIF}

  {$ENDIF}
  i               : integer;
  DataWmiClass    : TDataWmiClass;
  {$IFDEF _DEBUG}
  dt              : TDateTime;
  dg              : TDateTime;
  {$ENDIF}

  {$IFDEF WMI_COM_API}
  ppCallResult   : IWbemCallResult;
  OpResult       : HRESULT;
  oEnum          : IEnumWbemClassObject;
  puReturned     : ULONG;
  {$IFDEF Winapi_Wbem}
  WmiProperties  : PSafeArray;
  pQualifierVal  : Variant;
  plFlavor       : PInteger;
  pVal           : Variant;
  pType          : PCIMTYPE;
  {$ELSE}
  WmiProperties  : JwaActiveX.PSafeArray;
  plFlavor       : Integer;
  pVal           : OleVariant;
  pType          : Integer;
  {$ENDIF}
  lLbound        : Integer;
  lUbound        : Integer;
  pv             : WideString;
  sValue         : string;
  {$ENDIF}


begin;
 DisposeCollection;
 result:=True;
  try
    {$IFDEF _DEBUG} dt:=now; {$ENDIF}
    FWmiConnection.WmiConnect(False);
    {$IFDEF _DEBUG} OutputDebugString(PAnsiChar('Connected '+FormatDateTime('hh:nn:ss.zzz', Now-dt))); {$ENDIF}

    {$IFDEF _DEBUG} dt:=now; {$ENDIF}

    {$IFDEF WMI_LateBinding}
      {$IFDEF FPC}
       WQL              := Format('SELECT * FROM %s',[FWmiClass]);
       objWbemObjectSet := FWmiConnection.FWMIService.ExecQuery( WQL,'WQL',0);
       oEnum            := IUnknown(objWbemObjectSet._NewEnum) as IEnumVariant;
      {$ELSE}
       objWbemObjectSet := FWmiConnection.FWMIService.ExecQuery(Format('SELECT * FROM %s',[FWmiClass]),'WQL',wbemFlagForwardOnly or wbemFlagReturnImmediately);
       oEnum            := IUnknown(objWbemObjectSet._NewEnum) as IEnumVariant;
      {$ENDIF}
    {$ENDIF}

    {$IFDEF WbemScripting_TLB}
    objWbemObjectSet  := FWmiConnection.FWMIService.ExecQuery(Format('SELECT * FROM %s',[FWmiClass]),'WQL',wbemFlagForwardOnly or wbemFlagReturnImmediately,nil);
    oEnum             := (objWbemObjectSet._NewEnum) as IEnumVariant;
    {$ENDIF}

    {$IFDEF WMI_COM_API}
    OpResult := FWmiConnection.FWMIService.ExecQuery('WQL', Format('SELECT * FROM %s',[FWmiClass]), WBEM_FLAG_FORWARD_ONLY, nil, oEnum);
    if Succeeded(OpResult) then
    begin
       // Set security for the enumerator proxy
       if not FWmiConnection.FWmiIsLocal then
        if Failed(CoSetProxyBlanket(oEnum, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, PWideChar(Format('\\%s',[FWmiConnection.FWmiServer])), RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, @FWmiConnection.AuthInfo, EOAC_NONE)) then Exit;
    end;
    {$ENDIF}

    {$IFDEF _DEBUG} OutputDebugString(PAnsiChar('Query Executed in '+FormatDateTime('hh:nn:ss.zzz', Now-dt))); {$ENDIF}



    {$IFDEF WMI_COM_API}
    FWmiConnection.FWMIService.GetObject(FWmiClass,0,nil,FStaticInstance,ppCallResult);
    {$ELSE}
    FStaticInstance   := FWmiConnection.FWMIService.Get(FWmiClass,0,GetNullValue);
    {$ENDIF}


    {$IFDEF _DEBUG} dg:=now; {$ENDIF}

   {$IFDEF WMI_COM_API}
      while (oEnum.Next(WBEM_INFINITE, 1, oWmiObject, puReturned)=0) do
   {$ELSE}
     {$IFDEF FPC}
      while oEnum.Next(1, oWmiObject, nil) = S_OK do
     {$ELSE}
      while oEnum.Next(1, oWmiObject, iValue) = S_OK do
     {$ENDIF}
   {$ENDIF}
    begin


       {$IFDEF WbemScripting_TLB}
       SWbemObject     := IUnknown(oWmiObject) as ISWBemObject;
       WmiProperties   := SWbemObject.Properties_;
       {$ENDIF}

       {$IFDEF WMI_LateBinding}
       WmiProperties   := oWmiObject.Properties_;
       {$ENDIF}

       {$IFDEF WMI_COM_API}
       {
        Bounds[0].lLbound   := 0;
        Bounds[0].cElements := 255;
        WmiProperties := JwaActiveX.PSafeArray(SafeArrayCreate(VT_I1, 1, Bounds));
        //SafeArrayDestroy(Activex.PSafeArray(WmiProperties));
        }
       {$ENDIF}


      if FWmiPropsNames.Count=0 then
       begin
          {$IFDEF WMI_COM_API}

            {$IFDEF Winapi_Wbem}
            oWmiObject.GetNames(nil,WBEM_FLAG_ALWAYS OR WBEM_FLAG_NONSYSTEM_ONLY, pQualifierVal, WmiProperties);
            {$ELSE}
            oWmiObject.GetNames(nil,WBEM_FLAG_ALWAYS OR WBEM_FLAG_NONSYSTEM_ONLY, nil, WmiProperties);
            {$ENDIF}
            SafeArrayGetLBound(Activex.PSafeArray(WmiProperties), 1, lLbound);
            SafeArrayGetUBound(Activex.PSafeArray(WmiProperties), 1, lUbound);
            for i := lLbound to lUbound do
            begin
              SafeArrayGetElement(Activex.PSafeArray(WmiProperties), I, pv);
              FWmiPropsNames.Add(pv);
            end;
            SafeArrayDestroy(Activex.PSafeArray(WmiProperties));
          {$ELSE}

            {$IFDEF WMI_LateBinding}
            oEnumProps    := IUnknown(WmiProperties._NewEnum) as IEnumVariant;
            {$ENDIF}

            {$IFDEF WbemScripting_TLB}
            oEnumProps    := (WmiProperties._NewEnum) as IEnumVariant;
            {$ENDIF}

            {$IFDEF FPC}
            while oEnumProps.Next(1, PropItem, nil) = S_OK do
            {$ELSE}
            while oEnumProps.Next(1, PropItem, iValue) = S_OK do
            {$ENDIF}
            begin
              FWmiPropsNames.Add(PropItem.Name);
              PropItem:=Unassigned;
            end;

          {$ENDIF}
       end;


      DataWmiClass:=CreateInstanceDataWmiClass;
      FWmiCollection.Add(DataWmiClass);
      DataWmiClass.InstanceOf.Value:=oWmiObject;

      {$IFDEF _DEBUG} dt:=now; {$ENDIF}
         for i := 0 to FWmiPropsNames.Count - 1 do
         begin
          {$IFDEF WMI_LateBinding}
            {$IFDEF FPC}
            sValue:=FWmiPropsNames[i];
            DataWmiClass.PropsValues[i]:= WmiProperties.Item(sValue).Value;
            {$ELSE}
            DataWmiClass.PropsValues[i]:= WmiProperties.Item(FWmiPropsNames[i]).Value;
            {$ENDIF}
          {$ENDIF}

          {$IFDEF WbemScripting_TLB}
          DataWmiClass.PropsValues[i]:= WmiProperties.Item(FWmiPropsNames[i],0).Get_Value;
          {$ENDIF}

          {$IFDEF WMI_COM_API}
           sValue:=FWmiPropsNames[i];
           oWmiObject.Get(PChar(sValue), 0, pVal, pType, plFlavor);// String
           DataWmiClass.PropsValues[i]:=pVal;
           VarClear(pVal);
          {$ENDIF}

         end;

     {$IFNDEF WMI_COM_API}
     oWmiObject    :=Unassigned; //avoid leak cause by  IEnumVARIANT.Next
     {$ENDIF}

    {$IFDEF _DEBUG} OutputDebugString(PAnsiChar('Pass in '+FormatDateTime('hh:nn:ss.zzz', Now-dt))); {$ENDIF}
    end;
    {$IFDEF _DEBUG} OutputDebugString(PAnsiChar('Assigned in '+FormatDateTime('hh:nn:ss.zzz', Now-dg))); {$ENDIF}

    if FWmiCollection.Count>0 then
     SetCollectionIndex(0);
  except
   Result:=False;
  end;
end;


procedure TWmiClass.SetCollectionIndex(Index: Integer);
begin
  raise Exception.Create(Format('You must override this method %s', ['SetCollectionIndex']));
end;

procedure TWmiClass.SetWmiConnection(const Value: TWmiConnection);
begin
  if FWmiConnection<>nil then
   FreeAndNil(FWmiConnection);
  FWmiConnection  :=Value;
  FOwnedConnection:=False;
end;

procedure TWmiClass.DisposeCollection;
var
 i : integer;
begin
  if Assigned(FWmiCollection) then
  begin
    for i:= 0 to FWmiCollection.Count - 1 do
     DisposeDataWmiClass(TDataWmiClass(FWmiCollection[i]));
    FWmiCollection.Clear;
    FWmiCollectionIndex :=-1;
  end;
end;


{$IFDEF WMI_LateBinding}
function TWmiClass.ExecMethod(const strObjectPath: WideString; const strMethodName: WideString;
                    const objWbemInParameters: OleVariant; iFlags: Integer;
                    const objWbemNamedValueSet: OleVariant): OleVariant;
begin
   Result := WMIService.ExecMethod(WmiClass, strMethodName, objWbemInParameters, iFlags, GetNullValue);
end;
{$ENDIF}


{$IFDEF WbemScripting_TLB}
function TWmiClass.ExecMethod(const strObjectPath, strMethodName: WideString;
  const objWbemInParameters: IDispatch; iFlags: Integer;
  const objWbemNamedValueSet: IDispatch): IDispatch;
{$IFDEF WMI_COM_API}
var
   ppOutParams: IWbemClassObject;
   ppCallResult: IWbemCallResult;
{$ENDIF}
begin
   Result := WMIService.ExecMethod(WmiClass, strMethodName, objWbemInParameters, iFlags, GetNullValue);

  {$IFDEF WMI_COM_API}

  {
    function ExecMethod(strObjectPath: WideString; strMethodName: WideString; lFlags: Integer;
      const pCtx: IWbemContext; const pInParams: IWbemClassObject; out ppOutParams: IWbemClassObject;
      out ppCallResult: IWbemCallResult): HRESULT; stdcall;

  }
  WMIService.ExecMethod(strObjectPath, strMethodName, 0, nil, objWbemInParameters as IWbemClassObject, ppOutParams, ppCallResult);
  Result:=ppOutParams as IDispatch;

 {
                        OpResult := FWbemServices.ExecMethod('Win32_LogicalDisk', 'ScheduleAutoChk', 0, nil, pClassInstance, ppOutParams, ppCallResult);
                       if Succeeded(OpResult) then
                       begin
                         ppOutParams.Get('ReturnValue', 0, pVal, pType, plFlavor);
                         Writeln(Format('ReturnValue  %s',[pVal]));
                         VarClear(pVal);

                       end
                       else
                       if not GetExtendedErrorInfo(OpResult) then
                       Writeln(Format('Error ExecMethod %x',[OpResult]));
 }

  {$ENDIF}
end;
{$ENDIF}

procedure TWmiClass.GetWmiData;
begin
 FWMiDataLoaded:=_LoadWmiData;
end;

{ TWmiError }
{
constructor TWmiError.Create;
var
  objSWbemError :OleVariant;
begin
   inherited Create;
   CoInitialize(nil);
   objSWbemError  := CreateOleObject(SWbemScripting_SWbemLocator);
   FOperation     :=VarStrNull(objSWbemError.Operation);
   FProviderName  :=VarStrNull(objSWbemError.ProviderName);
   FParameterInfo :=VarStrNull(objSWbemError.ParameterInfo);
end;

destructor TWmiError.Destroy;
begin
  CoUninitialize;
  inherited;
end;
}


initialization
{$IFNDEF FPC}
  CoInitialize(nil);
{$ENDIF}

finalization
{$IFNDEF FPC}
  CoUninitialize;
{$ENDIF}
end.
