1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
| unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, Cfg, CfgMgr32, JwaWinBase, JwaWinIoCtl, SetupApi ;
type
TForm1 = class(TForm)
BitBtn1: TBitBtn;
testt: TLabel;
Dr: TEdit; // 'F:'
procedure BitBtn1Click(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
procedure DisplaySystemError;
function GetDeviceNumber(Drive : String) : Cardinal;
function NomDos(Drive : String) : String;
function GetDrivesDevInstByDeviceNumber(DeviceNom,DriveType : Cardinal; DriveName : String) : DEVINST;
end;
type
_PNP_VETO_TYPE = (
PNP_VetoTypeUnknown,
PNP_VetoLegacyDevice,
PNP_VetoPendingClose,
PNP_VetoWindowsApp,
PNP_VetoWindowsService,
PNP_VetoOutstandingOpen,
PNP_VetoDevice,
PNP_VetoDriver,
PNP_VetoIllegalDeviceRequest,
PNP_VetoInsufficientPower,
PNP_VetoNonDisableable,
PNP_VetoLegacyDriver);
PNP_VETO_TYPE = _PNP_VETO_TYPE;
PPNP_VETO_TYPE = ^PNP_VETO_TYPE;
TPnpVetoType = _PNP_VETO_TYPE;
PPnpVetoType = PPNP_VETO_TYPE;
var
Form1: TForm1;
implementation
{$R *.dfm}
{
Obtention du numéro réel? de volume à ejecter
}
function TForm1.GetDrivesDevInstByDeviceNumber(DeviceNom,DriveType : Cardinal; DriveName : String) : DEVINST;
var isFloppy : Boolean;
StorageGUID : TGUID;
PnPHandle: HDEVINFO;
DevData: TSPDevInfoData;
DeviceInterfaceData: TSPDeviceInterfaceData;
FunctionClassDeviceData: PSPDeviceInterfaceDetailData;
Success: LongBool;
Devn : Integer;
BytesReturned: Cardinal;
Hdrive : THandle;
sdn : STORAGE_DEVICE_NUMBER;
begin
result:=0;
isFloppy:=(Pos('\\Floppy',DriveName)>0);
case DriveType of
DRIVE_REMOVABLE :
if isFloppy then StorageGuid:=GUID_DEVINTERFACE_FLOPPY
else StorageGuid:=GUID_DEVINTERFACE_DISK;
DRIVE_FIXED : StorageGuid:=GUID_DEVINTERFACE_DISK;
DRIVE_CDROM : StorageGuid:=GUID_DEVINTERFACE_CDROM;
else exit;
end;
Result := 0;
PnPHandle := SetupDiGetClassDevs(@StorageGUID, nil, 0, DIGCF_PRESENT or DIGCF_DEVICEINTERFACE);
if PnPHandle = Pointer(INVALID_HANDLE_VALUE) then
begin
ShowMessage('erreur');
exit;
end;
Devn := 0;
repeat
DeviceInterfaceData.cbSize := SizeOf(TSPDeviceInterfaceData);
Success := SetupDiEnumDeviceInterfaces(PnPHandle, nil, StorageGUID, Devn, DeviceInterfaceData);
if Success then
begin
DevData.cbSize := SizeOf(DevData);
BytesReturned := 0;
SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData, nil, 0, BytesReturned, @DevData);
if (BytesReturned <> 0) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
FunctionClassDeviceData := AllocMem(BytesReturned);
try
FunctionClassDeviceData.cbSize := SizeOf(TSPDeviceInterfaceDetailData);
if SetupDiGetDeviceInterfaceDetail(PnPHandle, @DeviceInterfaceData,
FunctionClassDeviceData, BytesReturned, BytesReturned, @DevData) then
begin
// open the disk or cdrom or floppy
HDrive:=CreateFile(FunctionClassDeviceData.DevicePath, 0, FILE_SHARE_READ OR FILE_SHARE_WRITE,nil, OPEN_EXISTING, 0, 0);
if (HDrive<>INVALID_HANDLE_VALUE ) then
begin
// get its device number
Success := DeviceIoControl(HDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, nil, 0, @sdn, sizeof(sdn), @BytesReturned, nil);
if (Success) AND (DeviceNom=sdn.DeviceNumber) then
begin
// match the given device number with the one of the current device
CloseHandle(HDrive);
SetupDiDestroyDeviceInfoList(PnpHandle);
Result:=DevData.DevInst;
end;
CloseHandle(HDrive);
end;
end;
finally
FreeMem(FunctionClassDeviceData);
end;
end;
end;
Inc(Devn);
until not Success;
SetupDiDestroyDeviceInfoList(PnPHandle);
end;
{
Nom Dos du Volume (par exemple \device\floppy0)
apparement ce serait le seul moyen de savoir si c'est un floppy ou USB
}
function TForm1.NomDos(Drive: string) : String;
var Nom : String[60];
begin
Nom:='';
QueryDosDevice(Pchar(Drive),@Nom,60);
result:=Copy(nom,0,pos(#0,nom)-1);
end;
{
ACTION
}
procedure TForm1.BitBtn1Click(Sender: TObject);
var dtype,dnumber,retf : Cardinal ; // drivetype , drivenumber , retour de fonction
i : Word; // essais 1 à 3
nd : String; // nom dos du drive (permet de distinguer un floppy d'un USB)
DIParent : DEVINST; // identifiant du parent
ejecte : Boolean;
VetoName : array[0..256] of Char;
VetoType : TPnpVetoType;
begin
VetoType := PNP_VetoTypeUnknown;
dtype := GetDriveType(PChar(Dr.Text+'\'));
dnumber := GetDeviceNumber(Dr.Text);
nd:=NomDos(dr.text);
LoadSetupApi;
LoadConfigManagerApi;
dnumber:=GetDrivesDevInstByDeviceNumber(Dnumber,Dtype,nd);
if dnumber>0 then
begin
//****** ici il doit certainement y avoir un test manquant
//****** car pour un CD pas de parent ???
// Obtenir le parent, i.e. USB bridge, port SATA, Canal IDE avec 2 lecteurs!
DIParent:= 0;
CM_Get_Parent(DIParent,dnumber, 0);
for i:=1 to 3 do // au cas où cela ne marche pas du premier coup.
begin
VetoName[0] := '0';
//retf:= CM_Request_Device_EjectW(DIParent,nil, nil, 0, 0); // avec message (W2K, Vista) ou bulle (XP)
retf:= CM_Request_Device_EjectW(DIParent,@VetoType,@VetoName, MAX_PATH, 0); // sans message (W2K, Vista) ou bulle (XP) et indique type de veto a l'ejection
ejecte:=(retf=CR_SUCCESS) ;
if (ejecte) then break else Sleep(500); // Attendre avant de retenter!
end;
end;
UnloadConfigManagerApi;
UnloadSetupApi;
end;
{
Obtention du Numéro du Volume
}
function TForm1.GetDeviceNumber(Drive : String) : Cardinal;
var R : LongBool; // retour de fonction
HVolume : THandle; // Hande du volume
sdn : STORAGE_DEVICE_NUMBER; // n° du volume
dw : DWORD;
{Obtention du Handle du volume}
function GetHVolume(Drive : String) : THandle;
var CheminVolume : String;
begin
CheminVolume:='\\.\'+Drive;
Result:=CreateFile(Pchar(CheminVolume), 0,
FILE_SHARE_READ OR FILE_SHARE_WRITE,
Nil, OPEN_EXISTING, 0, 0);
end;
begin
HVolume:=GetHVolume(Drive);
R := DeviceIoControl(hVolume,
IOCTL_STORAGE_GET_DEVICE_NUMBER,
Nil, 0, @sdn, sizeof(sdn),
@dw, nil);
if R then Result := sdn.DeviceNumber
else begin
result:=0;
DisplaySystemError;
end;
CloseHandle(HVolume);
end;
{
Affichage de l'erreur
}
Procedure TForm1.DisplaySystemError; // merci à Eric Boisvert (DupDisk)
Var
ErrorCode: Integer;
Buf: Array[0..1023] Of Char;
ErrMsg: String;
result: DWord;
Begin
//== Obtient un message lisible de l'erreur... ==
ErrorCode := GetLastError;
FillChar(Buf, SizeOf(Buf), #0);
result := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, Nil, ErrorCode
, 0, Buf, sizeof(Buf), Nil);
If result <> 0 Then
Begin
ErrMsg := Trim(Buf);
Raise Exception.Create(buf);
End;
End;
end. |
Partager