WMI:如何区分内部“本地磁盘”和“本地磁盘” HDD和外部“本地磁盘”硬盘
背景
我一直在使用 Win32_DiskDrive 来查找闪存(USB 笔、SD 卡等),但在其他计算机上进行一些测试后,我发现它们并不总是被发现。因此,我使用 Win32_LogicalDisk,因为它具有 DriveType,所以我不必与两个类(例如分区)关联来首先查找驱动器,然后查找它们的驱动器号。
问题在于,外部硬盘驱动器在 LogicalDisk 中被检测为 DriveType 3(本地磁盘),而在 DiskDrive 的功能中没有 7(支持可移动媒体)。所以我无法区分内部和外部驱动器。
问题
我如何使用 LogicalDisk(或 DiskDrive,如果确实需要的话)或第三方来区分内部和外部硬盘驱动器。
好吧。问题已得到解答!
这是代码,如果有人感兴趣的话。
program GetWMI_USBConnectedInfo;
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
ActiveX,
Variants,
SysUtils,
WbemScripting_TLB, // Using the .pas supplied by the wrapper as it seems to be the XP version of 1.2
magwmi,
magsubs1;
function CheckType(Str: string): boolean;
var
I: Integer;
Str2: string;
begin
Result := False;
for I := 1 to Length(Str) - 1 do if Str[I] = '\' then begin
Str2 := Copy(Str, 1, I-1);
Str2 := LowerCase(Str2);
if (Str2 = 'usbstor') or (Str2 = 'flashmedia') then
Result := True;
Break;
end;
end;
procedure GetUSBDiskDriveInfo;
var
I, II, III: Integer;
Start, Stop, Freq: Int64;
instances, instances2, instances3: integer ;
WmiResults, WmiResults2, WmiResults3: T2DimStrArray ;
errstr: string ;
begin
QueryPerformanceFrequency(Freq);
QueryPerformanceCounter(Start);
try
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'SELECT * FROM Win32_DiskDrive', WmiResults, instances, errstr);
for I := 1 to instances do begin
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'ASSOCIATORS OF {Win32_DiskDrive.DeviceID=''' + WmiResults[I, 12] + '''} WHERE AssocClass = Win32_DiskDriveToDiskPartition', WmiResults2, instances2, errstr);
for II := 1 to instances2 do begin
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'ASSOCIATORS OF {Win32_DiskPartition.DeviceID=''' + WmiResults2[II, 11] + '''} WHERE AssocClass = Win32_LogicalDiskToPartition', WmiResults3, instances3, errstr);
for III := 1 to instances3 do begin
if CheckType(WmiResults[I, 32]) or (Pos('7', WmiResults[I, 3])>0) then begin
Write(WmiResults3[III, 4]);
Write(WmiResults3[III, 39]);
Writeln;
end;
end;
WmiResults3 := nil;
end;
WmiResults2 := nil;
end;
WmiResults := nil;
except
Writeln;
Writeln('error: '+errstr);
end;
Writeln;
QueryPerformanceCounter(Stop);
if (Freq > 0) then
Writeln('It took ' + FormatFloat('0.#0', (Stop-Start) / Freq) + ' seconds to complete.');
end;
begin
try
CoInitialize(nil);
GetUSBDiskDriveInfo;
Readln;
CoUninitialize;
except
on E:Exception do begin
CoUninitialize;
Writeln(E.Classname, ': ', E.Message);
Readln;
end;
end;
end.
还有一件事!
称其为肮脏的黑客或其他什么,但我注释掉了 MagWmiGetInfoEx 的这一部分(magwmi 中的第 298 行)以使其正常工作:
// if Pos ('SELECT', Arg) = 1 then
wmiObjectSet := wmiServices.ExecQuery (Arg, 'WQL', wbemFlagReturnImmediately, nil)
// else
// wmiObjectSet := wmiServices.InstancesOf (Arg, wbemFlagReturnImmediately or
// wbemQueryFlagShallow, nil)
;
Background
I've been using Win32_DiskDrive to find flash memory (usb pens, SD cards, etc.), but after some tests on other computers I noticed that they weren't always discovered. So I am using Win32_LogicalDisk and since it has DriveType I don't have to associate with two classes (e.g. partition) to find first the drives then their drive letters.
The problem is that external harddrives are detected as DriveType 3 (Local Disk) in LogicalDisk and doesn't have 7 (Supports Removable Media) in Capabilities in DiskDrive. So I can't tell the difference between an internal and external drive.
Question
How do I tell the difference between an internal and an external harddrive using LogicalDisk (or DiskDrive if you really have to) or something third.
Alright. The question has been answered!
Here's the code, if anyone is interested.
program GetWMI_USBConnectedInfo;
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
ActiveX,
Variants,
SysUtils,
WbemScripting_TLB, // Using the .pas supplied by the wrapper as it seems to be the XP version of 1.2
magwmi,
magsubs1;
function CheckType(Str: string): boolean;
var
I: Integer;
Str2: string;
begin
Result := False;
for I := 1 to Length(Str) - 1 do if Str[I] = '\' then begin
Str2 := Copy(Str, 1, I-1);
Str2 := LowerCase(Str2);
if (Str2 = 'usbstor') or (Str2 = 'flashmedia') then
Result := True;
Break;
end;
end;
procedure GetUSBDiskDriveInfo;
var
I, II, III: Integer;
Start, Stop, Freq: Int64;
instances, instances2, instances3: integer ;
WmiResults, WmiResults2, WmiResults3: T2DimStrArray ;
errstr: string ;
begin
QueryPerformanceFrequency(Freq);
QueryPerformanceCounter(Start);
try
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'SELECT * FROM Win32_DiskDrive', WmiResults, instances, errstr);
for I := 1 to instances do begin
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'ASSOCIATORS OF {Win32_DiskDrive.DeviceID=''' + WmiResults[I, 12] + '''} WHERE AssocClass = Win32_DiskDriveToDiskPartition', WmiResults2, instances2, errstr);
for II := 1 to instances2 do begin
MagWmiGetInfoEx('.', 'root\CIMV2', '', '', 'ASSOCIATORS OF {Win32_DiskPartition.DeviceID=''' + WmiResults2[II, 11] + '''} WHERE AssocClass = Win32_LogicalDiskToPartition', WmiResults3, instances3, errstr);
for III := 1 to instances3 do begin
if CheckType(WmiResults[I, 32]) or (Pos('7', WmiResults[I, 3])>0) then begin
Write(WmiResults3[III, 4]);
Write(WmiResults3[III, 39]);
Writeln;
end;
end;
WmiResults3 := nil;
end;
WmiResults2 := nil;
end;
WmiResults := nil;
except
Writeln;
Writeln('error: '+errstr);
end;
Writeln;
QueryPerformanceCounter(Stop);
if (Freq > 0) then
Writeln('It took ' + FormatFloat('0.#0', (Stop-Start) / Freq) + ' seconds to complete.');
end;
begin
try
CoInitialize(nil);
GetUSBDiskDriveInfo;
Readln;
CoUninitialize;
except
on E:Exception do begin
CoUninitialize;
Writeln(E.Classname, ': ', E.Message);
Readln;
end;
end;
end.
One more thing!
Call this a dirty hack or whatever, but I commented out this part of MagWmiGetInfoEx (line 298 in magwmi) in order to make it work:
// if Pos ('SELECT', Arg) = 1 then
wmiObjectSet := wmiServices.ExecQuery (Arg, 'WQL', wbemFlagReturnImmediately, nil)
// else
// wmiObjectSet := wmiServices.InstancesOf (Arg, wbemFlagReturnImmediately or
// wbemQueryFlagShallow, nil)
;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我建议坚持使用 WMI。有一个很好的 delphi 包装 可用,其中包含帮助您入门的完整源代码。
入门查询是“SELECT * FROM WIN32_DiskDrive”,它将返回系统中所有磁盘驱动器的所有信息。对于任何 USB 驱动器,PNPDeviceID 字段都应以 USBSTOR 开头。关于返回哪些字段的一个很好的资源是 MSDN 网站。只需将对象转换为查询即可。
如果您要从线程中调用此函数,则可能需要在进行任何调用之前添加初始化 COM (ComInitialize)。在销毁线程之前,调用 ComUnitialize。
I would suggest sticking with WMI. There is a good delphi wrapper available which includes full source to get you started.
A query to get you started is "SELECT * FROM WIN32_DiskDrive" which would return all of the information for all of the disk drives in your system. the PNPDeviceID field should start with USBSTOR for any USB drives. A good resource for what fields come back is the MSDN website. Just translate the objects into queries.
If your going to be calling this from a thread, you may need to add initialize COM (ComInitialize) before making any calls. Before destroying your thread, call ComUnitialialize.
您可以测试这个包; SourceForge 中的 GLibWMI 组件库。它是用于 WMI 的包装。包括 CDiskDriveInfo、CDiskPartitionInfo、CUSBControllerInfo 等可以为您提供帮助的组件。
此外,还包括所有代码。你可以评价一下。
问候。
You can test this package; GLibWMI Components Library in SourceForge. It's a wrapper for work with WMI. Include components like CDiskDriveInfo, CDiskPartitionInfo, CUSBControllerInfo,... that can help you.
Additionally all the code is included. You can evaluate it.
Regards.