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 time
from UM.Signal import Signal
from UM.Message import Message
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Logger import Logger
from . import RemovableDriveOutputDevice
from UM.Logger import Logger

View file

@ -4,16 +4,12 @@
from . import RemovableDrivePlugin
import threading
import string
from ctypes import windll
from ctypes import wintypes
import ctypes
import time
import os
import subprocess
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -32,6 +28,21 @@ IOCTL_STORAGE_EJECT_MEDIA = 2967560 # [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
class WindowsRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
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 )
if handle == -1:
print(windll.kernel32.GetLastError())
return
# 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.
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
if not windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, None, None, None, None, None):
result = False
else:
result = True
return_code = windll.kernel32.DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, None, 0, None, 0, ctypes.pointer(bytes_returned), None)
# DeviceIoControl with IOCTL_STORAGE_EJECT_MEDIA return 0 on error.
if return_code == 0:
# 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
windll.kernel32.CloseHandle(handle)
return result
# If an error happened in the DeviceIoControl, raise it now.
if error:
raise error
# Return success
return True