diff --git a/installer/osx/freeze.py b/installer/osx/freeze.py index ddef24075c..24be7aec0a 100644 --- a/installer/osx/freeze.py +++ b/installer/osx/freeze.py @@ -253,7 +253,7 @@ _check_symlinks_prescript() print 'Adding plugins' module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload') print 'Adding fontconfig' - for f in glob.glob(os.path.expanduser('~/fontconfig2/*')): + for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')): os.link(f, os.path.join(frameworks_dir, os.path.basename(f))) dst = os.path.join(resource_dir, 'fonts') if os.path.exists(dst): diff --git a/setup.py b/setup.py index 648872ecc1..4d2b8247e2 100644 --- a/setup.py +++ b/setup.py @@ -56,10 +56,16 @@ if __name__ == '__main__': include_dirs=['src/calibre/utils/lzx'])] if iswindows: ext_modules.append(Extension('calibre.plugins.winutil', - sources=['src/calibre/utils/winutil.c'], libraries=['shell32']) + sources=['src/calibre/utils/windows/winutil.c'], + libraries=['shell32', 'setupapi'], + include_dirs=['C:/WinDDK/6001.18001/inc/api/']) ) - # Build PyQt extensions - for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]: + if isosx: + ext_modules.append(Extension('calibre.plugins.usbobserver', + sources=['src/calibre/driver/usbobserver/usbobserver.c']) + ) + + def build_PyQt_extension(path): pro = glob.glob(os.path.join(path, '*.pro'))[0] raw = open(pro).read() base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1) @@ -72,7 +78,7 @@ if __name__ == '__main__': os.chdir('.build') subprocess.check_call(( (os.path.expanduser('~/qt/bin/qmake') if isosx else 'qmake'), '..'+os.sep+os.path.basename(pro))) subprocess.check_call(['mingw32-make' if iswindows else 'make']) - os.chdir(os.path.join('..'+(os.sep+'..' if iswindows else ''), 'PyQt')) + os.chdir(os.path.join('..', 'PyQt')) if not os.path.exists('.build'): os.mkdir('.build') os.chdir('.build') @@ -142,5 +148,8 @@ if __name__ == '__main__': ] ) + for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]: + build_PyQt_extension(path) + if 'develop' in ' '.join(sys.argv) and islinux: subprocess.check_call('calibre_postinstall', shell=True) diff --git a/src/calibre/debug.py b/src/calibre/debug.py index aecff15351..e25fd77c97 100644 --- a/src/calibre/debug.py +++ b/src/calibre/debug.py @@ -23,6 +23,10 @@ Run an embedded python interpreter. return parser def update_zipfile(zipfile, mod, path): + if 'win32' in sys.platform: + print 'WARNING: On Windows Vista you must run this from a console that has been started in Administrator mode.' + print 'Press Enter to continue or Ctrl-C to Cancel' + raw_input() pat = re.compile(mod.replace('.', '/')+r'\.py[co]*') name = mod.replace('.', '/') + os.path.splitext(path)[-1] update(zipfile, [pat], [path], [name]) diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py index 23c5420d4c..93145432db 100755 --- a/src/calibre/devices/kindle/driver.py +++ b/src/calibre/devices/kindle/driver.py @@ -133,31 +133,7 @@ class KINDLE(Device): def open_windows(self): - drives = [] - import wmi - c = wmi.WMI() - for drive in c.Win32_DiskDrive(): - '''print drive.PNPDeviceID''' - if self.__class__.is_device(drive.PNPDeviceID): - if drive.Partitions == 0: - continue - try: - partition = drive.associators("Win32_DiskDriveToDiskPartition")[0] - logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0] - prefix = logical_disk.DeviceID+os.sep - drives.append((drive.Index, prefix)) - except IndexError: - continue - - - if not drives: - print self.__class__.__name__ - raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,)) - - drives.sort(cmp=lambda a, b: cmp(a[0], b[0])) - self._main_prefix = drives[0][1] - if len(drives) > 1: - self._card_prefix = drives[1][1] + raise NotImplementedError def open_linux(self): diff --git a/src/calibre/devices/scanner.py b/src/calibre/devices/scanner.py index d0501ab5ff..e896505417 100644 --- a/src/calibre/devices/scanner.py +++ b/src/calibre/devices/scanner.py @@ -7,59 +7,48 @@ manner. import sys -from calibre import iswindows, isosx +from calibre import iswindows, isosx, plugins from calibre.devices import libusb -osx_scanner = None +osx_scanner = win_scanner = linux_scanner = None + try: import usbobserver osx_scanner = usbobserver.get_devices except ImportError: pass -linux_scanner = libusb.get_devices +if iswindows: + try: + win_scanner = plugins['winutil'][0].get_usb_devices + except: + raise RuntimeError('Failed to load the winutil plugin: %s'%plugins['winutil'][1]) +elif isosx: + try: + osx_scanner = plugins['usbobserver'][0].get_usb_devices + except: + raise RuntimeError('Failed to load the usbobserver plugin: %s'%plugins['usbobserver'][1]) +else: + linux_scanner = libusb.get_devices class DeviceScanner(object): - def __init__(self, wmi=None): - self.wmi = wmi - if iswindows and wmi is None: - raise RuntimeError('You must pass a wmi instance to DeviceScanner on windows.') + def __init__(self, *args): if isosx and osx_scanner is None: raise RuntimeError('The Python extension usbobserver must be available on OS X.') if not (isosx or iswindows) and not libusb.has_library(): raise RuntimeError('DeviceScanner requires libusb to work.') - + self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner self.devices = [] - def get_devices(self): - if iswindows: - devices = [] - for c in self.wmi.USBControllerDevice(): - devices.append(c.Dependent.DeviceID.upper()) - return devices - if isosx: - return osx_scanner() - return linux_scanner() - def scan(self): - try: # Windows WMI occasionally and temporarily barfs - self.devices = self.get_devices() - except Exception, e: - if not iswindows and e: - raise e - + '''Fetch list of connected USB devices from operating system''' + self.devices = self.scanner() def is_device_connected(self, device): if iswindows: for device_id in self.devices: - if 'VEN_'+device.VENDOR_NAME in device_id and \ - 'PROD_'+device.PRODUCT_NAME in device_id: - return True - vid, pid = hex(device.VENDOR_ID)[2:], hex(device.PRODUCT_ID)[2:] - if len(vid) < 4: vid = '0'+vid - if len(pid) < 4: pid = '0'+pid - vid, pid = 'VID_'+vid.upper(), 'PID_'+pid.upper() + vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID if vid in device_id and pid in device_id: return True return False diff --git a/src/calibre/devices/usbobserver/usbobserver.c b/src/calibre/devices/usbobserver/usbobserver.c index 14dafcad5c..99fe39362d 100644 --- a/src/calibre/devices/usbobserver/usbobserver.c +++ b/src/calibre/devices/usbobserver/usbobserver.c @@ -29,7 +29,7 @@ static PyObject * -usbobserver_get_devices(PyObject *self, PyObject *args) { +usbobserver_get_usb_devices(PyObject *self, PyObject *args) { mach_port_t masterPort; CFMutableDictionaryRef matchingDict; @@ -62,7 +62,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) { PyObject *devices, *device; devices = PyList_New(0); if (devices == NULL) { - PyErr_SetString(PyExc_RuntimeError, "Out of memory allocating list"); + PyErr_NoMemory(); mach_port_deallocate(mach_task_self(), masterPort); return NULL; } @@ -112,7 +112,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) { } static PyMethodDef usbobserver_methods[] = { - {"get_devices", usbobserver_get_devices, METH_VARARGS, + {"get_usb_devices", usbobserver_get_usb_devices, METH_VARARGS, "Get list of connected USB devices. Returns a list of tuples. Each tuple is of the form (vendor_id, product_id)." }, {NULL, NULL, 0, NULL} diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index d130bd9a1b..f2bcbc3022 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -131,13 +131,18 @@ Why does |app| show only some of my fonts on OS X? The graphical user interface of |app| is not starting on Windows? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you've never used the graphical user interface before, try deleting the file library1.db (it will be somewhere under :file:`C:\\Documents and Settings` on Windows XP and :file:`C:\\Users` on Windows Vista. If that doesn't fix the problem, locate the file calibre.log (in the same places as library1.db) and post its contents in a help message on the `Forums `_. If you can't find either file, try using the windows find feature to search for them. If the files dont exist on your system, try the following: - -Start a command prompt (press the windows key and R and type cmd.exe in the run dialog). At the command prompt type the following command and press Enter:: +There can be several causes for this: + + * **Any windows version**: Search for the files `calibre2.ini` and `calibre.ini` on your computer and delete them. Search for the file `library1.db` and rename it (this file contains all your converted books so deleting it is not a good idea. Now try again. + * **Windows Vista**: If the folder :file:`C:\Users\Your User Name\AppData\Local\VirtualStore\Program Files\calibre` exists, delete it. Uninstall |app|. Reboot. Re-install. + * **Any windows version**: Search your computer for a folder named :file:`_ipython`. Delete it and try again. + +If it still wont launch, start a command prompt (press the windows key and R; then type :command:`cmd.exe` in the Run dialog that appears). At the command prompt type the following command and press Enter:: calibre-debug -c "from calibre.gui2.main import main; main()" -Post any output you see when asking for help. +Post any output you see in a help message on the `Forums Copyright 2008 + +This module contains utility functions to interface with the windows operating +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 +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 + Get paths to common system folders. + See windows documentation of SHGetFolderPath. + The paths are returned as unicode objects. `csidl_id` should be one + of the symbolic constants defined in this module. You can also `OR` + a symbolic constant with :data:`CSIDL_FLAG_CREATE` to force the operating + system to create a folder if it does not exist. For example:: + + >>> from winutil import * + >>> special_folder_path(CSIDL_APPDATA) + u'C:\\Documents and Settings\\Kovid Goyal\\Application Data' + >>> special_folder_path(CSIDL_PERSONAL) + u'C:\\Documents and Settings\\Kovid Goyal\\My Documents' + +.. function:: argv() -> list of unicode command line arguments + Get command line arguments as unicode objects. Note that the + first argument will be the path to the interpreter, *not* the + script being run. So to replace sys.argv, you should use + sys.argv[1:] = winutil.argv()[1:]. + +*/ + + +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 512 +#define MAX_DRIVES 26 +static PyObject *DriveError; +static BOOL DEBUG = FALSE; + +//#define debug(fmt, ...) if DEBUG printf(x, __VA_ARGS__); +void +debug(const char *fmt, ...) { + va_list argList; + va_start(argList, fmt); + if (DEBUG) vprintf(fmt, argList); + va_end(argList); +} + +struct tagDrives +{ + WCHAR letter; + WCHAR volume[BUFSIZE]; +}; + +static PyObject * +winutil_folder_path(PyObject *self, PyObject *args) { + int res; DWORD dwFlags; + PyObject *ans = NULL; + TCHAR wbuf[MAX_PATH]; CHAR buf[4*MAX_PATH]; + memset(wbuf, 0, sizeof(TCHAR)*MAX_PATH); memset(buf, 0, sizeof(CHAR)*MAX_PATH); + + if (!PyArg_ParseTuple(args, "l", &dwFlags)) return NULL; + + res = SHGetFolderPath(NULL, dwFlags, NULL, 0, wbuf); + if (res != S_OK) { + if (res == E_FAIL) PyErr_SetString(PyExc_ValueError, "Folder does not exist."); + PyErr_SetString(PyExc_ValueError, "Folder not valid"); + return NULL; + } + res = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, 4*MAX_PATH, NULL, NULL); + ans = PyUnicode_DecodeUTF8(buf, res-1, "strict"); + return ans; +} + +static PyObject * +winutil_argv(PyObject *self, PyObject *args) { + PyObject *argv, *v; + LPWSTR *_argv; + LPSTR buf; + int argc, i, bytes; + if (!PyArg_ParseTuple(args, "")) return NULL; + _argv = CommandLineToArgvW(GetCommandLine(), &argc); + if (_argv == NULL) { PyErr_NoMemory(); return NULL; } + argv = PyList_New(argc); + if (argv != NULL) { + for (i = 0; i < argc; i++) { + bytes = WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, NULL, 0, NULL, NULL); + buf = (LPSTR)PyMem_Malloc(sizeof(CHAR)*bytes); + if (buf == NULL) { Py_DECREF(argv); argv = NULL; break; } + WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, buf, bytes, NULL, NULL); + v = PyUnicode_DecodeUTF8(buf, bytes-1, "strict"); + PyMem_Free(buf); + if (v == NULL) { Py_DECREF(argv); argv = NULL; break; } + PyList_SetItem(argv, i, v); + } + } + LocalFree(_argv); + return argv; +} + +static LPVOID +format_last_error() { + /* Format the last error as a string. The returned pointer should + be freed with :cfunction:`LocalFree(lpMsgBuf)`. It can be printed with + :cfunction:`printf("\n%ws\n", (LPCTSTR)lpMsgBuf)`. + */ + + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + return lpMsgBuf; +} + +static PyObject * +winutil_set_debug(PyObject *self, PyObject *args) { + PyObject *yes; + if (!PyArg_ParseTuple(args, "O", &yes)) return NULL; + DEBUG = (BOOL)PyObject_IsTrue(yes); + return Py_None; +} + +static LPTSTR +get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iterate) { + /* Get a 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; + LPTSTR buffer = NULL; + DWORD buffersize = 0; + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) { + *iterate = FALSE; + return NULL; + } + + while(!SetupDiGetDeviceRegistryProperty( + hDevInfo, + &DeviceInfoData, + property, + &DataT, + (PBYTE)buffer, + buffersize, + &buffersize)) { + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + buffer = (LPTSTR)PyMem_Malloc(2*buffersize); // Twice for bug in Win2k + } else { + PyMem_Free(buffer); + PyErr_SetFromWindowsErr(0); + buffer = NULL; + break; + } + } //while + + return buffer; +} + +static BOOL +check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) { + WCHAR xVid[9], dVid[9], xPid[9], dPid[9]; + unsigned int j; + swprintf(xVid, L"vid_%4.4x", vid); + swprintf(dVid, L"vid_%4.4d", vid); + swprintf(xPid, L"pid_%4.4x", pid); + swprintf(dPid, 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, + 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(g_drives[g_count].volume, 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; + +} + +PSP_DEVICE_INTERFACE_DETAIL_DATA +get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id, + BOOL *iterate) { + SP_DEVICE_INTERFACE_DATA interfaceData; + SP_DEVINFO_DATA devInfoData; + BOOL status; + PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; + DWORD interfaceDetailDataSize, + reqSize; + DEVINST parent; + + 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+10); + if ( interfaceDetailData == NULL ) { + PyErr_NoMemory(); + return NULL; + } + interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_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 ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;} + + // Get the device instance of parent. This points to USBSTOR. + CM_Get_Parent(&parent, devInfoData.DevInst, 0); + // Get the device ID of the USBSTORAGE volume + CM_Get_Device_ID(parent, volume_id, BUFSIZE, 0); + // Get the device instance of grand parent. This points to USB root. + CM_Get_Parent(&parent, parent, 0); + // Get the device ID of the USB root. + CM_Get_Device_ID(parent, buf, BUFSIZE, 0); + + return interfaceDetailData; +} + +static PyObject * +winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) { + unsigned int vid, pid, length, j; + HDEVINFO hDevInfo; + BOOL iterate = TRUE; + PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData; + DWORD i; + WCHAR buf[BUFSIZE], volume[BUFSIZE], volume_id[BUFSIZE]; + struct tagDrives g_drives[MAX_DRIVES]; + PyObject *volumes, *key, *val; + + if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) { + return NULL; + } + + volumes = PyDict_New(); + if (volumes == NULL) return NULL; + + for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0; + + // Find all removable drives + if (!get_all_removable_disks(g_drives)) { + return NULL; + } + + hDevInfo = create_device_info_set((LPGUID)&GUID_DEVINTERFACE_VOLUME, + NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (hDevInfo == INVALID_HANDLE_VALUE) return NULL; + + // Enumerate through the set + for (i=0; iterate; i++) { + interfaceDetailData = get_device_grandparent(hDevInfo, i, buf, volume_id, &iterate); + if (interfaceDetailData == NULL) { + PyErr_Print(); continue; + } + debug("Device num: %d Device Id: %ws\n\n", i, buf); + if (check_device_id(buf, vid, pid)) { + debug("Device matches\n\n"); + length = wcslen(interfaceDetailData->DevicePath); + interfaceDetailData->DevicePath[length] = '\\'; + interfaceDetailData->DevicePath[length+1] = 0; + if(GetVolumeNameForVolumeMountPoint(interfaceDetailData->DevicePath, volume, BUFSIZE)) { + + for(j = 0; j < MAX_DRIVES; j++) { + // Compare volume mount point with the one stored earlier. + // If both match, return the corresponding drive letter. + if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0) + { + key = PyUnicode_FromWideChar(volume_id, wcslen(volume_id)); + val = PyString_FromFormat("%c", (char)g_drives[j].letter); + if (key == NULL || val == NULL) { + PyErr_NoMemory(); + PyMem_Free(interfaceDetailData); + return NULL; + } + PyDict_SetItem(volumes, key, val); + } + } + + } else { + debug("Failed to get volume name for volume mount point:\n"); + if (DEBUG) debug("%ws\n\n", format_last_error()); + } + + PyMem_Free(interfaceDetailData); + } + + } //for + + SetupDiDestroyDeviceInfoList(hDevInfo); + return volumes; + +} + +static PyObject * +winutil_get_usb_devices(PyObject *self, PyObject *args) { + unsigned int j, buffersize; + HDEVINFO hDevInfo; + DWORD i; BOOL iterate = TRUE; + PyObject *devices, *temp = (PyObject *)1; + LPTSTR buffer; + + 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) + 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] = tolower(buffer[j]); + temp = PyUnicode_FromWideChar(buffer, buffersize); + PyMem_Free(buffer); + if (temp == NULL) { + PyErr_NoMemory(); + break; + } + PyList_Append(devices, temp); + } //for + if (temp == NULL) { 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; + LPTSTR 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 PyMethodDef WinutilMethods[] = { + {"special_folder_path", winutil_folder_path, METH_VARARGS, + "special_folder_path(csidl_id) -> path\n\n" + "Get paths to common system folders. " + "See windows documentation of SHGetFolderPath. " + "The paths are returned as unicode objects. csidl_id should be one " + "of the symbolic constants defined in this module. You can also OR " + "a symbolic constant with CSIDL_FLAG_CREATE to force the operating " + "system to create a folder if it does not exist."}, + + {"argv", winutil_argv, METH_VARARGS, + "argv() -> list of command line arguments\n\n" + "Get command line arguments as unicode objects. Note that the " + "first argument will be the path to the interpreter, *not* the " + "script being run. So to replace sys.argv, you should use " + "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_mounted_volumes_for_usb_device", winutil_get_mounted_volumes_for_usb_device, METH_VARARGS, + "get_mounted_volumes_for_usb_device(vid, pid) -> dict\n\n" + "Return a dictionary of volume_id:drive_letter for all" + "volumes mounted on the system that belong to the" + "usb device specified by vid (integer) and pid (integer)."}, + + {"set_debug", winutil_set_debug, METH_VARARGS, + "set_debug(bool)\n\nSet debugging mode." + }, + + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC +initwinutil(void) { + PyObject *m; + m = Py_InitModule3("winutil", WinutilMethods, + "Defines utility methods to interface with windows." + ); + if (m == NULL) return; + DriveError = PyErr_NewException("winutil.DriveError", NULL, NULL); + + PyModule_AddIntConstant(m, "CSIDL_ADMINTOOLS", CSIDL_ADMINTOOLS); + PyModule_AddIntConstant(m, "CSIDL_APPDATA", CSIDL_APPDATA); + PyModule_AddIntConstant(m, "CSIDL_COMMON_ADMINTOOLS", CSIDL_COMMON_ADMINTOOLS); + PyModule_AddIntConstant(m, "CSIDL_COMMON_APPDATA", CSIDL_COMMON_APPDATA); + PyModule_AddIntConstant(m, "CSIDL_COMMON_DOCUMENTS", CSIDL_COMMON_DOCUMENTS); + PyModule_AddIntConstant(m, "CSIDL_COOKIES", CSIDL_COOKIES); + PyModule_AddIntConstant(m, "CSIDL_FLAG_CREATE", CSIDL_FLAG_CREATE); + PyModule_AddIntConstant(m, "CSIDL_FLAG_DONT_VERIFY", CSIDL_FLAG_DONT_VERIFY); + PyModule_AddIntConstant(m, "CSIDL_HISTORY", CSIDL_HISTORY); + PyModule_AddIntConstant(m, "CSIDL_INTERNET_CACHE", CSIDL_INTERNET_CACHE); + PyModule_AddIntConstant(m, "CSIDL_LOCAL_APPDATA", CSIDL_LOCAL_APPDATA); + PyModule_AddIntConstant(m, "CSIDL_MYPICTURES", CSIDL_MYPICTURES); + PyModule_AddIntConstant(m, "CSIDL_PERSONAL", CSIDL_PERSONAL); + PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES", CSIDL_PROGRAM_FILES); + PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES_COMMON", CSIDL_PROGRAM_FILES_COMMON); + PyModule_AddIntConstant(m, "CSIDL_SYSTEM", CSIDL_SYSTEM); + PyModule_AddIntConstant(m, "CSIDL_WINDOWS", CSIDL_WINDOWS); + +} + diff --git a/src/calibre/utils/winutil.c b/src/calibre/utils/winutil.c deleted file mode 100644 index 04a4c3a49b..0000000000 --- a/src/calibre/utils/winutil.c +++ /dev/null @@ -1,99 +0,0 @@ -#define UNICODE -#include -#include -#include -#include - - -static PyObject * -winutil_folder_path(PyObject *self, PyObject *args) { - int res; DWORD dwFlags; - PyObject *ans = NULL; - TCHAR wbuf[MAX_PATH]; CHAR buf[4*MAX_PATH]; - memset(wbuf, 0, sizeof(TCHAR)*MAX_PATH); memset(buf, 0, sizeof(CHAR)*MAX_PATH); - - if (!PyArg_ParseTuple(args, "l", &dwFlags)) return NULL; - - res = SHGetFolderPath(NULL, dwFlags, NULL, 0, wbuf); - if (res != S_OK) { - if (res == E_FAIL) PyErr_SetString(PyExc_ValueError, "Folder does not exist."); - PyErr_SetString(PyExc_ValueError, "Folder not valid"); - return NULL; - } - res = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, 4*MAX_PATH, NULL, NULL); - ans = PyUnicode_DecodeUTF8(buf, res-1, "strict"); - return ans; -} - -static PyObject * -winutil_argv(PyObject *self, PyObject *args) { - PyObject *argv, *v; - LPWSTR *_argv; - LPSTR buf; - int argc, i, bytes; - if (!PyArg_ParseTuple(args, "")) return NULL; - _argv = CommandLineToArgvW(GetCommandLine(), &argc); - if (_argv == NULL) { PyErr_SetString(PyExc_RuntimeError, "Out of memory."); return NULL; } - argv = PyList_New(argc); - if (argv != NULL) { - for (i = 0; i < argc; i++) { - bytes = WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, NULL, 0, NULL, NULL); - buf = (LPSTR)PyMem_Malloc(sizeof(CHAR)*bytes); - if (buf == NULL) { Py_DECREF(argv); argv = NULL; break; } - WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, buf, bytes, NULL, NULL); - v = PyUnicode_DecodeUTF8(buf, bytes-1, "strict"); - PyMem_Free(buf); - if (v == NULL) { Py_DECREF(argv); argv = NULL; break; } - PyList_SetItem(argv, i, v); - } - } - LocalFree(_argv); - return argv; -} - -static PyMethodDef WinutilMethods[] = { - {"folder_path", winutil_folder_path, METH_VARARGS, - "folder_path(csidl_id) -> path\n\n" - "Get paths to common system folders. " - "See windows documentation of SHGetFolderPath. " - "The paths are returned as unicode objects. csidl_id should be one " - "of the symbolic constants defined in this module. You can also OR " - "a symbolic constant with CSIDL_FLAG_CREATE to force the operating " - "system to create a folder if it does not exist."}, - {"argv", winutil_argv, METH_VARARGS, - "argv() -> list of command line arguments\n\n" - "Get command line arguments as unicode objects. Note that the " - "first argument will be the path to the interpreter, *not* the " - "script being run. So to replace sys.argv, you should use " - "sys.argv[1:] = argv()[1:]."}, - - {NULL, NULL, 0, NULL} -}; - -PyMODINIT_FUNC -initwinutil(void) { - PyObject *m; - m = Py_InitModule3("winutil", WinutilMethods, - "Defines utility methods to interface with windows." - ); - if (m == NULL) return; - PyModule_AddIntConstant(m, "CSIDL_ADMINTOOLS", CSIDL_ADMINTOOLS); - PyModule_AddIntConstant(m, "CSIDL_APPDATA", CSIDL_APPDATA); - PyModule_AddIntConstant(m, "CSIDL_COMMON_ADMINTOOLS", CSIDL_COMMON_ADMINTOOLS); - PyModule_AddIntConstant(m, "CSIDL_COMMON_APPDATA", CSIDL_COMMON_APPDATA); - PyModule_AddIntConstant(m, "CSIDL_COMMON_DOCUMENTS", CSIDL_COMMON_DOCUMENTS); - PyModule_AddIntConstant(m, "CSIDL_COOKIES", CSIDL_COOKIES); - PyModule_AddIntConstant(m, "CSIDL_FLAG_CREATE", CSIDL_FLAG_CREATE); - PyModule_AddIntConstant(m, "CSIDL_FLAG_DONT_VERIFY", CSIDL_FLAG_DONT_VERIFY); - PyModule_AddIntConstant(m, "CSIDL_HISTORY", CSIDL_HISTORY); - PyModule_AddIntConstant(m, "CSIDL_INTERNET_CACHE", CSIDL_INTERNET_CACHE); - PyModule_AddIntConstant(m, "CSIDL_LOCAL_APPDATA", CSIDL_LOCAL_APPDATA); - PyModule_AddIntConstant(m, "CSIDL_MYPICTURES", CSIDL_MYPICTURES); - PyModule_AddIntConstant(m, "CSIDL_PERSONAL", CSIDL_PERSONAL); - PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES", CSIDL_PROGRAM_FILES); - PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES_COMMON", CSIDL_PROGRAM_FILES_COMMON); - PyModule_AddIntConstant(m, "CSIDL_SYSTEM", CSIDL_SYSTEM); - PyModule_AddIntConstant(m, "CSIDL_WINDOWS", CSIDL_WINDOWS); - -} -