如何知道两个分区是否在没有WMI的物理硬盘中?

我有这些分区(在Windows中)例如:

Hard Disk 1 - Partition C, Partition D Hard Disk 2 - Partition E 

有没有什么办法用程序语言来知道例如分区C和分区D是否在没有WMI的物理硬盘上?

我不想使用WMI,因为它很慢 – 在这个例子中,我花了0.5秒。 我需要它快速。

谢谢。

Solutions Collecting From Web of "如何知道两个分区是否在没有WMI的物理硬盘中?"

我不知道任何其他管理方式来获取磁盘分区信息。 您可以使用C#中的P / Invoke使用Win32 API。 但是,除非绝对必要,否则不应该这样做。

您需要的Win32函数称为DeviceIoControl()。 API文档可以在http://msdn.microsoft.com/en-us/library/aa363216(VS.85).aspx找到。 使用控制代码IOCTL_STORAGE_GET_DEVICE_NUMBER调用DeviceIoControl(),您将获得给定分区设备句柄的物理磁盘驱动器。 分区的设备句柄可以使用CreateFile()API进行检索。

但是,使用DeviceIoControl()非常麻烦,而且您很可能必须为32位和64位版本的Windows制作不同的版本。

要检索所有的分区,你可以像这样使用托管代码System.IO.DriveInfo:

 var x = from di in DriveInfo.GetDrives() where (di.DriveType == DriveType.Fixed) select di; foreach (DriveInfo di in x) { // Call DeviceIoControl() using the partition name from di.Name and the IOCTL_STORAGE_GET_DEVICE_NUMBER control code to retrieve the physical disk } 

看来pinvoke.net有一些C#签名。

这段Delphi代码应该很容易地转换成C#使用P / Invoke调用,并且完全按照你的意思。 (以及更多)导入和调用DeviceIOControl。

 type STORAGE_QUERY_TYPE = DWORD; const PropertyStandardQuery = 0; // Retrieves the descriptor PropertyExistsQuery = 1; // Used to test whether the descriptor is supported PropertyMaskQuery = 2; // Used to retrieve a mask of writeable fields in the descriptor type STORAGE_PROPERTY_ID = DWORD; const StorageDeviceProperty = 0; // Query structure - additional parameters for specific queries can follow the header type STORAGE_PROPERTY_QUERY = packed record PropertyId: STORAGE_PROPERTY_ID; QueryType: STORAGE_QUERY_TYPE; AdditionalParameters: Longword; end; const FILE_DEVICE_MASS_STORAGE = $0000002d; IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE; FILE_ANY_ACCESS = 0; METHOD_BUFFERED = 0; IOCTL_STORAGE_QUERY_PROPERTY = ( IOCTL_STORAGE_BASE shl 16 ) or ( $500 shl 2 ) or METHOD_BUFFERED or ( FILE_ANY_ACCESS shl 14 ); type STORAGE_BUS_TYPE = DWORD; const BusTypeUnknown = $00; BusTypeScsi = $01; BusTypeAtapi = $02; BusTypeAta = $03; BusType1394 = $04; BusTypeSsa = $05; BusTypeFibre = $06; BusTypeUsb = $07; BusTypeRAID = $08; BusTypeiScsi = $09; BusTypeSas = $0A; BusTypeSata = $0B; BusTypeSd = $0C; BusTypeMmc = $0D; BusTypeVirtual = $0E; BusTypeFileBackedVirtual = $0F; BusTypeMax = $10; BusTypeMaxReserved = $7F; type STORAGE_DEVICE_DESCRIPTOR = packed record // sizeof( STORAGE_DEVICE_DESCRIPTOR ) Version: DWORD; // Total size of the descriptor, including the space for additional data and id strings Size: DWORD; // The SCSI-2 device type DeviceType: BYTE; // The SCSI-2 device type modifier (if any) - this may be zero DeviceTypeModifier: BYTE; // Flag indicating whether the device's media (if any) is removable. This field should be ignored for media-less devices RemovableMedia: BOOLEAN; // Flag indicating whether the device can support multiple outstanding commands. // The actual synchronization in this case is the responsibility of the port driver. CommandQueueing: BOOLEAN; // Byte offset to the zero-terminated ascii string containing the device's vendor id string. // For devices with no such ID this will be zero VendorIdOffset: DWORD; // Byte offset to the zero-terminated ascii string containing the device's product id string. // For devices with no such ID this will be zero ProductIdOffset: DWORD; // Byte offset to the zero-terminated ascii string containing the device's product revision string. // For devices with no such string this will be zero ProductRevisionOffset: DWORD; // Byte offset to the zero-terminated ascii string containing the device's serial number. // For devices with no serial number this will be zero SerialNumberOffset: DWORD; // Contains the bus type (as defined above) of the device. It should be used to interpret the raw device // properties at the end of this structure (if any) BusType: STORAGE_BUS_TYPE; // The number of bytes of bus-specific data which have been appended to this descriptor RawPropertiesLength: DWORD; // Place holder for the first byte of the bus specific property data RawDeviceProperties: DWORD; end; PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR; STORAGE_DEVICE_NUMBER = packed record DeviceType: LONGWORD; // DEVICE_TYPE DeviceNumber: ULONG; PartitionNumber: ULONG; end; PSTORAGE_DEVICE_NUMBER = ^STORAGE_DEVICE_NUMBER; const IOCTL_STORAGE_GET_DEVICE_NUMBER = ( IOCTL_STORAGE_BASE shl 16 ) or ( $420 shl 2 ) or METHOD_BUFFERED or ( FILE_ANY_ACCESS shl 14 ); type TDriveBusType = ( dbtUnknown, dbtScsi, dbtAtapi, dbtAta, dbt1394, dbtSsa, dbtFibre, dbtUsb, dbtRAID, dbtiScsi, dbtSas, dbtSata, dbtSd, dbtMmc, dbtVirtual, dbtFileBackedVirtual ); TDeviceType = ( dtUnknown ); // todo: implement TDriveInfoResult = record // Drive: string; VendorID: string; ProductID: string; Revision: string; Serial: string; BusType: TDriveBusType; Removable: Boolean; // DeviceType: TDeviceType; DeviceNumber: Integer; Partition: Integer; end; const BusTypes: array [ TDriveBusType ] of AnsiString = ( 'Unknown', 'Scsi', 'Atapi', 'Ata', '1394', 'Ssa', 'Fibre', 'Usb', 'RAID', 'iScsi', 'Sas', 'Sata', 'Sd', 'Mmc', 'Virtual', 'FileBackedVirtual' ); function DriveInfo( const Drive: string ): TDriveInfoResult; var H: THandle; N: Longword; Query: STORAGE_PROPERTY_QUERY; Buffer: array [ 0..1023 ] of Byte; Desc: PSTORAGE_DEVICE_DESCRIPTOR; S, X: AnsiString; i: Integer; Info: PSTORAGE_DEVICE_NUMBER; begin // Clear out old data Result.Drive := Drive; Result.VendorID := ''; Result.ProductID := ''; Result.Revision := ''; Result.Serial := ''; // Open drive for querying H := CreateFile( PChar( '\\.\' + Drive ), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 ); if H = INVALID_HANDLE_VALUE then Exit; try // Query device. FillChar( Query, sizeof( Query ), 0 ); Query.PropertyId := StorageDeviceProperty; Query.QueryType := PropertyStandardQuery; FillChar( Buffer, sizeof( Buffer ), 0 ); if not DeviceIoControl ( H, IOCTL_STORAGE_QUERY_PROPERTY, @Query, sizeof( Query ), @Buffer, sizeof( Buffer ), N, nil ) then Exit; // Sanity checks. if N < sizeof( STORAGE_DEVICE_DESCRIPTOR ) then Exit; Desc := @Buffer; if Desc^.Version < sizeof( STORAGE_DEVICE_DESCRIPTOR ) then Exit; // And obtain result. if Desc^.VendorIdOffset <> 0 then Result.VendorID := Trim( PAnsiChar( @Buffer[ Desc^.VendorIdOffset ] ) ); if Desc^.ProductIdOffset <> 0 then Result.ProductID := Trim( PAnsiChar( @Buffer[ Desc^.ProductIdOffset ] ) ); if Desc^.ProductRevisionOffset <> 0 then Result.Revision := Trim( PAnsiChar( @Buffer[ Desc^.ProductRevisionOffset ] ) ); if Desc^.SerialNumberOffset <> 0 then begin // The serial number is encoded in HEX and with each two characters encoded swapped. ER ABCD -> BADC -> '42414443' S := PAnsiChar( @Buffer[ Desc^.SerialNumberOffset ] ); X := ''; for i := 1 to Length( S ) do if S[ i ] in [ '0'..'9', 'A'..'F', 'a'..'f' ] then X := X + S[ i ]; S := ''; SetLength( S, Length( X ) div 2 ); // i = 1,2,3,4,5,6 -> 3,1,7,5,11,9 for i := 1 to Length( S ) do S[ i ] := AnsiChar( StrToInt( '$' + Copy( X, 1 + ( ( ( i - 1 ) div 2 ) * 4 ) + 2 * ( i and 1 ), 2 ) ) ); Result.Serial := Trim( S ); end; if Desc^.BusType <= Longword( High( TDriveBusType ) ) then Result.BusType := TDriveBusType( Desc^.BusType ); Result.Removable := Desc^.RemovableMedia; System.FillChar( Buffer, sizeof( Buffer ), 0 ); if DeviceIoControl ( H, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @Buffer, sizeof( Buffer ), N, nil ) then begin Info := @Buffer; Result.DeviceType := dtUnknown; Result.DeviceNumber := Integer( Info^.DeviceNumber ); Result.Partition := Integer( Info^.PartitionNumber ); end; finally CloseHandle( H ); end; end; function GetLogicalDrives(): TStringDynArray; var Buffer: array [ 0..1023 ] of Char; N, i: Integer; begin SetLength( Result, 0 ); N := GetLogicalDriveStrings( High( Buffer ), @Buffer ); if N >= Length( Buffer ) then raise Exception.Create( 'Oops' ); i := 0; while ( i <= N ) and ( Buffer[ i ] <> #0 ) do begin SetLength( Result, Length( Result ) + 1 ); Result[ High( Result ) ] := PChar( @( Buffer[ i ] ) ); Inc( i, Length( Result[ High( Result ) ] ) + 1 ); end; end; function RemoveTrailingPathDelimiter( const Path: string ): string; begin if ( Length( Path ) = 0 ) or ( Path[ Length( Path ) ] <> PathDelim ) then Result := Path else Result := Copy( Path, 1, Length( Path ) - 1 ); end; procedure TForm7.Button1Click( Sender: TObject ); var Drives: TStringDynArray; Drive: string; Res: TDriveInfoResult; begin Memo1.Lines.BeginUpdate(); try Memo1.Lines.Clear(); Drives := GetLogicalDrives(); for Drive in Drives do begin Res := DriveInfo( RemoveTrailingPathDelimiter( Drive ) ); Memo1.Lines.Add( 'DRIVE: ' + Drive ); Memo1.Lines.Add( 'VendorID = ' + Res.VendorID ); Memo1.Lines.Add( 'ProductID = ' + Res.ProductID ); Memo1.Lines.Add( 'Revision = ' + Res.Revision ); Memo1.Lines.Add( 'Serial = ' + Res.Serial ); Memo1.Lines.Add( 'BusType = ' + BusTypes[ Res.BusType ] ); Memo1.Lines.Add( 'Removable = ' + IntToStr( Ord( Res.Removable ) ) ); // device type. Memo1.Lines.Add( 'Device = ' + IntToStr( Res.DeviceNumber ) ); Memo1.Lines.Add( 'Partition = ' + IntToStr( Res.Partition ) ); Memo1.Lines.Add( '' ); end; finally Memo1.Lines.EndUpdate(); end; end;