Workaround for bug on some Windows 10 machines that were upgraded from a previous windows version that was preventing calibre from detecting devices

This commit is contained in:
Kovid Goyal 2016-01-17 00:13:15 +05:30
parent d29f34face
commit 17e7e7bdb3

View File

@ -13,6 +13,8 @@ from ctypes import (
wstring_at, addressof, create_unicode_buffer, string_at, c_uint64 as QWORD) wstring_at, addressof, create_unicode_buffer, string_at, c_uint64 as QWORD)
from ctypes.wintypes import DWORD, WORD, ULONG, LPCWSTR, HWND, BOOL, LPWSTR, UINT, BYTE, HANDLE from ctypes.wintypes import DWORD, WORD, ULONG, LPCWSTR, HWND, BOOL, LPWSTR, UINT, BYTE, HANDLE
from calibre import prints
is64bit = sys.maxsize > (1 << 32) is64bit = sys.maxsize > (1 << 32)
# Data and function type definitions {{{ # Data and function type definitions {{{
@ -315,7 +317,7 @@ def iterdescendants(parent_devinst):
for gc in iterdescendants(child): for gc in iterdescendants(child):
yield gc yield gc
def get_all_removable_drives(): def get_all_removable_drives(allow_fixed=False):
mask = GetLogicalDrives() mask = GetLogicalDrives()
ans = {} ans = {}
buf = create_unicode_buffer(100) buf = create_unicode_buffer(100)
@ -323,7 +325,10 @@ def get_all_removable_drives():
drive_present = bool(mask & 0b1) drive_present = bool(mask & 0b1)
mask >>= 1 mask >>= 1
drive_root = drive_letter + ':' + os.sep drive_root = drive_letter + ':' + os.sep
if drive_present and GetDriveType(drive_root) == DRIVE_REMOVABLE: # Removable, present drive if not drive_present:
continue
drive_type = GetDriveType(drive_root)
if drive_type == DRIVE_REMOVABLE or (allow_fixed and drive_type == DRIVE_FIXED): # Removable, present drive
try: try:
GetVolumeNameForVolumeMountPoint(drive_root, buf, len(buf)) GetVolumeNameForVolumeMountPoint(drive_root, buf, len(buf))
except WindowsError: except WindowsError:
@ -437,12 +442,28 @@ def drive_letter_from_volume_devpath(devpath, drive_map):
return drive_map.get(pbuf.value) return drive_map.get(pbuf.value)
def get_removable_drives(debug=False): def get_removable_drives(debug=False):
drive_map = get_all_removable_drives() pbuf = create_unicode_buffer(512)
mask = GetLogicalDrives()
drives = {letter:GetDriveType(letter + ':' + os.sep) for i, letter in enumerate(string.ascii_uppercase) if mask & (1 << i)}
if debug:
prints('Drive type map: %s' % drives)
drive_map = {}
for letter, drive_type in drives.iteritems():
# We need to allow both removable and fixed drives because some windows
# 10 machines that have been upgraded from a previous windows release
# mark USB drives as fixed. The fixed drives will only be added if
# "USBSTOR" in present in the volume device path, indicating that the drives,
# are, in fact, USB drives.
if drive_type in (DRIVE_REMOVABLE, DRIVE_FIXED):
try:
GetVolumeNameForVolumeMountPoint(letter + ':' + os.sep, pbuf, len(pbuf))
except WindowsError:
continue
drive_map[pbuf.value] = letter
if not drive_map: if not drive_map:
raise NoRemovableDrives('No removable drives found!') raise NoRemovableDrives('No removable drives found!')
buf = None buf = None
pbuf = create_unicode_buffer(512)
ans = {} ans = {}
with get_device_set() as dev_list: with get_device_set() as dev_list:
interface_data = SP_DEVICE_INTERFACE_DATA() interface_data = SP_DEVICE_INTERFACE_DATA()
@ -471,8 +492,11 @@ def get_removable_drives(debug=False):
candidates.append(devpath) candidates.append(devpath)
drive_letter = drive_letter_from_volume_devpath(devpath, drive_map) drive_letter = drive_letter_from_volume_devpath(devpath, drive_map)
if drive_letter: drive_type = drives.get(drive_letter)
if drive_type == DRIVE_REMOVABLE or (drive_type == DRIVE_FIXED and 'usbstor' in devpath.lower()):
ans[drive_letter] = candidates ans[drive_letter] = candidates
if debug:
prints('Found volume with device path:', devpath, ' Drive letter:', drive_letter)
return ans return ans
# }}} # }}}
@ -514,7 +538,7 @@ def get_drive_letters_for_device(vendor_id, product_id, debug=False):
break break
if found_at is None: if found_at is None:
if debug: if debug:
print('Could not find device matching vid=0x%x pid=0x%x: %r' % (vendor_id, product_id)) prints('Could not find device matching vid=0x%x pid=0x%x: %r' % (vendor_id, product_id))
return ans return ans
# Get the device ids for all descendants of the found device # Get the device ids for all descendants of the found device
@ -523,11 +547,11 @@ def get_drive_letters_for_device(vendor_id, product_id, debug=False):
devid, wbuf = get_device_id(devinst, buf=wbuf) devid, wbuf = get_device_id(devinst, buf=wbuf)
device_ids.add(devid.upper().replace(os.sep, '#')) device_ids.add(devid.upper().replace(os.sep, '#'))
if debug: if debug:
print('Device ids for vid=0x%x pid=0x%x: %r' % (vendor_id, product_id, device_ids)) prints('Device ids for vid=0x%x pid=0x%x: %r' % (vendor_id, product_id, device_ids))
if not device_ids: if not device_ids:
return ans return ans
drive_map = get_all_removable_drives() drive_map = get_all_removable_drives(allow_fixed=True)
if not drive_map: if not drive_map:
raise NoRemovableDrives('No removable drives found!') raise NoRemovableDrives('No removable drives found!')
@ -549,7 +573,7 @@ def get_drive_letters_for_device(vendor_id, product_id, debug=False):
matched = True matched = True
break break
if debug: if debug:
print('Found volume with device path: %s Matches a device_id: %s' % (devpath, matched)) prints('Found volume with device path: %s Matches a device_id: %s' % (devpath, matched))
if matched: if matched:
drive_letter = drive_letter_from_volume_devpath(devpath, drive_map) drive_letter = drive_letter_from_volume_devpath(devpath, drive_map)
if drive_letter: if drive_letter:
@ -667,7 +691,7 @@ def develop(vendor_id=0x1949, product_id=0x4, do_eject=False):
print() print()
print('Is device connected:', is_usb_device_connected(vendor_id, product_id)) print('Is device connected:', is_usb_device_connected(vendor_id, product_id))
print('\nAll removable drives:') print('\nAll removable drives:')
pprint(get_all_removable_drives()) pprint(get_all_removable_drives(allow_fixed=False))
print('\nRemovable drives:') print('\nRemovable drives:')
rd = get_removable_drives(debug=True) rd = get_removable_drives(debug=True)
pprint(rd) pprint(rd)