Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 84 additions & 16 deletions comtypes/tools/codegenerator/codegenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,97 @@ def adjust_blank(
yield self.stream
self.last_item = item

def generate(self, item: Any) -> None:
def generate(
self,
item: _UnionT[
tlbparser.ParsedType,
tlbparser.SpecType,
typedesc.EnumValue,
typedesc.StructureHead,
typedesc.StructureBody,
typedesc.ComInterfaceHead,
typedesc.DispInterfaceHead,
typedesc.ComInterfaceBody,
typedesc.DispInterfaceBody,
],
) -> None:
if item in self.done:
return
if self._is_interface_typedesc(item):
self._define_interface(item)
return
if isinstance(item, typedesc.StructureHead):
name = getattr(item.struct, "name", None)
name = item.struct.name
elif isinstance(
item,
(
typedesc.External,
typedesc.PointerType,
typedesc.ArrayType,
typedesc.SAFEARRAYType,
typedesc.StructureBody,
),
):
name = None
else:
name = getattr(item, "name", None)
if name in self.known_symbols:
name = item.name
if name is not None and name in self.known_symbols:
self.imports.add(name, symbols=self.known_symbols)
self.done.add(item)
if isinstance(item, typedesc.Structure):
self.done.add(item.get_head())
self.done.add(item.get_body())
return
mth = getattr(self, type(item).__name__)
# to avoid infinite recursion, we have to mark it as done
# before actually generating the code.
self.done.add(item)
mth(item)
self._dispatch_by(item)

def _dispatch_by(self, item: Any) -> None:
if isinstance(item, typedesc.ArrayType):
self.ArrayType(item)
elif isinstance(item, typedesc.EnumValue):
self.EnumValue(item)
elif isinstance(item, typedesc.Enumeration):
self.Enumeration(item)
elif isinstance(item, typedesc.Typedef):
self.Typedef(item)
elif isinstance(item, typedesc.FundamentalType):
self.FundamentalType(item)
elif isinstance(item, typedesc.StructureHead):
self.StructureHead(item)
elif isinstance(item, typedesc.Structure):
self.Structure(item)
elif isinstance(item, typedesc.Union):
self.Union(item)
elif isinstance(item, typedesc.StructureBody):
self.StructureBody(item)
elif isinstance(item, typedesc.TypeLib):
self.TypeLib(item)
elif isinstance(item, typedesc.External):
self.External(item)
elif isinstance(item, typedesc.Constant):
self.Constant(item)
elif isinstance(item, typedesc.SAFEARRAYType):
self.SAFEARRAYType(item)
elif isinstance(item, typedesc.PointerType):
self.PointerType(item)
elif isinstance(item, typedesc.CoClass):
self.CoClass(item)
elif isinstance(item, typedesc.ComInterface):
self.ComInterface(item)
elif isinstance(item, typedesc.ComInterfaceHead):
self.ComInterfaceHead(item)
elif isinstance(item, typedesc.ComInterfaceBody):
self.ComInterfaceBody(item)
elif isinstance(item, typedesc.DispInterface):
self.DispInterface(item)
elif isinstance(item, typedesc.DispInterfaceHead):
self.DispInterfaceHead(item)
elif isinstance(item, typedesc.DispInterfaceBody):
self.DispInterfaceBody(item)
else:
raise TypeError(f"Unsupported: {type(item).__name__!r}")

def generate_all(self, items: Iterable[tlbparser.ParsedType]) -> None:
for item in items:
Expand Down Expand Up @@ -382,16 +451,16 @@ def StructureBody(self, body: typedesc.StructureBody) -> None:
fields: list[typedesc.Field] = []
methods: list[typedesc.Method] = []
for m in body.struct.members:
if type(m) is typedesc.Field:
if isinstance(m, typedesc.Field):
fields.append(m)
if type(m.typ) is typedesc.Typedef:
if isinstance(m.typ, typedesc.Typedef):
self.generate(get_real_type(m.typ))
self.generate(m.typ)
elif type(m) is typedesc.Method:
elif isinstance(m, typedesc.Method):
methods.append(m)
self.generate(m.returns)
self.generate_all(m.iterArgTypes())
elif type(m) is typedesc.Constructor:
elif isinstance(m, typedesc.Constructor):
pass

# we don't need _pack_ on Unions (I hope, at least), and not
Expand Down Expand Up @@ -528,17 +597,17 @@ def SAFEARRAYType(self, sa: typedesc.SAFEARRAYType) -> None:
self.imports.add("comtypes.automation", "_midlSAFEARRAY")

def PointerType(self, tp: typedesc.PointerType) -> None:
if type(tp.typ) is typedesc.ComInterface:
if isinstance(tp.typ, typedesc.ComInterface):
# this defines the class
self.generate(tp.typ.get_head())
# this defines the _methods_
self.more.add(tp.typ)
elif type(tp.typ) is typedesc.PointerType:
elif isinstance(tp.typ, typedesc.PointerType):
self.generate(tp.typ)
elif type(tp.typ) in (typedesc.Union, typedesc.Structure):
elif isinstance(tp.typ, (typedesc.Union, typedesc.Structure)):
self.generate(tp.typ.get_head())
self.more.add(tp.typ)
elif type(tp.typ) is typedesc.Typedef:
elif isinstance(tp.typ, typedesc.Typedef):
self.generate(tp.typ)
else:
self.generate(tp.typ)
Expand Down Expand Up @@ -610,8 +679,7 @@ def _define_interface(self, item: _InterfaceTypeDesc) -> None:
else:
raise TypeError
self.done.add(item) # to avoid infinite recursion.
mth = getattr(self, type(item).__name__)
mth(item)
self._dispatch_by(item)

def ComInterface(self, itf: typedesc.ComInterface) -> None:
self.generate(itf.get_head())
Expand Down
40 changes: 30 additions & 10 deletions comtypes/tools/tlbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from collections.abc import Mapping
from ctypes import alignment, c_void_p, sizeof, windll
from ctypes.wintypes import MAX_PATH
from typing import Any, Optional, TypeVar, overload
from typing import Any, Optional, TypeVar
from typing import Union as _UnionT

from comtypes import automation, typeinfo
Expand All @@ -16,14 +16,9 @@

################################
_PT = TypeVar("_PT", bound=_UnionT["ParsedType", "SpecType"])
_TypeDefNone = typedesc.Typedef[None]


@overload
def PTR(typ: _PT) -> typedesc.PointerType[_PT]: ...
@overload
def PTR(typ: _TypeDefNone) -> typedesc.PointerType[_TypeDefNone]: ...
def PTR(typ):
def PTR(typ: _PT) -> typedesc.PointerType[_PT]:
return typedesc.PointerType(typ, sizeof(c_void_p) * 8, alignment(c_void_p) * 8)


Expand Down Expand Up @@ -57,8 +52,34 @@ def PTR(typ):
bases=[],
size=sizeof(automation.VARIANT) * 8,
)
IDISPATCH_type = typedesc.Typedef("IDispatch", None)
IUNKNOWN_type = typedesc.Typedef("IUnknown", None)

