CURA-1104: Fix the incorrect "failed to eject drive" message for windows.

The C windows API call was wrong. The lpBytesReturned parameter was set to
NULL. While the docmentation at:
aa363406(v=vs.85).aspx
states that it CANNOT be NULL if lpOverlapped is NULL. Overlapped is for
async operations. So the easiest way to fix this is to supply a proper
pointer.

I've also removed unused includes. And supplied the DeviceIoControl with
proper ctypes calling information to prevent other python->c problems.
This commit is contained in:
daid 2016-03-11 15:13:09 +01:00
parent 3b66e887b0
commit 8980600292
2 changed files with 39 additions and 13 deletions

View file

@ -4,9 +4,9 @@
import threading import threading
import time import time
from UM.Signal import Signal
from UM.Message import Message from UM.Message import Message
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Logger import Logger
from . import RemovableDriveOutputDevice from . import RemovableDriveOutputDevice
from UM.Logger import Logger from UM.Logger import Logger

View file

@ -4,16 +4,12 @@
from . import RemovableDrivePlugin from . import RemovableDrivePlugin
import threading
import string import string
from ctypes import windll from ctypes import windll
from ctypes import wintypes from ctypes import wintypes
import ctypes import ctypes
import time
import os
import subprocess
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
@ -32,6 +28,21 @@ IOCTL_STORAGE_EJECT_MEDIA = 2967560 # [CodeStyle: Windows Enum value]
OPEN_EXISTING = 3 # [CodeStyle: Windows Enum value] OPEN_EXISTING = 3 # [CodeStyle: Windows Enum value]
# Setup the DeviceIoControl function arguments and return type.
# See ctypes documentation for details on how to call C functions from python, and why this is important.
windll.kernel32.DeviceIoControl.argtypes = [
wintypes.HANDLE, # _In_ HANDLE hDevice
wintypes.DWORD, # _In_ DWORD dwIoControlCode
wintypes.LPVOID, # _In_opt_ LPVOID lpInBuffer
wintypes.DWORD, # _In_ DWORD nInBufferSize
wintypes.LPVOID, # _Out_opt_ LPVOID lpOutBuffer
wintypes.DWORD, # _In_ DWORD nOutBufferSize
ctypes.POINTER(wintypes.DWORD), # _Out_opt_ LPDWORD lpBytesReturned
wintypes.LPVOID # _Inout_opt_ LPOVERLAPPED lpOverlapped
]
windll.kernel32.DeviceIoControl.restype = wintypes.BOOL
## Removable drive support for windows ## Removable drive support for windows
class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin): class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
def checkRemovableDrives(self): def checkRemovableDrives(self):
@ -83,16 +94,31 @@ class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
handle = windll.kernel32.CreateFileA("\\\\.\\{0}".format(device.getId()[:-1]).encode("ascii"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None ) handle = windll.kernel32.CreateFileA("\\\\.\\{0}".format(device.getId()[:-1]).encode("ascii"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None )
if handle == -1: if handle == -1:
print(windll.kernel32.GetLastError()) # ctypes.WinError sets up an GetLastError API call for windows as an Python OSError exception.
return # So we use this to raise the error to our caller.
raise ctypes.WinError()
# The DeviceIoControl requires a bytes_returned pointer to be a valid pointer.
# So create a ctypes DWORD to reference. (Without this pointer the DeviceIoControl function will crash with an access violation after doing it's job.
bytes_returned = wintypes.DWORD(0)
error = None
result = None
# Then, try and tell it to eject # Then, try and tell it to eject
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None): return_code = windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, 0, None, 0, ctypes.pointer(bytes_returned), None)
result = False # DeviceIoControl with IOCTL_STORAGE_EJECT_MEDIA return 0 on error.
else: if return_code == 0:
result = True # ctypes.WinError sets up an GetLastError API call for windows as an Python OSError exception.
# So we use this to raise the error to our caller.
error = ctypes.WinError()
# Do not raise an error here yet, so we can properly close the handle.
# Finally, close the handle # Finally, close the handle
windll.kernel32.CloseHandle(handle) windll.kernel32.CloseHandle(handle)
return result
# If an error happened in the DeviceIoControl, raise it now.
if error:
raise error
# Return success
return True