Skip to content

Commit

Permalink
Improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
PCigales authored Jul 13, 2024
1 parent eed88bd commit b17993a
Showing 1 changed file with 99 additions and 27 deletions.
126 changes: 99 additions & 27 deletions wic.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,6 @@ def CLSIDFromProgID(pid):
return None
else:
return GUID(clsid)
@staticmethod
def _agitem(arr, key):
e = arr.__class__.__bases__[0].__getitem__(arr, key)
if isinstance(key, int):
if (e := arr.__class__._base(e)) is not None:
e.AddRef(False)
else:
for i in (e := list(map(arr.__class__._base, e))):
if i is not None:
i.AddRef(False)
return e
@staticmethod
def _asitem(arr, key, value):
return arr.__class__.__bases__[0].__setitem__(arr, key, getattr(value, 'pI', value) if isinstance(key, int) else [getattr(v, 'pI', v) for v in value])

class _IMeta(type):
@classmethod
Expand All @@ -100,17 +86,17 @@ def __init__(cls, *args, **kwargs):
cls._protos[n] = ctypes.WINFUNCTYPE(wintypes.ULONG, *i, *o)(p, n, (*((1,) for _i in i), *((2,) for _o in o)))
cls._protos[n].errcheck = _IUtil._errcheck_no if len(o) == 0 else _IUtil._errcheck_o
def __mul__(bcls, size):
return _IUtil._mul_cache.setdefault((bcls, size), type('%s_Array_%d' % (bcls.__name__, size), (wintypes.LPVOID * size,), {'__getitem__': _IUtil._agitem, '__setitem__': _IUtil._asitem, '_base': bcls}))
return _IUtil._mul_cache.setdefault((bcls, size), type('%s_Array_%d' % (bcls.__name__, size), (COM * size, wintypes.LPVOID * size), {'_ibase': bcls}))

class IUnknown(metaclass=_IMeta):
IID = GUID('00000000-0000-0000-c000-000000000046')
_protos['QueryInterface'] = 0, (wintypes.LPCSTR,), (wintypes.PLPVOID,)
_protos['AddRef'] = ctypes.WINFUNCTYPE(wintypes.ULONG)(1, 'AddRef')
_protos['Release'] = ctypes.WINFUNCTYPE(wintypes.ULONG)(2, 'Release')
def __new__(cls, clsid_component=False, factory=None):
if clsid_component is None:
return None
if not clsid_component:
if clsid_component is not False:
return None
if (clsid_component := getattr(cls, 'CLSID', None)) is None:
raise TypeError('%s does not have an implicit constructor' % cls.__name__)
if isinstance(clsid_component, int):
Expand Down Expand Up @@ -164,6 +150,53 @@ def __del__(self):
while self.pI and self.refs > 0:
self.Release()

class _COMUtil:
_mul_cache = {}
@staticmethod
def _agitem(arr, key):
acls = arr.__class__
e = acls.__bases__[-1].__getitem__(arr, key)
return _COMUtil._interface(acls._base(e), getattr(arr, '_ibase', None)) if isinstance(key, int) else [_COMUtil._interface(acls._base(c), getattr(arr, '_ibase', None)) for c in e]
@staticmethod
def _asitem(arr, key, value):
acls = arr.__class__
return acls.__bases__[-1].__setitem__(arr, key, acls._base(value) if isinstance(key, int) else [acls._base(v) for v in value])
@staticmethod
def _interface(com, icls=None):
if not hasattr(com, 'com'):
com.com = ctypes.cast(com, wintypes.LPVOID)
if (i := (icls or com.icls)(com.com)) is None:
return None
i.AddRef(False)
return i

class _COMMeta(wintypes.LPVOID.__class__):
def __mul__(bcls, size):
return _COMUtil._mul_cache.setdefault((bcls, size), type('%s_Array_%d' % (bcls.__name__, size), (wintypes.LPVOID * size,), {'__getitem__': _COMUtil._agitem, '__setitem__': _COMUtil._asitem, '_base': bcls}))

class COM(wintypes.LPVOID, metaclass=_COMMeta):
icls = IUnknown
def __init__(self, interface=None):
if isinstance(interface, IUnknown):
self.interface = interface
self.value = getattr(interface.pI, 'value', interface.pI)
self.icls = interface.__class__
else:
self.interface = self.__class__.icls(None)
self.value = getattr(interface, 'value', interface)
self.icls = self.__class__.icls
self.com = ctypes.cast(self, wintypes.LPVOID)
@property
def value(self):
return getattr(getattr(self, 'com', ctypes.cast(self, wintypes.LPVOID)), 'value', None)
@value.setter
def value(self, val):
ctypes.c_void_p.from_address(ctypes.addressof(self)).value = val
self.com = ctypes.cast(self, wintypes.LPVOID)
@property
def content(self):
return _COMUtil._interface(self)

