PageRenderTime 65ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/rlib/rwin32.py

https://bitbucket.org/pypy/pypy/
Python | 445 lines | 428 code | 12 blank | 5 comment | 3 complexity | 1ea25145eed58dbc484c144a714a612f MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """ External functions accessing the win32 api.
  2. Common types, functions from core win32 libraries, such as kernel32
  3. """
  4. import os
  5. import errno
  6. from rpython.rlib.rposix_environ import make_env_impls
  7. from rpython.rtyper.tool import rffi_platform
  8. from rpython.tool.udir import udir
  9. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  10. from rpython.translator.platform import CompilationError
  11. from rpython.rtyper.lltypesystem import lltype, rffi
  12. from rpython.rlib.rarithmetic import intmask
  13. from rpython.rlib import jit
  14. # This module can be imported on any platform,
  15. # but most symbols are not usable...
  16. WIN32 = os.name == "nt"
  17. if WIN32:
  18. eci = ExternalCompilationInfo(
  19. includes = ['windows.h', 'stdio.h', 'stdlib.h'],
  20. libraries = ['kernel32'],
  21. )
  22. else:
  23. eci = ExternalCompilationInfo()
  24. class CConfig:
  25. _compilation_info_ = eci
  26. if WIN32:
  27. DWORD_PTR = rffi_platform.SimpleType("DWORD_PTR", rffi.LONG)
  28. WORD = rffi_platform.SimpleType("WORD", rffi.UINT)
  29. DWORD = rffi_platform.SimpleType("DWORD", rffi.UINT)
  30. BOOL = rffi_platform.SimpleType("BOOL", rffi.LONG)
  31. BYTE = rffi_platform.SimpleType("BYTE", rffi.UCHAR)
  32. WCHAR = rffi_platform.SimpleType("WCHAR", rffi.UCHAR)
  33. INT = rffi_platform.SimpleType("INT", rffi.INT)
  34. LONG = rffi_platform.SimpleType("LONG", rffi.LONG)
  35. PLONG = rffi_platform.SimpleType("PLONG", rffi.LONGP)
  36. LPVOID = rffi_platform.SimpleType("LPVOID", rffi.INTP)
  37. LPCVOID = rffi_platform.SimpleType("LPCVOID", rffi.VOIDP)
  38. LPSTR = rffi_platform.SimpleType("LPSTR", rffi.CCHARP)
  39. LPCSTR = rffi_platform.SimpleType("LPCSTR", rffi.CCHARP)
  40. LPWSTR = rffi_platform.SimpleType("LPWSTR", rffi.CWCHARP)
  41. LPCWSTR = rffi_platform.SimpleType("LPCWSTR", rffi.CWCHARP)
  42. LPDWORD = rffi_platform.SimpleType("LPDWORD", rffi.UINTP)
  43. SIZE_T = rffi_platform.SimpleType("SIZE_T", rffi.SIZE_T)
  44. ULONG_PTR = rffi_platform.SimpleType("ULONG_PTR", rffi.ULONG)
  45. HRESULT = rffi_platform.SimpleType("HRESULT", rffi.LONG)
  46. HLOCAL = rffi_platform.SimpleType("HLOCAL", rffi.VOIDP)
  47. FILETIME = rffi_platform.Struct('FILETIME',
  48. [('dwLowDateTime', rffi.UINT),
  49. ('dwHighDateTime', rffi.UINT)])
  50. SYSTEMTIME = rffi_platform.Struct('SYSTEMTIME',
  51. [])
  52. OSVERSIONINFOEX = rffi_platform.Struct(
  53. 'OSVERSIONINFOEX',
  54. [('dwOSVersionInfoSize', rffi.UINT),
  55. ('dwMajorVersion', rffi.UINT),
  56. ('dwMinorVersion', rffi.UINT),
  57. ('dwBuildNumber', rffi.UINT),
  58. ('dwPlatformId', rffi.UINT),
  59. ('szCSDVersion', rffi.CFixedArray(lltype.Char, 1)),
  60. ('wServicePackMajor', rffi.USHORT),
  61. ('wServicePackMinor', rffi.USHORT),
  62. ('wSuiteMask', rffi.USHORT),
  63. ('wProductType', rffi.UCHAR),
  64. ])
  65. LPSECURITY_ATTRIBUTES = rffi_platform.SimpleType(
  66. "LPSECURITY_ATTRIBUTES", rffi.CCHARP)
  67. DEFAULT_LANGUAGE = rffi_platform.ConstantInteger(
  68. "MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)")
  69. defines = """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM
  70. MAX_PATH _MAX_ENV FORMAT_MESSAGE_IGNORE_INSERTS
  71. WAIT_OBJECT_0 WAIT_TIMEOUT INFINITE
  72. ERROR_INVALID_HANDLE
  73. DELETE READ_CONTROL SYNCHRONIZE WRITE_DAC
  74. WRITE_OWNER PROCESS_ALL_ACCESS
  75. PROCESS_CREATE_PROCESS PROCESS_CREATE_THREAD
  76. PROCESS_DUP_HANDLE PROCESS_QUERY_INFORMATION
  77. PROCESS_SET_QUOTA
  78. PROCESS_SUSPEND_RESUME PROCESS_TERMINATE
  79. PROCESS_VM_OPERATION PROCESS_VM_READ
  80. PROCESS_VM_WRITE
  81. CTRL_C_EVENT CTRL_BREAK_EVENT
  82. MB_ERR_INVALID_CHARS ERROR_NO_UNICODE_TRANSLATION
  83. WC_NO_BEST_FIT_CHARS
  84. """
  85. from rpython.translator.platform import host_factory
  86. static_platform = host_factory()
  87. if static_platform.name == 'msvc':
  88. defines += ' PROCESS_QUERY_LIMITED_INFORMATION'
  89. for name in defines.split():
  90. locals()[name] = rffi_platform.ConstantInteger(name)
  91. for k, v in rffi_platform.configure(CConfig).items():
  92. globals()[k] = v
  93. def winexternal(name, args, result, **kwds):
  94. return rffi.llexternal(name, args, result, compilation_info=eci,
  95. calling_conv='win', **kwds)
  96. if WIN32:
  97. HANDLE = rffi.COpaquePtr(typedef='HANDLE')
  98. assert rffi.cast(HANDLE, -1) == rffi.cast(HANDLE, -1)
  99. LPHANDLE = rffi.CArrayPtr(HANDLE)
  100. HMODULE = HANDLE
  101. NULL_HANDLE = rffi.cast(HANDLE, 0)
  102. INVALID_HANDLE_VALUE = rffi.cast(HANDLE, -1)
  103. PFILETIME = rffi.CArrayPtr(FILETIME)
  104. _GetLastError = winexternal('GetLastError', [], DWORD,
  105. _nowrapper=True, sandboxsafe=True)
  106. _SetLastError = winexternal('SetLastError', [DWORD], lltype.Void,
  107. _nowrapper=True, sandboxsafe=True)
  108. def GetLastError_saved():
  109. """Return the value of the "saved LastError".
  110. The C-level GetLastError() is saved there after a call to a C
  111. function, if that C function was declared with the flag
  112. llexternal(..., save_err=rffi.RFFI_SAVE_LASTERROR).
  113. Functions without that flag don't change the saved LastError.
  114. Alternatively, if the function was declared RFFI_SAVE_WSALASTERROR,
  115. then the value of the C-level WSAGetLastError() is saved instead
  116. (into the same "saved LastError" variable).
  117. """
  118. from rpython.rlib import rthread
  119. return rffi.cast(lltype.Signed, rthread.tlfield_rpy_lasterror.getraw())
  120. def SetLastError_saved(err):
  121. """Set the value of the saved LastError. This value will be used in
  122. a call to the C-level SetLastError() just before calling the
  123. following C function, provided it was declared
  124. llexternal(..., save_err=RFFI_READSAVED_LASTERROR).
  125. """
  126. from rpython.rlib import rthread
  127. rthread.tlfield_rpy_lasterror.setraw(rffi.cast(DWORD, err))
  128. def GetLastError_alt_saved():
  129. """Return the value of the "saved alt LastError".
  130. The C-level GetLastError() is saved there after a call to a C
  131. function, if that C function was declared with the flag
  132. llexternal(..., save_err=RFFI_SAVE_LASTERROR | RFFI_ALT_ERRNO).
  133. Functions without that flag don't change the saved LastError.
  134. Alternatively, if the function was declared
  135. RFFI_SAVE_WSALASTERROR | RFFI_ALT_ERRNO,
  136. then the value of the C-level WSAGetLastError() is saved instead
  137. (into the same "saved alt LastError" variable).
  138. """
  139. from rpython.rlib import rthread
  140. return rffi.cast(lltype.Signed, rthread.tlfield_alt_lasterror.getraw())
  141. def SetLastError_alt_saved(err):
  142. """Set the value of the saved alt LastError. This value will be used in
  143. a call to the C-level SetLastError() just before calling the
  144. following C function, provided it was declared
  145. llexternal(..., save_err=RFFI_READSAVED_LASTERROR | RFFI_ALT_ERRNO).
  146. """
  147. from rpython.rlib import rthread
  148. rthread.tlfield_alt_lasterror.setraw(rffi.cast(DWORD, err))
  149. # In tests, the first call to _GetLastError() is always wrong,
  150. # because error is hidden by operations in ll2ctypes. Call it now.
  151. _GetLastError()
  152. GetModuleHandle = winexternal('GetModuleHandleA', [rffi.CCHARP], HMODULE)
  153. LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], HMODULE,
  154. save_err=rffi.RFFI_SAVE_LASTERROR)
  155. GetProcAddress = winexternal('GetProcAddress',
  156. [HMODULE, rffi.CCHARP],
  157. rffi.VOIDP)
  158. FreeLibrary = winexternal('FreeLibrary', [HMODULE], BOOL, releasegil=False)
  159. LocalFree = winexternal('LocalFree', [HLOCAL], DWORD)
  160. CloseHandle = winexternal('CloseHandle', [HANDLE], BOOL, releasegil=False,
  161. save_err=rffi.RFFI_SAVE_LASTERROR)
  162. CloseHandle_no_err = winexternal('CloseHandle', [HANDLE], BOOL,
  163. releasegil=False)
  164. FormatMessage = winexternal(
  165. 'FormatMessageA',
  166. [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CCHARP, DWORD, rffi.VOIDP],
  167. DWORD)
  168. _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], HANDLE)
  169. def get_osfhandle(fd):
  170. from rpython.rlib.rposix import validate_fd
  171. validate_fd(fd)
  172. handle = _get_osfhandle(fd)
  173. if handle == INVALID_HANDLE_VALUE:
  174. raise WindowsError(ERROR_INVALID_HANDLE, "Invalid file handle")
  175. return handle
  176. def build_winerror_to_errno():
  177. """Build a dictionary mapping windows error numbers to POSIX errno.
  178. The function returns the dict, and the default value for codes not
  179. in the dict."""
  180. # Prior to Visual Studio 8, the MSVCRT dll doesn't export the
  181. # _dosmaperr() function, which is available only when compiled
  182. # against the static CRT library.
  183. from rpython.translator.platform import host_factory
  184. static_platform = host_factory()
  185. if static_platform.name == 'msvc':
  186. static_platform.cflags = ['/MT'] # static CRT
  187. static_platform.version = 0 # no manifest
  188. cfile = udir.join('dosmaperr.c')
  189. cfile.write(r'''
  190. #include <errno.h>
  191. #include <WinError.h>
  192. #include <stdio.h>
  193. #ifdef __GNUC__
  194. #define _dosmaperr mingw_dosmaperr
  195. #endif
  196. int main()
  197. {
  198. int i;
  199. for(i=1; i < 65000; i++) {
  200. _dosmaperr(i);
  201. if (errno == EINVAL) {
  202. /* CPython issue #12802 */
  203. if (i == ERROR_DIRECTORY)
  204. errno = ENOTDIR;
  205. else
  206. continue;
  207. }
  208. printf("%d\t%d\n", i, errno);
  209. }
  210. return 0;
  211. }''')
  212. try:
  213. exename = static_platform.compile(
  214. [cfile], ExternalCompilationInfo(),
  215. outputfilename = "dosmaperr",
  216. standalone=True)
  217. except (CompilationError, WindowsError):
  218. # Fallback for the mingw32 compiler
  219. assert static_platform.name == 'mingw32'
  220. errors = {
  221. 2: 2, 3: 2, 4: 24, 5: 13, 6: 9, 7: 12, 8: 12, 9: 12, 10: 7,
  222. 11: 8, 15: 2, 16: 13, 17: 18, 18: 2, 19: 13, 20: 13, 21: 13,
  223. 22: 13, 23: 13, 24: 13, 25: 13, 26: 13, 27: 13, 28: 13,
  224. 29: 13, 30: 13, 31: 13, 32: 13, 33: 13, 34: 13, 35: 13,
  225. 36: 13, 53: 2, 65: 13, 67: 2, 80: 17, 82: 13, 83: 13, 89: 11,
  226. 108: 13, 109: 32, 112: 28, 114: 9, 128: 10, 129: 10, 130: 9,
  227. 132: 13, 145: 41, 158: 13, 161: 2, 164: 11, 167: 13, 183: 17,
  228. 188: 8, 189: 8, 190: 8, 191: 8, 192: 8, 193: 8, 194: 8,
  229. 195: 8, 196: 8, 197: 8, 198: 8, 199: 8, 200: 8, 201: 8,
  230. 202: 8, 206: 2, 215: 11, 267: 20, 1816: 12,
  231. }
  232. else:
  233. output = os.popen(str(exename))
  234. errors = dict(map(int, line.split())
  235. for line in output)
  236. return errors, errno.EINVAL
  237. # A bit like strerror...
  238. def FormatError(code):
  239. return llimpl_FormatError(code)
  240. def llimpl_FormatError(code):
  241. "Return a message corresponding to the given Windows error code."
  242. buf = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw')
  243. buf[0] = lltype.nullptr(rffi.CCHARP.TO)
  244. try:
  245. msglen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  246. FORMAT_MESSAGE_FROM_SYSTEM |
  247. FORMAT_MESSAGE_IGNORE_INSERTS,
  248. None,
  249. rffi.cast(DWORD, code),
  250. DEFAULT_LANGUAGE,
  251. rffi.cast(rffi.CCHARP, buf),
  252. 0, None)
  253. buflen = intmask(msglen)
  254. # remove trailing cr/lf and dots
  255. s_buf = buf[0]
  256. while buflen > 0 and (s_buf[buflen - 1] <= ' ' or
  257. s_buf[buflen - 1] == '.'):
  258. buflen -= 1
  259. if buflen <= 0:
  260. result = 'Windows Error %d' % (code,)
  261. else:
  262. result = rffi.charpsize2str(s_buf, buflen)
  263. finally:
  264. LocalFree(rffi.cast(rffi.VOIDP, buf[0]))
  265. lltype.free(buf, flavor='raw')
  266. return result
  267. def lastSavedWindowsError(context="Windows Error"):
  268. code = GetLastError_saved()
  269. return WindowsError(code, context)
  270. def FAILED(hr):
  271. return rffi.cast(HRESULT, hr) < 0
  272. _GetModuleFileName = winexternal('GetModuleFileNameA',
  273. [HMODULE, rffi.CCHARP, DWORD],
  274. DWORD)
  275. def GetModuleFileName(module):
  276. size = MAX_PATH
  277. buf = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
  278. try:
  279. res = _GetModuleFileName(module, buf, size)
  280. if not res:
  281. return ''
  282. else:
  283. return ''.join([buf[i] for i in range(res)])
  284. finally:
  285. lltype.free(buf, flavor='raw')
  286. _GetVersionEx = winexternal('GetVersionExA',
  287. [lltype.Ptr(OSVERSIONINFOEX)],
  288. DWORD,
  289. save_err=rffi.RFFI_SAVE_LASTERROR)
  290. @jit.dont_look_inside
  291. def GetVersionEx():
  292. info = lltype.malloc(OSVERSIONINFOEX, flavor='raw')
  293. rffi.setintfield(info, 'c_dwOSVersionInfoSize',
  294. rffi.sizeof(OSVERSIONINFOEX))
  295. try:
  296. if not _GetVersionEx(info):
  297. raise lastSavedWindowsError()
  298. return (rffi.cast(lltype.Signed, info.c_dwMajorVersion),
  299. rffi.cast(lltype.Signed, info.c_dwMinorVersion),
  300. rffi.cast(lltype.Signed, info.c_dwBuildNumber),
  301. rffi.cast(lltype.Signed, info.c_dwPlatformId),
  302. rffi.charp2str(rffi.cast(rffi.CCHARP,
  303. info.c_szCSDVersion)),
  304. rffi.cast(lltype.Signed, info.c_wServicePackMajor),
  305. rffi.cast(lltype.Signed, info.c_wServicePackMinor),
  306. rffi.cast(lltype.Signed, info.c_wSuiteMask),
  307. rffi.cast(lltype.Signed, info.c_wProductType))
  308. finally:
  309. lltype.free(info, flavor='raw')
  310. _WaitForSingleObject = winexternal(
  311. 'WaitForSingleObject', [HANDLE, DWORD], DWORD,
  312. save_err=rffi.RFFI_SAVE_LASTERROR)
  313. def WaitForSingleObject(handle, timeout):
  314. """Return values:
  315. - WAIT_OBJECT_0 when the object is signaled
  316. - WAIT_TIMEOUT when the timeout elapsed"""
  317. res = _WaitForSingleObject(handle, timeout)
  318. if res == rffi.cast(DWORD, -1):
  319. raise lastSavedWindowsError("WaitForSingleObject")
  320. return res
  321. _WaitForMultipleObjects = winexternal(
  322. 'WaitForMultipleObjects', [
  323. DWORD, rffi.CArrayPtr(HANDLE), BOOL, DWORD], DWORD,
  324. save_err=rffi.RFFI_SAVE_LASTERROR)
  325. def WaitForMultipleObjects(handles, waitall=False, timeout=INFINITE):
  326. """Return values:
  327. - WAIT_OBJECT_0 + index when an object is signaled
  328. - WAIT_TIMEOUT when the timeout elapsed"""
  329. nb = len(handles)
  330. handle_array = lltype.malloc(rffi.CArrayPtr(HANDLE).TO, nb,
  331. flavor='raw')
  332. try:
  333. for i in range(nb):
  334. handle_array[i] = handles[i]
  335. res = _WaitForMultipleObjects(nb, handle_array, waitall, timeout)
  336. if res == rffi.cast(DWORD, -1):
  337. raise lastSavedWindowsError("WaitForMultipleObjects")
  338. return res
  339. finally:
  340. lltype.free(handle_array, flavor='raw')
  341. _CreateEvent = winexternal(
  342. 'CreateEventA', [rffi.VOIDP, BOOL, BOOL, LPCSTR], HANDLE,
  343. save_err=rffi.RFFI_SAVE_LASTERROR)
  344. def CreateEvent(*args):
  345. handle = _CreateEvent(*args)
  346. if handle == NULL_HANDLE:
  347. raise lastSavedWindowsError("CreateEvent")
  348. return handle
  349. SetEvent = winexternal(
  350. 'SetEvent', [HANDLE], BOOL)
  351. ResetEvent = winexternal(
  352. 'ResetEvent', [HANDLE], BOOL)
  353. _OpenProcess = winexternal(
  354. 'OpenProcess', [DWORD, BOOL, DWORD], HANDLE,
  355. save_err=rffi.RFFI_SAVE_LASTERROR)
  356. def OpenProcess(*args):
  357. ''' OpenProcess( dwDesiredAccess, bInheritHandle, dwProcessId)
  358. where dwDesiredAccess is a combination of the flags:
  359. DELETE (0x00010000L)
  360. READ_CONTROL (0x00020000L)
  361. SYNCHRONIZE (0x00100000L)
  362. WRITE_DAC (0x00040000L)
  363. WRITE_OWNER (0x00080000L)
  364. PROCESS_ALL_ACCESS
  365. PROCESS_CREATE_PROCESS (0x0080)
  366. PROCESS_CREATE_THREAD (0x0002)
  367. PROCESS_DUP_HANDLE (0x0040)
  368. PROCESS_QUERY_INFORMATION (0x0400)
  369. PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
  370. PROCESS_SET_QUOTA (0x0100)
  371. PROCESS_SUSPEND_RESUME (0x0800)
  372. PROCESS_TERMINATE (0x0001)
  373. PROCESS_VM_OPERATION (0x0008)
  374. PROCESS_VM_READ (0x0010)
  375. PROCESS_VM_WRITE (0x0020)
  376. SYNCHRONIZE (0x00100000L)
  377. '''
  378. handle = _OpenProcess(*args)
  379. if handle == NULL_HANDLE:
  380. raise lastSavedWindowsError("OpenProcess")
  381. return handle
  382. TerminateProcess = winexternal(
  383. 'TerminateProcess', [HANDLE, rffi.UINT], BOOL,
  384. save_err=rffi.RFFI_SAVE_LASTERROR)
  385. GenerateConsoleCtrlEvent = winexternal(
  386. 'GenerateConsoleCtrlEvent', [DWORD, DWORD], BOOL,
  387. save_err=rffi.RFFI_SAVE_LASTERROR)
  388. _GetCurrentProcessId = winexternal(
  389. 'GetCurrentProcessId', [], DWORD)
  390. def GetCurrentProcessId():
  391. return rffi.cast(lltype.Signed, _GetCurrentProcessId())
  392. _GetConsoleCP = winexternal('GetConsoleCP', [], DWORD)
  393. _GetConsoleOutputCP = winexternal('GetConsoleOutputCP', [], DWORD)
  394. def GetConsoleCP():
  395. return rffi.cast(lltype.Signed, _GetConsoleCP())
  396. def GetConsoleOutputCP():
  397. return rffi.cast(lltype.Signed, _GetConsoleOutputCP())
  398. _wenviron_items, _wgetenv, _wputenv = make_env_impls(win32=True)