From 7d6828c9e7a031c4c92cb2227388cc1014f3d967 Mon Sep 17 00:00:00 2001 From: Jun Komoda <45822440+junkmd@users.noreply.github.com> Date: Sat, 2 Nov 2024 17:54:25 +0900 Subject: [PATCH] Separate patch processing within `_com_interface_meta` into a module (part 3 of #646). (#649) * Remove unnecessary stuffs. * Restore methods for keeping change history. * Add comments. * Remove redundant comments. --- .../_cominterface_meta_patcher.py | 178 +++++++++--------- 1 file changed, 86 insertions(+), 92 deletions(-) diff --git a/comtypes/_post_coinit/_cominterface_meta_patcher.py b/comtypes/_post_coinit/_cominterface_meta_patcher.py index 7e86b4c0..8e7ef7b8 100644 --- a/comtypes/_post_coinit/_cominterface_meta_patcher.py +++ b/comtypes/_post_coinit/_cominterface_meta_patcher.py @@ -1,5 +1,3 @@ -# https://learn.microsoft.com/en-us/windows/win32/api/unknwn/ - from _ctypes import COMError import types @@ -80,93 +78,89 @@ def has_name(name): return name.lower() in self.__map_case__ return hasattr(self, name) - # XXX These special methods should be generated by the code generator. - if has_name("Count"): - - @patcher.Patch(self) - class _(object): - def __len__(self): - "Return the the 'self.Count' property." - return self.Count - - if has_name("Item"): - - @patcher.Patch(self) - class _(object): - # 'Item' is the 'default' value. Make it available by - # calling the instance (Not sure this makes sense, but - # win32com does this also). - def __call__(self, *args, **kw): - "Return 'self.Item(*args, **kw)'" - return self.Item(*args, **kw) - - # does this make sense? It seems that all standard typelibs I've - # seen so far that support .Item also support ._NewEnum - @patcher.no_replace - def __getitem__(self, index): - "Return 'self.Item(index)'" - # Handle tuples and all-slice - if isinstance(index, tuple): - args = index - elif index == _all_slice: - args = () - else: - args = (index,) - - try: - result = self.Item(*args) - except COMError as err: - (hresult, text, details) = err.args - if hresult == -2147352565: # DISP_E_BADINDEX - raise IndexError("invalid index") - else: - raise - - # Note that result may be NULL COM pointer. There is no way - # to interpret this properly, so it is returned as-is. - - # Hm, should we call __ctypes_from_outparam__ on the - # result? - return result - - @patcher.no_replace - def __setitem__(self, index, value): - "Attempt 'self.Item[index] = value'" - try: - self.Item[index] = value - except COMError as err: - (hresult, text, details) = err.args - if hresult == -2147352565: # DISP_E_BADINDEX - raise IndexError("invalid index") - else: - raise - except TypeError: - msg = "%r object does not support item assignment" - raise TypeError(msg % type(self)) - - if has_name("_NewEnum"): - - @patcher.Patch(self) - class _(object): - def __iter__(self): - "Return an iterator over the _NewEnum collection." - # This method returns a pointer to _some_ _NewEnum interface. - # It relies on the fact that the code generator creates next() - # methods for them automatically. - # - # Better would maybe to return an object that - # implements the Python iterator protocol, and - # forwards the calls to the COM interface. - enum = self._NewEnum - if isinstance(enum, types.MethodType): - # _NewEnum should be a propget property, with dispid -4. - # - # Sometimes, however, it is a method. - enum = enum() - if hasattr(enum, "Next"): - return enum - # _NewEnum returns an IUnknown pointer, QueryInterface() it to - # IEnumVARIANT - from comtypes.automation import IEnumVARIANT - - return enum.QueryInterface(IEnumVARIANT) + # XXX These special methods should be generated by the code generator. + def _patch_sized(self): + @patcher.Patch(self) + class _(object): + def __len__(self): + "Return the the 'self.Count' property." + return self.Count + + def _patch_callable_and_subscriptable(self): + @patcher.Patch(self) + class _(object): + # 'Item' is the 'default' value. Make it available by + # calling the instance (Not sure this makes sense, but + # win32com does this also). + def __call__(self, *args, **kw): + "Return 'self.Item(*args, **kw)'" + return self.Item(*args, **kw) + + # does this make sense? It seems that all standard typelibs I've + # seen so far that support .Item also support ._NewEnum + @patcher.no_replace + def __getitem__(self, index): + "Return 'self.Item(index)'" + # Handle tuples and all-slice + if isinstance(index, tuple): + args = index + elif index == _all_slice: + args = () + else: + args = (index,) + + try: + result = self.Item(*args) + except COMError as err: + (hresult, text, details) = err.args + if hresult == -2147352565: # DISP_E_BADINDEX + raise IndexError("invalid index") + else: # Unknown error + raise + + # Note that result may be NULL COM pointer. There is no way + # to interpret this properly, so it is returned as-is. + + # Hm, should we call __ctypes_from_outparam__ on the + # result? + return result + + @patcher.no_replace + def __setitem__(self, index, value): + "Attempt 'self.Item[index] = value'" + try: + self.Item[index] = value + except COMError as err: + (hresult, text, details) = err.args + if hresult == -2147352565: # DISP_E_BADINDEX + raise IndexError("invalid index") + else: # Unknown error + raise + except TypeError: + msg = "%r object does not support item assignment" + raise TypeError(msg % type(self)) + + def _patch_iterator(self): + @patcher.Patch(self) + class _(object): + def __iter__(self): + "Return an iterator over the _NewEnum collection." + # This method returns a pointer to _some_ _NewEnum interface. + # It relies on the fact that the code generator creates next() + # methods for them automatically. + # + # Better would maybe to return an object that + # implements the Python iterator protocol, and + # forwards the calls to the COM interface. + enum = self._NewEnum + if isinstance(enum, types.MethodType): + # _NewEnum should be a propget property, with dispid -4. + # Sometimes, however, it is a method. + enum = enum() + if hasattr(enum, "Next"): + return enum + # _NewEnum returns an IUnknown pointer, QueryInterface() it to + # IEnumVARIANT + from comtypes.automation import IEnumVARIANT + + return enum.QueryInterface(IEnumVARIANT)