Delphi - كيفية الحصول على قائمة بمحركات الأقراص الصلبة القابلة للإزالة USB وعصي الذاكرة؟
-
02-10-2019 - |
سؤال
في طلبي (Delphi) ، أحتاج إلى سرد جميع أجهزة تخزين USB. يمكن أن تكون هذه إما عصي ذاكرة فلاش أو محركات التخزين الخارجية.
هناك Jvcl
مكون JvDriveCombo
, ولديه DriveType
الخاصية - المشكلة هي إذا اخترت DriveType := Fixed
ثم بالإضافة إلى محرك الأقراص الخارجي ، يسرد أيضًا محركات الأقراص الداخلية (C:\
, D:\
إلخ). ومع ذلك ، أريد فقط سرد محركات الأقراص الخارجية.
أعتقد أن هناك وظيفة iviceiocontrol (رأيتها على MSDN) ولكن ليس لدي أي فكرة عن كيفية استخدامها.
أتساءل عما إذا كان يمكن لأي شخص مساعدتي في الطريق / الكود المناسب لسرد أجهزة تخزين USB؟
شكرًا.
تعديل:
لقد وجدت للتو بعض رمز النماذج وأقوم بنشره هنا:
uses .... jwawinbase, JwaWinIoctl;
procedure TForm1.Button1Click(Sender: TObject);
var
DriveCmdStr: string;
DriveHandle: THandle;
ADriveLetter: string;
hp: STORAGE_HOTPLUG_INFO;
rlen: DWORD;
begin
ADriveLetter := 'H';
DriveCmdStr := Format('\\.\%s:', [ADriveLetter]);
DriveHandle := CreateFile(PChar(DriveCmdStr), GENERIC_READ, FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if DriveHandle = INVALID_HANDLE_VALUE then
Exit;
DeviceIoControl(DriveHandle, IOCTL_STORAGE_GET_HOTPLUG_INFO, nil, 0, @hp,
SizeOf(hp), @rlen, nil);
CloseHandle(DriveHandle);
if hp.MediaRemovable then
showmessage('media removable');
end;
الآن أود فقط أن أعرف كيفية تعداد جميع رسائل القيادة. ما هي الوظيفة الأكثر كفاءة؟
المحلول
{$MINENUMSIZE 4}
const
IOCTL_STORAGE_QUERY_PROPERTY = $002D1400;
type
STORAGE_QUERY_TYPE = (PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined);
TStorageQueryType = STORAGE_QUERY_TYPE;
STORAGE_PROPERTY_ID = (StorageDeviceProperty = 0, StorageAdapterProperty);
TStoragePropertyID = STORAGE_PROPERTY_ID;
STORAGE_PROPERTY_QUERY = packed record
PropertyId: STORAGE_PROPERTY_ID;
QueryType: STORAGE_QUERY_TYPE;
AdditionalParameters: array [0..9] of AnsiChar;
end;
TStoragePropertyQuery = STORAGE_PROPERTY_QUERY;
STORAGE_BUS_TYPE = (BusTypeUnknown = 0, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre,
BusTypeUsb, BusTypeRAID, BusTypeiScsi, BusTypeSas, BusTypeSata, BusTypeMaxReserved = $7F);
TStorageBusType = STORAGE_BUS_TYPE;
STORAGE_DEVICE_DESCRIPTOR = packed record
Version: DWORD;
Size: DWORD;
DeviceType: Byte;
DeviceTypeModifier: Byte;
RemovableMedia: Boolean;
CommandQueueing: Boolean;
VendorIdOffset: DWORD;
ProductIdOffset: DWORD;
ProductRevisionOffset: DWORD;
SerialNumberOffset: DWORD;
BusType: STORAGE_BUS_TYPE;
RawPropertiesLength: DWORD;
RawDeviceProperties: array [0..0] of AnsiChar;
end;
TStorageDeviceDescriptor = STORAGE_DEVICE_DESCRIPTOR;
function GetBusType(Drive: AnsiChar): TStorageBusType;
var
H: THandle;
Query: TStoragePropertyQuery;
dwBytesReturned: DWORD;
Buffer: array [0..1023] of Byte;
sdd: TStorageDeviceDescriptor absolute Buffer;
OldMode: UINT;
begin
Result := BusTypeUnknown;
OldMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
H := CreateFile(PChar(Format('\\.\%s:', [AnsiLowerCase(Drive)])), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
OPEN_EXISTING, 0, 0);
if H <> INVALID_HANDLE_VALUE then
begin
try
dwBytesReturned := 0;
FillChar(Query, SizeOf(Query), 0);
FillChar(Buffer, SizeOf(Buffer), 0);
sdd.Size := SizeOf(Buffer);
Query.PropertyId := StorageDeviceProperty;
Query.QueryType := PropertyStandardQuery;
if DeviceIoControl(H, IOCTL_STORAGE_QUERY_PROPERTY, @Query, SizeOf(Query), @Buffer, SizeOf(Buffer), dwBytesReturned, nil) then
Result := sdd.BusType;
finally
CloseHandle(H);
end;
end;
finally
SetErrorMode(OldMode);
end;
end;
procedure GetUsbDrives(List: TStrings);
var
DriveBits: set of 0..25;
I: Integer;
Drive: AnsiChar;
begin
List.BeginUpdate;
try
Cardinal(DriveBits) := GetLogicalDrives;
for I := 0 to 25 do
if I in DriveBits then
begin
Drive := Chr(Ord('a') + I);
if GetBusType(Drive) = BusTypeUsb then
List.Add(Drive);
end;
finally
List.EndUpdate;
end;
end;
نصائح أخرى
يمكنك الوصول إلى هذه المعلومات باستخدام WMI. إذا كنت تستخدم SQL هذا ، فيمكنك الوصول إلى معلومات حول الأقراص المثبتة.
select * from Win32_diskdrive where size<>NULL
هذا الرمز يحسب المعلومات حول محركات الأقراص.
procedure TForm1.DoInventario(aWSQL:string; var mmResult:TMemo);
var
Locator:ISWbemLocator;
Services:ISWbemServices;
SObject:ISWbemObject;
ObjSet:ISWbemObjectSet;
Enum:IEnumVariant;
TempObj:OleVariant;
Value:Cardinal;
TS:TStrings;
begin
try
Locator := CoSWbemLocator.Create();
// Conectar con el Servicio de WMI
Services := Locator.ConnectServer(
STR_LOCALHOST, {ordenador local}
STR_CIM2_ROOT, {root}
STR_EMPTY, STR_EMPTY, {usuario y password -en local no son necesarios-}
STR_EMPTY,STR_EMPTY, 0, nil);
// Acceder a los datos
ObjSet := Services.ExecQuery(aWSQL, 'WQL',
wbemFlagReturnImmediately and wbemFlagForwardOnly , nil);
Enum := (ObjSet._NewEnum) as IEnumVariant;
// Hemos encontrado algun objeto?
while (Enum.Next(1, TempObj, Value) = S_OK) do begin
SObject := IUnknown(TempObj) as ISWBemObject;
// encontrado?
if (SObject <> nil) then begin
// Acceder a la propiedad
SObject.Properties_;
// Cargamos las propiedades
TS := TStringList.Create();
try
TS.Add(SObject.GetObjectText_(0));
// lo pasamos al memo
mmResult.Lines.Text := mmResult.Lines.Text + TS.Text;
finally
FreeAndNil(TS);
end;
end;
end;
except
// Recuperar excepciones
end;
end;
يجب عليك إضافة ActiveX و WBEmscripting_tlb (يجب استيراد هذا) في استخداماتك. مع هذا ، يمكنك الوصول إلى جميع معلومات الأقراص.
لإعادة محاكمة الحرف من جميع القرص الذي يمكنك دمجه (يمكن أن تفعل الاسترداد مع نفس الرمز) الوصول إلى الفئات win32_logicalDiskTopartition و Win32_DiskDrive.
select * from Win32_LogicalDiskToPartition
select * from Win32_DiskDrive
إذا قمت بالبحث في WMI ، يمكنك العثور على المزيد من الرموز ذات الصلة.
يعتبر.
لست متأكدًا مما إذا كنت تتطلع فقط إلى تعداد رسائل القيادة؟ يقوم الحلقة أدناه بذلك ، حيث يمر بجميع الرسائل ، بغض النظر عما إذا كان هناك محرك لهذه الرسالة.
أو ، إذا كنت تبحث عن طريقة مختلفة للعثور على محركات أقراص قابلة للإزالة ، فهناك وظيفة لذلك أدناه أيضًا. (قد يكون لك أفضل ...) من المستغرب ، في الاختبار الخاص بي ، لا تعتبر windows.getDrivetype محركات الأقراص المضغوطة قابلة للإزالة. يتم وضع علامة على محركات أقراص USB على أنها قابلة للإزالة ، كما يتوقع المرء.
Function RemovableDrive(Drive: char): Boolean;
begin
Result := (Windows.GetDriveType(PChar(Drive + ':\')) = Windows.Drive_Removable);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Drive: Char;
begin
for Drive := 'A' to 'Z' do
Memo1.Lines.Add('Drive: ' + Drive + ' is ' + BoolToStr(RemovableDrive(Drive), TRUE));
end;