Eryk Sun <eryk...@gmail.com> added the comment:
Pointers to resource type/name strings use the lower 16-bit range for integer identifiers such as RT_ICON (3) and RT_GROUP_ICON (14). C code checks for these cases using the IS_INTRESOURCE() macro. It's incorrect to use a simple C string pointer type such as ctypes.c_wchar_p (i.e. wintypes.LPWSTR) for a resource type/name string. Simple types get automatically converted to the corresponding Python type (e.g. str), but a 16-bit ID is not a valid pointer. Support for resource IDs can be implemented by a subclass of ctypes.c_wchar_p, since subclasses of simple types don't get converted automatically. For example: class LPWSTR(ctypes.c_wchar_p): @property def value(self): v = ctypes.c_void_p.from_buffer(self).value or 0 if v >> 16 == 0: return v return super().value @value.setter def value(self, v): ctypes.c_wchar_p.value.__set__(self, v) def __eq__(self, other): if not isinstance(other, __class__): return NotImplemented return self.value == other.value def __hash__(self): return hash(self.value) RT_ICON = LPWSTR(3) RT_GROUP_ICON = LPWSTR(RT_ICON.value + 11) > kernel32 = ctypes.windll.kernel32 I recommend using `kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)`, which creates function pointers that capture the last error value before they return. Call ctypes.get_last_error() to get the captured error value. To get an exception for the error value, use ctypes.WinError(ctypes.get_last_error()). This is more reliable since there's a chance that the thread executes some WinAPI code that modifies the last error before GetLastError() is called. This is particularly likely when working with ctypes calls in the interactive shell. Using a separate WinDLL() instance also isolates a library from other libraries. Since ctypes.windll caches modules, which cache function pointers, it's a problem when multiple libraries require different function prototypes (i.e. restype, argtypes, errcheck). The last library to set the prototype wins. The other libraries will probably be broken in some way. Their function calls may raise a ctypes.ArgumentError, or their post-call errcheck() isn't used, or their required restype isn't returned. > hmod = GetModuleHandle(sys.executable) This is unnecessary and possibly wrong since there's no guarantee that sys.executable is a valid file, let alone a file that's loaded as a module in the current process. Pass hModule as NULL (None) to use the main module of the process (i.e. the process image / executable). > context structure that is used to use regular python functions as callbacks > where external C code expects C callbacks with a certain signature. Generally there's no need to use C context parameters, which aren't necessary in object-oriented and functional programming paradigms. The callback function can defined as a nested function, with access to closure variables, or as a method, with access to instance attributes. ---------- nosy: +eryksun _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue47001> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com