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

Reply via email to