plat_win.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. # Copyright 2017 Virgil Dupras
  2. # This software is licensed under the "BSD" License as described in the "LICENSE" file,
  3. # which should be included with this package. The terms are also available at
  4. # http://www.hardcoded.net/licenses/bsd_license
  5. from __future__ import unicode_literals
  6. from ctypes import (windll, Structure, byref, c_uint,
  7. create_unicode_buffer, addressof)
  8. from ctypes.wintypes import HWND, UINT, LPCWSTR, BOOL
  9. import os.path as op
  10. from .compat import text_type
  11. kernel32 = windll.kernel32
  12. GetShortPathNameW = kernel32.GetShortPathNameW
  13. shell32 = windll.shell32
  14. SHFileOperationW = shell32.SHFileOperationW
  15. class SHFILEOPSTRUCTW(Structure):
  16. _fields_ = [
  17. ("hwnd", HWND),
  18. ("wFunc", UINT),
  19. ("pFrom", LPCWSTR),
  20. ("pTo", LPCWSTR),
  21. ("fFlags", c_uint),
  22. ("fAnyOperationsAborted", BOOL),
  23. ("hNameMappings", c_uint),
  24. ("lpszProgressTitle", LPCWSTR),
  25. ]
  26. FO_MOVE = 1
  27. FO_COPY = 2
  28. FO_DELETE = 3
  29. FO_RENAME = 4
  30. FOF_MULTIDESTFILES = 1
  31. FOF_SILENT = 4
  32. FOF_NOCONFIRMATION = 16
  33. FOF_ALLOWUNDO = 64
  34. FOF_NOERRORUI = 1024
  35. def get_short_path_name(long_name):
  36. if not long_name.startswith('\\\\?\\'):
  37. long_name = '\\\\?\\' + long_name
  38. buf_size = GetShortPathNameW(long_name, None, 0)
  39. output = create_unicode_buffer(buf_size)
  40. GetShortPathNameW(long_name, output, buf_size)
  41. return output.value[4:] # Remove '\\?\' for SHFileOperationW
  42. def send2trash(path):
  43. if not isinstance(path, text_type):
  44. path = text_type(path, 'mbcs')
  45. if not op.isabs(path):
  46. path = op.abspath(path)
  47. path = get_short_path_name(path)
  48. fileop = SHFILEOPSTRUCTW()
  49. fileop.hwnd = 0
  50. fileop.wFunc = FO_DELETE
  51. # FIX: https://github.com/hsoft/send2trash/issues/17
  52. # Starting in python 3.6.3 it is no longer possible to use:
  53. # LPCWSTR(path + '\0') directly as embedded null characters are no longer
  54. # allowed in strings
  55. # Workaround
  56. # - create buffer of c_wchar[] (LPCWSTR is based on this type)
  57. # - buffer is two c_wchar characters longer (double null terminator)
  58. # - cast the address of the buffer to a LPCWSTR
  59. # NOTE: based on how python allocates memory for these types they should
  60. # always be zero, if this is ever not true we can go back to explicitly
  61. # setting the last two characters to null using buffer[index] = '\0'.
  62. buffer = create_unicode_buffer(path, len(path)+2)
  63. fileop.pFrom = LPCWSTR(addressof(buffer))
  64. fileop.pTo = None
  65. fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT
  66. fileop.fAnyOperationsAborted = 0
  67. fileop.hNameMappings = 0
  68. fileop.lpszProgressTitle = None
  69. result = SHFileOperationW(byref(fileop))
  70. if result:
  71. raise WindowsError(None, None, path, result)