PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rlib/rwin32.py

https://bitbucket.org/dac_io/pypy
Python | 310 lines | 294 code | 11 blank | 5 comment | 4 complexity | cac26fec7d54194e4b5ae81aa0a704bd MD5 | raw file
  1. """ External functions accessing the win32 api.
  2. Common types, functions from core win32 libraries, such as kernel32
  3. """
  4. from pypy.rpython.tool import rffi_platform
  5. from pypy.tool.udir import udir
  6. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  7. from pypy.translator.platform import CompilationError
  8. from pypy.rpython.lltypesystem import lltype, rffi
  9. from pypy.rlib.rarithmetic import intmask
  10. from pypy.rlib import jit
  11. import os, sys, errno
  12. # This module can be imported on any platform,
  13. # but most symbols are not usable...
  14. WIN32 = os.name == "nt"
  15. if WIN32:
  16. eci = ExternalCompilationInfo(
  17. includes = ['windows.h'],
  18. libraries = ['kernel32'],
  19. )
  20. else:
  21. eci = ExternalCompilationInfo()
  22. class CConfig:
  23. _compilation_info_ = eci
  24. if WIN32:
  25. DWORD_PTR = rffi_platform.SimpleType("DWORD_PTR", rffi.LONG)
  26. WORD = rffi_platform.SimpleType("WORD", rffi.UINT)
  27. DWORD = rffi_platform.SimpleType("DWORD", rffi.UINT)
  28. BOOL = rffi_platform.SimpleType("BOOL", rffi.LONG)
  29. BYTE = rffi_platform.SimpleType("BYTE", rffi.UCHAR)
  30. WCHAR = rffi_platform.SimpleType("WCHAR", rffi.UCHAR)
  31. INT = rffi_platform.SimpleType("INT", rffi.INT)
  32. LONG = rffi_platform.SimpleType("LONG", rffi.LONG)
  33. PLONG = rffi_platform.SimpleType("PLONG", rffi.LONGP)
  34. LPVOID = rffi_platform.SimpleType("LPVOID", rffi.INTP)
  35. LPCVOID = rffi_platform.SimpleType("LPCVOID", rffi.VOIDP)
  36. LPSTR = rffi_platform.SimpleType("LPSTR", rffi.CCHARP)
  37. LPCSTR = rffi_platform.SimpleType("LPCSTR", rffi.CCHARP)
  38. LPWSTR = rffi_platform.SimpleType("LPWSTR", rffi.CWCHARP)
  39. LPCWSTR = rffi_platform.SimpleType("LPCWSTR", rffi.CWCHARP)
  40. LPDWORD = rffi_platform.SimpleType("LPDWORD", rffi.UINTP)
  41. SIZE_T = rffi_platform.SimpleType("SIZE_T", rffi.SIZE_T)
  42. ULONG_PTR = rffi_platform.SimpleType("ULONG_PTR", rffi.ULONG)
  43. HRESULT = rffi_platform.SimpleType("HRESULT", rffi.LONG)
  44. HLOCAL = rffi_platform.SimpleType("HLOCAL", rffi.VOIDP)
  45. FILETIME = rffi_platform.Struct('FILETIME',
  46. [('dwLowDateTime', rffi.UINT),
  47. ('dwHighDateTime', rffi.UINT)])
  48. SYSTEMTIME = rffi_platform.Struct('SYSTEMTIME',
  49. [])
  50. OSVERSIONINFOEX = rffi_platform.Struct(
  51. 'OSVERSIONINFOEX',
  52. [('dwOSVersionInfoSize', rffi.UINT),
  53. ('dwMajorVersion', rffi.UINT),
  54. ('dwMinorVersion', rffi.UINT),
  55. ('dwBuildNumber', rffi.UINT),
  56. ('dwPlatformId', rffi.UINT),
  57. ('szCSDVersion', rffi.CFixedArray(lltype.Char, 1)),
  58. ('wServicePackMajor', rffi.USHORT),
  59. ('wServicePackMinor', rffi.USHORT),
  60. ('wSuiteMask', rffi.USHORT),
  61. ('wProductType', rffi.UCHAR),
  62. ])
  63. LPSECURITY_ATTRIBUTES = rffi_platform.SimpleType(
  64. "LPSECURITY_ATTRIBUTES", rffi.CCHARP)
  65. DEFAULT_LANGUAGE = rffi_platform.ConstantInteger(
  66. "MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)")
  67. for name in """FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM
  68. MAX_PATH
  69. WAIT_OBJECT_0 WAIT_TIMEOUT INFINITE
  70. """.split():
  71. locals()[name] = rffi_platform.ConstantInteger(name)
  72. for k, v in rffi_platform.configure(CConfig).items():
  73. globals()[k] = v
  74. def winexternal(name, args, result, **kwds):
  75. return rffi.llexternal(name, args, result, compilation_info=eci,
  76. calling_conv='win', **kwds)
  77. if WIN32:
  78. HANDLE = rffi.COpaquePtr(typedef='HANDLE')
  79. assert rffi.cast(HANDLE, -1) == rffi.cast(HANDLE, -1)
  80. LPHANDLE = rffi.CArrayPtr(HANDLE)
  81. HMODULE = HANDLE
  82. NULL_HANDLE = rffi.cast(HANDLE, 0)
  83. INVALID_HANDLE_VALUE = rffi.cast(HANDLE, -1)
  84. PFILETIME = rffi.CArrayPtr(FILETIME)
  85. _GetLastError = winexternal('GetLastError', [], DWORD, threadsafe=False)
  86. _SetLastError = winexternal('SetLastError', [DWORD], lltype.Void)
  87. def GetLastError():
  88. return rffi.cast(lltype.Signed, _GetLastError())
  89. def SetLastError(err):
  90. _SetLastError(rffi.cast(DWORD, err))
  91. # In tests, the first call to GetLastError is always wrong, because error
  92. # is hidden by operations in ll2ctypes. Call it now.
  93. GetLastError()
  94. LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], HMODULE)
  95. GetProcAddress = winexternal('GetProcAddress',
  96. [HMODULE, rffi.CCHARP],
  97. rffi.VOIDP)
  98. FreeLibrary = winexternal('FreeLibrary', [HMODULE], BOOL, threadsafe=False)
  99. LocalFree = winexternal('LocalFree', [HLOCAL], DWORD)
  100. CloseHandle = winexternal('CloseHandle', [HANDLE], BOOL, threadsafe=False)
  101. FormatMessage = winexternal(
  102. 'FormatMessageA',
  103. [DWORD, rffi.VOIDP, DWORD, DWORD, rffi.CCHARP, DWORD, rffi.VOIDP],
  104. DWORD)
  105. _get_osfhandle = rffi.llexternal('_get_osfhandle', [rffi.INT], HANDLE)
  106. def build_winerror_to_errno():
  107. """Build a dictionary mapping windows error numbers to POSIX errno.
  108. The function returns the dict, and the default value for codes not
  109. in the dict."""
  110. # Prior to Visual Studio 8, the MSVCRT dll doesn't export the
  111. # _dosmaperr() function, which is available only when compiled
  112. # against the static CRT library.
  113. from pypy.translator.platform import host_factory
  114. static_platform = host_factory()
  115. if static_platform.name == 'msvc':
  116. static_platform.cflags = ['/MT'] # static CRT
  117. static_platform.version = 0 # no manifest
  118. cfile = udir.join('dosmaperr.c')
  119. cfile.write(r'''
  120. #include <errno.h>
  121. #include <stdio.h>
  122. #ifdef __GNUC__
  123. #define _dosmaperr mingw_dosmaperr
  124. #endif
  125. int main()
  126. {
  127. int i;
  128. for(i=1; i < 65000; i++) {
  129. _dosmaperr(i);
  130. if (errno == EINVAL)
  131. continue;
  132. printf("%d\t%d\n", i, errno);
  133. }
  134. return 0;
  135. }''')
  136. try:
  137. exename = static_platform.compile(
  138. [cfile], ExternalCompilationInfo(),
  139. outputfilename = "dosmaperr",
  140. standalone=True)
  141. except (CompilationError, WindowsError):
  142. # Fallback for the mingw32 compiler
  143. errors = {
  144. 2: 2, 3: 2, 4: 24, 5: 13, 6: 9, 7: 12, 8: 12, 9: 12, 10: 7,
  145. 11: 8, 15: 2, 16: 13, 17: 18, 18: 2, 19: 13, 20: 13, 21: 13,
  146. 22: 13, 23: 13, 24: 13, 25: 13, 26: 13, 27: 13, 28: 13,
  147. 29: 13, 30: 13, 31: 13, 32: 13, 33: 13, 34: 13, 35: 13,
  148. 36: 13, 53: 2, 65: 13, 67: 2, 80: 17, 82: 13, 83: 13, 89: 11,
  149. 108: 13, 109: 32, 112: 28, 114: 9, 128: 10, 129: 10, 130: 9,
  150. 132: 13, 145: 41, 158: 13, 161: 2, 164: 11, 167: 13, 183: 17,
  151. 188: 8, 189: 8, 190: 8, 191: 8, 192: 8, 193: 8, 194: 8,
  152. 195: 8, 196: 8, 197: 8, 198: 8, 199: 8, 200: 8, 201: 8,
  153. 202: 8, 206: 2, 215: 11, 1816: 12,
  154. }
  155. else:
  156. output = os.popen(str(exename))
  157. errors = dict(map(int, line.split())
  158. for line in output)
  159. return errors, errno.EINVAL
  160. # A bit like strerror...
  161. def FormatError(code):
  162. return llimpl_FormatError(code)
  163. def llimpl_FormatError(code):
  164. "Return a message corresponding to the given Windows error code."
  165. buf = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw')
  166. try:
  167. msglen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  168. FORMAT_MESSAGE_FROM_SYSTEM,
  169. None,
  170. rffi.cast(DWORD, code),
  171. DEFAULT_LANGUAGE,
  172. rffi.cast(rffi.CCHARP, buf),
  173. 0, None)
  174. if msglen <= 2: # includes the case msglen < 0
  175. return fake_FormatError(code)
  176. # FormatMessage always appends \r\n.
  177. buflen = intmask(msglen - 2)
  178. assert buflen > 0
  179. result = rffi.charpsize2str(buf[0], buflen)
  180. LocalFree(rffi.cast(rffi.VOIDP, buf[0]))
  181. finally:
  182. lltype.free(buf, flavor='raw')
  183. return result
  184. def fake_FormatError(code):
  185. return 'Windows Error %d' % (code,)
  186. def lastWindowsError(context="Windows Error"):
  187. code = GetLastError()
  188. return WindowsError(code, context)
  189. def FAILED(hr):
  190. return rffi.cast(HRESULT, hr) < 0
  191. _GetModuleFileName = winexternal('GetModuleFileNameA',
  192. [HMODULE, rffi.CCHARP, DWORD],
  193. DWORD)
  194. def GetModuleFileName(module):
  195. size = MAX_PATH
  196. buf = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
  197. try:
  198. res = _GetModuleFileName(module, buf, size)
  199. if not res:
  200. return ''
  201. else:
  202. return ''.join([buf[i] for i in range(res)])
  203. finally:
  204. lltype.free(buf, flavor='raw')
  205. _GetVersionEx = winexternal('GetVersionExA',
  206. [lltype.Ptr(OSVERSIONINFOEX)],
  207. DWORD)
  208. @jit.dont_look_inside
  209. def GetVersionEx():
  210. info = lltype.malloc(OSVERSIONINFOEX, flavor='raw')
  211. rffi.setintfield(info, 'c_dwOSVersionInfoSize',
  212. rffi.sizeof(OSVERSIONINFOEX))
  213. try:
  214. if not _GetVersionEx(info):
  215. raise lastWindowsError()
  216. return (rffi.cast(lltype.Signed, info.c_dwMajorVersion),
  217. rffi.cast(lltype.Signed, info.c_dwMinorVersion),
  218. rffi.cast(lltype.Signed, info.c_dwBuildNumber),
  219. rffi.cast(lltype.Signed, info.c_dwPlatformId),
  220. rffi.charp2str(rffi.cast(rffi.CCHARP,
  221. info.c_szCSDVersion)),
  222. rffi.cast(lltype.Signed, info.c_wServicePackMajor),
  223. rffi.cast(lltype.Signed, info.c_wServicePackMinor),
  224. rffi.cast(lltype.Signed, info.c_wSuiteMask),
  225. rffi.cast(lltype.Signed, info.c_wProductType))
  226. finally:
  227. lltype.free(info, flavor='raw')
  228. _WaitForSingleObject = winexternal(
  229. 'WaitForSingleObject', [HANDLE, DWORD], DWORD)
  230. def WaitForSingleObject(handle, timeout):
  231. """Return values:
  232. - WAIT_OBJECT_0 when the object is signaled
  233. - WAIT_TIMEOUT when the timeout elapsed"""
  234. res = _WaitForSingleObject(handle, timeout)
  235. if res == rffi.cast(DWORD, -1):
  236. raise lastWindowsError("WaitForSingleObject")
  237. return res
  238. _WaitForMultipleObjects = winexternal(
  239. 'WaitForMultipleObjects', [
  240. DWORD, rffi.CArrayPtr(HANDLE), BOOL, DWORD], DWORD)
  241. def WaitForMultipleObjects(handles, waitall=False, timeout=INFINITE):
  242. """Return values:
  243. - WAIT_OBJECT_0 + index when an object is signaled
  244. - WAIT_TIMEOUT when the timeout elapsed"""
  245. nb = len(handles)
  246. handle_array = lltype.malloc(rffi.CArrayPtr(HANDLE).TO, nb,
  247. flavor='raw')
  248. try:
  249. for i in range(nb):
  250. handle_array[i] = handles[i]
  251. res = _WaitForMultipleObjects(nb, handle_array, waitall, timeout)
  252. if res == rffi.cast(DWORD, -1):
  253. raise lastWindowsError("WaitForMultipleObjects")
  254. return res
  255. finally:
  256. lltype.free(handle_array, flavor='raw')
  257. _CreateEvent = winexternal(
  258. 'CreateEventA', [rffi.VOIDP, BOOL, BOOL, LPCSTR], HANDLE)
  259. def CreateEvent(*args):
  260. handle = _CreateEvent(*args)
  261. if handle == NULL_HANDLE:
  262. raise lastWindowsError("CreateEvent")
  263. return handle
  264. SetEvent = winexternal(
  265. 'SetEvent', [HANDLE], BOOL)
  266. ResetEvent = winexternal(
  267. 'ResetEvent', [HANDLE], BOOL)