from typing import Dict, List, Optional, Sequence, Tuple, Union
try:
from typing import TypeGuard
except ImportError:
from typing_extensions import TypeGuard
import pythoncom
import win32api
import win32con
from pywintypes import IIDType
from win32com.client.genpy import (
DispatchItem,
EnumerationItem,
Generator,
RecordItem,
VTableItem,
)
from win32com.client.selecttlb import EnumKeys, TypelibSpec
[docs]PyITypeLib = "PyITypeLib"
[docs]PyIIDLike = Union[PyIID, str]
[docs]def IsPyIID(value) -> TypeGuard[PyIID]:
return isinstance(value, IIDType)
[docs]def IsPyITypeLib(value) -> TypeGuard[PyITypeLib]:
return type(value).__name__ == PyITypeLib
[docs]def IsPyIIDLike(value) -> TypeGuard[PyIIDLike]:
return IsPyIID(value) or isinstance(value, str)
[docs]def GetTypelibSpecs(iid: PyIIDLike) -> List[TypelibSpec]:
specs: List[TypelibSpec] = []
try:
key = win32api.RegOpenKey(win32con.HKEY_CLASSES_ROOT, "TypeLib")
key2 = win32api.RegOpenKey(key, str(iid))
except win32api.error:
enum_keys = []
else:
enum_keys = EnumKeys(key2)
for version, tlbdesc in enum_keys:
major_minor = version.split(".", 1)
if len(major_minor) < 2:
major_minor.append("0")
major = major_minor[0]
minor = major_minor[1]
key3 = win32api.RegOpenKey(key2, str(version))
try:
flags = int(win32api.RegQueryValue(key3, "FLAGS"))
except (win32api.error, ValueError):
flags = 0
for lcid, _ in EnumKeys(key3):
try:
lcid = int(lcid)
except ValueError:
continue
try:
key4 = win32api.RegOpenKey(key3, "{}\\win32".format(lcid))
except win32api.error:
try:
key4 = win32api.RegOpenKey(key3, "{}\\win64".format(lcid))
except win32api.error:
continue
try:
dll, typ = win32api.RegQueryValueEx(key4, None)
if typ == win32con.REG_EXPAND_SZ:
dll = win32api.ExpandEnvironmentStrings(dll)
except win32api.error:
dll = None
spec = TypelibSpec(iid, lcid, major, minor, flags)
spec.dll = dll
spec.desc = tlbdesc
spec.ver_desc = tlbdesc + " (" + version + ")"
specs.append(spec)
return specs
[docs]def GetLatestTypelibSpec(
specs: Union[Sequence[TypelibSpec], PyIIDLike]
) -> Optional[TypelibSpec]:
spec: Optional[TypelibSpec] = None
if IsPyIIDLike(specs):
specs = GetTypelibSpecs(specs)
if len(specs) > 0:
specs = sorted(specs)
spec = specs[-1]
return spec
[docs]def LoadTypeLib(spec: Union[TypelibSpec, PyIIDLike]) -> Optional[PyITypeLib]:
tlb: Optional[PyITypeLib] = None
if IsPyIIDLike(spec):
spec = GetLatestTypelibSpec(spec)
if spec:
if spec.dll:
tlb = pythoncom.LoadTypeLib(spec.dll)
else:
tlb = pythoncom.LoadRegTypeLib(
spec.clsid,
spec.major,
spec.minor,
spec.lcid,
)
return tlb
[docs]def BuildOleItems(
spec: Union[TypelibSpec, PyIIDLike],
tlb: Optional[PyITypeLib] = None,
) -> Tuple[
Dict[PyIID, DispatchItem],
Dict[PyIID, EnumerationItem],
Dict[PyIID, RecordItem],
Dict[PyIID, VTableItem],
]:
oleItems: Dict[PyIID, DispatchItem] = {}
enumItems: Dict[PyIID, EnumerationItem] = {}
recordItems: Dict[PyIID, RecordItem] = {}
vtableItems: Dict[PyIID, VTableItem] = {}
if IsPyIIDLike(spec):
spec = GetLatestTypelibSpec(spec)
if spec:
if not tlb:
tlb = LoadTypeLib(spec)
progressInstance = None
gen = Generator(tlb, spec.dll, progressInstance, bBuildHidden=1)
oleItems, enumItems, recordItems, vtableItems = gen.BuildOleItemsFromType()
return oleItems, enumItems, recordItems, vtableItems