mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Use a little C code to interface with windows for device detection and unicode command line arguments
This commit is contained in:
parent
e854a9ffd5
commit
50add0c72d
@ -253,7 +253,7 @@ _check_symlinks_prescript()
|
|||||||
print 'Adding plugins'
|
print 'Adding plugins'
|
||||||
module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
|
module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
|
||||||
print 'Adding fontconfig'
|
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)))
|
os.link(f, os.path.join(frameworks_dir, os.path.basename(f)))
|
||||||
dst = os.path.join(resource_dir, 'fonts')
|
dst = os.path.join(resource_dir, 'fonts')
|
||||||
if os.path.exists(dst):
|
if os.path.exists(dst):
|
||||||
|
17
setup.py
17
setup.py
@ -56,10 +56,16 @@ if __name__ == '__main__':
|
|||||||
include_dirs=['src/calibre/utils/lzx'])]
|
include_dirs=['src/calibre/utils/lzx'])]
|
||||||
if iswindows:
|
if iswindows:
|
||||||
ext_modules.append(Extension('calibre.plugins.winutil',
|
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
|
if isosx:
|
||||||
for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]:
|
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]
|
pro = glob.glob(os.path.join(path, '*.pro'))[0]
|
||||||
raw = open(pro).read()
|
raw = open(pro).read()
|
||||||
base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1)
|
base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1)
|
||||||
@ -72,7 +78,7 @@ if __name__ == '__main__':
|
|||||||
os.chdir('.build')
|
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(( (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'])
|
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'):
|
if not os.path.exists('.build'):
|
||||||
os.mkdir('.build')
|
os.mkdir('.build')
|
||||||
os.chdir('.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:
|
if 'develop' in ' '.join(sys.argv) and islinux:
|
||||||
subprocess.check_call('calibre_postinstall', shell=True)
|
subprocess.check_call('calibre_postinstall', shell=True)
|
||||||
|
@ -23,6 +23,10 @@ Run an embedded python interpreter.
|
|||||||
return parser
|
return parser
|
||||||
|
|
||||||
def update_zipfile(zipfile, mod, path):
|
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]*')
|
pat = re.compile(mod.replace('.', '/')+r'\.py[co]*')
|
||||||
name = mod.replace('.', '/') + os.path.splitext(path)[-1]
|
name = mod.replace('.', '/') + os.path.splitext(path)[-1]
|
||||||
update(zipfile, [pat], [path], [name])
|
update(zipfile, [pat], [path], [name])
|
||||||
|
@ -133,31 +133,7 @@ class KINDLE(Device):
|
|||||||
|
|
||||||
|
|
||||||
def open_windows(self):
|
def open_windows(self):
|
||||||
drives = []
|
raise NotImplementedError
|
||||||
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]
|
|
||||||
|
|
||||||
|
|
||||||
def open_linux(self):
|
def open_linux(self):
|
||||||
|
@ -7,59 +7,48 @@ manner.
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from calibre import iswindows, isosx
|
from calibre import iswindows, isosx, plugins
|
||||||
from calibre.devices import libusb
|
from calibre.devices import libusb
|
||||||
|
|
||||||
osx_scanner = None
|
osx_scanner = win_scanner = linux_scanner = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import usbobserver
|
import usbobserver
|
||||||
osx_scanner = usbobserver.get_devices
|
osx_scanner = usbobserver.get_devices
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
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
|
linux_scanner = libusb.get_devices
|
||||||
|
|
||||||
class DeviceScanner(object):
|
class DeviceScanner(object):
|
||||||
|
|
||||||
def __init__(self, wmi=None):
|
def __init__(self, *args):
|
||||||
self.wmi = wmi
|
|
||||||
if iswindows and wmi is None:
|
|
||||||
raise RuntimeError('You must pass a wmi instance to DeviceScanner on windows.')
|
|
||||||
if isosx and osx_scanner is None:
|
if isosx and osx_scanner is None:
|
||||||
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
|
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
|
||||||
if not (isosx or iswindows) and not libusb.has_library():
|
if not (isosx or iswindows) and not libusb.has_library():
|
||||||
raise RuntimeError('DeviceScanner requires libusb to work.')
|
raise RuntimeError('DeviceScanner requires libusb to work.')
|
||||||
|
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
|
||||||
self.devices = []
|
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):
|
def scan(self):
|
||||||
try: # Windows WMI occasionally and temporarily barfs
|
'''Fetch list of connected USB devices from operating system'''
|
||||||
self.devices = self.get_devices()
|
self.devices = self.scanner()
|
||||||
except Exception, e:
|
|
||||||
if not iswindows and e:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
|
|
||||||
def is_device_connected(self, device):
|
def is_device_connected(self, device):
|
||||||
if iswindows:
|
if iswindows:
|
||||||
for device_id in self.devices:
|
for device_id in self.devices:
|
||||||
if 'VEN_'+device.VENDOR_NAME in device_id and \
|
vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
|
||||||
'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()
|
|
||||||
if vid in device_id and pid in device_id:
|
if vid in device_id and pid in device_id:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
usbobserver_get_devices(PyObject *self, PyObject *args) {
|
usbobserver_get_usb_devices(PyObject *self, PyObject *args) {
|
||||||
|
|
||||||
mach_port_t masterPort;
|
mach_port_t masterPort;
|
||||||
CFMutableDictionaryRef matchingDict;
|
CFMutableDictionaryRef matchingDict;
|
||||||
@ -62,7 +62,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
|
|||||||
PyObject *devices, *device;
|
PyObject *devices, *device;
|
||||||
devices = PyList_New(0);
|
devices = PyList_New(0);
|
||||||
if (devices == NULL) {
|
if (devices == NULL) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Out of memory allocating list");
|
PyErr_NoMemory();
|
||||||
mach_port_deallocate(mach_task_self(), masterPort);
|
mach_port_deallocate(mach_task_self(), masterPort);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef usbobserver_methods[] = {
|
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)."
|
"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}
|
{NULL, NULL, 0, NULL}
|
||||||
|
@ -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?
|
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 <http://calibre.kovidgoyal.net/discussion>`_. 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:
|
There can be several causes for this:
|
||||||
|
|
||||||
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::
|
* **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()"
|
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 <http://calibre.kovidgoyal.net/discussion`_.
|
||||||
|
|
||||||
|
|
||||||
I want some feature added to |app|. What can I do?
|
I want some feature added to |app|. What can I do?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -22,7 +22,7 @@ match to a given font specification. The main functions in this module are:
|
|||||||
.. autofunction:: match
|
.. autofunction:: match
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, os, locale, codecs, platform
|
import sys, os, locale, codecs, ctypes
|
||||||
from ctypes import cdll, c_void_p, Structure, c_int, POINTER, c_ubyte, c_char, util, \
|
from ctypes import cdll, c_void_p, Structure, c_int, POINTER, c_ubyte, c_char, util, \
|
||||||
pointer, byref, create_string_buffer, Union, c_char_p, c_double
|
pointer, byref, create_string_buffer, Union, c_char_p, c_double
|
||||||
|
|
||||||
@ -34,13 +34,24 @@ except:
|
|||||||
|
|
||||||
iswindows = 'win32' in sys.platform or 'win64' in sys.platform
|
iswindows = 'win32' in sys.platform or 'win64' in sys.platform
|
||||||
isosx = 'darwin' in sys.platform
|
isosx = 'darwin' in sys.platform
|
||||||
is64bit = '64bit' in platform.architecture()[0]
|
DISABLED = False
|
||||||
|
#if isosx:
|
||||||
|
# libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
|
||||||
|
# size = ctypes.c_uint(0)
|
||||||
|
# ok = libc.sysctlbyname("hw.cpu64bit_capable", None, byref(size), None, 0)
|
||||||
|
# if ok != 0:
|
||||||
|
# is64bit = False
|
||||||
|
# else:
|
||||||
|
# buf = ctypes.c_char_p("\0" * size.value)
|
||||||
|
# ok = libc.sysctlbyname("hw.cpu64bit_capable", buf, byref(size), None, 0)
|
||||||
|
# if ok != 0:
|
||||||
|
# is64bit = False
|
||||||
|
# else:
|
||||||
|
# is64bit = '1' in buf.value
|
||||||
|
# DISABLED = is64bit
|
||||||
|
|
||||||
def load_library():
|
def load_library():
|
||||||
if isosx:
|
if isosx:
|
||||||
if os.path.exists('/usr/X11/lib/libfontconfig.1.dylib'): # The fontconfig shipped with calibre doesn't work on Leopard
|
|
||||||
lib = '/usr/X11/lib/libfontconfig.1.dylib'
|
|
||||||
else:
|
|
||||||
lib = os.path.join(getattr(sys, 'frameworks_dir'), 'libfontconfig.1.dylib') \
|
lib = os.path.join(getattr(sys, 'frameworks_dir'), 'libfontconfig.1.dylib') \
|
||||||
if hasattr(sys, 'frameworks_dir') else util.find_library('fontconfig')
|
if hasattr(sys, 'frameworks_dir') else util.find_library('fontconfig')
|
||||||
return cdll.LoadLibrary(lib)
|
return cdll.LoadLibrary(lib)
|
||||||
@ -160,7 +171,7 @@ class FontScanner(Thread):
|
|||||||
global _initialized
|
global _initialized
|
||||||
_initialized = True
|
_initialized = True
|
||||||
|
|
||||||
|
if not DISABLED:
|
||||||
_scanner = FontScanner()
|
_scanner = FontScanner()
|
||||||
_scanner.start()
|
_scanner.start()
|
||||||
|
|
||||||
@ -178,6 +189,8 @@ def find_font_families(allowed_extensions=['ttf', 'otf']):
|
|||||||
`allowed_extensions`: A list of allowed extensions for font file types. Defaults to
|
`allowed_extensions`: A list of allowed extensions for font file types. Defaults to
|
||||||
`['ttf', 'otf']`. If it is empty, it is ignored.
|
`['ttf', 'otf']`. If it is empty, it is ignored.
|
||||||
'''
|
'''
|
||||||
|
if DISABLED:
|
||||||
|
return []
|
||||||
join()
|
join()
|
||||||
allowed_extensions = [i.lower() for i in allowed_extensions]
|
allowed_extensions = [i.lower() for i in allowed_extensions]
|
||||||
|
|
||||||
@ -220,6 +233,8 @@ def files_for_family(family, normalize=True):
|
|||||||
they are a tuple (slant, weight) otherwise they are strings from the set
|
they are a tuple (slant, weight) otherwise they are strings from the set
|
||||||
`('normal', 'bold', 'italic', 'bi', 'light', 'li')`
|
`('normal', 'bold', 'italic', 'bi', 'light', 'li')`
|
||||||
'''
|
'''
|
||||||
|
if DISABLED:
|
||||||
|
return {}
|
||||||
join()
|
join()
|
||||||
if isinstance(family, unicode):
|
if isinstance(family, unicode):
|
||||||
family = family.encode(preferred_encoding)
|
family = family.encode(preferred_encoding)
|
||||||
@ -296,6 +311,8 @@ def match(name, sort=False, verbose=False):
|
|||||||
decreasing closeness of matching.
|
decreasing closeness of matching.
|
||||||
`verbose`: If `True` print debugging information to stdout
|
`verbose`: If `True` print debugging information to stdout
|
||||||
'''
|
'''
|
||||||
|
if DISABLED:
|
||||||
|
return []
|
||||||
join()
|
join()
|
||||||
if isinstance(name, unicode):
|
if isinstance(name, unicode):
|
||||||
name = name.encode(preferred_encoding)
|
name = name.encode(preferred_encoding)
|
||||||
|
18
src/calibre/utils/windows/Makefile
Normal file
18
src/calibre/utils/windows/Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Makefile to test the winutil module
|
||||||
|
# Invoke with nmake /f Makefile.winutil
|
||||||
|
|
||||||
|
test : winutil.pyd
|
||||||
|
python.exe -c "import winutil; winutil.set_debug(True); print winutil.get_usb_devices(); print winutil.get_mounted_volumes_for_usb_device(0x054c, 0x031e)"
|
||||||
|
|
||||||
|
winutil.pyd : winutil.obj
|
||||||
|
link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:c:\Python25\libs \
|
||||||
|
/LIBPATH:c:\Python25\PCBuild shell32.lib setupapi.lib /EXPORT:initwinutil \
|
||||||
|
winutil.obj /OUT:winutil.pyd
|
||||||
|
|
||||||
|
|
||||||
|
winutil.obj : winutil.c
|
||||||
|
cl.exe /c /nologo /Ox /MD /W3 /GX /DNDEBUG -Ic:\Python25\include \
|
||||||
|
-Ic:\Python25\PC -Ic:\WinDDK\6001.18001\inc\api /Tcwinutil.c /Fowinutil.obj
|
||||||
|
|
||||||
|
clean :
|
||||||
|
del winutil.pyd winutil.obj winutil.exp winutil.lib
|
587
src/calibre/utils/windows/winutil.c
Normal file
587
src/calibre/utils/windows/winutil.c
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
/*
|
||||||
|
:mod:`winutil` -- Interface to Windows
|
||||||
|
============================================
|
||||||
|
|
||||||
|
.. module:: winutil
|
||||||
|
:platform: Windows
|
||||||
|
:synopsis: Various methods to interface with the operating system
|
||||||
|
|
||||||
|
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> 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 <Windows.h>
|
||||||
|
#include <Python.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
#include <devguid.h>
|
||||||
|
#include <cfgmgr32.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,99 +0,0 @@
|
|||||||
#define UNICODE
|
|
||||||
#include <shlobj.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <Python.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user