【问题标题】:How to call a list of the physically attached hard disks using Free Pascal, or, failing that, Delphi?如何使用 Free Pascal 或 Delphi 调用物理连接的硬盘列表?
【发布时间】:2012-01-21 02:57:44
【问题描述】:

除了this questionthis one,我最近问过但没有正确的细节……最后是我在 Free Pascal 论坛上专门问过的this one……

任何人都可以向我提供指导、示例或链接,以解释如何使用 Free Pascal 调用物理连接的硬盘列表,或者,如果失败,Delphi,无论磁盘是否已安装操作系统与否?我正在尝试实现的屏幕截图中显示了一个示例(此屏幕截图中显示的是另一个软件产品)。因此,拉出一个逻辑卷列表(C:\、E:\ 等)并不是我想要做的。如果磁盘有操作系统无法挂载的文件系统,我仍然希望看到列出的物理磁盘。

我强调 C\C++\C Sharp 的例子很多,但不是我所追求的。我主要需要 Free Pascal 示例,或者,如果没有,则需要 Delphi。

【问题讨论】:

  • +1 this question shows research effort :-) 你看过Win3.1组件下TDriveComboBox的源代码吗?
  • 我坚信内核对物理磁盘使用连续编号,因此您只需枚举直到失败

标签: delphi freepascal lazarus


【解决方案1】:

对于带有驱动器号的已安装驱动器,请调用 Win32 ShellApi 函数SHGetSpecialFolderLocation(0, CSIDL_DRIVES, Drives)。声明局部变量Drives: PItemIdList。这是在 delphi 中名为 ShellAPI 的单元中。希望 FreePascal 中存在类似的单元。

对于未安装的驱动器,您必须以某种方式通过GUID_DEVINTERFACE_DISK 的设备驱动程序类枚举设备驱动程序。 windows的SetupAPI应该可以帮到你。

您可以从 JEDI JCL 或 JEDI API 项目中获取 SetupAPI.pas。

procedure GetListFromSetupApi(aStrings: TStrings);
var
  iDev: Integer;
  RegDataType: Cardinal;
  reqSize:DWORD;
  prop:Cardinal;
  pszData:PByte;
  hinfo:   HDEVINFO;
  bResult: BOOL;
  devinfo: SP_DEVINFO_DATA;
  dwRequiredSize,dwPropertyRegDataType,dwAllocSz:Cardinal;
begin
  LoadSetupApi;
  if not Assigned(SetupDiGetClassDevs) then
    Exit;

  hinfo := SetupDiGetClassDevs(@GUID_DEVINTERFACE_DISK, nil, HWND(nil),
                               DIGCF_DEVICEINTERFACE or DIGCF_PRESENT or DIGCF_PROFILE);

  devinfo.ClassGuid.D1 := 0;
  devinfo.ClassGuid.D2 := 0;
  devinfo.ClassGuid.D3 := 0;
  devinfo.cbSize := SizeOf(SP_DEVINFO_DATA);

  iDev := 0;
   while SetupDiEnumDeviceInfo(hinfo, iDev, devinfo) do
    begin

    dwRequiredSize := 0;

    prop := SPDRP_PHYSICAL_DEVICE_OBJECT_NAME;
    // results on my computer:
    // \Device\Ide\IAAStorageDevice-1
    // \Device\Ide\IAAStorageDevice-2
    // \Device\0000008a                 (this one is a usb disk, use SPDRP_ENUMERATOR_NAME, returns USBSTOR)

//   prop := SPDRP_ENUMERATOR_NAME; // results: IDE, USBSTOR, or other bus type.

//   prop := SPDRP_LOCATION_INFORMATION; // a number like 1,2,3.


    { SPDRP_DRIVER - driver guid }
    { Get Size of property }
     SetupDiGetDeviceRegistryProperty
                (hinfo,
                devinfo,
                prop,
                dwPropertyRegDataType,
                nil,
                0,
                dwRequiredSize);   { dwRequiredSize should be around 88 after this point, in unicode delphi }

     if dwRequiredSize>0 then begin

        dwAllocSz := dwRequiredSize+4;
        pszData := AllocMem(dwAllocSz);
        bResult := SetupDiGetDeviceRegistryProperty
                (hinfo,
                devinfo,
                prop,
                dwPropertyRegDataType,
                pszData,
                dwAllocSz,
                dwRequiredSize);

        aStrings.Add(IntToStr(aStrings.Count)+': '+PChar(pszData));
        FreeMem(pszData);

    end;
    inc(iDev);
  end;
  SetupDiDestroyDeviceInfoList(hinfo);
end;

包含上述代码和相应 JEDI API 单元的完整 DELPHI 示例是 here。你可以很容易地将它改编为 free pascal 和 lazarus。

【讨论】:

  • RRUZ - 非常感谢!我刚刚尝试了使用 Lazarus 0.9.31 和 FPC 2.5.1 将您粘贴到新的基本终端程序中的代码,并且无需更改任何内容即可立即运行。我只是编译并构建它,然后运行编译的 exe,果然,它完全符合我的需要。现在我可以将它实现到我自己的项目中。你帮助我实现了我花了无数时间试图做的事情!祝福你!
【解决方案2】:

尝试Win32_DiskDrive WMI 类,查看此示例代码

{$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
    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.    

运行此代码后,您将获得如下输出

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 2011-11-06
    • 2011-12-09
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多