win32.py: add argtypes and restype
authorAdrian Buehlmann <adrian@cadifra.com>
Sun, 15 May 2011 21:33:51 +0200
changeset 14345 bf9a105aed0a
parent 14344 e1db8a00188b
child 14346 bf85c2639700
win32.py: add argtypes and restype This is a feature of ctypes. Without these, pypy complains with RuntimeWarning: C function without declared arguments called RuntimeWarning: C function without declared return type called As a side effect of specifying restypes, the return value of e.g. CreateFileA is now implicitly converted to an instance of _HANDLE, so we also need to change the definition _INVALID_HANDLE_VALUE = -1 to _INVALID_HANDLE_VALUE = _HANDLE(-1).value Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like def _getfileinfo(name): fh = _kernel32.CreateFileA(name, 0, _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE, None, _OPEN_EXISTING, 0, None) if fh == _INVALID_HANDLE_VALUE: _raiseoserror(name) would now fail to detect an invalid handle, which in turn would lead to exceptions raised with wrong errno values, like e.g. >>> nlinks('missing.txt') Traceback (most recent call last): ... OSError: [Errno 9] missing.txt: The handle is invalid. instead of the correct (as per this patch and before it) >>> nlinks('missing.txt') Traceback (most recent call last): ... OSError: [Errno 2] missing.txt: The system cannot find the file specified.
mercurial/win32.py
--- a/mercurial/win32.py	Sun May 15 21:27:59 2011 +0200
+++ b/mercurial/win32.py	Sun May 15 21:33:51 2011 +0200
@@ -9,15 +9,19 @@
 import ctypes, errno, os, struct, subprocess, random
 
 _kernel32 = ctypes.windll.kernel32
+_advapi32 = ctypes.windll.advapi32
+_user32 = ctypes.windll.user32
 
 _BOOL = ctypes.c_long
 _WORD = ctypes.c_ushort
 _DWORD = ctypes.c_ulong
+_UINT = ctypes.c_uint
+_LONG = ctypes.c_long
 _LPCSTR = _LPSTR = ctypes.c_char_p
 _HANDLE = ctypes.c_void_p
 _HWND = _HANDLE
 
-_INVALID_HANDLE_VALUE = -1
+_INVALID_HANDLE_VALUE = _HANDLE(-1).value
 
 # GetLastError
 _ERROR_SUCCESS = 0
@@ -122,6 +126,81 @@
 
 _STD_ERROR_HANDLE = _DWORD(-12).value
 
+# types of parameters of C functions used (required by pypy)
+
+_kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
+    _DWORD, _DWORD, _HANDLE]
+_kernel32.CreateFileA.restype = _HANDLE
+
+_kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
+_kernel32.GetFileInformationByHandle.restype = _BOOL
+
+_kernel32.CloseHandle.argtypes = [_HANDLE]
+_kernel32.CloseHandle.restype = _BOOL
+
+_kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
+_kernel32.CreateHardLinkA.restype = _BOOL
+
+_kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
+_kernel32.SetFileAttributesA.restype = _BOOL
+
+_kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
+_kernel32.OpenProcess.restype = _HANDLE
+
+_kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
+_kernel32.GetExitCodeProcess.restype = _BOOL
+
+_kernel32.GetLastError.argtypes = []
+_kernel32.GetLastError.restype = _DWORD
+
+_kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
+_kernel32.GetModuleFileNameA.restype = _DWORD
+
+_kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
+    ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
+    ctypes.c_void_p]
+_kernel32.CreateProcessA.restype = _BOOL
+
+_kernel32.ExitProcess.argtypes = [_UINT]
+_kernel32.ExitProcess.restype = None
+
+_kernel32.GetCurrentProcessId.argtypes = []
+_kernel32.GetCurrentProcessId.restype = _DWORD
+
+_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
+_kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
+_kernel32.SetConsoleCtrlHandler.restype = _BOOL
+
+_kernel32.GetStdHandle.argtypes = [_DWORD]
+_kernel32.GetStdHandle.restype = _HANDLE
+
+_kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
+_kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
+
+_advapi32.RegOpenKeyExA.argtypes = [_HANDLE, _LPCSTR, _DWORD, _DWORD,
+    ctypes.c_void_p]
+_advapi32.RegOpenKeyExA.restype = _LONG
+
+_advapi32.RegQueryValueExA.argtypes = [_HANDLE, _LPCSTR, ctypes.c_void_p,
+    ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
+_advapi32.RegQueryValueExA.restype = _LONG
+
+_advapi32.RegCloseKey.argtypes = [_HANDLE]
+_advapi32.RegCloseKey.restype = _LONG
+
+_advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
+_advapi32.GetUserNameA.restype = _BOOL
+
+_user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
+_user32.GetWindowThreadProcessId.restype = _DWORD
+
+_user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
+_user32.ShowWindow.restype = _BOOL
+
+_WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
+_user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
+_user32.EnumWindows.restype = _BOOL
+
 def _raiseoserror(name):
     err = ctypes.WinError()
     raise OSError(err.errno, '%s: %s' % (name, err.strerror))
@@ -189,7 +268,6 @@
     a sequence of scopes to look up in order. Default (CURRENT_USER,
     LOCAL_MACHINE).
     '''
-    adv = ctypes.windll.advapi32
     byref = ctypes.byref
     if scope is None:
         scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
@@ -197,14 +275,14 @@
         scope = (scope,)
     for s in scope:
         kh = _HANDLE()
-        res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
+        res = _advapi32.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
         if res != _ERROR_SUCCESS:
             continue
         try:
             size = _DWORD(600)
             type = _DWORD()
             buf = ctypes.create_string_buffer(size.value + 1)
-            res = adv.RegQueryValueExA(kh.value, valname, None,
+            res = _advapi32.RegQueryValueExA(kh.value, valname, None,
                                        byref(type), buf, byref(size))
             if res != _ERROR_SUCCESS:
                 continue
@@ -216,7 +294,7 @@
                 s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
                 return struct.unpack(fmt, s)[0]
         finally:
-            adv.RegCloseKey(kh.value)
+            _advapi32.RegCloseKey(kh.value)
 
 def executablepath():
     '''return full path of hg.exe'''
@@ -231,14 +309,12 @@
 
 def getuser():
     '''return name of current user'''
-    adv = ctypes.windll.advapi32
     size = _DWORD(300)
     buf = ctypes.create_string_buffer(size.value + 1)
-    if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
+    if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
         raise ctypes.WinError()
     return buf.value
 
-_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
 _signalhandler = []
 
 def setsignalhandler():
@@ -256,21 +332,18 @@
     if not _kernel32.SetConsoleCtrlHandler(h, True):
         raise ctypes.WinError()
 
-_WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
-
 def hidewindow():
-    user32 = ctypes.windll.user32
 
     def callback(hwnd, pid):
         wpid = _DWORD()
-        user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
+        _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
         if pid == wpid.value:
-            user32.ShowWindow(hwnd, _SW_HIDE)
+            _user32.ShowWindow(hwnd, _SW_HIDE)
             return False # stop enumerating windows
         return True
 
     pid = _kernel32.GetCurrentProcessId()
-    user32.EnumWindows(_WNDENUMPROC(callback), pid)
+    _user32.EnumWindows(_WNDENUMPROC(callback), pid)
 
 def termwidth():
     # cmd.exe does not handle CR like a unix console, the CR is