Jump to content











Photo

Updated WinRE Extractor

winre winpe windows 8 wimboot

  • Please log in to reply
60 replies to this topic

#26 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:25 PM

That's very kind! I'll check this and let you know. Any chance for a snippet for the delete mode as well?

 

On another note, one more improvement I am considering is running chkdsk before beginning a DoubleSpace compression operation. Some users have had errors, which would have been avoidable altogether had they known that their disk was in an inconsistent state to begin with.

 

I have been playing with the undocumented fmifs.dll API Chkdsk, but at least on Win64 (Windows 8.1) this API does not appear to be playing very nice. Returning cancel from a callback seems to be a no-op (it does not abort the process), and even when the API seems to have returned, the system process still consumes CPU in the background. I have also experienced a lot of lockups and freezes of the system (temporary) while trying to fit the API in. Last but not least, there seems to be an even newer ChkdskEx API, also undocumented, of course.

 

Do you have any experience with these APIs, or know of any resources for the same?



#27 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:31 PM

Here below the shrink example.

function _SHRINK_VOLUME(drive:string;new_size:int64):boolean;
const
ShrinkPrepare = 1;
ShrinkCommit=2;
ShrinkAbort=3;
type
 _SHRINK_VOLUME_INFORMATION =record
   ShrinkRequestType:dword; //SHRINK_VOLUME_REQUEST_TYPES;
   Flags:DWORDLONG;
   NewNumberOfSectors:LONGLONG;
end;
PSHRINK_VOLUME_INFORMATION = ^_SHRINK_VOLUME_INFORMATION;
var
svi:PSHRINK_VOLUME_INFORMATION;
buf:pointer;
hDevice:thandle;
dwBytesReturned:dword;
ret:boolean;
FSCTL_SHRINK_VOLUME:cardinal;
begin
FSCTL_SHRINK_VOLUME:=CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 108, METHOD_BUFFERED, FILE_SPECIAL_ACCESS);
result:=false;

 hDevice := CreateFile( pchar(drive),GENERIC_WRITE or GENERIC_READ,
 FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);

new(svi);
svi^.ShrinkRequestType :=ShrinkPrepare;
svi^.NewNumberOfSectors :=new_size ;
svi^.Flags :=0;
ret:=DeviceIoControl( hDevice,FSCTL_SHRINK_VOLUME,svi,sizeof(_SHRINK_VOLUME_INFORMATION),nil, 0,dwBytesReturned,nil );
if ret=false
  then showmessage('FSCTL_SHRINK_VOLUME failed:'+SysErrorMessage(GetLastError))
  else
  begin
  svi^.ShrinkRequestType :=ShrinkCommit;
  svi^.NewNumberOfSectors :=0;
  svi^.Flags :=0;
  ret:=DeviceIoControl( hDevice,FSCTL_SHRINK_VOLUME,svi,sizeof(_SHRINK_VOLUME_INFORMATION),nil, 0,dwBytesReturned,nil );
  result:=ret;

  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,nil,0,nil,0,dwBytesReturned,nil);

  dwBytesReturned := 0;
  getmem(buf,sizeof(_disk_geometry));
  ret:=DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_DRIVE_SIZE,nil,0,buf,sizeof(_disk_geometry),dwBytesReturned,nil);
  if ret=false then showmessage('IOCTL_DISK_UPDATE_DRIVE_SIZE failed+'+SysErrorMessage(GetLastError));
  freemem(buf);

  end;

closehandle(hdevice);
end;

About fmifs, i am using this one as well from within clonedisk (32 and 64 bits).

I did not (yet) encouter issues there.


  • simonking likes this

#28 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:35 PM

Could I also have an example for the volume delete IOCTL please?

 

On fmifs, would you mind sharing how you've handled the callback functions? Do you call Chkdsk or ChkdskEx?

 

I'll also test CloneDisk now to make sure there's no odd interactions with my current setup.



#29 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:38 PM

