Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如果对话框打开或excel正在等待用户,则win32com中的被调用方拒绝调用_Python_Excel_Win32com - Fatal编程技术网

Python 如果对话框打开或excel正在等待用户,则win32com中的被调用方拒绝调用

Python 如果对话框打开或excel正在等待用户,则win32com中的被调用方拒绝调用,python,excel,win32com,Python,Excel,Win32com,我需要确定Excel是否准备好接受Python中win32com的COM对象。例如,如果在excel中打开了一个对话框,则对win32com函数的任何调用都将导致“被调用方拒绝调用”错误 通过反复试验,我发现如果Excel(实际上我假设任何Office产品)打开了一个对话框,那么对win32com的任何调用都会导致错误 在谷歌搜索了相当长一段时间后,我发现了很多问题,关于什么是自作自受的对话框被打开。i、 e.执行Excel.SaveAs()操作将在工作表上打开一个对话框,直到用户关闭该对话框,

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

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

在谷歌搜索了相当长一段时间后,我发现了很多问题,关于什么是自作自受的对话框被打开。i、 e.执行Excel.SaveAs()操作将在工作表上打开一个对话框,直到用户关闭该对话框,您才会被卡住

在我的例子中,有一个用户打开了一个对话框,或者以其他方式与Excel交互,并让它等待输入。开始在公式栏上输入公式这样简单的操作将导致win32com函数返回错误

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


我知道我可以做一个try: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.
导入win32com.client
从pywintypes导入com_错误
导入时间
导入日志记录
_延迟=0.05秒
_超时=60.0秒
定义com调用包装器(f、*args、**kwargs):
"""
COMWrapper支持函数。
在“呼叫被被叫方拒绝”时重复呼叫。发生异常。
"""
#展开输入
args=[arg.\u包装的\u对象如果是instance(arg,ComWrapper),则为args中的arg添加else arg]
kwargs=dict([(键、值和对象)
如果isinstance(值,ComWrapper)
else(键、值)
对于键,dict中的值(kwargs.items())
开始时间=无
尽管如此:
尝试:
结果=f(*args,**kwargs)
除了com_错误,如e:
如果e.strerror==“被调用方拒绝了调用”:
如果开始时间为无:
开始时间=time.time()
logging.warning('被调用方拒绝了调用')
elif time.time()-开始时间>=\u超时:
提升
时间。睡眠(延迟)
持续
提升
打破
如果isinstance(结果,win32com.client.CDispatch)或callable(结果):
返回ComWrapper(结果)
返回结果
类ComWrapper(对象):
"""
类包装COM对象,以便在“调用被被叫方拒绝”时重复调用。发生异常。
"""
def uuu init uuuu(自包装对象):
断言isinstance(wrapped_对象,win32com.client.CDispatch)或callable(wrapped_对象)
self.\uuuu dict\uuuuu['''u wrapped\u object']=wrapped\u object
def _uGetAttr _;(自身,项目):
return\u com\u call\u wrapper(self.\u wrapped\u object.\u\u getattr\u,item)
定义获取项目(自身,项目):
return\u com\u call\u wrapper(self.\u wrapped\u object.\u\u getitem\u,item)
定义设置属性(自身、键、值):
_com_调用_包装器(self._包装的_对象._setattr__,键,值)
定义设置项(自身、键、值):
_com_调用_包装器(self._包装的_对象._设置项_uuuuuuuuuuuuuuuu,键,值)
定义调用(self,*args,**kwargs):
return\u com\u call\u wrapper(self.\u wrapped\u object.\u\u call\u、*args、**kwargs)
定义报告(自我):
返回“ComWrapper”。格式(repr(self.\u wrapped\u对象))
_xl=win32com.client.dynamic.Dispatch('Excel.Application')
xl=ComWrapper(_xl)
#使用xl而不是xl进行填充,将尝试调用,直到超时结束
#如果“被调用者拒绝了调用”,则达到-引发异常。

你好!虽然这段代码可以回答这个问题,但提供关于如何和/或为什么解决问题的附加上下文将提高答案的长期价值。@Valentino I在代码之前添加了一些上下文。我希望有帮助!试图使用你的代码。获取错误:AttributeError:“”对象在调用:self.xlApp.Workbooks.Add()时没有属性“Add”,其中:self.\u xl=win32com.client.gencache.EnsureDispatch('Excel.Application')self.xlApp=ComWrapper(self.\u xl),因此用户可以在任何Excel工作表上打开对话框,您也会遇到同样的问题。也就是说,如果用户正在使用另一个Excel实例,则不相关工作表上打开的对话框可能会导致相同的问题。