EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Scanning for physical disks

Also by EldoS: CallbackProcess
A component to control process creation and termination in Windows and .NET applications.
Posted: 05/28/2015 07:01:09
by T SMITH (Basic support level)
Joined: 03/02/2015
Posts: 18


Further to my interest in using RawDisk, the first step in its use is to scan and list the PhysicalDisks (\\?\PhysicalDiskX)connected to the computer, regardless of whether there are valid and mounted partitions on it\them or not.

I've spent a lot of time, here and there, over the years looking for "professional" (as in solid, reliable) solutions to doing this and even posted several threads asking for help and I'm always surprised at what an enormous hassle it seems to be. Using ActiveX components, OLE EVents and all sorts. I did eventually find a way that works, but it is clumbsy and feels a bit old and outdated to me ((http://stackoverflow.com/questions/8519658/how-to-call-a-list-of-the-physically-attached-hard-disks-using-free-pascal-or)

I wonder if Eldos have or know of a good, reliable, professional way to simply have a buttonclick event that, when pressed, traverses and lists the disks adding the \\?\PhyscialDiskX value to a variable or something? From there of course RawDisk Open() can then be used to access the chosen disk. As far as I can see, the RD API has Open to initiate the handle to the disk, but there isn't a procedure for scanning for the disks initially (https://www.eldos.com/documentation/rawdisk/ref_cl_rawdisk.html)?

If Eldos have a way that they could share with me, privately or publically, I'd appreciate it.

For ref, the solution I use now is a modified version of the following (there must be a cleaner way!?)

{$mode objfpc}{$H+}
{$R *.res}

// The Win32_DiskDrive class represents a physical disk drive as seen by a computer running the Win32 operating system. Any interface to a Win32 physical disk drive is a descendent (or member) of this class. The features of the disk drive seen through this object correspond to the logical and management characteristics of the drive. In some cases, this may not reflect the actual physical characteristics of the device. Any object based on another logical device would not be a member of this class.
// Example: IDE Fixed Disk.

procedure  GetWin32_DiskDriveInfo;
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : Variant;
  oEnum         : IEnumvariant;
  sValue        : string;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
  FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive','WQL',wbemFlagForwardOnly);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  while oEnum.Next(1, FWbemObject, nil) = 0 do
    sValue:= FWbemObject.Properties_.Item('Caption').Value;
    Writeln(Format('Caption        %s',[sValue]));// String
    sValue:= FWbemObject.Properties_.Item('DeviceID').Value;
    Writeln(Format('DeviceID       %s',[sValue]));// String i.e. '\\?\PHYSICALDISKX'
    sValue:= FWbemObject.Properties_.Item('Model').Value;
    Writeln(Format('Model          %s',[sValue]));// String
    sValue:= FWbemObject.Properties_.Item('Partitions').Value;
    Writeln(Format('Partitions     %s',[sValue]));// Uint32
    sValue:= FWbemObject.Properties_.Item('PNPDeviceID').Value;
    Writeln(Format('PNPDeviceID    %s',[sValue]));// String
    sValue:= FormatFloat('#,', FWbemObject.Properties_.Item('Size').Value / (1024*1024));
    Writeln(Format('Size           %s mb',[sValue]));// Uint64

    FWbemObject:= Unassigned;

    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
  Writeln('Press Enter to exit');
Posted: 05/28/2015 07:37:53
by Eugene Mayevski (EldoS Corp.)

Thank you for a good idea. I've added it to the WishList ( https://www.eldos.com/rawdisk/wishlist.php ) and you are welcome to vote for the idea there. We will review the possibility to implement such function and add it to RawDisk 4 when its time comes.

Sincerely yours
Eugene Mayevski
Posted: 05/29/2015 03:06:44
by T SMITH (Basic support level)
Joined: 03/02/2015
Posts: 18

Not that you'll need help with that but other users might. I spent a few days trying to do this and eventually came up with this Freepascal Lazarus compliant example courtesy of my hero Stackoverflow user, RRUZ. It utilises the WMI Windows system for low level API calls:


    {$mode objfpc}
    function ListDrives : string;
      FSWbemLocator  : Variant;
      objWMIService  : Variant;
      colDiskDrives  : Variant;
      colLogicalDisks: Variant;
      colPartitions  : Variant;
      objdiskDrive   : Variant;
      objPartition   : Variant;
      objLogicalDisk : Variant;
      oEnumDiskDrive : IEnumvariant;
      oEnumPartition : IEnumvariant;
      oEnumLogical   : IEnumvariant;
      iValue         : pULONG;
      DeviceID       : widestring;
      s : widestring;
      FSWbemLocator   := CreateOleObject('WbemScripting.SWbemLocator');
      objWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
      colDiskDrives   := objWMIService.ExecQuery('SELECT DeviceID FROM Win32_DiskDrive', 'WQL');
      oEnumDiskDrive  := IUnknown(colDiskDrives._NewEnum) as IEnumVariant;
      while oEnumDiskDrive.Next(1, objdiskDrive, nil) = 0 do
          Writeln(Format('DeviceID %s',[string(objdiskDrive.DeviceID)]));
          //Escape the `\` chars in the DeviceID value because the '\' is a reserved character in WMI.
          DeviceID        := StringReplace(objdiskDrive.DeviceID,'\','\\',[rfReplaceAll]);
          //link the Win32_DiskDrive class with the Win32_DiskDriveToDiskPartition class
          s:=Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="%s"} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[DeviceID]);
          colPartitions   := objWMIService.ExecQuery(s, 'WQL');
          oEnumPartition  := IUnknown(colPartitions._NewEnum) as IEnumVariant;
          while oEnumPartition.Next(1, objPartition, nil) = 0 do
           if not VarIsNull(objPartition.DeviceID) then
            Writeln(Format('   Partition %s',[string(objPartition.DeviceID)]));
            //link the Win32_DiskPartition class with theWin32_LogicalDiskToPartition class.
            s:='ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+VarToStr(objPartition.DeviceID)+'"} WHERE AssocClass = Win32_LogicalDiskToPartition';
            colLogicalDisks := objWMIService.ExecQuery(s);
            oEnumLogical  := IUnknown(colLogicalDisks._NewEnum) as IEnumVariant;
              while oEnumLogical.Next(1, objLogicalDisk, nil) = 0 do
                  Writeln(Format('     Logical Disk %s',[string(objLogicalDisk.DeviceID)]));
        // CoInitialize(nil); Needed for Delphi but not Freepascal
         // CoUninitialize;  Needed for Delphi but not Freepascal
       on E:EOleException do
           Writeln(E.Message + '  Code '+IntToStr(E.ErrorCode));
        on E:Exception do
            Writeln(E.Classname, ':', E.Message);

For my details (https://theroadtodelphi.wordpress.com/2010/12/01/accesing-the-wmi-from-pascal-code-delphi-oxygene-freepascal/#Lazarus) and http://stackoverflow.com/questions/12271269/how-can-i-correlate-logical-drives-and-physical-disks-using-the-wmi-and-delphi/12271778#comment49108167_12271778
Posted: 05/29/2015 03:29:51
by Eugene Mayevski (EldoS Corp.)

I appreciate the code very much as well, thank you. If we don't don't find a kernel way to enumerate disks, we'll just stick with referring users to your post with the sample code.

Sincerely yours
Eugene Mayevski



Topic viewed 6518 times

Number of guests: 1, registered members: 0, in total hidden: 0


Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!