mapping partitions starting from PhysicalDrive
I want to map all partitions from all drives in Windows (the ones who are not mapped already). I mean I want to assign to each of them drive letters. I know that you can do it with FindFirstVolume, FindNextVolume, FindVolumeClose but there are situations where you can't use them. I tried with Que开发者_开发百科ryDosDevice, same thing.
The idea is to start from \.\PhysicalDrive[n], find out the partitions and map them. I know it's doable because I saw a program that can do that. But I don't like it, because it maps hidden partitions also.
Does someone know a way...? Thank you.
I did it :) I made a program who adds or removes drive letters when it's started - if one or more storage drives were added or removed from the computer:
program MapDrives;
uses Windows;
type
TPARTITION_INFORMATION = record
StartingOffset: _LARGE_INTEGER; //TLargeInteger;
PartitionLength: _LARGE_INTEGER; //TLargeInteger;
HiddenSectors: DWORD;
PartitionNumber: DWORD;
PartitionType: BYTE;
BootIndicator: BOOLEAN;
RecognizedPartition: BOOLEAN;
RewritePartition: BOOLEAN;
end;
function IntToStr(Value: Integer): string;
begin
if Value < 10 then
Result := Char(Value + 48)
else
Result := Char(Value div 10 + 48) + Char(Value + 48);
end;
function GetNextAvailableLetter: AnsiChar;
var Drives, mask: DWord;
i: Integer;
begin
Drives := GetLogicalDrives;
mask := 4;
Result := 'Z';
for i := 3 to 26 do //C to Z
begin
if mask and Drives = 0 then
begin
Result := AnsiChar(64 + i);
Exit;
end;
mask := mask shl 1;
end;
end;
const IOCTL_DISK_GET_PARTITION_INFO = $0074004;
var i, j, k: Integer;
H: THandle;
dwBytesReturned: DWORD;
BreakCycle, DoMount: Boolean;
NextLetter: AnsiChar;
PartitionInformation: TPARTITION_INFORMATION;
PartitionsInformation: array of TPARTITION_INFORMATION;
Drives, mask: DWord;
OldMode: UINT;
begin
OldMode := SetErrorMode(SEM_FAILCRITICALERRORS); //so it shouldn't ask to insert CD or card
//gets informations about already mounted partitions
SetLength(PartitionsInformation, 0);
Drives := GetLogicalDrives;
mask := 4;
for i := 3 to 26 do //C to Z
begin
if mask and Drives <> 0 then
begin
H := CreateFile(PAnsiChar('\\.\' + Char(64 + i) + ':'), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if H <> INVALID_HANDLE_VALUE then
begin
SetLength(PartitionsInformation, Length(PartitionsInformation) + 1);
DeviceIoControl(H, IOCTL_DISK_GET_PARTITION_INFO, nil, 0, @PartitionsInformation[High(PartitionsInformation)], SizeOf(TPARTITION_INFORMATION), dwBytesReturned, nil);
CloseHandle(H);
end
else //removes unaccessible drives
DefineDosDevice(DDD_REMOVE_DEFINITION or DDD_RAW_TARGET_PATH, PAnsiChar(string(Char(64 + i) + ':')), nil);
end;
mask := mask shl 1;
end;
for i := 0 to 99 do
begin
H := CreateFile(PAnsiChar('\\.\PhysicalDrive' + IntToStr(i)), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if H = INVALID_HANDLE_VALUE then //no more hdd's
Break;
CloseHandle(H);
for j := 1 to 20 do
begin
BreakCycle := False;
NextLetter := GetNextAvailableLetter;
DefineDosDevice(DDD_RAW_TARGET_PATH or DDD_NO_BROADCAST_SYSTEM, PAnsiChar(string(NextLetter + ':')), PAnsiChar('\Device\Harddisk' + IntToStr(i) + '\Partition' + IntToStr(j)));
DoMount := True;
H := CreateFile(PAnsiChar('\\.\' + NextLetter + ':'), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if H = INVALID_HANDLE_VALUE then //no more partitions
BreakCycle := True
else
begin
PartitionInformation.PartitionType := 0;
DeviceIoControl(H, IOCTL_DISK_GET_PARTITION_INFO, nil, 0, @PartitionInformation, SizeOf(TPARTITION_INFORMATION), dwBytesReturned, nil);
DoMount := PartitionInformation.PartitionType in [0, 1, 6, 7, 11, 12, 114];
CloseHandle(H);
end;
if DoMount then
begin
for k := 0 to High(PartitionsInformation) do //compare with already mounted partitions
if (PartitionsInformation[k].StartingOffset.LowPart = PartitionInformation.StartingOffset.LowPart) and
(PartitionsInformation[k].StartingOffset.HighPart = PartitionInformation.StartingOffset.HighPart) and
(PartitionsInformation[k].StartingOffset.QuadPart = PartitionInformation.StartingOffset.QuadPart) and
(PartitionsInformation[k].PartitionLength.LowPart = PartitionInformation.PartitionLength.LowPart) and
(PartitionsInformation[k].PartitionLength.HighPart = PartitionInformation.PartitionLength.HighPart) and
(PartitionsInformation[k].PartitionLength.QuadPart = PartitionInformation.PartitionLength.QuadPart) and
(PartitionsInformation[k].HiddenSectors = PartitionInformation.HiddenSectors) and
(PartitionsInformation[k].PartitionType = PartitionInformation.PartitionType) and
(PartitionsInformation[k].BootIndicator = PartitionInformation.BootIndicator) and
(PartitionsInformation[k].RecognizedPartition = PartitionInformation.RecognizedPartition) then
Break;
DoMount := k > High(PartitionsInformation);
end;
DefineDosDevice(DDD_REMOVE_DEFINITION or DDD_RAW_TARGET_PATH, PAnsiChar(string(NextLetter + ':')), nil);
if (not BreakCycle) and DoMount then
DefineDosDevice(DDD_RAW_TARGET_PATH, PAnsiChar(string(NextLetter + ':')), PAnsiChar('\Device\Harddisk' + IntToStr(i) + '\Partition' + IntToStr(j)));
if BreakCycle then
Break;
end;
end;
SetErrorMode(OldMode); //restore original mode
end.
On the computers that I mentioned it works perfectly.
Thank you guys for all your ideas which helped me to make this code.
If someone notice some bugs or has any good ideas about how to improve it, I'll be glad to fix/implement them.
You can do This using WMI.
In library GLibWMI (http://neftali.clubdelphi.com or SourceForge) you can find the TDiskPartitionInfo and TDiskDriveInfo.
The first can give you the created partitions and all of your properties.
Test the Generic Sample and check the results. In an partitioned disk like this:
You obtains 4 instantes with the properties of 4 partitions like this:
The library it's totally free and source is avaible. Check the samples.
You can find some other codes to access this information using WMI. If you want use another, you can search for "WMI and Win32_DiskPartition Class" (Link doc).
Excuse-me for mistakes with English.
Regards
Maybe my Change DriveLetter commandline tool can help you, at least you can start it with commandline parameters and see if it lists all volumes you expect.
This link might also be useful: Converting a volume name to a devicename
精彩评论