Discussion:
[comtypes-users] Using comtypes.automation.VARIANT() with user-defined types (structs)
Alex Huszagh
2016-03-24 17:34:52 UTC
Permalink
Hi,

I'm working with a well-documented, but proprietary DLL I would like to
call from Python, meaning I have no ability to edit the DLL.

The method documentation itself follows something similar to the following:

GetDataFromScan(long nScanNumber,
LPVARIANT pvarScanData,
LPLONG pnArraySize)


Where pvarScanData is filled with ScanData structs of the similar format:

struct ScanData
{
double dMassWidth;
double dMass;
long nCharge;
long nScan;
};

So far, to try to extract data from the DLL, I have tried using various
parameters with comtypes.automation.VARIANT, with no success.


import comtypes
import ctypes

CLSID = '{........-....-....-....-............}'
handle = comtypes.client.CreateObject(CLSID)


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

# response is 0 for success, > 0 for error
response = handle.GetDataFromScan(scandata, size)


Now, this works when no data is returned, however, for size > 1, an
error is returned and no data fills the variant. So I therefore looked
to initialize the variant. I also tried throwing various parameters,
such as `comtypes.automation.VARIANT(comtypes.automation.VT_ARRAY)`,
however, the few I tried (VT_ARRAY, VT_UNKNOWN) all caused the method to
fail (produce a response > 0) even when no data was returned.

I'm wondering if there's any method to initialize the Variant with a
method like VariantInit, and then copy the data to a numpy array using
the comtypes safearray. Any insight would be wonderful.

Thank you,
Alex
--
Alex Huszagh
Lan Huang Laboratory
Department of Physiology and Biophysics
University of California, Irvine
Alex Huszagh
2016-03-24 20:40:45 UTC
Permalink
Nevermind, I was able to solve it using _midlSAFEARRAY, and am posting
my solution below in case anyone else is having similar difficulty
(since the mailing lists are indexed by search engines).


import comtypes
import ctypes

class ScanData(ctypes.Structure):
_fields_ = [('mass_width', ctypes.c_double),
('mass', ctypes.c_double),
('charge', ctypes.c_long),
('scan', 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()


scandata = comtypes.automation.VARIANT()
size = ctypes.c_long()
handle.GetDataFromScan(scandata, size)
items = to_struct(scandata, ScanData)
print(items[0].mass_width)


Thanks for the excellent library,
Alex
Post by Alex Huszagh
Hi,
I'm working with a well-documented, but proprietary DLL I would like to
call from Python, meaning I have no ability to edit the DLL.
GetDataFromScan(long nScanNumber,
LPVARIANT pvarScanData,
LPLONG pnArraySize)
struct ScanData
{
double dMassWidth;
double dMass;
long nCharge;
long nScan;
};
So far, to try to extract data from the DLL, I have tried using various
parameters with comtypes.automation.VARIANT, with no success.
import comtypes
import ctypes
CLSID = '{........-....-....-....-............}'
handle = comtypes.client.CreateObject(CLSID)
scandata = comtypes.automation.VARIANT()
size = ctypes.c_long()
# response is 0 for success, > 0 for error
response = handle.GetDataFromScan(scandata, size)
Now, this works when no data is returned, however, for size > 1, an
error is returned and no data fills the variant. So I therefore looked
to initialize the variant. I also tried throwing various parameters,
such as `comtypes.automation.VARIANT(comtypes.automation.VT_ARRAY)`,
however, the few I tried (VT_ARRAY, VT_UNKNOWN) all caused the method to
fail (produce a response > 0) even when no data was returned.
I'm wondering if there's any method to initialize the Variant with a
method like VariantInit, and then copy the data to a numpy array using
the comtypes safearray. Any insight would be wonderful.
Thank you,
Alex
--
Alex Huszagh
Lan Huang Laboratory
Department of Physiology and Biophysics
University of California, Irvine
Loading...