# These are simplified definitions of `IUnknown` and `IDispatch` from `stdole`.
# Their full definitions include method arguments and IDL flags. However, these
# basic interfaces are replaced with suitable definitions for each use case, so
# they do not need to be modeled perfectly here. Even a complete model would not
# be used, and adding more redundant fields would make maintenance harder.
IUNKNOWN_type = typedesc.ComInterface(
"IUnknown", None, "{00000000-0000-0000-C000-000000000046}", [], None
)
IUNKNOWN_type.extend_members(
[
typedesc.ComMethod(1, 1610612736, "QueryInterface", HRESULT_type, [], None),
typedesc.ComMethod(1, 1610612737, "AddRef", ulong_type, [], None),
typedesc.ComMethod(1, 1610612738, "Release", ulong_type, [], None),
]
)
IDISPATCH_type = typedesc.ComInterface(
"IDispatch", IUNKNOWN_type, "{00020400-0000-0000-C000-000000000046}", [], None
)
IDISPATCH_type.extend_members(
[
typedesc.ComMethod(1, 1610678272, "GetTypeInfoCount", HRESULT_type, [], None),
typedesc.ComMethod(1, 1610678273, "GetTypeInfo", HRESULT_type, [], None),
typedesc.ComMethod(1, 1610678274, "GetIDsOfNames", HRESULT_type, [], None),
typedesc.ComMethod(1, 1610678275, "Invoke", HRESULT_type, [], None),
]
)