What do you mean by delete volume? delete disk layout (disk and all its partitions) ?

 

Have a look in CloneDisk and let me know which functions is of interest for you.



#30 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:39 PM

Actually with the latest x64 build I just downloaded of CloneDisk, I see the same behavior. Looks like we're both basing our code off of the Magenta component; cancelling also failed with CloneDisk.



#31 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:39 PM

I mean, delete a single partition that has been assigned a drive letter (this would be the partition containing the WIMBoot WIM which is unnecessary after the disk has been DoubleSpace'd).



#32 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:42 PM

About fmifs, I use these 2 functions :

 

    Chkdsk := GetProcAddress (MagFmifsib, 'Chkdsk') ;
    FormatEx := GetProcAddress (MagFmifsib, 'FormatEx') ;
 
with the below callbacks
 
function FormatCallback (Command: TCallBackCommand; SubAction: DWORD;
                                             ActionInfo: Pointer): Boolean; stdcall;
 
function ChkDskCallback (Command: TCallBackCommand; SubAction: DWORD;
                                             ActionInfo: Pointer): Boolean; stdcall;
 
 


#33 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:42 PM

Actually with the latest x64 build I just downloaded of CloneDisk, I see the same behavior. Looks like we're both basing our code off of the Magenta component; cancelling also failed with CloneDisk.

 

Good catch : I do indeed use the magenta code :)



#34 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:44 PM

Good catch : I do indeed use the magenta code :)

 

I think their code runs without a hitch on Windows 7 and older, but doesn't seem to be very reliable on Windows 8.x and newer. As you know the FS stuff changed somewhat in Windows 8.x (such as the ability to repair most errors online with chkdsk), regretfully these improvements probably have some side effects that are causing undesirable results in Magenta code.



#35 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:45 PM

I mean, delete a single partition that has been assigned a drive letter (this would be the partition containing the WIMBoot WIM which is unnecessary after the disk has been DoubleSpace'd).

 

I use this IOCTL : IOCTL_DISK_SET_DRIVE_LAYOUT_ex, to handle partitions.

I built a whole partition editor in clonedisk actually based on this IOCTL.


  • simonking likes this

#36 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:45 PM

I use this IOCTL : IOCTL_DISK_SET_DRIVE_LAYOUT_ex, to handle partitions.

I built a whole partition editor in clonedisk actually based on this IOCTL.

 

That's very cool!



#37 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:48 PM

I use this IOCTL : IOCTL_DISK_SET_DRIVE_LAYOUT_ex, to handle partitions.

I built a whole partition editor in clonedisk actually based on this IOCTL.

 

Is there any chance you might already have an API like function _DELETE_VOLUME(drive:string):boolean;, or would this be a lot of refactoring work?



#38 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 05:55 PM

Is there any chance you might already have an API like function _DELETE_VOLUME(drive:string):boolean;, or would this be a lot of refactoring work?

 

Just to be sure we are talking about the same thing, you mean the below right? (delete partition)

 

pxCwjJj.png



#39 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 05:59 PM

Well, I suppose so, yes - Delete Partition on that list.

 

The diskpart equivalent would be:

 

select volume X
delete volume

 

The WMI equivalent would be:

 

function DeletePartition(Drive: String): String;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : Cardinal;
  l: TStringList;
  s: OLEVariant;
  ui32: UInt32;
  i: Integer;
begin
  Result := '';
  try
    CoInitialize(nil);
    try
      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\Microsoft\Windows\Storage', WbemUser, WbemPassword);
      FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM MSFT_Partition','WQL',wbemFlagForwardOnly);
      oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
      while oEnum.Next(1, FWbemObject, iValue) = 0 do
      begin
        l := TStringList.Create;
        VarArrayToArray(FWbemObject.AccessPaths, l);
        for i := 1 to l.Count do
          if AnsiCompareText(l[i -1], IncludeTrailingPathDelimiter(Drive + ':')) = 0 then
          begin
            ui32 := FWbemObject.DeleteObject(s);
            if (ui32 <> 0) and (ui32 <> 2) then // it can return unspec ole error ("2") even when it worked!
            begin
              Result := 'DeleteObject Failed: #' + IntToStr(ui32);
              Exit;
            end;
          end;
          l.Free;
        FWbemObject:=Unassigned;
      end;
    finally
      CoUninitialize;
    end;
  except
    on E:EOleException do
      Result := Result + E.Message + ';' + IntToStr(E.ErrorCode) + ';';
    on E:Exception do
      Result := Result + E.ClassName + ';' + E.Message + ';';
  end;
end;
 

I suppose the only issue is - is a volume equal to a partition at all times?

 

But in my use case I will guarantee that the partition to delete will always have a drive letter assigned, so possibly, minus that drive letter (which gives us a volume), we have a partition - right? In fact, I would be specifying the partition to delete by its volume letter (where allowed by the API I am using).



#40 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 06:00 PM

my code to delete a partition

function _Delete_Part(drive:string;partition_number,partition_count:byte;disk_signature:dword):boolean;
var
info:TGetLengthInformation;
DRIVE_LAYOUT:TDriveLayoutInformation2 ;
hDevice:thandle;
dwBytesReturned:dword;
ret:boolean;
buf:pointer;
StartingOffset:int64;
i:byte;
begin
result:=false;

 hDevice := CreateFile( pchar(drive),GENERIC_WRITE or GENERIC_READ,
     FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);


// dismount first
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,nil,0,nil,0,dwBytesReturned,nil);
//
fillchar(DRIVE_LAYOUT ,sizeof(TDriveLayoutInformation2 ),0);

