Re: MoveWindow with Windows API
eryk sun <[email protected]> Sat, 22 Apr 2017 03:35:17 +0000
| Newsgroups | gmane.comp.python.ctypes |
|---|---|
| Message-ID | <CACL+1asU-QR3nO_pCjJmw+1uTcuAKtO+KcqYyeWtME+hWV2=YA@mail.gmail.com> |
On Fri, Apr 21, 2017 at 11:19 PM, Michael C <[email protected]> wrote: > Hi all, > > I am trying to move and resize a window of a video game, but the following > code doesn't work for some reason. How it works is that it acquire the > handle to the foreground window, and then move it to the specified location > and size. Since it works on notepad, but not my game window, i used > Kernel32.GetLastError() to find out what went wrong. Since you've loaded the library with use_last_error=True, you should use the more reliable function, ctypes.get_last_error() to get the thread's last WinAPI error. But probably in this case GetLastError() has returned the right error value. In a reply you mentioned you're getting the error code ERROR_ACCESS_DENIED (5). This is to be expected when the target window is at a higher integrity level. With UAC enabled, standard users and administrators are logged on with a medium integrity-level access token. You'll have to elevate your script or run it from an elevated command prompt if you need to work with high integrity windows. > import ctypes > import time > > time.sleep(2) > > User32 = ctypes.WinDLL('User32', use_last_error=True) > Kernel32 = ctypes.WinDLL('Kernel32', use_last_error=True) > > handle = User32.GetForegroundWindow() > > print(User32.MoveWindow(handle, 50, 50, 500, 500, False)) If this is running in 64-bit Python 2, avoid passing integer handle arguments without defining the prototype. Handles are 64-bit pointers in 64-bit Windows (though the actual values of real handles are limited to 32-bit), but for ctypes the default integer argument type is a 32-bit C int. In Python 2, ctypes doesn't zero the call stack when copying the 32-bit integer value, so it's possible for garbage to be passed in the high DWORD, which will be read as an invalid handle value. Python 3 overwrites the full 64-bit QWORD in this case by casting the value to intptr_t, so it doesn't have this problem. Plus it's better in general to define a function's prototype and set an errcheck handler. You'll get a safer, more pythonic interface. It's not free though. ctypes is pretty clunky. You can write functions to paper over some of the awkwardness. Here's an example DEF function. import ctypes from ctypes import wintypes user32 = ctypes.WinDLL('user32', use_last_error=True) def DEF(name, lib, restype=Ellipsis, errcheck=None, argtypes=(), use_last_error=None): base = lib._FuncPtr if restype is Ellipsis: restype = base._restype_ if use_last_error is None: use_last_error = bool(base._flags_ & ctypes._FUNCFLAG_USE_LASTERROR) if (argtypes and isinstance(argtypes[0], (tuple, list)) and len(argtypes[0]) > 1): paramflags = tuple(tuple(p[1:]) if isinstance(p[1], int) else (0,) + tuple(p[1:]) for p in argtypes) argtypes = tuple(a[0] for a in argtypes) else: paramflags = None proto = ctypes.WINFUNCTYPE(restype, *argtypes, use_last_error=use_last_error) func = proto((name, lib), paramflags) if errcheck: func.errcheck = errcheck setattr(lib, name, func) def _check_bool(result, func, args): if not result: err = ctypes.get_last_error() if err: raise ctypes.WinError(err) return args DEF('GetForegroundWindow', user32, wintypes.HWND) DEF('MoveWindow', user32, wintypes.BOOL, _check_bool, [(wintypes.HWND, 'hWnd'), (ctypes.c_int, 'X'), (ctypes.c_int, 'Y'), (ctypes.c_int, 'nWidth'), (ctypes.c_int, 'nHeight'), (wintypes.BOOL, 'bRepaint')]) def get_foreground_window(): while True: hwnd = user32.GetForegroundWindow() if hwnd is not None: return hwnd if __name__ == '__main__': import time time.sleep(2) hwnd = get_foreground_window() user32.MoveWindow(hwnd, X=50, Y=50, nWidth=500, nHeight=500, bRepaint=False) ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot