Does FreePascal have a WMI Query library? lazarus / 34-Windows ---------------------------------------------------------------------- vfclists · 2014-05-06 15:27 Does FreePascal have a WMI Query , Windows Management instrumentation library? ---------------------------------------------------------------------- taazz · 2014-05-06 15:41 As far as I know there isn't any wmi specific lirary and I don't think it is needed. Use this http://code.google.com/p/wmi-delphi-code- creator/ download binaries from http://theroadtodelphi.wordpress.com/wmi-delphi-code-creator/ ---------------------------------------------------------------------- Jurassic Pork · 2015-07-28 22:37 Hello, i have made a function to get System Infos with WMI request (wmi only in Windows)  : Code: [Select]Function GetWMIInfo(const WMIClass: string ; const WMIProperty:tstringList;                      const Condition: string = ''):tlist; WMIClass : Class in which to find infos   example : Win32_NetworkAdapter WMIProperty : a list of properties to get   example : Name,MACAddress Condition : a Condition to limit results example : WHERE NETENABLED = TRUE The result is a list of Properties list. Usage example to get all the active network cards and their MACAddresses : Code: [Select]procedure TForm1.Button3Click(Sender: TObject); var ResultatWMI : TList;     Infos : TStringList;   i,j       : Integer; begin   Memo1.Clear;   Infos := TstringList.Create;   // Prepare Infos to get  in a Name-Value StringList   Infos.CommaText:='Name=,MACAddress=';   ResultatWMI := GetWMIInfo('Win32_NetworkAdapter',Infos,'WHERE NETENABLED = TRUE');    for i := 0 to ResultatWMI.Count-1 do     begin      Memo1.Lines.add('================================================');      for j := 0 to Infos.Count-1 do          begin          Memo1.Lines.add(TstringList(ResultatWMI[i]).Names[j]+' : '+          TstringList (ResultatWMI[i]).ValueFromIndex[j]);          end;     end;   // Nettoyage   - Cleaning     for i := 0 to ResultatWMI.Count-1 do          begin            TstringList(ResultatWMI[i]).Free;          end;     Infos.Free; end;Function is in the utilwmi unit  ( attachment ) hope help some people with this. If you see errors or optimizations in source code , say it to me. To be continued if useful. Friendly, J.P ---------------------------------------------------------------------- Jurassic Pork · 2016-01-03 00:42 hello, a new version of the unit has been released. Thanks to Molly for the improvements :  Quote// 0.1  Jurassic Pork Juillet 2015 // 0.2  Molly  Janvier 2016 : improvement : fpc 3.0 compatibility + usage of  TFPObjectList // Changes 2016-jan-02 (Mol) // - updated/corrected comments // - Introduction of variable nrValue. // - Generic solution for variable nr, using nrValue (inc. pointer assignment) // - re-introduction of calling ShowMessage() when exception occurs (code only //   active when USE_DIALOG is defined) + reorganized defines example of use : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses contnrs,utilwmi, ...procedure TForm1.Button1Click(Sender: TObject);var  WMIResult         : TFPObjectList;  i                 : Integer;  PropNamesIndex    : Integer;  PropNames         : Array[0..2] of String = ( 'Name','MACAddress','NetConnectionId' );begin  WMIResult := GetWMIInfo('Win32_NetworkAdapter', PropNames,'WHERE NETENABLED = TRUE');  for i := 0 to Pred(WMIResult.Count) do  begin    Memo1.Append('================================================');    for PropNamesIndex := Low(PropNames) to High(PropNames) do    begin    Memo1.Append(TStringList(WMIResult[i]).Names[PropNamesIndex] + ' : ' +              TStringList(WMIResult[i]).ValueFromIndex[PropNamesIndex]);    end;  end;  // Clean up  WMIResult.Free;end;                   Edit : oops , sorry     in the example , something was wrong (Win32_NetwokAdapter to check exception handling). Now it is OK with Win32_NetworkAdapter. Friendly J.P ---------------------------------------------------------------------- chineselzh · 2016-03-18 12:52 thank you very much! Quote from: Jurassic Pork on January 03, 2016, 01:42:53 amhello, a new version of the unit has been released. Thanks to Molly for the improvements :  Quote// 0.1  Jurassic Pork Juillet 2015 // 0.2  Molly  Janvier 2016 : improvement : fpc 3.0 compatibility + usage of  TFPObjectList // Changes 2016-jan-02 (Mol) // - updated/corrected comments // - Introduction of variable nrValue. // - Generic solution for variable nr, using nrValue (inc. pointer assignment) // - re-introduction of calling ShowMessage() when exception occurs (code only //   active when USE_DIALOG is defined) + reorganized defines example of use : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses contnrs,utilwmi, ...procedure TForm1.Button1Click(Sender: TObject);var  WMIResult         : TFPObjectList;  i                 : Integer;  PropNamesIndex    : Integer;  PropNames         : Array[0..2] of String = ( 'Name','MACAddress','NetConnectionId' );begin  WMIResult := GetWMIInfo('Win32_NetworkAdapter', PropNames,'WHERE NETENABLED = TRUE');  for i := 0 to Pred(WMIResult.Count) do  begin    Memo1.Append('================================================');    for PropNamesIndex := Low(PropNames) to High(PropNames) do    begin    Memo1.Append(TStringList(WMIResult[i]).Names[PropNamesIndex] + ' : ' +              TStringList(WMIResult[i]).ValueFromIndex[PropNamesIndex]);    end;  end;  // Clean up  WMIResult.Free;end;                   Edit : oops , sorry     in the example , something was wrong (Win32_NetwokAdapter to check exception handling). Now it is OK with Win32_NetworkAdapter. Friendly J.P ---------------------------------------------------------------------- christensen · 2016-06-10 16:13 Hi, I've been working on a project for long time which is using this WMI library, now i'm trying to reinstall the system after my HDD fail and lost everything. So from backup of my source code i'm trying to recover as much i can. When i'm trying to compile i got this error on WMI lib: Quoteutilwmi.pas(47,37) Error: Call by var for arg no. 3 has to match exactly: Got "Pointer" expected "LongWord" with other warning as well: QuoteMessages, Warnings: 1 Exit code 1, Errors: 1, Warnings: 5 utilwmi.pas(41,15) Warning: Implicit string type conversion from "AnsiString" to "WideString" utilwmi.pas(43,15) Warning: Implicit string type conversion from "AnsiString" to "WideString" utilwmi.pas(47,37) Error: Call by var for arg no. 3 has to match exactly: Got "Pointer" expected "LongWord" utilwmi.pas(53,22) Warning: Implicit string type conversion from "AnsiString" to "WideString" utilwmi.pas(56,36) Warning: Symbol "SysToUTF8" is deprecated: "Use the function in LazUTF8 unit" utilwmi.pas(61,67) Warning: Implicit string type conversion with potential data loss from "WideString" to "AnsiString" ---------------------------------------------------------------------- d.ioannidis · 2016-06-10 19:29 Hi, Quote from: vfclists on May 06, 2014, 05:27:24 pmDoes FreePascal have a WMI Query , Windows Management instrumentation library?  I played a little with this WMI Delphi Code Creator ( don't let the name misguide you, it works with fpc also, or at least it worked  ) in the past. You could look at it if it's suitable for you. [EDIT] Ooops, I din't see that taazz already mention it. Sorry... regards, ---------------------------------------------------------------------- molly · 2016-06-11 03:48 Quote from: christensen on June 10, 2016, 06:13:49 pmutilwmi.pas(47,37) Error: Call by var for arg no. 3 has to match exactly: Got "Pointer" expected "LongWord" with other warning as well: Seems you upgraded your FPC version as well ? Try version 0.2 of wmiutil unit. In theory that version should be able to support fpc 3.0.0 (as well as previous versions). ---------------------------------------------------------------------- christensen · 2016-06-14 20:36 Yes, i've upgrade everything. I've tried v2 and now i got other error: Quotemain.pas(239,50) Error: Incompatible type for arg no. 2: Got "TStringList", expected "{Open} Array Of AnsiString" in this section of code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  // read bios sn    Infos := TstringList.Create;        Infos.CommaText:='SerialNumber=';      ResultatWMI := GetWMIInfo('Win32_BIOS',Infos);      Result:=TstringList (ResultatWMI[f]).ValueFromIndex[j];       Infos.Free; ---------------------------------------------------------------------- molly · 2016-06-14 21:22 Quote from: christensen on June 14, 2016, 10:36:15 pmI've tried v2 and now i got other error: Quotemain.pas(239,50) Error: Incompatible type for arg no. 2: Got "TStringList", expected "{Open} Array Of AnsiString"The argument type was changed from a stringlist into an open array of strings, hence the error. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program example; {$MODE OBJFPC}{$H+} uses  classes,  utilwmi2,  contnrs; procedure BIOS;var  WMIResult         : TFPObjectList;  f,j             : integer;  retVal            : String;begin  WMIResult := GetWMIInfo('Win32_BIOS', ['SerialNumber', 'Manufacturer']);   for f := 0 to Pred(WMIResult.Count) do  begin    j := 0;  // first entry = SerialNumber    retVal := TStringList(WMIResult[f]).ValueFromIndex[j];    WriteLn(retVal);     j := 1;  // second entry = Manufacturer    retVal := TStringList(WMIResult[f]).ValueFromIndex[j];    WriteLn(retVal);  end;   WMIResult.Free;end; begin  BIOS;end. ---------------------------------------------------------------------- jma_sp · 2016-12-19 13:46 Thanks Jurasic Pork and Molly, it works!!! What license uses it? I have been trying with tprocess and wmic but it stops and nothing returns. With this all ok. There is a lot of information that can be returned, by example: wmic -? Returns a list of parameters... if it get BIOS we change as Win32_BIOS, if CPU Win32_CPU, If Desktop Win32_Desktop,............ For people searching for info in BIOS.....thereis also a project: https://github.com/RRUZ/tsmbios  It can be compiled easily with Lazarus. ---------------------------------------------------------------------- molly · 2016-12-19 14:04 Quote from: jma_sp on December 19, 2016, 02:46:09 pmThanks Jurasic Pork and Molly, it works!!! What license uses it? I have no idea. afaik It's Jurasic Pork's project so whatever J.P. says/tells goes as far as i am concerned. I'm just glad that you liked it and/or the project was useful for you. Thanks for the link to tsmbios as it is a very nice project. I already stumbled upon it a while ago but forgot about it already ---------------------------------------------------------------------- ASerge · 2016-12-19 15:10 Quote from: molly on December 19, 2016, 03:04:35 pmQuote from: jma_sp on December 19, 2016, 02:46:09 pmThanks Jurasic Pork and Molly, it works!!! I'm new here, but I think the design Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i try...except  on e: Exception do raise;end;is not very good. And with this approach you need to free the memory occupied by the Result. I.e. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i except  Result.Free;  raise;end; ---------------------------------------------------------------------- molly · 2016-12-19 15:32 @ASerge: You are correct. I would choose another solution though, e.g. the way exceptions are intended to be used. The example codes seen can sometimes be wrong in that regards, and actually should look more like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i begin  try    WMIResult := GetWMIInfo('Win32_BIOS', ['SerialNumber', 'Manufacturer']);    for i := 0 to Pred(WMIResult.Count) do    begin    ..    end;  finally    WMIResult.Free;  end; end;  Can you notice the difference ? Also note that v3 was released here, which adds support for WMI array return values. ---------------------------------------------------------------------- Jurassic Pork · 2016-12-19 16:24 hello, here is now the official version of utilwmi in attachment with a MIT Licence : Quote(**************************************************************** ******************  Copyright (c) 2016 Jurassic Pork - Molly Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ********************************************************************** *************) unit Utilwmi; // 0.1  Jurassic Pork Juillet 2015 // 0.2  Molly  Janvier 2016 : improvement : fpc 3.0 compatibility + usage of  TFPObjectList // Changes 2016-jan-02 (Mol) // - updated/corrected comments // - Introduction of variable nrValue. // - Generic solution for variable nr, using nrValue (inc. pointer assignment) // - re-introduction of calling ShowMessage() when exception occurs (code only //   active when USE_DIALOG is defined) + reorganized defines // 0.3  Molly  November 2016 : improvement : support for variant arrays // Changes 2016-nov-11 (Mol) // - Add support for variant arrays    to test the support for variant arrays  try : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  WMIResult := GetWMIInfo('Win32_BIOS', ['BIOSVersion', 'Manufacturer']);   BIOSVersion wmi result is a variant array. Friendly, J.P ---------------------------------------------------------------------- jma_sp · 2016-12-20 08:49 Thanks, It´s very useful because WMI let´s obtain a lot of information. By example it can return the total amount of physical memory: . This one is a very frequent question in Internet GetWMIInfo('Win32_COMPUTERSYSTEM', ['TotalPhysicalMemory']); Saludos. ---------------------------------------------------------------------- ASerge · 2016-12-20 15:17 Quote from: molly on December 19, 2016, 04:32:17 pmCan you notice the difference ? Of course. Try must be used AFTER the resource allocation. But to write code with errors based on incorrect application is also wrong. ---------------------------------------------------------------------- molly · 2016-12-21 15:37 @ASerge: You are correct in that code can become a bit awkward when attempting to handle such exception correctly. But what would you propose then ? I'm uncomfortable with the solution as shown by you earlier, because it is usually end-user responsibility to act on exceptions. In addition to that. It might be that only one 'entry' went wrong while all other entries are (still) valid. It would be unwise to clear the whole objectlist for that ? There probably is/was a good reason that Jurassic Pork left things open as it currently is. Note that J.P. 's unit is only a small helper routine that offer you quick WMI access. A better choice would probably be to use an implementation based on something like a dataset. I'm all for improving things, that is why i contributed. In case you have something to offer/contribute then please feel free to contact J.P. and make an offer. He's a very reasonable person (and after all, it is his idea/project. e.g. my vote doesn't really count). ---------------------------------------------------------------------- ASerge · 2016-12-22 14:51 Quote from: molly on December 21, 2016, 04:37:29 pm@ASerge: I'm uncomfortable with the solution as shown by you earlier, because it is usually end-user responsibility to act on exceptions. In addition to that. It might be that only one 'entry' went wrong while all other entries are (still) valid. It would be unwise to clear the whole objectlist for that ? Why not? Once the memory is allocated inside the function, when internal errors - it is must to clean. In my opinion it is more convenient when cleaning the one, who allocate. But if we delegate to function allocate only, I prefer this approach: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function ProducedSomeData(const ByParams: TInputParamsClass;  out DataHolder: TDataHolderClass): Boolean;//...begin  try    DataHolder := TDataHolderClass.Create({...});    //...    Result := True;  except  DataHolder.Free; // Escape memory leak    raise; // End-user responsibility to act on exceptions    // { Or handle this on their own} DataHolder := nil; Result := False;  end;end; procedure UseSomeData;//...begin  if ProducedSomeData(InputParams, DataHolder) then  try    //...  finally    DataHolder.Free;  end;end; ---------------------------------------------------------------------- vonskie · 2017-08-30 15:07 I have this code in vbscript Sub networkcard    Set colItems = objWMIService.ExecQuery _    ("Select * From Win32_NetworkAdapterConfiguration Where IPEnabled = True")    For Each objItem In colItems       If InStr(objItem.Description,"WAN")=0 Then          report=report  & "Description: " & objItem.Description &vbCrLf          report=report  & "IP Address: " &vbCrLf          For Each strAddress In objItem.IPAddress             report=report  & strAddress & vbCrLf          Next       End If    Next End Sub I have gotten this far but I do not know how to do the "strAddress In objItem.IPAddress" using the wmi call please help! PropNamesNetworkAdapterConfiguration: array[0..0] of string = ('Description'); WMIResult := GetWMIInfo('Win32_NetworkAdapterConfiguration',         PropNamesNetworkAdapterConfiguration, 'Where IPEnabled = True');       for i := 0 to Pred(WMIResult.Count) do       begin         REPORT := report + '================================================' + #13#10;         for PropNamesIndex := Low(PropNamesNetworkAdapterConfiguration) to High(PropNamesNetworkAdapterConfiguration) do         begin           REPORT := report + TStringList(WMIResult).Names[PropNamesIndex] +             ' : ' + TStringList(WMIResult).ValueFromIndex[PropNamesIndex] + #13#10;         end;       end;       // Clean up       WMIResult.Free;      Please help! ---------------------------------------------------------------------- molly · 2017-08-30 15:42 Please don't ignore the warnings that the compiler throws at you as they give you a clue. Not sure if this is what you meant to do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program example_nwadaptercfg; {$MODE OBJFPC}{$H+} uses  classes, contnrs, utilwmi; procedure DoIt;var  WMIResult         : TFPObjectList;  i               : Integer;  PropNamesIndex    : Integer;  PropNames       : Array[0..1] of String = ( 'Description', 'IPAddress' );begin  WMIResult := GetWMIInfo('Win32_NetworkAdapterConfiguration', PropNames, 'Where IPEnabled = True');   for i := 0 to Pred(WMIResult.Count) do  begin    WriteLn('================================================');     for PropNamesIndex := Low(PropNames) to High(PropNames) do    begin      WriteLn(TStringList(WMIResult[i]).Names[PropNamesIndex] + ' : ' +            TStringList(WMIResult[i]).ValueFromIndex[PropNamesIndex]);    end;  end;  // Clean up  WMIResult.Free;end; begin  DoIt;end. ---------------------------------------------------------------------- Thaddy · 2017-08-30 17:17 Since when can you hardcast to a TStringlist? If that works it is by accident.... Tstringlist is not an array..... it is a class. ---------------------------------------------------------------------- rvk · 2017-08-30 17:35 Quote from: Thaddy on August 30, 2017, 07:17:00 pmSince when can you hardcast to a TStringlist? If that works it is by accident.... Tstringlist is not an array..... it is a class. Have you checked out what WMIResult := GetWMIInfo() really does before posting that comment ?? It creates a TFPObjectList of multiple TStringLists so the hardcast is perfectly legit. (i.e. WMIResult[i] is a TStringList of itself) ---------------------------------------------------------------------- molly · 2017-08-30 18:14 Indeed as rvk wrote, the objectlist contains stringlists. There is much room for further improvements... ---------------------------------------------------------------------- molly · 2017-08-30 18:54 Sorry ASerge, i seem to have missed your latest response  Quote from: ASerge on December 22, 2016, 03:51:25 pmWhy not? Once the memory is allocated inside the function, when internal errors - it is must to clean. In my opinion it is more convenient when cleaning the one, who allocate. But if we delegate to function allocate only, I prefer this approach: Sure, but even better would be to have a separate wmi class that does everything internally (an act correctly when something goes wrong, e.g. not bother the user with it). As said, there is much room for improvements. If you have something to offer then offer it to J.P. Because of the backwards compatibility with fpc 2.6.4 i have not given it very much additional thoughts (generics, operator overloading etc.). There is a wmi dataset class floating around for Delphi. That could perhaps work as a good alternative for my clumsy coding ? ---------------------------------------------------------------------- 9ep2rz · 2017-12-24 12:56 Hi Jurassic Port, Using utilwmi unit I can get serial number of hard drives but I want to get from a specific drive, because I have 2 hard drive in my computer. Here is the code but I need to pass drive letter (D, F, H) and want to get physical serial number: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);  var    WMIResult         : TFPObjectList;    WMIResult2         : TFPObjectList;    f            : integer;    retVal            : String;begin WMIResult := GetWMIInfo('Win32_DiskDrive', ['DeviceID', 'SerialNumber']);  for f := 0 to Pred(WMIResult.Count) do  begin    retVal := TStringList(WMIResult[f]).ValueFromIndex[0] + ' : ' + TStringList(WMIResult[f]).ValueFromIndex[1];    Memo1.Lines.add(Retval);  end;   WMIResult.Free;end;  Thanks, ---------------------------------------------------------------------- molly · 2017-12-24 23:34 Quote from: 9ep2rz on December 24, 2017, 01:56:25 pmHere is the code but I need to pass drive letter (D, F, H) and want to get physical serial number: Not possible to accomplish with using utilWMI. Use your own instance of wmi and associate the proper objects to each other.  Hint: you need to parse things the other way around and in the end match your drive-letter. (DiskDrive -> Partition -> LogicalDisk -> DriveLetter -> DiskDrive.SerialNumber) ---------------------------------------------------------------------- Jurassic Pork · 2017-12-25 06:38 hello, utilwmi can only do Select WQL  Request. Quote from: molly on December 25, 2017, 12:34:42 amNot possible to accomplish with using utilWMI. Use your own instance of wmi and associate the proper objects to each other.  Hint: you need to parse things the other way around and in the end match your drive-letter. (DiskDrive -> Partition -> LogicalDisk -> DriveLetter -> DiskDrive.SerialNumber) To do this , you must use Associators of WQL Request. here is an example  : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // uses  Variants,ActiveX, ComObj        ; procedure TForm1.Button1Click(Sender: TObject);const  wbemFlagForwardOnly = $00000020;var  FSWbemLocator     : OLEVariant;  FWMIService       : OLEVariant;  wmiDiskDrives     : OLEVariant;  wmiDiskPartitions : OLEVariant;  wmiLogicalDisks   : OLEVariant;  wmiDiskDrive      : OLEVariant;  wmiDiskPartition  : OLEVariant;  wmiLogicalDisk    : OLEVariant;  oEnum             : IEnumvariant;  oEnum2            : IEnumvariant;  oEnum3            : IEnumvariant;  iValue            : LongWord;  DeviceID          : string;  Partitions        : string;  SerNum,SerNumByDriveLetter  : string;begin;  FSWbemLocator   := CreateOleObject('WbemScripting.SWbemLocator');  FSWbemLocator.Security_.privileges.addasstring('sedebugprivilege', true);  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');  FWMIService.Security_.ImpersonationLevel := 3;  //Get the physical disk drive  wmiDiskDrives := FWMIService.ExecQuery('SELECT Caption, DeviceID,SerialNumber FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);  oEnum         := IUnknown(wmiDiskDrives._NewEnum) as IEnumVariant;  while oEnum.Next(1, wmiDiskDrive, iValue) = 0 do  begin     SerNum := '';     Memo1.Lines.add(wmiDiskDrive.Caption);     if wmiDiskDrive.SerialNumber <> Null then     SerNum := UpperCase(String( wmiDiskDrive.SerialNumber));     Memo1.Lines.add('Serial Number : ' + SerNum  +                     '  =  ' + HexStrToStr(SerNum));      Partitions := '';     //Use the disk drive device id to find associated partition     DeviceID:=StringReplace(String(wmiDiskDrive.D eviceID),'\','\\',[rfReplaceAll]);     wmiDiskPartitions := FWMIService.ExecQuery(     WideString('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="'+     DeviceID+'"} WHERE AssocClass = Win32_DiskDriveToDiskPartition'),     'WQL',wbemFlagForwardOnly);     oEnum2          := IUnknown(wmiDiskPartitions._NewEnum) as IEnumVariant;     while oEnum2.Next(1, wmiDiskPartition, iValue) = 0 do     begin        wmiLogicalDisks := FWMIService.ExecQuery(        WideString('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+        String(wmiDiskPartition.DeviceID)+        '"} WHERE AssocClass = Win32_LogicalDiskToPartition'),        'WQL',wbemFlagForwardOnly);      oEnum3          := IUnknown(wmiLogicalDisks._NewEnum) as IEnumVariant;        while oEnum3.Next(1, wmiLogicalDisk, iValue) = 0 do        begin          if  (wmiLogicalDisk.DeviceID = 'C:') AND        (wmiDiskDrive.SerialNumber <> Null)  then          SerNumByDriveLetter :=   HexStrToStr(SerNum);           Partitions := Partitions + String(wmiLogicalDisk.DeviceID)+ ' ,';          wmiLogicalDisk:=Unassigned;        end;       wmiDiskPartition:=Unassigned;     end;    wmiDiskDrive:=Unassigned;  Memo1.Lines.Append('Partitions : ' + Partitions);    Memo1.Lines.add('=======================================');  end;    Memo1.Append('Disk Serial Number for C: is ' + SerNumByDriveLetter );end;  The function HexStrToStr is a code of ASerge : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses Classes; function HexStrToStr(const HexStr: string): string;var  ResultLen: Integer;begin  ResultLen := Length(HexStr) div 2;  SetLength(Result, ResultLen);  if ResultLen > 0 then    SetLength(Result, HexToBin(Pointer(HexStr), Pointer(Result), ResultLen));end; Friendly J.P ---------------------------------------------------------------------- 9ep2rz · 2017-12-25 10:01 Thanks Jurassi Pork, It really helped me. ---------------------------------------------------------------------- CM630 · 2025-12-15 22:20 I do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var ResultWMI : TFPObjectList;  i : Integer = 0;begin  Memo1.Clear;    ResultWMI := GetWMIInfo('Win32_PnPEntity',['Caption','DeviceID'],'WHERE Caption LIKE ''%%(COM%%)''');      for i:= 0 to ResultWMI.Count - 1 do        memo1.append(TstringList (ResultWMI[i]).ValueFromIndex[0]);end;    to get the list of the serial devices. But if I try to do it when a device is plugged/unplugged I get: “an outgoing call cannot be made since the application is dispatching an input-synchronous call”. So I commented {$DEFINE USE_DIALOG} in utilwmi.pas and extended the code to: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var ResultWMI : TFPObjectList;  i : Integer = 0;  retries : integer = 0;  failed: boolean = false;begin  Memo1.Clear;  for retries := 1 to 10 do  begin    failed := false;    try    ResultWMI := GetWMIInfo('Win32_PnPEntity',['Caption','DeviceID'],'WHERE Caption LIKE ''%%(COM%%)''');      for i:= 0 to ResultWMI.Count - 1 do        memo1.append(TstringList (ResultWMI[i]).ValueFromIndex[0]);    except        failed := true;        sleep(1000);        Memo1.Append('Failed')  ;    end;    if (failed = false) then break;  end;end;     Now I get the desired result, but maybe I could simply set some timeout? EDIT: I wrapped it in Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure xxxx.UpdatePorts {$ifdef windows}(Data: PtrInt){$endif};var....begin                                               ...    ResultWMI := GetWMIInfo('Win32_PnPEntity',['Caption','DeviceID'],'WHERE Caption LIKE ''%%(COM%%)''');...end;... Application.QueueAsyncCall(@UpdatePort s,0);  Now it does not crash. ---------------------------------------------------------------------- CM630 · 2026-02-05 12:02 I added Attempts and RetryInterval parameters. So far, it works without async calls. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i (********** ********************************************************************** ** Copyright (c) 2016 Jurassic Pork - Molly Permission is hereby granted, free of charge, to any person obtaining a copy ofthis software and associated documentation files (the "Software"), to deal in theSoftware without restriction, including without limitation the rights to use, copy,modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,and to permit persons to whom the Software is furnished to do so, subject to thefollowing conditions:The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR APARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHTHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTIONOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.************* ********************************************************************** )unit Utilwmi; // 0.1  Jurassic Pork Juillet 2015// 0.2  Molly  Janvier 2016 : improvement : fpc 3.0 compatibility + usage of  TFPObjectList // Changes 2016-jan-02 (Mol)// - updated/corrected comments// - Introduction of variable nrValue.// - Generic solution for variable nr, using nrValue (inc. pointer assignment)// - re- introduction of calling ShowMessage() when exception occurs (code only//   active when USE_DIALOG is defined) + reorganized defines // 0.3  Molly  November 2016 : improvement : support for variant arrays// Changes 2016-nov-11 (Mol)// - Add support for variant arrays  {$MODE OBJFPC}{$H+}{$HINTS ON} {$IF FPC_FULLVERSION > 29999}  // FPC > 2.9.9  {$INFO "Use new WMI"}{$ELSE}  {$INFO "Use old WMI"}  {$DEFINE USE_OLD_WMI}{$ENDIF} // Enable this define if wanting to use ShowMessage() to inform about an// exception.// Please realize that using unit Dialogs can 'clash', as both Freevision and// lazarus have a unit with the same name.//{$DEFINE USE_DIALOG}  interface uses  Classes,  contnrs;  function GetWMIInfo(const WMIClass: string; const WMIPropertyNames: Array of String; const Condition: string = ''; Attempts: integer=1; RetryInterval: Integer= 1000): TFPObjectList;  implementation Uses  {$IFDEF USE_DIALOG}  Dialogs,  {$ENDIF}  Variants,  ActiveX,  ComObj,  SysUtils; function VarArrayToStr(Value: Variant): String;var  i : Integer;begin  Result := '[';  for i := VarArrayLowBound(Value, 1) to VarArrayHighBound(Value, 1) do  begin    if Result <> '[' then Result := Result + ',';    if not VarIsNull(Value[i]) then    begin      if VarIsArray(Value[i])       then Result := Result + VarArrayToStr(Value[i])      else Result := Result + VartoStr(Value[i])    end    else Result := Result + '';  end;  Result := Result + ']';end; function GetobjWMIService(Attempts: integer = 1; RetryInterval: Integer = 1000): variant;var  FSWbemLocator : variant;  i: integer;  success: boolean = false;begin  for i:= 1 to Attempts do  begin    try      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');      Result := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', ''); //Executing this line might take a few seconds!      success := true;    except      Sleep(RetryInterval);    end;    if success then Break;  end;end; function GetWMIInfo(const WMIClass: string; const WMIPropertyNames: Array of String; const Condition: string = ''; Attempts: integer=1; RetryInterval: Integer= 1000): TFPObjectList;const  wbemFlagForwardOnly = $00000020;var  objWMIService : Variant;  colWMI        : Variant;  oEnumWMI      : IEnumvariant;  nrValue       : LongWord;  {$IFDEF USE_OLD_WMI}  objWMI        : Variant;                     // FPC < 3.0 requires WMIobj to be an variant, not an OleVariant  nr            : PLongWord;                 // FPC < 3.0 requires IEnumvariant.next to supply a pointer to a longword for # returned values  {$ELSE}  objWMI        : OLEVariant;                  // FPC 3.0 requires WMIobj to be an olevariant, not a variant  nr            : LongWord absolute nrValue;   // FPC 3.0 requires IEnumvariant.next to supply a longword variable for # returned values  {$ENDIF}  WMIproperties : String;  WMIProp       : TStringList;  Request       : String;  PropertyName  : String;  PropertyStrVal: String;  i             : integer;begin  {$IFDEF USE_OLD_WMI}  nr := @nrValue;  {$ENDIF}  // Prepare the search query  WMIProperties := '';  for i := low(WMIPropertyNames) to High(WMIPropertyNames)    do WMIProperties := WMIProperties + WMIPropertyNames[i] + ',';  Delete(WMIProperties, length(WMIProperties), 1);  // Let FPObjectList take care of freeing the objects  Result:= TFPObjectList.Create(True);  try    objWMIService := GetobjWMIService(Attempts, RetryInterval);    if Condition = ''      then Request := Format('SELECT %s FROM %s'   , [WMIProperties, WMIClass])      else Request := Format('SELECT %s FROM %s %s', [WMIProperties, WMIClass, Condition]);    // Start Request    colWMI   := objWMIService.ExecQuery(WideString(Request), 'WQL', wbemFlagForwardOnly);    // Enum for requested results    oEnumWMI := IUnknown(colWMI._NewEnum) as IEnumVariant;    // Enumerate results from query, one by one    while oEnumWMI.Next(1, objWMI, nr) = 0 do  begin      // Store all property name/value pairs for this enum to TStringList.      WMIprop := TStringList.Create;      for i := low(WMIPropertyNames) to High(WMIPropertyNames) do      begin        PropertyName := WMIPropertyNames[i];        If not VarIsNull(objWMI.Properties_.Item(WideString(PropertyName)).value) then        begin            if VarIsArray(objWMI.Properties_.Item(WideString(PropertyName)).value)           then PropertyStrVal := VarArrayToStr(objWMI.Properties_.Item( WideString(PropertyName)).value)            else PropertyStrVal := VartoStr(objWMI.Properties_.Item(WideString(PropertyName)).value)      end        else PropertyStrVal := '';        WMIProp.Add(PropertyName + '=' + PropertyStrVal);      end; //for i    // Add properties from this enum to FPObjectList as TStringList    Result.Add(WMIProp);    end; //while   except    {$IFDEF USE_DIALOG}  on e: Exception do       ShowMessage('Error WMI with ' + Request + #13#10 + 'Error : ' + e.Message);    {$ELSE}      // Replace Raise with more appropiate exception if wanted.      on e: Exception do Raise;    {$ENDIF}  end; //tryend; end. ---------------------------------------------------------------------- CM630 · 2026-06-29 07:53 It does not compile in fpc 3.2.4, the (hopefully) fixed code is attached. ---------------------------------------------------------------------- marcov · 2026-06-29 09:41 I've played with this myself also back then, and hit a problem that you have to redo the whole loop if you want the iteration to be different. So my idea was to condense the iterator loop and make it reusable by using a for..in enumerator.  I tried to add CM630's fix for 3.2.4, and now it works for 3.3.1 (which should be similar in this respect).  It fails on 3.2.4RC1, which is logical, as it is different from fixes and a final 3.2.4 in this respect. The good part of this approach, that by fixing one location, all iteration over properties is fixed at once. Iterating over properties becomes something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure DumpProperties(obj : OleVariant;condense : boolean=true);var  objprop  : OLEVariant;  propiter : oEnumIterator;  s        : string;begin   for objprop in propiter.Enumerate(obj.Properties_) do      begin      s:=OleVariantToText(objprop.Value);        if (s<>'') or not condense then           Writeln(padright(objprop.Name,40),' = ',s);    end;end; procedure  GetWin32_DesktopMonitorInfo;const  WbemUser          ='';  WbemPassword        ='';  WbemComputer        ='localhost';  wbemFlagForwardOnly = $00000020;var  FSWbemLocator : OLEVariant;  FWMIService   : OLEVariant;  FWbemObjectSet: OLEVariant;  obj           : OLEVariant;  oEnum         : oEnumIterator;begin;  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_DesktopMonitor','WQL',wbemFlagForwardOnly);   for obj in oEnum.Enumerate(FWbemObjectSet) do    begin      writeln;      DumpProperties(obj);  // which is a OleVariantToText variant wrapper.    end;end; ---------------------------------------------------------------------- CM630 · 2026-06-30 08:19 Sorry, I cannot understand you. Does the attached file contain a different implementation of a WMI Query library or is it something else? ---------------------------------------------------------------------- marcov · 2026-06-30 08:50 Quote from: CM630 on June 30, 2026, 10:19:25 amSorry, I cannot understand you. Does the attached file contain a different implementation of a WMI Query library or is it something else? It is my WMI util library with some examples. The interesting part is the iterator, used to iterate over properties. Easier to use, and easier to fix, as the iterator code is in one central location ---------------------------------------------------------------------- CM630 · 2026-06-30 08:58 Does it crash with  “an outgoing call cannot be made since the application is dispatching an input-synchronous call” like described here: https://forum.lazarus.freepascal.org/index.php/topic,24490.msg572378.h tml#msg572378  ? Or is it fixed? ---------------------------------------------------------------------- marcov · 2026-06-30 12:10 Probably not. it just allows to use for..in for  Code: [Select]while oEnumWMI.Next(1, objWMI, nr) = 0 do like loops. ---------------------------------------------------------------------- CM630 · 2026-06-30 14:31 I loaded wmishowwinver.lpr in Lazarus, clicked Create project, then selected Program, when I tried to run it,  I got: QuoteDebugger Exception Notification Project wmishowwinver raised exception class 'EOleSysError' with message: Member not found. At address 425C93 [ ] Ignore this exception type                      [ Break ] [ Continue ] Edit: I also tried Console Application, the result is the same. ---------------------------------------------------------------------- LeP · 2026-06-30 15:04 I want to point about to use the new MI (Management Interface) that works without OLE. In other post I attatch the full API of windows, here you'll find "Windows.System.Wmi" that publish all interfaces, classes, records, procedure and functions to use the WMI without call "OLE". I don't have any case of use 'cause I don't use WMI since lot of time, but I don't think is very difficult to implement it instead of OLE WMI. This is the post with Windows API: https://forum.lazarus.freepascal.or g/index.php/topic,74305.msg585513.html#msg585513 [EDIT}: I tried tha wrapper but inside there are lot of missing MI APIs, so is not usefull at the moment, I'll see why is missing. ---------------------------------------------------------------------- marcov · 2026-06-30 15:05 I don't get that (32-bit windows, 3.3.1) ---------------------------------------------------------------------- CM630 · 2026-07-02 10:34 It shows the version, then it crashes on Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i           dtmConvertedDate.Value:=colitem.InstallDate;   Maybe related to some regional settings? Lazarus 32 bit on Win11(64 bit). Lazarus 4.8 (rev lazarus_4_8) FPC 3.2.2 i386-win32-win32/win64 ---------------------------------------------------------------------- marcov · 2026-07-02 11:07 Here your code works and prints Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Version: 10.0.26200Install Date: 18-12-2024 22:20:39  It could be some regional settings, it could be some of the string conversion fixes in unit variants.  Most of those should be in fixes too. ---------------------------------------------------------------------- CM630 · 2026-07-03 06:51 Quote from: marcov on July 02, 2026, 01:07:20 pmHere your code works and prints Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Version: 10.0.26200Install Date: 18-12-2024 22:20:39  It could be some regional settings, it could be some of the string conversion fixes in unit variants.  Most of those should be in fixes too. If the bug is not in WMI, but somewhere else it should be fine. I have attached a snippet which gets the info for the COM ports with your routines. I have not tried if it crashed in Lazarus applications, in a console program it worked fine so far. ---------------------------------------------------------------------- LeP · 2026-07-03 07:48 Quote from: LeP on June 30, 2026, 05:04:30 pmI want to point about to use the new MI (Management Interface) that works without OLE. In other post I attatch the full API of windows, here you'll find "Windows.System.Wmi" that publish all interfaces, classes, records, procedure and functions to use the WMI without call "OLE". I don't have any case of use 'cause I don't use WMI since lot of time, but I don't think is very difficult to implement it instead of OLE WMI. This is the post with Windows API: https://forum.lazarus.freepascal.or g/index.php/topic,74305.msg585513.html#msg585513 [EDIT}: I tried tha wrapper but inside there are lot of missing MI APIs, so is not usefull at the moment, I'll see why is missing. About new WMI (MI) functions, its totally different story .... the wrapper cannot be made from MD Microsoft datas, beacuse in the MD it's not descript the "firms" of the functions called. All MI definition is based on records with array of functions (and this is very good, my think)  that will be fullfilled when you call the initialization of MI (that is a normal DLL call). But all functions are defined like "Pointer" ... so no way to decode what are the parametrs to call. I take the mi.h and the documentation and create some missing things to test, but lot of works should be done. In this example I made the definitions of  Close and NewSession and all other missings ... (not all are exposed here). All the Pointers all fullfilled by calling "MI_Application_InitializeV1" Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i PMI_ApplicationFT = ^MI_ApplicationFT;  PMiApplicationft = PMI_ApplicationFT;  PMI_Application = ^MI_Application;  PMiApplication = PMI_Application;  ///   MI_Application = record    reserved1: UInt64;    reserved2: NativeInt;    ft: PMI_ApplicationFT;  end;  ///   MI_ApplicationFT = record    Close: function(App: MI_Application): MI_Result; stdcall;    NewSession: function( App: PMI_Application; Protocol: PMI_Char; Destination: PMI_Char; Options: Pointer; BookMark: Pointer; Instance: Pointer;  out Session: MI_Session): MI_Result; stdcall;    NewHostedProvider: Pointer;    NewInstance: Pointer;    NewOperationOptions: Pointer;    NewDestinationOptions: Pointer;    NewSubscriptionDeliveryOptions: Pointer;    NewSerializer: Pointer;    NewDeserializer: Pointer;    NewInstanceFromClass: Pointer;    NewClass: Pointer;  end; //USEvar MyMI:  MI_Application;      Result_: MI_Result; begin  Result_ := MI_Application_InitializeV1(0, nil, nil, MyMI);  if Result_ <> MI_RESULT_OK then    begin      Writeln('Init error MI_Application: ', Result_);      Exit;    end;   if MyMI.ft^.NewSession( ...........) = MI_RESULT_OK then    writeln('Ok, the function worked');