winutils.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2013-2021, PyInstaller Development Team.
  3. #
  4. # Distributed under the terms of the GNU General Public License (version 2
  5. # or later) with exception for distributing the bootloader.
  6. #
  7. # The full license is in the file COPYING.txt, distributed with this software.
  8. #
  9. # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
  10. #-----------------------------------------------------------------------------
  11. """
  12. Utilities for Windows platform.
  13. """
  14. import os
  15. import sys
  16. import PyInstaller.log as logging
  17. from PyInstaller import compat
  18. logger = logging.getLogger(__name__)
  19. def get_windows_dir():
  20. """
  21. Return the Windows directory, e.g., C:\\Windows.
  22. """
  23. # Imported here to avoid circular import.
  24. from PyInstaller import compat
  25. windir = compat.win32api.GetWindowsDirectory()
  26. if not windir:
  27. raise SystemExit("Error: Cannot determine Windows directory!")
  28. return windir
  29. def get_system_path():
  30. """
  31. Return the required Windows system paths.
  32. """
  33. # Imported here to avoid circular import.
  34. from PyInstaller import compat
  35. _bpath = []
  36. sys_dir = compat.win32api.GetSystemDirectory()
  37. # Ensure C:\Windows\system32 and C:\Windows directories are always present in PATH variable.
  38. # C:\Windows\system32 is valid even for 64-bit Windows. Access do DLLs are transparently redirected to
  39. # C:\Windows\syswow64 for 64bit applactions.
  40. # See http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx
  41. _bpath = [sys_dir, get_windows_dir()]
  42. return _bpath
  43. def extend_system_path(paths):
  44. """
  45. Add new paths at the beginning of environment variable PATH.
  46. Some hooks might extend PATH where PyInstaller should look for dlls.
  47. """
  48. # imported here to avoid circular import
  49. from PyInstaller import compat
  50. old_path = compat.getenv('PATH', '')
  51. paths.append(old_path)
  52. new_path = os.pathsep.join(paths)
  53. compat.setenv('PATH', new_path)
  54. def import_pywin32_module(module_name):
  55. """
  56. Import and return the PyWin32 module with the passed name.
  57. When imported, the `pywintypes` and `pythoncom` modules both internally import dynamic libraries
  58. (e.g., `pywintypes.py` imports `pywintypes34.dll` under Python 3.4). The Anaconda Python distribution for Windows
  59. installs these libraries to non-standard directories, resulting in
  60. `"ImportError: No system module 'pywintypes' (pywintypes34.dll)"`
  61. exceptions. This function catches these exceptions, searches for these libraries, adds their directories to
  62. `sys.path`, and retries.
  63. Parameters
  64. ----------
  65. module_name : str
  66. Fully-qualified name of this module.
  67. Returns
  68. ----------
  69. types.ModuleType
  70. The desired module.
  71. """
  72. module = None
  73. try:
  74. module = __import__(module_name, globals={}, locals={}, fromlist=[''])
  75. except ImportError as exc:
  76. if str(exc).startswith('No system module'):
  77. # True if "sys.frozen" is currently set.
  78. is_sys_frozen = hasattr(sys, 'frozen')
  79. # Current value of "sys.frozen" if any.
  80. sys_frozen = getattr(sys, 'frozen', None)
  81. # Force PyWin32 to search "sys.path" for DLLs. By default, PyWin32 only searches "site-packages\win32\lib",
  82. # "sys.prefix", and Windows system directories (e.g., "C:\Windows\System32"). This is an ugly hack, but
  83. # there is no other way.
  84. sys.frozen = '|_|GLYH@CK'
  85. # If isolated to a venv, the preferred site.getsitepackages() function is unreliable. Fall back to searching
  86. # "sys.path" instead.
  87. if compat.is_venv:
  88. sys_paths = sys.path
  89. else:
  90. sys_paths = compat.getsitepackages()
  91. for sys_path in sys_paths:
  92. # Absolute path of the directory containing PyWin32 DLLs.
  93. pywin32_dll_dir = os.path.join(sys_path, 'pywin32_system32')
  94. if os.path.isdir(pywin32_dll_dir):
  95. sys.path.append(pywin32_dll_dir)
  96. try:
  97. module = __import__(name=module_name, globals={}, locals={}, fromlist=[''])
  98. break
  99. except ImportError:
  100. pass
  101. # If "sys.frozen" was previously set, restore its prior value.
  102. if is_sys_frozen:
  103. sys.frozen = sys_frozen
  104. # Else, undo this hack entirely.
  105. else:
  106. del sys.frozen
  107. # If this module remains unimportable, PyWin32 is not installed. Fail.
  108. if module is None:
  109. raise
  110. return module
  111. def convert_dll_name_to_str(dll_name):
  112. """
  113. Convert dll names from 'bytes' to 'str'.
  114. Latest pefile returns type 'bytes'.
  115. :param dll_name:
  116. :return:
  117. """
  118. # Imported here to avoid circular import.
  119. if isinstance(dll_name, bytes):
  120. return str(dll_name, encoding='UTF-8')
  121. else:
  122. return dll_name
  123. def fixup_exe_headers(exe_path, timestamp=None):
  124. """
  125. Set executable's checksum and build timestamp in its headers.
  126. This optional checksum is supposed to protect the executable against corruption but some anti-viral software have
  127. taken to flagging anything without it set correctly as malware. See issue #5579.
  128. """
  129. import pefile
  130. pe = pefile.PE(exe_path, fast_load=False) # full load because we need all headers
  131. # Set build timestamp.
  132. # See: https://0xc0decafe.com/malware-analyst-guide-to-pe-timestamps
  133. if timestamp is not None:
  134. timestamp = int(timestamp)
  135. # Set timestamp field in FILE_HEADER
  136. pe.FILE_HEADER.TimeDateStamp = timestamp
  137. # MSVC-compiled executables contain (at least?) one DIRECTORY_ENTRY_DEBUG entry that also contains timestamp
  138. # with same value as set in FILE_HEADER. So modify that as well, as long as it is set.
  139. debug_entries = getattr(pe, 'DIRECTORY_ENTRY_DEBUG', [])
  140. for debug_entry in debug_entries:
  141. if debug_entry.struct.TimeDateStamp:
  142. debug_entry.struct.TimeDateStamp = timestamp
  143. # Set PE checksum
  144. pe.OPTIONAL_HEADER.CheckSum = pe.generate_checksum()
  145. pe.close()
  146. pe.write(exe_path)