DRIVE_LAYOUT.PartitionCount :=partition_count;
DRIVE_LAYOUT.Signature :=disk_signature;

for i:=0 to partition_count-1 do DRIVE_LAYOUT.PartitionEntry [i-1].rewritePartition :=false;

DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionNumber :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].StartingOffset.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionLength.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].BootIndicator := false; //active
DRIVE_LAYOUT.PartitionEntry [partition_number-1].RecognizedPartition := TRUE;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].HiddenSectors :=0; // 63;//(arraypartinfn_x[0].StartingOffset.QuadPart - 1)/diskGeometry.BytesPerSector;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionType := 0; //PARTITION_IFS
DRIVE_LAYOUT.PartitionEntry [partition_number-1].rewritePartition :=TRUE;

ret:=DeviceIoControl( hDevice,IOCTL_DISK_SET_DRIVE_LAYOUT,@DRIVE_LAYOUT,sizeof(TDriveLayoutInformation2),nil, 0,dwBytesReturned,nil );
if ret=false
  then showmessage('IOCTL_DISK_SET_DRIVE_LAYOUT failed:'+SysErrorMessage(GetLastError))
  else
  begin
  result:=true;
  //
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_PROPERTIES,nil,0,nil,0,dwBytesReturned,nil);
  end;
//
closehandle(hdevice);
end;

  • simonking likes this

#41 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 06:00 PM

double post - deleted


#42 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 06:02 PM

Well, I suppose so, yes - Delete Partition on that list.

 

The diskpart equivalent would be:

 

select volume X
delete volume

 

The WMI equivalent would be:

 

function DeletePartition(Drive: String): String;
const
  WbemUser            ='';
  WbemPassword        ='';
  WbemComputer        ='localhost';
  wbemFlagForwardOnly = $00000020;
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : Cardinal;
  l: TStringList;
  s: OLEVariant;
  ui32: UInt32;
  i: Integer;
