Eryk Sun <[email protected]> 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 <[email protected]>
<https://bugs.python.org/issue47001>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com