class IClassFactory(IUnknown):
IID = GUID('00000001-0000-0000-c000-000000000046')
_protos['CreateInstance'] = 3, (wintypes.LPVOID, wintypes.LPCSTR,), (wintypes.PLPVOID,)
Expand Down Expand Up @@ -1177,12 +1210,16 @@ def InitializeFromPalette(self, palette):
class _BLOBUtil:
_mul_cache = {}
@staticmethod
def _agitem(arr, key):
e = arr.__class__.__bases__[0].__getitem__(arr, key)
return e.content if isinstance(key, int) else [b.content for b in e]
@staticmethod
def _asitem(arr, key, value):
return arr.__class__.__bases__[0].__setitem__(arr, key, BLOB(value) if isinstance(key, int) else list(map(BLOB, value)))

class _BLOBMeta(ctypes.Structure.__class__):
def __mul__(bcls, size):
return _BLOBUtil._mul_cache.setdefault((bcls, size), type('BLOB_Array_%d' % size, (ctypes.Structure.__class__.__mul__(bcls, size),), {'__setitem__': _BLOBUtil._asitem}))
return _BLOBUtil._mul_cache.setdefault((bcls, size), type('BLOB_Array_%d' % size, (ctypes.Structure.__class__.__mul__(bcls, size),), {'__getitem__': _BLOBUtil._agitem, '__setitem__': _BLOBUtil._asitem}))

class BLOB(ctypes.Structure, metaclass=_BLOBMeta):
_fields_ = [('cbSize', wintypes.ULONG), ('pBlobdata', wintypes.LPVOID)]
Expand All @@ -1201,12 +1238,16 @@ def __init__(self, data=None):
class _BSTRUtil:
_mul_cache = {}
@staticmethod
def _agitem(arr, key):
e = arr.__class__.__bases__[0].__getitem__(arr, key)
return e.content if isinstance(key, int) else [b.content for b in e]
@staticmethod
def _asitem(arr, key, value):
return arr.__class__.__bases__[0].__setitem__(arr, key, (value if isinstance(value, BSTR) else BSTR(value)) if isinstance(key, int) else [v if isinstance(v, BSTR) else BSTR(v) for v in value])

class _BSTRMeta(ctypes._Pointer.__class__):
def __mul__(bcls, size):
return _BSTRUtil._mul_cache.setdefault((bcls, size), type('BSTR_Array_%d' % size, (ctypes._Pointer.__class__.__mul__(bcls, size),), {'__setitem__': _BSTRUtil._asitem}))
return _BSTRUtil._mul_cache.setdefault((bcls, size), type('BSTR_Array_%d' % size, (ctypes._Pointer.__class__.__mul__(bcls, size),), {'__getitem__': _BSTRUtil._agitem, '__setitem__': _BSTRUtil._asitem}))

class BSTR(ctypes.POINTER(wintypes.WCHAR), metaclass=_BSTRMeta):
_type_ = wintypes.WCHAR
Expand Down Expand Up @@ -1235,12 +1276,11 @@ def __new__(cls, data=None):
else:
self._needsfree = True
bstr = wintypes.LPVOID(oleauto32.SysAllocStringByteLen(PBUFFER.from_param(data),PBUFFER.length(data)))
ctypes.c_void_p.from_address(ctypes.addressof(self)).value = bstr.value
self.bstr = ctypes.cast(self, ctypes.c_void_p)
self.value = bstr.value
return self
@property
def value(self):
return getattr(getattr(self, 'bstr', ctypes.cast(self, ctypes.c_void_p)), 'value', 0)
return getattr(getattr(self, 'bstr', ctypes.cast(self, ctypes.c_void_p)), 'value', None)
@value.setter
def value(self, val):
ctypes.c_void_p.from_address(ctypes.addressof(self)).value = val
Expand All @@ -1266,7 +1306,7 @@ def __ctypes_from_outparam__(self):
return self
PBSTR = ctypes.POINTER(BSTR)

class DATE(float):
class FDate(float):
def __new__(cls, dt=0):
if isinstance(dt, str):
try:
Expand All @@ -1284,6 +1324,8 @@ def __new__(cls, dt=0):
dt = (dt - datetime.datetime(1899, 12, 30, 0, 0, 0, 0, (None if dt.tzinfo is None else datetime.timezone.utc))) / datetime.timedelta(1)
elif isinstance(dt, (int, float)):
pass
elif isinstance(dt, wintypes.DOUBLE):
dt = dt.value
else:
return None
self = float.__new__(cls, dt)
Expand All @@ -1305,6 +1347,30 @@ def __str__(self):
def __repr__(self):
return str(self)

