310
GetDrivesDevInstByDeviceNumber(long DeviceNumber,
311
UINT DriveType, LPWSTR szDosDeviceName)
315
DWORD dwIndex, dwBytesReturned;
318
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
321
STORAGE_DEVICE_NUMBER sdn;
322
SP_DEVICE_INTERFACE_DATA spdid;
323
SP_DEVINFO_DATA spdd;
327
IsFloppy = (wcsstr(szDosDeviceName, L"\\Floppy") != NULL); // is there a better way?
330
case DRIVE_REMOVABLE:
332
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
334
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
338
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
341
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
344
PyErr_SetString(PyExc_ValueError, "Invalid drive type");
348
// Get device interface info set handle
349
// for all devices attached to system
350
hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
351
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
353
if (hDevInfo == INVALID_HANDLE_VALUE) {
354
PyErr_SetString(PyExc_ValueError, "Invalid handle value");
358
// Retrieve a context structure for a device interface
359
// of a device information set.
364
pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
365
spdid.cbSize = sizeof(spdid);
368
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
369
guid, dwIndex, &spdid);
375
SetupDiGetDeviceInterfaceDetail(hDevInfo,
376
&spdid, NULL, 0, &dwSize, NULL);
378
if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
379
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
381
ZeroMemory((PVOID)&spdd, sizeof(spdd));
382
spdd.cbSize = sizeof(spdd);
385
SetupDiGetDeviceInterfaceDetail(hDevInfo, &
390
hDrive = CreateFile(pspdidd->DevicePath,0,
391
FILE_SHARE_READ | FILE_SHARE_WRITE,
392
NULL, OPEN_EXISTING, 0, NULL);
393
if ( hDrive != INVALID_HANDLE_VALUE ) {
395
res = DeviceIoControl(hDrive,
396
IOCTL_STORAGE_GET_DEVICE_NUMBER,
397
NULL, 0, &sdn, sizeof(sdn),
398
&dwBytesReturned, NULL);
400
if ( DeviceNumber == (long)sdn.DeviceNumber ) {
402
SetupDiDestroyDeviceInfoList(hDevInfo);
413
SetupDiDestroyDeviceInfoList(hDevInfo);
414
PyErr_SetString(PyExc_ValueError, "Invalid device number");
422
eject_drive_letter(WCHAR DriveLetter) {
423
LPWSTR szRootPath = L"X:\\",
424
szDevicePath = L"X:",
425
szVolumeAccessPath = L"\\\\.\\X:";
426
WCHAR szDosDeviceName[MAX_PATH];
427
long DeviceNumber, res, tries;
429
STORAGE_DEVICE_NUMBER sdn;
430
DWORD dwBytesReturned;
435
PNP_VETO_TYPE VetoType;
436
WCHAR VetoNameW[MAX_PATH];
438
DEVINST DevInstParent;
440
szRootPath[0] = DriveLetter;
441
szDevicePath[0] = DriveLetter;
442
szVolumeAccessPath[4] = DriveLetter;
446
hVolume = CreateFile(szVolumeAccessPath, 0,
447
FILE_SHARE_READ | FILE_SHARE_WRITE,
448
NULL, OPEN_EXISTING, 0, NULL);
449
if (hVolume == INVALID_HANDLE_VALUE) {
450
PyErr_SetString(PyExc_ValueError, "Invalid handle value for drive letter");
455
res = DeviceIoControl(hVolume,
456
IOCTL_STORAGE_GET_DEVICE_NUMBER,
457
NULL, 0, &sdn, sizeof(sdn),
458
&dwBytesReturned, NULL);
460
DeviceNumber = sdn.DeviceNumber;
462
CloseHandle(hVolume);
464
if ( DeviceNumber == -1 ) {
465
PyErr_SetString(PyExc_ValueError, "Can't find drive number");
469
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
471
PyErr_SetString(PyExc_ValueError, "Can't find dos device");
475
DriveType = GetDriveType(szRootPath);
477
DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,
478
DriveType, szDosDeviceName);
479
if (DevInst == 0) return FALSE;
486
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
488
for ( tries = 0; tries < 3; tries++ ) {
491
res = CM_Request_Device_EjectW(DevInstParent,
492
&VetoType, VetoNameW, MAX_PATH, 0);
494
bSuccess = (res==CR_SUCCESS &&
495
VetoType==PNP_VetoTypeUnknown);
500
Sleep(500); // required to give the next tries a chance!
502
if (!bSuccess) PyErr_SetString(PyExc_ValueError, "Failed to eject drive after three tries");
507
winutil_eject_drive(PyObject *self, PyObject *args) {
510
if (!PyArg_ParseTuple(args, "c", &DriveLetter)) return NULL;
512
if (!eject_drive_letter((WCHAR)DriveLetter)) return NULL;
309
517
PSP_DEVICE_INTERFACE_DETAIL_DATA
310
518
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,