enthought / comtypes

A pure Python, lightweight COM client and server framework, based on the ctypes Python FFI package.
Other
292 stars 97 forks source link

Feature Request: Structs as valid variant types #100

Open Alexhuszagh opened 8 years ago

Alexhuszagh commented 8 years ago

Please close if feature requests are not supported here. I would be happy to submit a pull request for the above feature.

Currently, converting variants of structs with heterogeneous types is doable, although the documentation is poor and the methods are somewhat tricky, and the data returned is often much longer than desired, as well as incoherent.

This is since the variant assumes the type of the first item within the first struct, so the following struct would assume all items are doubles, even though x and y are both longs.

struct Data {
    double value;
long x;
    long y;
 };

To fix this, you can do the following:

import comtypes
import ctypes

class Data(ctypes.Structure):
    _fields_ = [('value', ctypes.c_double),
                ('x', ctypes.c_long),
                ('y', ctypes.c_long)]

def to_struct(variant, struct):
    '''
    Convert variant array of structs to tuple of structs.

    Args:
        variant (VARIANT):      filled VARIANT
        struct (Structure):     struct with _fields_
    '''

    safe_array = comtypes.safearray._midlSAFEARRAY(struct)
    return ctypes.cast(variant._.pparray, safe_array).unpack()

data = comtypes.automation.VARIANT()
size = ctypes.c_long()

com_object.GetData(data, size)
items = to_struct(data, Data)[:size.value]

This fixes the above issue, which I propose could be fixed using a VARIANT.vt_fromstruct classmethod. The object size could by acquired from VARIANT..pparray, allowing the full functionality above using a very clean interface.

junkmd commented 2 months ago

@Alexhuszagh

Are you still interested in this issue?

Recently, there have been extensions related to SAFEARRAY functionality, like in #576, so the community might be able to help.