class _DATEUtil:
_mul_cache = {}
@staticmethod
def _agitem(arr, key):
e = arr.__class__.__bases__[0].__getitem__(arr, key)
return e.content if isinstance(key, int) else [d.content for d in e]
@staticmethod
def _asitem(arr, key, value):
return arr.__class__.__bases__[0].__setitem__(arr, key, (value if isinstance(value, DATE) else DATE(value)) if isinstance(key, int) else [v if isinstance(v, DATE) else DATE(v) for v in value])

class _DATEMeta(wintypes.DOUBLE.__class__):
def __mul__(bcls, size):
return _DATEUtil._mul_cache.setdefault((bcls, size), type('DATE_Array_%d' % size, (wintypes.DOUBLE.__class__.__mul__(bcls, size),), {'__getitem__': _DATEUtil._agitem, '__setitem__': _DATEUtil._asitem}))

class DATE(wintypes.DOUBLE, metaclass=_DATEMeta):
def __init__(self, dt=0):
wintypes.DOUBLE.__init__(self, FDate(dt))
@property
def content(self):
return FDate(self)
@content.setter
def content(self, data):
self.value = FDate(data)

class CA(ctypes.Structure):
_fields_ = [('vc', wintypes.DWORD), ('vp', wintypes.LPVOID)]
def content(self, etype):
Expand Down Expand Up @@ -1333,6 +1399,8 @@ class PSAFEARRAY(ctypes.POINTER(wintypes.USHORT)):
_type_ = wintypes.USHORT
oleauto32.SafeArrayCreate.restype = wintypes.LPVOID
def __new__(cls, *args):
if len(args) == 2 and isinstance(args[1], PSAFEARRAY):
args = (args[1],)
if len(args) == 1:
if (psafearray := (args[0].psafearray if isinstance(args[0], PSAFEARRAY) else args[0])) is None:
return None
Expand Down Expand Up @@ -1360,6 +1428,7 @@ def __new__(cls, *args):
self.size = self.esize
for dim in range(self.ndims):
self.size *= shape[dim]
self._pdata = args[0]
elif len(args) == 2:
vtype, data = args
if (vtype := _BVType.vtype_code(vtype)) is None:
Expand Down Expand Up @@ -1397,6 +1466,8 @@ def __new__(cls, *args):
ctypes.memmove(pdata, ctypes.pointer(ctypes.c_byte.from_buffer(data)), self.size)
if oleauto32.SafeArrayUnaccessData(psafearray):
return None
if issubclass(_BVARIANT.code_ctype[vtype], (ctypes.c_void_p, ctypes.c_char_p, ctypes.c_wchar_p, ctypes._Pointer, VARIANT)):
self._pdata = ctypes.pointer(data)
else:
return None
ctypes.c_void_p.from_address(ctypes.addressof(self)).value = psafearray.value
Expand Down Expand Up @@ -1486,7 +1557,6 @@ class PropVariantType(_BVType):
class _BVUtil:
_mul_cache = {}
@staticmethod

def _ainit(arr, *args, needsclear=False, **kwargs):
arr.__class__.__bases__[0].__init__(arr, *args, **kwargs)
arr._needsclear = needsclear
Expand All @@ -1512,6 +1582,8 @@ def _ptie(addr, bvar):
p = wintypes.LPVOID(addr)
p._bvariant = bvar
return p
class COMSTREAM(COM):
icls = IStream