DECIMAL_type = typedesc.Structure(
"DECIMAL",
align=alignment(automation.DECIMAL) * 8,
Expand Down Expand Up @@ -123,7 +144,6 @@ def midlSAFEARRAY(typ: _PT) -> typedesc.SAFEARRAYType[_PT]:
typedesc.ComInterface,
typedesc.DispInterface,
typedesc.Typedef["_UnionT[ParsedType, SpecType]"],
_TypeDefNone,
typedesc.Structure,
typedesc.Union,
typedesc.Enumeration,
Expand Down
16 changes: 15 additions & 1 deletion comtypes/tools/typedesc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import ctypes
from collections.abc import Sequence
from typing import Any, Generic, Optional, TypeVar
from typing import Any, Generic, Optional, TypeVar, final
from typing import Union as _UnionT

from comtypes import typeinfo
Expand Down Expand Up @@ -34,6 +34,7 @@
_TD = TypeVar("_TD")


@final
class TypeLib:
def __init__(
self, name: str, guid: str, major: int, minor: int, doc: Optional[str] = None
Expand All @@ -48,6 +49,7 @@ def __repr__(self):
return f"<TypeLib({self.name}: {self.guid}, {self.major}, {self.minor})>"


@final
class Constant:
def __init__(
self,
Expand All @@ -62,6 +64,7 @@ def __init__(
self.doc = doc


@final
class External:
def __init__(
self,
Expand All @@ -85,12 +88,14 @@ def get_head(self) -> "External":
return self


@final
class SAFEARRAYType(Generic[_TD]):
def __init__(self, typ: _TD) -> None:
self.typ = typ
self.align = self.size = ctypes.sizeof(ctypes.c_void_p) * 8


@final
class ComMethod:
# custom COM method, parsed from typelib
def __init__(
Expand All @@ -116,6 +121,7 @@ def add_argument(
self.arguments.append((typ, name, idlflags, default))


@final
class DispMethod:
# dispatchable COM method, parsed from typelib
def __init__(
Expand All @@ -141,6 +147,7 @@ def add_argument(
self.arguments.append((typ, name, idlflags, default))


@final
class DispProperty:
# dispatchable COM property, parsed from typelib
def __init__(
Expand All @@ -153,16 +160,19 @@ def __init__(
self.doc = doc


@final
class DispInterfaceHead:
def __init__(self, itf: "DispInterface") -> None:
self.itf = itf


@final
class DispInterfaceBody:
def __init__(self, itf: "DispInterface") -> None:
self.itf = itf


@final
class DispInterface:
def __init__(
self,
Expand Down Expand Up @@ -191,16 +201,19 @@ def get_head(self) -> DispInterfaceHead:
return self.itf_head


@final
class ComInterfaceHead:
def __init__(self, itf: "ComInterface") -> None:
self.itf = itf


@final
class ComInterfaceBody:
def __init__(self, itf: "ComInterface") -> None:
self.itf = itf


@final
class ComInterface:
def __init__(
self,
Expand Down Expand Up @@ -233,6 +246,7 @@ def get_head(self) -> ComInterfaceHead:
_Interface = _UnionT[ComInterface, DispInterface]


@final
class CoClass:
def __init__(
self,
Expand Down
Loading
Loading