void lockUsb(char* letter) { try { char szRootPath[16] = { 0 }; sprintf(szRootPath, "%s:\\", letter); //char szRootPath[] = "D:\\"; // "X:\" -> for GetDriveType //char szDevicePath[] = "D:"; // "X:" -> for QueryDosDevice char szDevicePath[16] = { 0 }; sprintf(szDevicePath, "%s:", letter); //char szVolumeAccessPath[] = "\\\\.\\D:"; // "\\.\X:" -> to open the volume char szVolumeAccessPath[16] = { 0 }; sprintf(szVolumeAccessPath, "\\\\.\\%s:", letter); //szVolumeAccessPath[4] = DriveLetter; long DeviceNumber = -1; // open the storage volume HANDLE hVolume = CreateFileA(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL); if (hVolume == INVALID_HANDLE_VALUE) { return; } // get the volume's device number STORAGE_DEVICE_NUMBER sdn; DWORD dwBytesReturned = 0; long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL); if (res) { DeviceNumber = sdn.DeviceNumber; } CloseHandle(hVolume); if (DeviceNumber == -1) { return; } // get the drive type which is required to match the device numbers correctely UINT DriveType = GetDriveTypeA(szRootPath); // get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way? char szDosDeviceName[168]; res = QueryDosDeviceA(szDevicePath, szDosDeviceName, 168); if (!res) { return; } // get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName); if (DevInst == 0) { return; } PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown; WCHAR VetoNameW[MAX_PATH]; VetoNameW[0] = 0; bool bSuccess = false; // get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives! DEVINST DevInstParent = 0; res = CM_Get_Parent(&DevInstParent, DevInst, 0); //WriteLog("target : %s", szDosDeviceName); for (long tries = 1; tries <= 3; tries++) { VetoNameW[0] = 0; // CM_Query_And_Remove_SubTree doesn't work for restricted users //res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K! //res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART); // with messagebox (W2K, Vista) or balloon (XP) res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0); //res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP) bSuccess = (res == CR_SUCCESS && VetoType == PNP_VetoTypeUnknown); if (bSuccess) { break; } Sleep(500); // required to give the next tries a chance! } //WriteLog("success : %d", bSuccess); if (bSuccess) { sendData(TYPE_USBDISCONNECTED, szDosDeviceName); return; } /* if (VetoNameW[0]) { WriteLog("VetoName=%ws)\n\n", VetoNameW); } */ } catch (TCHAR * pszError) { } }