Recent

Author Topic: Does FreePascal have a WMI Query library?  (Read 19810 times)

jma_sp

  • Full Member
  • ***
  • Posts: 133
  • El conocimiento si ocupa lugar.
Re: Does FreePascal have a WMI Query library?
« Reply #15 on: December 20, 2016, 09:49:06 am »
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.
« Last Edit: December 20, 2016, 09:56:40 am by jma_sp »
Devuan ASCII 2.0 ( JWM/ROX/iDesk  without systemd ) - Puppy Linux, ReactOS 0.4.xx  - FreeDos - OctaOS - KolibriOS

ASerge

  • Hero Member
  • *****
  • Posts: 1420
Re: Does FreePascal have a WMI Query library?
« Reply #16 on: December 20, 2016, 04:17:51 pm »
Can 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

  • Hero Member
  • *****
  • Posts: 2345
Re: Does FreePascal have a WMI Query library?
« Reply #17 on: December 21, 2016, 04:37:29 pm »
@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

  • Hero Member
  • *****
  • Posts: 1420
Re: Does FreePascal have a WMI Query library?
« Reply #18 on: December 22, 2016, 03:51:25 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]
  1. function ProducedSomeData(const ByParams: TInputParamsClass;
  2.   out DataHolder: TDataHolderClass): Boolean;
  3. //...
  4. begin
  5.   try
  6.     DataHolder := TDataHolderClass.Create({...});
  7.     //...
  8.     Result := True;
  9.   except
  10.     DataHolder.Free; // Escape memory leak
  11.     raise; // End-user responsibility to act on exceptions
  12.     // { Or handle this on their own} DataHolder := nil; Result := False;
  13.   end;
  14. end;
  15.  
  16. procedure UseSomeData;
  17. //...
  18. begin
  19.   if ProducedSomeData(InputParams, DataHolder) then
  20.   try
  21.     //...
  22.   finally
  23.     DataHolder.Free;
  24.   end;
  25. end;                    

vonskie

  • Full Member
  • ***
  • Posts: 138
Re: Does FreePascal have a WMI Query library?
« Reply #19 on: August 30, 2017, 05:07:57 pm »
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

  • Hero Member
  • *****
  • Posts: 2345
Re: Does FreePascal have a WMI Query library?
« Reply #20 on: August 30, 2017, 05:42:48 pm »
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]
  1. program example_nwadaptercfg;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses
  6.   classes, contnrs, utilwmi;
  7.  
  8. procedure DoIt;
  9. var
  10.   WMIResult         : TFPObjectList;
  11.   i                 : Integer;
  12.   PropNamesIndex    : Integer;
  13.   PropNames         : Array[0..1] of String = ( 'Description', 'IPAddress' );
  14. begin
  15.   WMIResult := GetWMIInfo('Win32_NetworkAdapterConfiguration', PropNames, 'Where IPEnabled = True');
  16.  
  17.   for i := 0 to Pred(WMIResult.Count) do
  18.   begin
  19.     WriteLn('================================================');
  20.  
  21.     for PropNamesIndex := Low(PropNames) to High(PropNames) do
  22.     begin
  23.       WriteLn(TStringList(WMIResult[i]).Names[PropNamesIndex] + ' : ' +
  24.               TStringList(WMIResult[i]).ValueFromIndex[PropNamesIndex]);
  25.     end;
  26.   end;
  27.   // Clean up
  28.   WMIResult.Free;
  29. end;
  30.  
  31. begin
  32.   DoIt;
  33. end.
  34.  

Thaddy

  • Hero Member
  • *****
  • Posts: 9282
Re: Does FreePascal have a WMI Query library?
« Reply #21 on: August 30, 2017, 07:17:00 pm »
Since when can you hardcast to a TStringlist? If that works it is by accident.... Tstringlist is not an array..... it is a class.
also related to equus asinus.

rvk

  • Hero Member
  • *****
  • Posts: 3842
Re: Does FreePascal have a WMI Query library?
« Reply #22 on: August 30, 2017, 07:35:05 pm »
Since 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)
« Last Edit: August 30, 2017, 07:38:02 pm by rvk »

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: Does FreePascal have a WMI Query library?
« Reply #23 on: August 30, 2017, 08:14:04 pm »
Indeed as rvk wrote, the objectlist contains stringlists.

There is much room for further improvements...

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: Does FreePascal have a WMI Query library?
« Reply #24 on: August 30, 2017, 08:54:28 pm »
Sorry ASerge, i seem to have missed your latest response  :-[

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:
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

  • Newbie
  • Posts: 3
Re: Does FreePascal have a WMI Query library?
« Reply #25 on: December 24, 2017, 01:56:25 pm »
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]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2.   var
  3.     WMIResult         : TFPObjectList;
  4.     WMIResult2         : TFPObjectList;
  5.     f              : integer;
  6.     retVal            : String;
  7. begin
  8.  WMIResult := GetWMIInfo('Win32_DiskDrive', ['DeviceID', 'SerialNumber']);
  9.   for f := 0 to Pred(WMIResult.Count) do
  10.   begin
  11.     retVal := TStringList(WMIResult[f]).ValueFromIndex[0] + ' : ' + TStringList(WMIResult[f]).ValueFromIndex[1];
  12.     Memo1.Lines.add(Retval);
  13.   end;
  14.  
  15.   WMIResult.Free;
  16. end;
  17.  

Thanks,