begin
  Result := '';
  try
    CoInitialize(nil);
    try
      FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
      FWMIService   := FSWbemLocator.ConnectServer(WbemComputer, 'root\Microsoft\Windows\Storage', WbemUser, WbemPassword);
      FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM MSFT_Partition','WQL',wbemFlagForwardOnly);
      oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
      while oEnum.Next(1, FWbemObject, iValue) = 0 do
      begin
        l := TStringList.Create;
        VarArrayToArray(FWbemObject.AccessPaths, l);
        for i := 1 to l.Count do
          if AnsiCompareText(l[i -1], IncludeTrailingPathDelimiter(Drive + ':')) = 0 then
          begin
            ui32 := FWbemObject.DeleteObject(s);
            if (ui32 <> 0) and (ui32 <> 2) then // it can return unspec ole error ("2") even when it worked!
            begin
              Result := 'DeleteObject Failed: #' + IntToStr(ui32);
              Exit;
            end;
          end;
          l.Free;
        FWbemObject:=Unassigned;
      end;
    finally
      CoUninitialize;
    end;
  except
    on E:EOleException do
      Result := Result + E.Message + ';' + IntToStr(E.ErrorCode) + ';';
    on E:Exception do
      Result := Result + E.ClassName + ';' + E.Message + ';';
  end;
end;
 

I suppose the only issue is - is a volume equal to a partition at all times?

 

But in my use case I will guarantee that the partition to delete will always have a drive letter assigned, so possibly, minus that drive letter (which gives us a volume), we have a partition - right? In fact, I would be specifying the partition to delete by its volume letter (where allowed by the API I am using).

 

My advice : stay away from WMI (or dotnet or any intermediate layer) whenever you can.

Stick to native win32 api's.

 

Now, regarding your question: I always work with partitions, not volumes.

Wonko would be best to clarify what is a partition / volume :)



#43 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:02 PM

double post - deleted

 

Haha, I've had a few of those today myself, went back and re-edited them :)

 

Thanks - this latest code is exactly what I was needing.

 

I'll let you know how these run under WinRE :)



#44 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:04 PM

My advice : stay away from WMI (or dotnet or any intermediate layer) whenever you can.

Stick to native win32 api's.

 

Of course, I very strongly dislike WMI, .NET, etc. I am a Delphi developer, after all :)

 

Unfortunately in this case the only documented layer was the WMI, so I had to deal with it (a very unpleasant experience).



#45 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:10 PM

A couple quick questions:

 

function _EXTEND_VOLUME(drive:string;new_size:int64):boolean;

 

1) How would I obtain the new_size parameter, where I want it to be the maximum possible size? The WMI objects have something called "GetSupportedSize" which returns the minimum and maximum possible size available for the partition. Apparently I need an equivalent of that on the IOCtl side as well.

 

function _Delete_Part(drive:string;partition_number,partition_count:byte;disk_signature:dword):boolean;

 

2) Once I have identified the drive letter to delete, how do I populate the remainder parameters - are they required if I just want to delete the partition hosting the specified drive letter?



#46 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 06:12 PM

About the delete partition, use the below, less parameters to put in.

 

"Drive" in the form of : \\.\physicaldriveX.

function _Delete_Part_Ex_MBR(drive:string;partition_number:byte):boolean;
var
DRIVE_LAYOUT:TDriveLayoutInformation_Ex2  ;
hDevice:thandle;
dwBytesReturned:dword;
ret:boolean;
i:byte;
begin
result:=false;

 hDevice := CreateFile( pchar(drive),GENERIC_WRITE or GENERIC_READ,
     FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);


// dismount first
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,nil,0,nil,0,dwBytesReturned,nil);
//
fillchar(DRIVE_LAYOUT ,sizeof(TDriveLayoutInformation_Ex2 ),0);

ret:=DeviceIoControl( hDevice,IOCTL_DISK_GET_DRIVE_LAYOUT_EX,nil,0,@DRIVE_LAYOUT,sizeof(TDriveLayoutInformation_ex2),dwBytesReturned,nil );
if ret=true then
begin

DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionStyle :=PARTITION_STYLE_MBR;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionNumber :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].StartingOffset.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionLength.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].Mbr.BootIndicator := false; //active
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.RecognizedPartition := false;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.HiddenSectors :=0; // 63;//(arraypartinfn_x[0].StartingOffset.QuadPart - 1)/diskGeometry.BytesPerSector;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.PartitionType := 0; //PARTITION_IFS
DRIVE_LAYOUT.PartitionEntry [partition_number-1].rewritePartition :=TRUE;

ret:=DeviceIoControl( hDevice,IOCTL_DISK_SET_DRIVE_LAYOUT_ex,@DRIVE_LAYOUT,sizeof(TDriveLayoutInformation_ex2),nil, 0,dwBytesReturned,nil );
if ret=false
  then showmessage('IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed:'+SysErrorMessage(GetLastError))
  else
  begin
  result:=true;
  //
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_PROPERTIES,nil,0,nil,0,dwBytesReturned,nil);
  end;
end
else showmessage('IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed:'+SysErrorMessage(GetLastError));
//
closehandle(hdevice);
end;

  • simonking likes this

#47 erwan.l

erwan.l

    Gold Member

  • Developer
  • 1914 posts
  • Location:Nantes - France
  •  
    France

Posted 13 February 2015 - 06:18 PM

About the shrink function, beware you need to provide the new amount of sectors you want to increase to.

if windows.GetDiskFreeSpace(PChar(current_drive+'\'),SectorsPerCluster,BytesPerSector,NumberOfFreeClusters,TotalNumberOfClusters)=true
  then
  begin
  total_sectors :=(SectorsPerCluster*TotalNumberOfClusters);
  total_bytes:=(SectorsPerCluster * BytesPerSector * int64(TotalNumberOfClusters)) ;
  end
  else
  begin
  showmessage('Could not GetDiskFreeSpace');
  exit;
  end;


frmresize.txtcurrent.Text :=inttostr(total_bytes div 1024 div 1024);

new_total_bytes :=strtoint(frmresize.txtnew.text)*1024*1024;

extra_bytes:=new_total_bytes - total_bytes;   //exemple : 200 to 250 = 50 MB extra

new_total_sectors:=total_sectors+(extra_bytes div BytesPerSector);

bret:=_SHRINK_VOLUME(trim_('\\.\'+CURRENT_DRIVE),new_total_sectors);


  • simonking likes this

#48 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:23 PM

 

About the delete partition, use the below, less parameters to put in.

 

"Drive" in the form of : \\.\physicaldriveX.

function _Delete_Part_Ex_MBR(drive:string;partition_number:byte):boolean;
var
DRIVE_LAYOUT:TDriveLayoutInformation_Ex2  ;
hDevice:thandle;
dwBytesReturned:dword;
ret:boolean;
i:byte;
begin
result:=false;

 hDevice := CreateFile( pchar(drive),GENERIC_WRITE or GENERIC_READ,
     FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);


// dismount first
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,nil,0,nil,0,dwBytesReturned,nil);
//
fillchar(DRIVE_LAYOUT ,sizeof(TDriveLayoutInformation_Ex2 ),0);

ret:=DeviceIoControl( hDevice,IOCTL_DISK_GET_DRIVE_LAYOUT_EX,nil,0,@DRIVE_LAYOUT,sizeof(TDriveLayoutInformation_ex2),dwBytesReturned,nil );
if ret=true then
begin

DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionStyle :=PARTITION_STYLE_MBR;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionNumber :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].StartingOffset.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].PartitionLength.quadpart :=0;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].Mbr.BootIndicator := false; //active
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.RecognizedPartition := false;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.HiddenSectors :=0; // 63;//(arraypartinfn_x[0].StartingOffset.QuadPart - 1)/diskGeometry.BytesPerSector;
DRIVE_LAYOUT.PartitionEntry [partition_number-1].mbr.PartitionType := 0; //PARTITION_IFS
DRIVE_LAYOUT.PartitionEntry [partition_number-1].rewritePartition :=TRUE;

