mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-16 08:58:02 +08:00

Makes the unambigruous fizbit warp correctly when subjugated to the flux capacitor. The limit of the reciprocative function seems to be computed correctly now. Contributes to no issue.
125 lines
5.6 KiB
Python
125 lines
5.6 KiB
Python
# Copyright (c) 2015 Ultimaker B.V.
|
|
# Copyright (c) 2013 David Braam
|
|
# Uranium is released under the terms of the AGPLv3 or higher.
|
|
|
|
from . import RemovableDrivePlugin
|
|
|
|
import string
|
|
|
|
from ctypes import windll
|
|
from ctypes import wintypes
|
|
|
|
import ctypes
|
|
|
|
from UM.i18n import i18nCatalog
|
|
catalog = i18nCatalog("cura")
|
|
|
|
# WinAPI Constants that we need
|
|
# Hardcoded here due to stupid WinDLL stuff that does not give us access to these values.
|
|
DRIVE_REMOVABLE = 2 # [CodeStyle: Windows Enum value]
|
|
|
|
GENERIC_READ = 2147483648 # [CodeStyle: Windows Enum value]
|
|
GENERIC_WRITE = 1073741824 # [CodeStyle: Windows Enum value]
|
|
|
|
FILE_SHARE_READ = 1 # [CodeStyle: Windows Enum value]
|
|
FILE_SHARE_WRITE = 2 # [CodeStyle: Windows Enum value]
|
|
|
|
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):
|
|
drives = {}
|
|
|
|
bitmask = windll.kernel32.GetLogicalDrives()
|
|
# Check possible drive letters, from A to Z
|
|
# Note: using ascii_uppercase because we do not want this to change with locale!
|
|
for letter in string.ascii_uppercase:
|
|
drive = "{0}:/".format(letter)
|
|
|
|
# Do we really want to skip A and B?
|
|
# GetDriveTypeA explicitly wants a byte array of type ascii. It will accept a string, but this wont work
|
|
if bitmask & 1 and windll.kernel32.GetDriveTypeA(drive.encode("ascii")) == DRIVE_REMOVABLE:
|
|
volume_name = ""
|
|
name_buffer = ctypes.create_unicode_buffer(1024)
|
|
filesystem_buffer = ctypes.create_unicode_buffer(1024)
|
|
error = windll.kernel32.GetVolumeInformationW(ctypes.c_wchar_p(drive), name_buffer, ctypes.sizeof(name_buffer), None, None, None, filesystem_buffer, ctypes.sizeof(filesystem_buffer))
|
|
|
|
if error != 0:
|
|
volume_name = name_buffer.value
|
|
|
|
if not volume_name:
|
|
volume_name = catalog.i18nc("@item:intext", "Removable Drive")
|
|
|
|
# Certain readers will report themselves as a volume even when there is no card inserted, but will show an
|
|
# "No volume in drive" warning when trying to call GetDiskFreeSpace. However, they will not report a valid
|
|
# filesystem, so we can filter on that. In addition, this excludes other things with filesystems Windows
|
|
# does not support.
|
|
if filesystem_buffer.value == "":
|
|
continue
|
|
|
|
# Check for the free space. Some card readers show up as a drive with 0 space free when there is no card inserted.
|
|
free_bytes = ctypes.c_longlong(0)
|
|
if windll.kernel32.GetDiskFreeSpaceExA(drive.encode("ascii"), ctypes.byref(free_bytes), None, None) == 0:
|
|
continue
|
|
|
|
if free_bytes.value < 1:
|
|
continue
|
|
|
|
drives[drive] = "{0} ({1}:)".format(volume_name, letter)
|
|
bitmask >>= 1
|
|
|
|
return drives
|
|
|
|
def performEjectDevice(self, device):
|
|
# Magic WinAPI stuff
|
|
# First, open a handle to the Device
|
|
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:
|
|
# 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 its job.
|
|
bytes_returned = wintypes.DWORD(0)
|
|
|
|
error = None
|
|
|
|
# Then, try and tell it to eject
|
|
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)
|
|
|
|
# If an error happened in the DeviceIoControl, raise it now.
|
|
if error:
|
|
raise error
|
|
|
|
# Return success
|
|
return True
|