mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-07 09:01:38 -04:00
Remove code superseeded by winusb
This commit is contained in:
parent
5d3415dcfb
commit
deb72df077
@ -275,7 +275,7 @@ if iswindows:
|
|||||||
extensions.extend([
|
extensions.extend([
|
||||||
Extension('winutil',
|
Extension('winutil',
|
||||||
['calibre/utils/windows/winutil.c'],
|
['calibre/utils/windows/winutil.c'],
|
||||||
libraries=['shell32', 'setupapi', 'wininet'],
|
libraries=['shell32', 'wininet'],
|
||||||
cflags=['/X']
|
cflags=['/X']
|
||||||
),
|
),
|
||||||
Extension('wpd',
|
Extension('wpd',
|
||||||
|
@ -13,24 +13,6 @@ system. It should be compiled with the same version of VisualStudio used to
|
|||||||
compile python. It hasn't been tested with MinGW. We try to use unicode
|
compile python. It hasn't been tested with MinGW. We try to use unicode
|
||||||
wherever possible in this module.
|
wherever possible in this module.
|
||||||
|
|
||||||
.. exception:: winutil.DriveError
|
|
||||||
Raised when scanning for mounted volumes fails.
|
|
||||||
|
|
||||||
.. function:: is_usb_device_connected(vid : integer, pid : integer) -> bool
|
|
||||||
Return `True` iff the USB device identified by the VendorID `vid` and
|
|
||||||
ProductID `pid` is connected to the system.
|
|
||||||
|
|
||||||
.. function:: get_usb_devices() -> list of lowercase strings
|
|
||||||
Return a list of all USB devices connected to the system. Each
|
|
||||||
device is represented by a lowercase unicode string whoose format is
|
|
||||||
the windows *Device Identifier* format. See the MSDN documentation.
|
|
||||||
|
|
||||||
.. function:: get_mounted_volumes_for_usb_device(vid : integer, pid : integer) -> dictionary
|
|
||||||
Return a dictionary of the form `volume_id`:`drive_letter` for all
|
|
||||||
volumes mounted from the device specified by `vid` and `pid`.
|
|
||||||
|
|
||||||
:raises: :exception:`winutil.DriveError` if scanning fails.
|
|
||||||
|
|
||||||
.. function:: special_folder_path(csidl_id) -> path
|
.. function:: special_folder_path(csidl_id) -> path
|
||||||
Get paths to common system folders.
|
Get paths to common system folders.
|
||||||
See windows documentation of SHGetFolderPath.
|
See windows documentation of SHGetFolderPath.
|
||||||
@ -77,7 +59,6 @@ wherever possible in this module.
|
|||||||
|
|
||||||
#define BUFSIZE 512
|
#define BUFSIZE 512
|
||||||
#define MAX_DRIVES 26
|
#define MAX_DRIVES 26
|
||||||
static PyObject *DriveError;
|
|
||||||
static BOOL DEBUG = FALSE;
|
static BOOL DEBUG = FALSE;
|
||||||
|
|
||||||
//#define debug(fmt, ...) if DEBUG printf(x, __VA_ARGS__);
|
//#define debug(fmt, ...) if DEBUG printf(x, __VA_ARGS__);
|
||||||
@ -89,12 +70,6 @@ debug(const char *fmt, ...) {
|
|||||||
va_end(argList);
|
va_end(argList);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tagDrives
|
|
||||||
{
|
|
||||||
WCHAR letter;
|
|
||||||
WCHAR volume[BUFSIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void console_out(LPCWSTR fmt, LPCWSTR arg) {
|
static void console_out(LPCWSTR fmt, LPCWSTR arg) {
|
||||||
char *bfmt, *barg;
|
char *bfmt, *barg;
|
||||||
int sz;
|
int sz;
|
||||||
@ -187,593 +162,6 @@ winutil_set_debug(PyObject *self, PyObject *args) {
|
|||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obsolete device code {{{ */
|
|
||||||
static LPWSTR
|
|
||||||
get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iterate) {
|
|
||||||
/* Get the property specified by `property` from the registry for the
|
|
||||||
* device enumerated by `index` in the collection `hDevInfo`. `iterate`
|
|
||||||
* will be set to `FALSE` if `index` points outside `hDevInfo`.
|
|
||||||
* :return: A string allocated on the heap containing the property or
|
|
||||||
* `NULL` if an error occurred.
|
|
||||||
*/
|
|
||||||
SP_DEVINFO_DATA DeviceInfoData;
|
|
||||||
DWORD DataT;
|
|
||||||
LPWSTR buffer = NULL;
|
|
||||||
DWORD buffersize = 0;
|
|
||||||
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
||||||
|
|
||||||
if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) {
|
|
||||||
*iterate = FALSE;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(!SetupDiGetDeviceRegistryPropertyW(
|
|
||||||
hDevInfo,
|
|
||||||
&DeviceInfoData,
|
|
||||||
property,
|
|
||||||
&DataT,
|
|
||||||
(PBYTE)buffer,
|
|
||||||
buffersize,
|
|
||||||
&buffersize)) {
|
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
||||||
if (buffer != NULL) { PyMem_Free(buffer); buffer = NULL; }
|
|
||||||
buffer = (LPWSTR)PyMem_Malloc(2*buffersize); // Twice for bug in Win2k
|
|
||||||
} else {
|
|
||||||
if (buffer != NULL) { PyMem_Free(buffer); buffer = NULL; }
|
|
||||||
PyErr_SetFromWindowsErr(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} //while
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL
|
|
||||||
check_device_id(LPWSTR buffer, unsigned int vid, unsigned int pid) {
|
|
||||||
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
|
|
||||||
unsigned int j;
|
|
||||||
_snwprintf_s(xVid, 9, _TRUNCATE, L"vid_%4.4x", vid);
|
|
||||||
_snwprintf_s(dVid, 9, _TRUNCATE, L"vid_%4.4d", vid);
|
|
||||||
_snwprintf_s(xPid, 9, _TRUNCATE, L"pid_%4.4x", pid);
|
|
||||||
_snwprintf_s(dPid, 9, _TRUNCATE, L"pid_%4.4d", pid);
|
|
||||||
|
|
||||||
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
|
|
||||||
|
|
||||||
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
|
|
||||||
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static HDEVINFO
|
|
||||||
create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) {
|
|
||||||
HDEVINFO hDevInfo;
|
|
||||||
hDevInfo = SetupDiGetClassDevs(
|
|
||||||
guid,
|
|
||||||
enumerator,
|
|
||||||
parent,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
|
||||||
PyErr_SetFromWindowsErr(0);
|
|
||||||
}
|
|
||||||
return hDevInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n;
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
get_all_removable_disks(struct tagDrives *g_drives)
|
|
||||||
{
|
|
||||||
WCHAR caDrive[4];
|
|
||||||
WCHAR volume[BUFSIZE];
|
|
||||||
int nLoopIndex;
|
|
||||||
DWORD dwDriveMask;
|
|
||||||
unsigned int g_count=0;
|
|
||||||
|
|
||||||
|
|
||||||
caDrive[0] = 'A';
|
|
||||||
caDrive[1] = ':';
|
|
||||||
caDrive[2] = '\\';
|
|
||||||
caDrive[3] = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Get all drives in the system.
|
|
||||||
dwDriveMask = GetLogicalDrives();
|
|
||||||
|
|
||||||
|
|
||||||
if(dwDriveMask == 0)
|
|
||||||
{
|
|
||||||
PyErr_SetString(DriveError, "GetLogicalDrives failed");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Loop for all drives (MAX_DRIVES = 26)
|
|
||||||
|
|
||||||
|
|
||||||
for(nLoopIndex = 0; nLoopIndex < MAX_DRIVES; nLoopIndex++)
|
|
||||||
{
|
|
||||||
// if a drive is present (we cannot ignore the A and B drives as there
|
|
||||||
// are people out there that think mapping devices to use those letters
|
|
||||||
// is a good idea, sigh)
|
|
||||||
if(dwDriveMask & 1)
|
|
||||||
{
|
|
||||||
caDrive[0] = 'A' + nLoopIndex;
|
|
||||||
|
|
||||||
|
|
||||||
// If a drive is removable
|
|
||||||
if(GetDriveType(caDrive) == DRIVE_REMOVABLE)
|
|
||||||
{
|
|
||||||
//Get its volume info and store it in the global variable.
|
|
||||||
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE))
|
|
||||||
{
|
|
||||||
g_drives[g_count].letter = caDrive[0];
|
|
||||||
wcscpy_s(g_drives[g_count].volume, BUFSIZE, volume);
|
|
||||||
g_count ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dwDriveMask >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// success if atleast one removable drive is found.
|
|
||||||
if(g_count == 0)
|
|
||||||
{
|
|
||||||
PyErr_SetString(DriveError, "No removable drives found");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static DEVINST
|
|
||||||
GetDrivesDevInstByDeviceNumber(long DeviceNumber,
|
|
||||||
UINT DriveType, LPWSTR szDosDeviceName)
|
|
||||||
{
|
|
||||||
GUID *guid;
|
|
||||||
HDEVINFO hDevInfo;
|
|
||||||
DWORD dwIndex, dwBytesReturned;
|
|
||||||
BOOL bRet, IsFloppy;
|
|
||||||
BYTE Buf[1024];
|
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd;
|
|
||||||
long res;
|
|
||||||
HANDLE hDrive;
|
|
||||||
STORAGE_DEVICE_NUMBER sdn;
|
|
||||||
SP_DEVICE_INTERFACE_DATA spdid;
|
|
||||||
SP_DEVINFO_DATA spdd;
|
|
||||||
DWORD dwSize;
|
|
||||||
|
|
||||||
|
|
||||||
IsFloppy = (wcsstr(szDosDeviceName, L"\\Floppy") != NULL); // is there a better way?
|
|
||||||
|
|
||||||
switch (DriveType) {
|
|
||||||
case DRIVE_REMOVABLE:
|
|
||||||
if ( IsFloppy ) {
|
|
||||||
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
|
|
||||||
} else {
|
|
||||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DRIVE_FIXED:
|
|
||||||
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
|
|
||||||
break;
|
|
||||||
case DRIVE_CDROM:
|
|
||||||
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid drive type");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get device interface info set handle
|
|
||||||
// for all devices attached to system
|
|
||||||
hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL,
|
|
||||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
||||||
|
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid handle value");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve a context structure for a device interface
|
|
||||||
// of a device information set.
|
|
||||||
dwIndex = 0;
|
|
||||||
bRet = FALSE;
|
|
||||||
|
|
||||||
|
|
||||||
pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
|
|
||||||
spdid.cbSize = sizeof(spdid);
|
|
||||||
|
|
||||||
while ( TRUE ) {
|
|
||||||
bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL,
|
|
||||||
guid, dwIndex, &spdid);
|
|
||||||
if ( !bRet ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwSize = 0;
|
|
||||||
SetupDiGetDeviceInterfaceDetail(hDevInfo,
|
|
||||||
&spdid, NULL, 0, &dwSize, NULL);
|
|
||||||
|
|
||||||
if ( dwSize!=0 && dwSize<=sizeof(Buf) ) {
|
|
||||||
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
|
|
||||||
|
|
||||||
ZeroMemory((PVOID)&spdd, sizeof(spdd));
|
|
||||||
spdd.cbSize = sizeof(spdd);
|
|
||||||
|
|
||||||
res =
|
|
||||||
SetupDiGetDeviceInterfaceDetail(hDevInfo, &
|
|
||||||
spdid, pspdidd,
|
|
||||||
dwSize, &dwSize,
|
|
||||||
&spdd);
|
|
||||||
if ( res ) {
|
|
||||||
hDrive = CreateFile(pspdidd->DevicePath,0,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
NULL, OPEN_EXISTING, 0, NULL);
|
|
||||||
if ( hDrive != INVALID_HANDLE_VALUE ) {
|
|
||||||
dwBytesReturned = 0;
|
|
||||||
res = DeviceIoControl(hDrive,
|
|
||||||
IOCTL_STORAGE_GET_DEVICE_NUMBER,
|
|
||||||
NULL, 0, &sdn, sizeof(sdn),
|
|
||||||
&dwBytesReturned, NULL);
|
|
||||||
if ( res ) {
|
|
||||||
if ( DeviceNumber == (long)sdn.DeviceNumber ) {
|
|
||||||
CloseHandle(hDrive);
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
||||||
return spdd.DevInst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloseHandle(hDrive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dwIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Invalid device number");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL
|
|
||||||
eject_drive_letter(WCHAR DriveLetter) {
|
|
||||||
LPWSTR szRootPath = L"X:\\",
|
|
||||||
szDevicePath = L"X:",
|
|
||||||
szVolumeAccessPath = L"\\\\.\\X:";
|
|
||||||
WCHAR szDosDeviceName[MAX_PATH];
|
|
||||||
long DeviceNumber, res, tries;
|
|
||||||
HANDLE hVolume;
|
|
||||||
STORAGE_DEVICE_NUMBER sdn;
|
|
||||||
DWORD dwBytesReturned;
|
|
||||||
DEVINST DevInst;
|
|
||||||
ULONG Status;
|
|
||||||
ULONG ProblemNumber;
|
|
||||||
UINT DriveType;
|
|
||||||
PNP_VETO_TYPE VetoType;
|
|
||||||
WCHAR VetoNameW[MAX_PATH];
|
|
||||||
BOOL bSuccess;
|
|
||||||
DEVINST DevInstParent;
|
|
||||||
|
|
||||||
szRootPath[0] = DriveLetter;
|
|
||||||
szDevicePath[0] = DriveLetter;
|
|
||||||
szVolumeAccessPath[4] = DriveLetter;
|
|
||||||
|
|
||||||
DeviceNumber = -1;
|
|
||||||
|
|
||||||
hVolume = CreateFileW(szVolumeAccessPath, 0,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
NULL, OPEN_EXISTING, 0, NULL);
|
|
||||||
if (hVolume == INVALID_HANDLE_VALUE) {
|
|
||||||
PyErr_SetFromWindowsErr(0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwBytesReturned = 0;
|
|
||||||
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 ) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Can't find drive number");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
|
|
||||||
if ( !res ) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Can't find dos device");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DriveType = GetDriveType(szRootPath);
|
|
||||||
|
|
||||||
DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber,
|
|
||||||
DriveType, szDosDeviceName);
|
|
||||||
if (DevInst == 0) return FALSE;
|
|
||||||
|
|
||||||
DevInstParent = 0;
|
|
||||||
Status = 0;
|
|
||||||
ProblemNumber = 0;
|
|
||||||
bSuccess = FALSE;
|
|
||||||
|
|
||||||
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
|
|
||||||
|
|
||||||
for ( tries = 0; tries < 3; tries++ ) {
|
|
||||||
VetoNameW[0] = 0;
|
|
||||||
|
|
||||||
res = CM_Request_Device_EjectW(DevInstParent,
|
|
||||||
&VetoType, VetoNameW, MAX_PATH, 0);
|
|
||||||
|
|
||||||
bSuccess = (res==CR_SUCCESS &&
|
|
||||||
VetoType==PNP_VetoTypeUnknown);
|
|
||||||
if ( bSuccess ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sleep(500); // required to give the next tries a chance!
|
|
||||||
}
|
|
||||||
if (!bSuccess) PyErr_SetString(PyExc_ValueError, "Failed to eject drive after three tries");
|
|
||||||
return bSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
winutil_eject_drive(PyObject *self, PyObject *args) {
|
|
||||||
char letter = '0';
|
|
||||||
WCHAR DriveLetter = L'0';
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "c", &letter)) return NULL;
|
|
||||||
|
|
||||||
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &letter, 1, &DriveLetter, 1) == 0) {
|
|
||||||
PyErr_SetFromWindowsErr(0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!eject_drive_letter(DriveLetter)) return NULL;
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA
|
|
||||||
get_device_ancestors(HDEVINFO hDevInfo, DWORD index, PyObject *candidates, BOOL *iterate, BOOL ddebug) {
|
|
||||||
SP_DEVICE_INTERFACE_DATA interfaceData;
|
|
||||||
SP_DEVINFO_DATA devInfoData;
|
|
||||||
BOOL status;
|
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
|
||||||
DWORD interfaceDetailDataSize,
|
|
||||||
reqSize;
|
|
||||||
DEVINST parent, pos;
|
|
||||||
wchar_t temp[BUFSIZE];
|
|
||||||
int i;
|
|
||||||
PyObject *devid;
|
|
||||||
|
|
||||||
interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
|
|
||||||
devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
|
|
||||||
|
|
||||||
status = SetupDiEnumDeviceInterfaces (
|
|
||||||
hDevInfo, // Interface Device Info handle
|
|
||||||
NULL, // Device Info data
|
|
||||||
(LPGUID)&GUID_DEVINTERFACE_VOLUME, // Interface registered by driver
|
|
||||||
index, // Member
|
|
||||||
&interfaceData // Device Interface Data
|
|
||||||
);
|
|
||||||
if ( status == FALSE ) {
|
|
||||||
*iterate = FALSE;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
SetupDiGetDeviceInterfaceDetail (
|
|
||||||
hDevInfo, // Interface Device info handle
|
|
||||||
&interfaceData, // Interface data for the event class
|
|
||||||
NULL, // Checking for buffer size
|
|
||||||
0, // Checking for buffer size
|
|
||||||
&reqSize, // Buffer size required to get the detail data
|
|
||||||
NULL // Checking for buffer size
|
|
||||||
);
|
|
||||||
|
|
||||||
interfaceDetailDataSize = reqSize;
|
|
||||||
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+50);
|
|
||||||
if ( interfaceDetailData == NULL ) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
|
|
||||||
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
||||||
|
|
||||||
status = SetupDiGetDeviceInterfaceDetail (
|
|
||||||
hDevInfo, // Interface Device info handle
|
|
||||||
&interfaceData, // Interface data for the event class
|
|
||||||
interfaceDetailData, // Interface detail data
|
|
||||||
interfaceDetailDataSize, // Interface detail data size
|
|
||||||
&reqSize, // Buffer size required to get the detail data
|
|
||||||
&devInfoData); // Interface device info
|
|
||||||
if (ddebug) printf("Getting ancestors\n"); fflush(stdout);
|
|
||||||
|
|
||||||
if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}
|
|
||||||
|
|
||||||
pos = devInfoData.DevInst;
|
|
||||||
|
|
||||||
for(i = 0; i < 10; i++) {
|
|
||||||
// Get the device instance of parent.
|
|
||||||
if (CM_Get_Parent(&parent, pos, 0) != CR_SUCCESS) break;
|
|
||||||
if (CM_Get_Device_ID(parent, temp, BUFSIZE, 0) == CR_SUCCESS) {
|
|
||||||
if (ddebug) console_out(L"device id: %s\n", temp);
|
|
||||||
devid = PyUnicode_FromWideChar(temp, wcslen(temp));
|
|
||||||
if (devid) {
|
|
||||||
PyList_Append(candidates, devid);
|
|
||||||
Py_DECREF(devid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return interfaceDetailData;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
winutil_get_removable_drives(PyObject *self, PyObject *args) {
|
|
||||||
HDEVINFO hDevInfo;
|
|
||||||
BOOL iterate = TRUE, ddebug = FALSE;
|
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
|
|
||||||
DWORD i;
|
|
||||||
unsigned int j;
|
|
||||||
size_t length;
|
|
||||||
WCHAR volume[BUFSIZE];
|
|
||||||
struct tagDrives g_drives[MAX_DRIVES];
|
|
||||||
PyObject *volumes, *key, *candidates, *pdebug = Py_False, *temp;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|O", &pdebug)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all removable drives
|
|
||||||
for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0;
|
|
||||||
if (!get_all_removable_disks(g_drives)) return NULL;
|
|
||||||
|
|
||||||
volumes = PyDict_New();
|
|
||||||
if (volumes == NULL) return PyErr_NoMemory();
|
|
||||||
ddebug = PyObject_IsTrue(pdebug);
|
|
||||||
|
|
||||||
hDevInfo = create_device_info_set((LPGUID)&GUID_DEVINTERFACE_VOLUME,
|
|
||||||
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE) { Py_DECREF(volumes); return NULL; }
|
|
||||||
|
|
||||||
// Enumerate through the set
|
|
||||||
for (i=0; iterate; i++) {
|
|
||||||
candidates = PyList_New(0);
|
|
||||||
if (candidates == NULL) { Py_DECREF(volumes); return PyErr_NoMemory();}
|
|
||||||
|
|
||||||
interfaceDetailData = get_device_ancestors(hDevInfo, i, candidates, &iterate, ddebug);
|
|
||||||
if (interfaceDetailData == NULL) {
|
|
||||||
PyErr_Print();
|
|
||||||
Py_DECREF(candidates); candidates = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
length = wcslen(interfaceDetailData->DevicePath);
|
|
||||||
interfaceDetailData->DevicePath[length] = L'\\';
|
|
||||||
interfaceDetailData->DevicePath[length+1] = 0;
|
|
||||||
|
|
||||||
if (ddebug) console_out(L"Device path: %s\n", interfaceDetailData->DevicePath);
|
|
||||||
// On Vista+ DevicePath contains the information we need.
|
|
||||||
temp = PyUnicode_FromWideChar(interfaceDetailData->DevicePath, length);
|
|
||||||
if (temp == NULL) return PyErr_NoMemory();
|
|
||||||
PyList_Append(candidates, temp);
|
|
||||||
Py_DECREF(temp);
|
|
||||||
if(GetVolumeNameForVolumeMountPointW(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
|
|
||||||
if (ddebug) console_out(L"Volume: %s\n", volume);
|
|
||||||
|
|
||||||
for(j = 0; j < MAX_DRIVES; j++) {
|
|
||||||
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0) {
|
|
||||||
if (ddebug) printf("Found drive: %c\n", (char)g_drives[j].letter); fflush(stdout);
|
|
||||||
key = PyBytes_FromFormat("%c", (char)g_drives[j].letter);
|
|
||||||
if (key == NULL) return PyErr_NoMemory();
|
|
||||||
PyDict_SetItem(volumes, key, candidates);
|
|
||||||
Py_DECREF(key); key = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Py_XDECREF(candidates); candidates = NULL;
|
|
||||||
PyMem_Free(interfaceDetailData);
|
|
||||||
} //for
|
|
||||||
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
||||||
return volumes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
winutil_get_usb_devices(PyObject *self, PyObject *args) {
|
|
||||||
unsigned int j;
|
|
||||||
size_t buffersize;
|
|
||||||
HDEVINFO hDevInfo;
|
|
||||||
DWORD i; BOOL iterate = TRUE;
|
|
||||||
PyObject *devices, *temp = (PyObject *)1;
|
|
||||||
LPWSTR buffer;
|
|
||||||
BOOL ok = 1;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "")) return NULL;
|
|
||||||
|
|
||||||
devices = PyList_New(0);
|
|
||||||
if (devices == NULL) {PyErr_NoMemory(); return NULL;}
|
|
||||||
|
|
||||||
// Create a Device information set with all USB devices
|
|
||||||
hDevInfo = create_device_info_set(NULL, L"USB", 0,
|
|
||||||
DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
|
||||||
Py_DECREF(devices);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// Enumerate through the set
|
|
||||||
for (i=0; iterate; i++) {
|
|
||||||
buffer = get_registry_property(hDevInfo, i, SPDRP_HARDWAREID, &iterate);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
PyErr_Print(); continue;
|
|
||||||
}
|
|
||||||
buffersize = wcslen(buffer);
|
|
||||||
for (j = 0; j < buffersize; j++) buffer[j] = towlower(buffer[j]);
|
|
||||||
temp = PyUnicode_FromWideChar(buffer, buffersize);
|
|
||||||
PyMem_Free(buffer);
|
|
||||||
if (temp == NULL) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
ok = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PyList_Append(devices, temp); Py_DECREF(temp); temp = NULL;
|
|
||||||
} //for
|
|
||||||
if (!ok) { Py_DECREF(devices); devices = NULL; }
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
winutil_is_usb_device_connected(PyObject *self, PyObject *args) {
|
|
||||||
unsigned int vid, pid;
|
|
||||||
HDEVINFO hDevInfo;
|
|
||||||
DWORD i; BOOL iterate = TRUE;
|
|
||||||
LPWSTR buffer;
|
|
||||||
int found = FALSE;
|
|
||||||
PyObject *ans;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a Device information set with all USB devices
|
|
||||||
hDevInfo = create_device_info_set(NULL, L"USB", 0,
|
|
||||||
DIGCF_PRESENT | DIGCF_ALLCLASSES);
|
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Enumerate through the set
|
|
||||||
for (i=0; iterate && !found; i++) {
|
|
||||||
buffer = get_registry_property(hDevInfo, i, SPDRP_HARDWAREID, &iterate);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
PyErr_Print(); continue;
|
|
||||||
}
|
|
||||||
found = check_device_id(buffer, vid, pid);
|
|
||||||
PyMem_Free(buffer);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
||||||
ans = (found) ? Py_True : Py_False;
|
|
||||||
Py_INCREF(ans);
|
|
||||||
return ans;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gettmarg(PyObject *args, struct tm *p)
|
gettmarg(PyObject *args, struct tm *p)
|
||||||
{
|
{
|
||||||
@ -951,23 +339,6 @@ static PyMethodDef WinutilMethods[] = {
|
|||||||
"script being run. So to replace sys.argv, you should use "
|
"script being run. So to replace sys.argv, you should use "
|
||||||
"sys.argv[1:] = argv()[1:]."},
|
"sys.argv[1:] = argv()[1:]."},
|
||||||
|
|
||||||
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
|
|
||||||
"is_usb_device_connected(vid, pid) -> bool\n\n"
|
|
||||||
"Check if the USB device identified by VendorID: vid (integer) and"
|
|
||||||
" ProductID: pid (integer) is currently connected."},
|
|
||||||
|
|
||||||
{"get_usb_devices", winutil_get_usb_devices, METH_VARARGS,
|
|
||||||
"get_usb_devices() -> list of strings\n\n"
|
|
||||||
"Return a list of the hardware IDs of all USB devices "
|
|
||||||
"connected to the system."},
|
|
||||||
|
|
||||||
{"get_removable_drives", winutil_get_removable_drives, METH_VARARGS,
|
|
||||||
"get_removable_drives(debug=False) -> dict\n\n"
|
|
||||||
"Return mapping of all removable drives in the system. Maps drive letters "
|
|
||||||
"to a list of device id strings, atleast one of which will carry the information "
|
|
||||||
"needed for device matching. On Vista+ it is always the last string in the list. "
|
|
||||||
"Note that you should upper case all strings."},
|
|
||||||
|
|
||||||
{"set_debug", winutil_set_debug, METH_VARARGS,
|
{"set_debug", winutil_set_debug, METH_VARARGS,
|
||||||
"set_debug(bool)\n\nSet debugging mode."
|
"set_debug(bool)\n\nSet debugging mode."
|
||||||
},
|
},
|
||||||
@ -981,10 +352,6 @@ is not present, current time as returned by localtime() is used. format must\n\
|
|||||||
be a unicode string. Returns unicode strings."
|
be a unicode string. Returns unicode strings."
|
||||||
},
|
},
|
||||||
|
|
||||||
{"eject_drive", winutil_eject_drive, METH_VARARGS,
|
|
||||||
"eject_drive(drive_letter)\n\nEject a drive. Raises an exception on failure."
|
|
||||||
},
|
|
||||||
|
|
||||||
{"internet_connected", winutil_internet_connected, METH_VARARGS,
|
{"internet_connected", winutil_internet_connected, METH_VARARGS,
|
||||||
"internet_connected()\n\nReturn True if there is an active internet connection"
|
"internet_connected()\n\nReturn True if there is an active internet connection"
|
||||||
},
|
},
|
||||||
@ -1003,9 +370,6 @@ initwinutil(void) {
|
|||||||
"Defines utility methods to interface with windows."
|
"Defines utility methods to interface with windows."
|
||||||
);
|
);
|
||||||
if (m == NULL) return;
|
if (m == NULL) return;
|
||||||
DriveError = PyErr_NewException("winutil.DriveError", NULL, NULL);
|
|
||||||
if (DriveError == NULL) return;
|
|
||||||
PyModule_AddObject(m, "DriveError", DriveError);
|
|
||||||
|
|
||||||
PyModule_AddIntConstant(m, "CSIDL_ADMINTOOLS", CSIDL_ADMINTOOLS);
|
PyModule_AddIntConstant(m, "CSIDL_ADMINTOOLS", CSIDL_ADMINTOOLS);
|
||||||
PyModule_AddIntConstant(m, "CSIDL_APPDATA", CSIDL_APPDATA);
|
PyModule_AddIntConstant(m, "CSIDL_APPDATA", CSIDL_APPDATA);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user