ret:=DeviceIoControl( hDevice,IOCTL_DISK_SET_DRIVE_LAYOUT_ex,@DRIVE_LAYOUT,sizeof(TDriveLayoutInformation_ex2),nil, 0,dwBytesReturned,nil );
if ret=false
  then showmessage('IOCTL_DISK_SET_DRIVE_LAYOUT_EX failed:'+SysErrorMessage(GetLastError))
  else
  begin
  result:=true;
  //
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_PROPERTIES,nil,0,nil,0,dwBytesReturned,nil);
  end;
end
else showmessage('IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed:'+SysErrorMessage(GetLastError));
//
closehandle(hdevice);
end;

 

Thanks! What do I spec as the partition number? Got declares for the TDriveLayoutInformation_Ex2?



#49 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:24 PM

 

About the shrink function, beware you need to provide the new amount of sectors you want to increase to.

if windows.GetDiskFreeSpace(PChar(current_drive+'\'),SectorsPerCluster,BytesPerSector,NumberOfFreeClusters,TotalNumberOfClusters)=true
  then
  begin
  total_sectors :=(SectorsPerCluster*TotalNumberOfClusters);
  total_bytes:=(SectorsPerCluster * BytesPerSector * int64(TotalNumberOfClusters)) ;
  end
  else
  begin
  showmessage('Could not GetDiskFreeSpace');
  exit;
  end;


frmresize.txtcurrent.Text :=inttostr(total_bytes div 1024 div 1024);

new_total_bytes :=strtoint(frmresize.txtnew.text)*1024*1024;

extra_bytes:=new_total_bytes - total_bytes;   //exemple : 200 to 250 = 50 MB extra

new_total_sectors:=total_sectors+(extra_bytes div BytesPerSector);

bret:=_SHRINK_VOLUME(trim_('\\.\'+CURRENT_DRIVE),new_total_sectors);

Thanks, but I don't need shrink at all. Also I don't know about the IOCtl's, but in my testing, shrink generally never works very well (disk fragmentation etc. effectively reduces possible shrink size, even if the partition has plenty of space).



#50 simonking

simonking

    Frequent Member

  • Advanced user
  • 236 posts
  •  
    Australia

Posted 13 February 2015 - 06:25 PM

 

A dirty copy/paste from CloneDisk. If you need a working/complete example (binary+source), i'll put up something later.

function _EXTEND_VOLUME(drive:string;new_size:int64):boolean;
var
buf:pointer;
hDevice:thandle;
dwBytesReturned:dword;
ret:boolean;
begin
result:=false;

 hDevice := CreateFile( pchar(drive),GENERIC_WRITE or GENERIC_READ,
 FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);

ret:=DeviceIoControl( hDevice,FSCTL_EXTEND_VOLUME,@new_size,sizeof(new_size),nil, 0,dwBytesReturned,nil );
result:=ret;
if ret=false
  then showmessage('FSCTL_EXTEND_VOLUME failed:'+SysErrorMessage(GetLastError))
  else
  begin
  dwBytesReturned := 0;
  ret:=DeviceIoControl(hDevice,FSCTL_DISMOUNT_VOLUME,nil,0,nil,0,dwBytesReturned,nil);

  dwBytesReturned := 0;
  getmem(buf,sizeof(_disk_geometry));
  ret:=DeviceIoControl(hDevice,IOCTL_DISK_UPDATE_DRIVE_SIZE,nil,0,buf,sizeof(_disk_geometry),dwBytesReturned,nil);
  if ret=false then showmessage('IOCTL_DISK_UPDATE_DRIVE_SIZE failed+'+SysErrorMessage(GetLastError));
  freemem(buf);

  end;

closehandle(hdevice);
end;

And here I think I need the declaration of _disk_geometry.







Also tagged with one or more of these keywords: winre, winpe, windows 8, wimboot

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users