molly

  • Hero Member
  • *****
  • Posts: 2345
Re: Does FreePascal have a WMI Query library?
« Reply #26 on: December 25, 2017, 12:34:42 am »
Here 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

  • Hero Member
  • *****
  • Posts: 753
Re: Does FreePascal have a WMI Query library?
« Reply #27 on: December 25, 2017, 07:38:36 am »
hello,
utilwmi can only do Select WQL  Request.
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)
To do this , you must use Associators of WQL Request.
here is an example  :
Code: Pascal  [Select]
  1. // uses  Variants,ActiveX, ComObj        ;
  2. procedure TForm1.Button1Click(Sender: TObject);
  3. const
  4.   wbemFlagForwardOnly = $00000020;
  5. var
  6.   FSWbemLocator     : OLEVariant;
  7.   FWMIService       : OLEVariant;
  8.   wmiDiskDrives     : OLEVariant;
  9.   wmiDiskPartitions : OLEVariant;
  10.   wmiLogicalDisks   : OLEVariant;
  11.   wmiDiskDrive      : OLEVariant;
  12.   wmiDiskPartition  : OLEVariant;
  13.   wmiLogicalDisk    : OLEVariant;
  14.   oEnum             : IEnumvariant;
  15.   oEnum2            : IEnumvariant;
  16.   oEnum3            : IEnumvariant;
  17.   iValue            : LongWord;
  18.   DeviceID          : string;
  19.   Partitions        : string;
  20.   SerNum,SerNumByDriveLetter  : string;
  21. begin;
  22.   FSWbemLocator   := CreateOleObject('WbemScripting.SWbemLocator');
  23.   FSWbemLocator.Security_.privileges.addasstring('sedebugprivilege', true);
  24.   FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  25.   FWMIService.Security_.ImpersonationLevel := 3;
  26.   //Get the physical disk drive
  27.   wmiDiskDrives := FWMIService.ExecQuery('SELECT Caption, DeviceID,SerialNumber FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);
  28.   oEnum         := IUnknown(wmiDiskDrives._NewEnum) as IEnumVariant;
  29.   while oEnum.Next(1, wmiDiskDrive, iValue) = 0 do
  30.   begin
  31.      SerNum := '';
  32.      Memo1.Lines.add(wmiDiskDrive.Caption);
  33.      if wmiDiskDrive.SerialNumber <> Null then
  34.      SerNum := UpperCase(String( wmiDiskDrive.SerialNumber));
  35.      Memo1.Lines.add('Serial Number : ' + SerNum  +
  36.                      '  =  ' + HexStrToStr(SerNum));
  37.  
  38.      Partitions := '';
  39.      //Use the disk drive device id to find associated partition
  40.      DeviceID:=StringReplace(String(wmiDiskDrive.DeviceID),'\','\\',[rfReplaceAll]);
  41.      wmiDiskPartitions := FWMIService.ExecQuery(
  42.      WideString('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="'+
  43.      DeviceID+'"} WHERE AssocClass = Win32_DiskDriveToDiskPartition'),
  44.      'WQL',wbemFlagForwardOnly);
  45.      oEnum2          := IUnknown(wmiDiskPartitions._NewEnum) as IEnumVariant;
  46.      while oEnum2.Next(1, wmiDiskPartition, iValue) = 0 do
  47.      begin
  48.         wmiLogicalDisks := FWMIService.ExecQuery(
  49.         WideString('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+
  50.         String(wmiDiskPartition.DeviceID)+
  51.         '"} WHERE AssocClass = Win32_LogicalDiskToPartition'),
  52.         'WQL',wbemFlagForwardOnly);
  53.         oEnum3          := IUnknown(wmiLogicalDisks._NewEnum) as IEnumVariant;
  54.         while oEnum3.Next(1, wmiLogicalDisk, iValue) = 0 do
  55.         begin
  56.           if  (wmiLogicalDisk.DeviceID = 'C:') AND
  57.           (wmiDiskDrive.SerialNumber <> Null)  then
  58.           SerNumByDriveLetter :=   HexStrToStr(SerNum);
  59.  
  60.           Partitions := Partitions + String(wmiLogicalDisk.DeviceID)+ ' ,';
  61.           wmiLogicalDisk:=Unassigned;
  62.         end;
  63.        wmiDiskPartition:=Unassigned;
  64.      end;
  65.     wmiDiskDrive:=Unassigned;
  66.     Memo1.Lines.Append('Partitions : ' + Partitions);
  67.     Memo1.Lines.add('=======================================');
  68.   end;
  69.     Memo1.Append('Disk Serial Number for C: is ' + SerNumByDriveLetter );
  70. end;  
The function HexStrToStr is a code of ASerge :
Code: Pascal  [Select]
  1. uses Classes;
  2.  
  3. function HexStrToStr(const HexStr: string): string;
  4. var
  5.   ResultLen: Integer;
  6. begin
  7.   ResultLen := Length(HexStr) div 2;
  8.   SetLength(Result, ResultLen);
  9.   if ResultLen > 0 then
  10.     SetLength(Result, HexToBin(Pointer(HexStr), Pointer(Result), ResultLen));
  11. end;

Friendly J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

9ep2rz

  • Newbie
  • Posts: 3
Re: Does FreePascal have a WMI Query library?
« Reply #28 on: December 25, 2017, 11:01:24 am »
Thanks Jurassi Pork,

It really helped me.