Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #108246

Re: python, ctypes and GetIconInfo issue

From eryk sun <eryksun@gmail.com>
Newsgroups comp.lang.python
Subject Re: python, ctypes and GetIconInfo issue
Date 2016-05-06 18:39 -0500
Message-ID <mailman.441.1462577987.32212.python-list@python.org> (permalink)
References <f02f269a-703c-42c6-9419-0a8e667bd6b0@googlegroups.com> <CACL+1atJ+aP1zbMukcqszWC6ycizvjKu+4oc41K1WGmu0-kfXg@mail.gmail.com> <mailman.419.1462493404.32212.python-list@python.org> <5dd5db3e-ffa9-4c7b-9385-dc20f85dd45b@googlegroups.com> <CACL+1av9OSbmeunBGuk2rsFz0mcoX+sgfVdi6oFRZpNxGyApyA@mail.gmail.com>

Show all headers | View raw


On Fri, May 6, 2016 at 9:49 AM,  <mymyxin@gmail.com> wrote:
>
> In your example you used a base class
> and ICONINFO well as ICONINFOEX inherit it.
> As the members of ICONINFO are part of ICONINFOEX
> couldn't we do something like
>
> class ICONINFO_BASE(ctypes.Structure):
>     def __del__(self, ):
>         if self.hbmMask:
>             gdi32.DeleteObject(self.hbmMask)
>             self.hbmMask = None
>         if self.hbmColor:
>             gdi32.DeleteObject(self.hbmColor)
>             self.hbmColor = None
>
> class ICONINFO(ICONINFO_BASE):
>     _fields_ = (('fIcon',    wintypes.BOOL),
>                 ('xHotspot', wintypes.DWORD),
>                 ('yHotspot', wintypes.DWORD),
>                 ('hbmMask',  wintypes.HBITMAP),
>                 ('hbmColor', wintypes.HBITMAP))
>
> class ICONINFOEX(ICONINFO):
>     _fields_ = (('cbSize',    wintypes.DWORD),
>                 # ('fIcon',     wintypes.BOOL),
>                 # ('xHotspot',  wintypes.DWORD),
>                 # ('yHotspot',  wintypes.DWORD),
>                 # ('hbmMask',   wintypes.HBITMAP),
>                 # ('hbmColor',  wintypes.HBITMAP),
>                 ('wResID',    wintypes.WORD),
>                 ('szModName', wintypes.WCHAR * MAX_PATH),
>                 ('szResName', wintypes.WCHAR * MAX_PATH))

In this case, cbSize field will be offset after hbmColor:

    >>> ICONINFOEX.hbmColor.offset
    24
    >>> ICONINFOEX.cbSize.offset
    32

A struct subclass appends its fields to the base class fields. In
theory, you can do this in some cases, but in practice I don't
recommend it (see below).

For example, look at SHARE_INFO_0 [1], SHARE_INFO_1 [2], and
SHARE_INFO_2 [3], which are used to query different levels of
information about network shares.

[1]: https://msdn.microsoft.com/en-us/library/bb525402
[2]: https://msdn.microsoft.com/en-us/library/bb525407
[3]: https://msdn.microsoft.com/en-us/library/bb525408

It can help to maintain a consistent type hierarchy, such as in the
following answer that I wrote to list network shares on Windows:

http://stackoverflow.com/a/36848031/205580

When ctypes checks the type of a pointer argument, it first checks
whether its _type_ is a subclass of the _type_ of the corresponding
pointer type in argtypes. If not, it falls back on checking whether
the pointer argument itself is an instance of the argtypes pointer
type. Similarly, for a byref() argument it checks whether the referent
is an instance of the _type_ of the argtypes pointer type. Maintaining
a consistent type hierarchy provides type safety without having to
tediously cast pointers.

However, I don't recommend subclassing to append _fields_ because it
has a bug. The code that updates the StgDictObject (i.e. the subclass
of dict used by ctypes types for FFI storgage info) for structs and
union types doesn't doesn't properly initialize the ffi_type elements
array. The length field of the stgdict needs to be the total number of
fields, inclusive of all base classes, in order to copy the entire
ffi_type elements array from the base class. However, storing the
total length in the stgdict's length field would require rewriting the
way an instance of a struct is recursively initialized over the base
classes.

This bug affects passing structs by value. This isn't common (passing
unions by value isn't even supported), so I haven't bothered to submit
a patch for this. Here's an example crash on 64-bit Linux:

test.c:

    #include <stdio.h>

    typedef struct _data_t {
        int x, y, z;
    } data_t;

    int test(data_t d) {
        printf("%d, %d, %d\n", d.x, d.y, d.z);
        return 0;
    }

test.py:

    from ctypes import *

    lib = CDLL('./test.so')

    class A(Structure):
        _fields_ = (('a', c_int), ('b', c_int), ('c', c_int),)

    class B(Structure):
        _fields_ = (('a', c_int),)
    class C(B):
        _fields_ = (('b', c_int),)
    class D(C):
        _fields_ = (('c', c_int),)

    print('test A')
    lib.test(A(42, 84, 168))

    print('test D')
    lib.test(D(42, 84, 168))

output:
    test A
    42, 84, 168
    test D
    Aborted

Back to comp.lang.python | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

python, ctypes and GetIconInfo issue mymyxin@gmail.com - 2016-05-05 13:47 -0700
  Re: python, ctypes and GetIconInfo issue eryk sun <eryksun@gmail.com> - 2016-05-05 19:09 -0500
    Re: python, ctypes and GetIconInfo issue mymyxin@gmail.com - 2016-05-06 06:36 -0700
      Re: python, ctypes and GetIconInfo issue eryk sun <eryksun@gmail.com> - 2016-05-06 18:38 -0500
    Re: python, ctypes and GetIconInfo issue mymyxin@gmail.com - 2016-05-06 07:49 -0700
      Re: python, ctypes and GetIconInfo issue eryk sun <eryksun@gmail.com> - 2016-05-06 18:39 -0500
        Re: python, ctypes and GetIconInfo issue mymyxin@gmail.com - 2016-05-07 14:58 -0700

csiph-web