====== Conversion WbemScripting_TLB de Delphi vers Lazarus ====== ===== Énoncé du problème ===== Dans mes recherches j'ai trouvé du code **Delphi** faisant (a peu prés) ce que je cherche a faire. Et effectivement avec **Delphi** çà marche, mais avec **Lazarus**, cela ne fonctionne pas ! Le **PROBLÈME** est ce fichu fichier ''WbemScripting_TLB.pas'' qui vient d'une importation d'un fichier TLB ''C:\WINDOWS\system32\wbem\wbemdisp.TLB'' pour le fichier originale et ''C:\Windows\SysWOW64\wbem\wbemdisp.TLB'' pour le fichier que j'ai moi même régénéré.\\ Ce fichier n'est pas compatible avec **Lazarus**. J'ai donc décidé de créer ce fichier à partir de **Lazarus** et j'explique ci-dessous comment j'ai fait et les modifications a faire au code source pour que cela fonctionne. Ci dessous nous allons trouver : - La source originale en Delphi que j'ai trouvé. - Comment importer un TLB avec Lazarus - La source corrigé en Free Pascal ===== Sources Delphi Originales ===== unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, WbemScripting_TLB, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private FSink: TSWbemSink; FLocator: ISWbemLocator; FServices: ISWbemServices; procedure EventReceived(ASender: TObject; const objWbemObject: ISWbemObject; const objWbemAsyncContext: ISWbemNamedValueSet); public { Déclarations publiques } end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject); const WQL = 'SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Win32_Process"'; begin FLocator := CoSWbemLocator.Create; //Connect to the WMI service FServices := FLocator.ConnectServer('.', 'root\cimv2', '','', '', '', wbemConnectFlagUseMaxWait, nil); //create the sink instance FSink := TSWbemSink.Create(self); //assign the event handler FSink.OnObjectReady := EventReceived; //Run the ExecNotificationQueryAsync FServices.ExecNotificationQueryAsync(FSink.DefaultInterface,WQL,'WQL', 0, nil, nil); end; procedure TForm1.EventReceived(ASender: TObject; const objWbemObject: ISWbemObject; const objWbemAsyncContext: ISWbemNamedValueSet); var PropVal: OLEVariant; begin PropVal := objWbemObject; Memo1.Lines.Add(Format('Caption : %s ',[PropVal.TargetInstance.Caption])); Memo1.Lines.Add(Format('ProcessID : %s ',[PropVal.TargetInstance.ProcessID])); end; end. Source de ce sode : [[https://theroadtodelphi.com/2011/04/18/delphi-and-wmi-events/]] ===== Importer un fichier TLB avec Lazarus ===== ==== LazActiveX ==== Dans un premier temps il faut que le paquet ''LazActiveX'' soit installé : {{:prog:lazarus:cas:wmi:activx1.jpg?400|}} Plus d'infos ici : [[https://wiki.lazarus.freepascal.org/LazActiveX]] ==== Importer le TLB ==== Cela nous donne accés a un nouveau menu ''Importer la bibliothèque de types...'' : {{:prog:lazarus:cas:wmi:actx2.jpg|}} Une fois cliqué sur le menu on se retrouve dans cette fenêtre. * On choisi [ActiveX References] * On cherche [Microsoft WMI Scripting] * On clique sur OK et cela nous génére un fichier ''WbemScripting_1_2_TLB.pas'' {{:prog:lazarus:cas:wmi:actx3.jpg|}} ===== Adaptation du code ===== ATTENTION il y a de grosses differences entre le code généré en **Delphi** et celui en **Lazarus**, hormis le nom du fichier... ==== Exemple avec TSWbemSink ==== Exemple ''TSWbemSink'' est devenu ''TEvsSWbemSink'' et ses properties ont changé: TSWbemSink = class(TOleServer) private FOnObjectReady: TSWbemSinkOnObjectReady; FOnCompleted: TSWbemSinkOnCompleted; FOnProgress: TSWbemSinkOnProgress; FOnObjectPut: TSWbemSinkOnObjectPut; FIntf: ISWbemSink; ... function GetDefaultInterface: ISWbemSink; protected procedure InitServerData; override; procedure InvokeEvent(DispID: TDispID; var Params: TVariantArray); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Connect; override; procedure ConnectTo(svrIntf: ISWbemSink); procedure Disconnect; override; procedure Cancel; property DefaultInterface: ISWbemSink read GetDefaultInterface; published property OnObjectReady: TSWbemSinkOnObjectReady read FOnObjectReady write FOnObjectReady; property OnCompleted: TSWbemSinkOnCompleted read FOnCompleted write FOnCompleted; property OnProgress: TSWbemSinkOnProgress read FOnProgress write FOnProgress; property OnObjectPut: TSWbemSinkOnObjectPut read FOnObjectPut write FOnObjectPut; end; TEvsSWbemSink = Class(TEventSink) Private FOnOnObjectReady:TISWbemSinkEventsOnObjectReady; FOnOnCompleted:TISWbemSinkEventsOnCompleted; FOnOnProgress:TISWbemSinkEventsOnProgress; FOnOnObjectPut:TISWbemSinkEventsOnObjectPut; fServer:ISWbemSink; procedure EventSinkInvoke(Sender: TObject; DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; Params: tagDISPPARAMS; VarResult, ExcepInfo, ArgErr: Pointer); Public constructor Create(TheOwner: TComponent); override; property ComServer:ISWbemSink read fServer; property OnOnObjectReady : TISWbemSinkEventsOnObjectReady read FOnOnObjectReady write FOnOnObjectReady; property OnOnCompleted : TISWbemSinkEventsOnCompleted read FOnOnCompleted write FOnOnCompleted; property OnOnProgress : TISWbemSinkEventsOnProgress read FOnOnProgress write FOnOnProgress; property OnOnObjectPut : TISWbemSinkEventsOnObjectPut read FOnOnObjectPut write FOnOnObjectPut; end; ==== Code Lazarus ==== unit Unit1; {$mode objfpc}{$H+} interface uses ActiveX, StdCtrls, SysUtils, Forms, Controls, Dialogs, WbemScripting_1_2_TLB; type { TForm1 } TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private FSink: TEvsSWbemSink; FLocator: ISWbemLocator; FServices: ISWbemServices; procedure EventReceived(Sender: TObject; objWbemObject: ISWbemObject; objWbemAsyncContext: ISWbemNamedValueSet); public end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject); const WQL = 'SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Win32_Process"'; begin FLocator := CoSWbemLocator.Create; //Connect to the WMI service FServices := FLocator.ConnectServer('.', 'root\cimv2', '', '', '', '', wbemConnectFlagUseMaxWait, nil); //create the sink instance FSink := TEvsSWbemSink.Create(self); //assign the event handler FSink.OnOnObjectReady := @EventReceived; //Run the ExecNotificationQueryAsync FServices.ExecNotificationQueryAsync(FSink.ComServer, WQL, 'WQL', 0, nil, nil); end; procedure TForm1.EventReceived(Sender: TObject; objWbemObject: ISWbemObject; objWbemAsyncContext: ISWbemNamedValueSet); var PropVal: olevariant; begin PropVal := objWbemObject; Memo1.Lines.Add(Format('Caption : %s ', [PropVal.TargetInstance.Caption])); Memo1.Lines.Add(Format('ProcessID : %s ', [PropVal.TargetInstance.ProcessID])); end; initialization CoInitializeEx(nil, COINIT_MULTITHREADED); {Je ne sais pas si c'est utile, mais...} finalization; CoUninitialize(); end. ===== Résultat ===== {{:prog:lazarus:cas:wmi:extra1.jpg|}} ====== Sources & Ressources ====== * [[https://wiki.lazarus.freepascal.org/LazActiveX]] * [[https://theroadtodelphi.com/2011/04/18/delphi-and-wmi-events/]]