class _BVMeta(ctypes.Structure.__class__):
def __mul__(bcls, size):
Expand Down Expand Up @@ -1545,11 +1617,11 @@ def __init__(cls, *args, **kwargs):
cls.filetime = property(lambda s: wintypes.FILETIME.from_buffer_copy(s._filetime), cls._filetime.__set__, cls._filetime.__delete__)
if hasattr(cls, 'date'):
cls._date = cls.date
cls.date = property(lambda s: DATE(s._date), lambda s, v: setattr(s, '_date', DATE(v)), cls._date.__delete__)
cls.date = property(lambda s: DATE(s._date).content, lambda s, v: setattr(s, '_date', DATE(v)), cls._date.__delete__)
for n in ('punkVal', 'pdispVal', 'pStorage', 'pStream'):
if hasattr(cls, n):
setattr(cls, '_' + n, getattr(cls, n))
setattr(cls, n, property(lambda s, _n='_'+n: _BVUtil._idup(getattr(s, _n), IStream if _n == '_pStream' else IUnknown), lambda s, v, _n='_'+n: setattr(s, _n, v.pI if isinstance(v, IUnknown) else v), getattr(cls, '_' + n, '__delete__')))
setattr(cls, n, property(lambda s, _n='_'+n: getattr(s, _n).content, lambda s, v, _n='_'+n: setattr(s, _n, COM(v)), getattr(cls, '_' + n, '__delete__')))
if hasattr(cls, 'pclipdata'):
cls._pclipdata = cls.pclipdata
cls.pclipdata = property(lambda s: _BVUtil._padup(s._pclipdata), lambda s, v: setattr(s, '_pclipdata', v if isinstance(v, wintypes.PBYTES16) else ((ctypes.pointer(v) if isinstance(v, wintypes.BYTES16) else ctypes.cast(ctypes.c_char_p(v), wintypes.PBYTES16)))), cls._pclipdata.__delete__)
Expand All @@ -1569,7 +1641,7 @@ def __init__(cls, *args, **kwargs):
class _BVARIANT(metaclass=_BVMeta):
vtype_code = {'VT_EMPTY': 0, 'VT_NULL': 1, 'VT_I1': 16, 'VT_UI1': 17, 'VT_I2': 2, 'VT_UI2': 18, 'VT_I4': 3, 'VT_UI4': 19, 'VT_INT': 22, 'VT_UINT': 23, 'VT_I8': 20, 'VT_UI8': 21, 'VT_R4': 4, 'VT_R8': 5, 'VT_BOOL': 11, 'VT_ERROR': 10, 'VT_CY': 6, 'VT_DATE': 7, 'VT_FILETIME': 64, 'VT_CLSID': 72, 'VT_CF': 71, 'VT_BSTR': 8, 'VT_BLOB': 65, 'VT_BLOBOBJECT': 70, 'VT_LPSTR': 30, 'VT_LPWSTR': 31, 'VT_UNKNOWN': 13, 'VT_DISPATCH': 9, 'VT_STREAM': 66, 'VT_STREAMED_OBJECT': 68, 'VT_STORAGE': 67, 'VT_STORED_OBJECT': 69, 'VT_VERSIONED_STREAM': 73, 'VT_DECIMAL': 14, 'VT_VECTOR': 4096, 'VT_ARRAY': 8192, 'VT_BYREF': 16384, 'VT_VARIANT': 12}
code_vtype = {co: vt for vt, co in vtype_code.items()}
code_ctype = {16: wintypes.CHAR, 17: wintypes.BYTE, 2: wintypes.SHORT, 18: wintypes.USHORT, 3: wintypes.LONG, 19: wintypes.ULONG, 22: wintypes.INT, 23: wintypes.UINT, 20: wintypes.LARGE_INTEGER, 21: wintypes.ULARGE_INTEGER, 4: wintypes.FLOAT, 5: wintypes.DOUBLE, 11: wintypes.VARIANT_BOOL, 10: wintypes.ULONG, 6: wintypes.LARGE_INTEGER, 7: wintypes.DOUBLE, 64: wintypes.FILETIME, 72: wintypes.PGUID, 71: wintypes.PBYTES16, 8: BSTR, 65: BLOB, 70: BLOB, 30: wintypes.LPSTR, 31: wintypes.LPWSTR, 13: wintypes.LPVOID, 9: wintypes.LPVOID, 66: wintypes.LPVOID, 68: wintypes.LPVOID, 67: wintypes.LPVOID, 69: wintypes.LPVOID, 73: wintypes.LPVOID, 14: wintypes.BYTES16, 12: None, 4096: CA, 8192: wintypes.LPVOID, 16384: wintypes.LPVOID}
code_ctype = {16: wintypes.CHAR, 17: wintypes.BYTE, 2: wintypes.SHORT, 18: wintypes.USHORT, 3: wintypes.LONG, 19: wintypes.ULONG, 22: wintypes.INT, 23: wintypes.UINT, 20: wintypes.LARGE_INTEGER, 21: wintypes.ULARGE_INTEGER, 4: wintypes.FLOAT, 5: wintypes.DOUBLE, 11: wintypes.VARIANT_BOOL, 10: wintypes.ULONG, 6: wintypes.LARGE_INTEGER, 7: wintypes.DOUBLE, 64: wintypes.FILETIME, 72: wintypes.PGUID, 71: wintypes.PBYTES16, 8: BSTR, 65: BLOB, 70: BLOB, 30: wintypes.LPSTR, 31: wintypes.LPWSTR, 13: COM, 9: COM, 66: _BVUtil.COMSTREAM, 68: _BVUtil.COMSTREAM, 67: COM, 69: COM, 73: wintypes.LPVOID, 14: wintypes.BYTES16, 12: None, 4096: CA, 8192: wintypes.LPVOID, 16384: wintypes.LPVOID}
_vtype = _BVType
@classmethod
def vt_co(cls, vt):
Expand Down

0 comments on commit b17993a

Please sign in to comment.