gpt4 book ai didi

python - 如果对话框打开或 Excel 正在等待用户,则 win32com 中的被调用者拒绝调用

转载 作者:行者123 更新时间:2023-12-02 13:21:46 27 4
gpt4 key购买 nike

我需要确定 Excel 是否准备好接受来自 Python 中 win32com 的 COM 对象。例如,如果在 Excel 中打开一个对话框,则对 win32com 函数的任何调用都将导致“调用被被调用者拒绝”错误。

通过反复试验,我发现如果 Excel(实际上我假设任何 Office 产品)打开了一个对话框,则任何对 win32com 的调用都会导致错误。

经过相当多的谷歌搜索后,我发现了很多关于打开自残对话框的问题。即,执行 Excel.SaveAs() 将在工作表上打开一个对话框,并且您会被卡住,直到用户关闭它。

就我而言,我有一个用户打开了一个对话框或以其他方式与 Excel 进行了交互,并让其等待输入。像在公式栏上输入公式这样简单的事情都会导致 win32com 函数返回错误。

有几个问题:有没有办法确定 Excel 是否准备好执行命令?有没有办法告诉哪个盒子打开了(excel在等什么?)有没有办法通过 win32com 关闭该框...请记住,据我所知,我对 win32com 所做的任何操作都会在处于这种状态时返回错误

我知道我可以尝试:catch:但我需要围绕每个 win32com 函数(此时有很多)。我认为这种方法会使代码不必要地冗长和复杂。

最佳答案

我一直在努力解决同样的问题,但现在我已经找到了一个迄今为止对我有用的解决方案。

我创建了一个类 ComWrapper,我将 Excel COM 对象包装在其中。它会自动包装 ComWrapper 中的每个嵌套对象和调用,并在它们用作函数调用的参数或包装对象的赋值时解开它们。包装器的工作原理是捕获“调用被被调用者拒绝”异常并重试调用,直到达到顶部定义的超时。如果达到超时,异常最终会被抛出到包装对象之外。

对包装对象的函数调用由函数 _com_call_wrapper 自动包装,这就是神奇发生的地方。

要使其正常工作,只需使用 ComWrapper 包装来自 Dispatch 的 com 对象,然后照常使用它,就像代码底部一样。有问题请评论。

import win32com.client
from pywintypes import com_error
import time
import logging

_DELAY = 0.05 # seconds
_TIMEOUT = 60.0 # seconds


def _com_call_wrapper(f, *args, **kwargs):
"""
COMWrapper support function.
Repeats calls when 'Call was rejected by callee.' exception occurs.
"""
# Unwrap inputs
args = [arg._wrapped_object if isinstance(arg, ComWrapper) else arg for arg in args]
kwargs = dict([(key, value._wrapped_object)
if isinstance(value, ComWrapper)
else (key, value)
for key, value in dict(kwargs).items()])

start_time = None
while True:
try:
result = f(*args, **kwargs)
except com_error as e:
if e.strerror == 'Call was rejected by callee.':
if start_time is None:
start_time = time.time()
logging.warning('Call was rejected by callee.')

elif time.time() - start_time >= _TIMEOUT:
raise

time.sleep(_DELAY)
continue

raise

break

if isinstance(result, win32com.client.CDispatch) or callable(result):
return ComWrapper(result)
return result


class ComWrapper(object):
"""
Class to wrap COM objects to repeat calls when 'Call was rejected by callee.' exception occurs.
"""

def __init__(self, wrapped_object):
assert isinstance(wrapped_object, win32com.client.CDispatch) or callable(wrapped_object)
self.__dict__['_wrapped_object'] = wrapped_object

def __getattr__(self, item):
return _com_call_wrapper(self._wrapped_object.__getattr__, item)

def __getitem__(self, item):
return _com_call_wrapper(self._wrapped_object.__getitem__, item)

def __setattr__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setattr__, key, value)

def __setitem__(self, key, value):
_com_call_wrapper(self._wrapped_object.__setitem__, key, value)

def __call__(self, *args, **kwargs):
return _com_call_wrapper(self._wrapped_object.__call__, *args, **kwargs)

def __repr__(self):
return 'ComWrapper<{}>'.format(repr(self._wrapped_object))


_xl = win32com.client.dynamic.Dispatch('Excel.Application')
xl = ComWrapper(_xl)

# Do stuff with xl instead of _xl, and calls will be attempted until the timeout is
# reached if "Call was rejected by callee."-exceptions are thrown.

关于python - 如果对话框打开或 Excel 正在等待用户,则 win32com 中的被调用者拒绝调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54449520/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com