EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Scanning for physical disks

Also by EldoS: Solid File System
A virtual file system that offers a feature-rich storage for application documents and data with built-in compression and encryption.
#33466
Posted: 05/28/2015 07:01:09
by T SMITH (Basic support level)
Joined: 03/02/2015
Posts: 18

Hi

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!?)

Code
{$mode objfpc}{$H+}
uses
  SysUtils,ActiveX,ComObj,Variants;
{$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;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : Variant;
  oEnum         : IEnumvariant;
  sValue        : string;
begin;
  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
  begin
    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

    Writeln;
    FWbemObject:= Unassigned;
  end;
end;

begin
  try
    GetWin32_DiskDriveInfo;
  except
    on E:EOleException do
        Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
    on E:Exception do
        Writeln(E.Classname, ':', E.Message);
  end;
  Writeln('Press Enter to exit');
  Readln;
end.    
#33468
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
#33474
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:

Code
   

    {$mode objfpc}
    
    uses
      Windows,
      SysUtils,
      ActiveX,
      ComObj,
      Variants;
    
    
    function ListDrives : string;
    var
      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;
    begin;
      Result:='';
      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
       begin
          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
          begin
           if not VarIsNull(objPartition.DeviceID) then
           begin
            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
              begin
                  Writeln(Format('     Logical Disk %s',[string(objLogicalDisk.DeviceID)]));
                  objLogicalDisk:=Unassigned;
              end;
           end;
           objPartition:=Unassigned;
          end;
           objdiskDrive:=Unassigned;
       end;
    end;
    
    begin
     try
        // CoInitialize(nil); Needed for Delphi but not Freepascal
        try
          ListDrives;
        finally
         // CoUninitialize;  Needed for Delphi but not Freepascal
        end;
     except
       on E:EOleException do
           Writeln(E.Message + '  Code '+IntToStr(E.ErrorCode));
        on E:Exception do
            Writeln(E.Classname, ':', E.Message);
      end;
      Writeln('Done');
      Readln;
    end.


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
#33475
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

Reply

Statistics

Topic viewed 5748 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!