【问题标题】:Getting last opened MS Word document object获取最后打开的 MS Word 文档对象
【发布时间】:2015-12-01 22:56:39
【问题描述】:

我有一个从 MS Word 2003 模板 (.dot) 中的 VBA AutoNew() 子调用的 python 脚本 - 所以每次从这个 Word 模板创建文档时它都会运行。

第三方应用程序使用此模板创建文档。第三方应用程序如何设置文档存在许多格式问题,因此我的脚本会在第三方脚本完成运行后对其进行调整。 (我最初用 VBA 编写脚本,但 VBA 计时器的问题导致它在很大一部分时间崩溃。python 版本完美无缺。)​​

我希望脚本只与调用它的文档一起工作,该文档将始终是最近打开的 Word 文件。 (文件是 .doc 而不是 .docx,如果这有什么不同的话。)我找到了三种方法来获取 Word 的打开实例(因为 AutoNew 调用了这个脚本,所以总会有一个可用的打开实例):

win32com.client.GetActiveObject (Class = 'Word.Application')
win32com.client.gencache.EnsureDispatch('Word.Application')
win32com.client.Dispatch('Word.Application')

如果新创建的文档是唯一打开的 Word 文件,这三个中的任何一个都可以很好地工作。但是如果一个 Word 文档已经打开,并且我运行第三方软件从这个模板创建一个新文档,python 脚本每次都会使用所有三种方法抓取旧实例。

我尝试寻找循环遍历 Word 文档的方法,我的想法是我可以检查所有名称并选择最后一个具有最高数字的名称(在脚本运行时文档不会被保存,所以它的名字将是 Document1、Document2 等。)不幸的是,我只找到了循环关闭文档的方法(打开一个,做某事,关闭它,继续下一个),而不是(在我的情况下)已经打开的.

有没有办法将 python 定向到最近打开的 Word 文档?

编辑相关问题:Word VBA and Multiple Word Instances

我找到了如何获取我要控制的文档的 Windows 句柄整数:

import win32gui
import re

#Create a list of all open Microsoft Word document titles and their
#handle integers
titles = []
def foreach_window(hwnd, lParam):
    if win32gui.IsWindowVisible(hwnd):
        title = win32gui.GetWindowText(hwnd)
        if 'Microsoft Word' in title:
            titles.append([title, hwnd])
    return True
win32gui.EnumWindows(foreach_window, None)

#Find the handle of the newest open, unsaved Word document
winOrder = []
for s in titles:
    item = re.search(r'Document\d', s[0])
    if item:
        winOrder.append(int(re.search(r'\d+', s[0]).group()))
    else:
        winOrder.append(0)
hwnd = titles[winOrder.index(max(winOrder))][1]

#Get the edit window from inside the Word instance
def callback(hwnd, hwnds):
    if win32gui.GetClassName(hwnd) == '_WwG':
        hwnds.append(hwnd)
        #I think there should be a 'return False' here to let EnumChildWindows
        #know it doesn't have to keep looping once it finds the edit window,
        #but it crashes with 'pywintypes.error: (0, 'EnumChildWindows', 
        #'No error message is available') if I try that
    return True
hwnds = []
win32gui.EnumChildWindows(whndl, callback, hwnds)

#Something like this...
#window = win32gui.AccessibleObjectFromWindow(hwnds[0])

那么现在 - 如何从 Windows 句柄创建 COM 对象?

【问题讨论】:

    标签: ms-word pywin32


    【解决方案1】:

    在 NVDA (Non-Visual Desktop Access) 的 GitHub 代码中进行了一番搜索,终于找到了我正在寻找的对象:

    #Part of the pywin32 package that must be installed with the pywin32
    #installer:
    import win32com.client as win32
    import win32gui
    
    from ctypes import oledll
    from ctypes import byref
    
    #installed by easy_install comtypes
    from comtypes import POINTER
    from comtypes.automation import IDispatch
    import comtypes.client.dynamic as comDy
    
    #Handle integer hwnds[0] per my edit in the question
    
    OBJID_NATIVEOM = -16
    p = POINTER(IDispatch)()
    oledll.oleacc.AccessibleObjectFromWindow(hwnds[0], OBJID_NATIVEOM,
        byref(IDispatch._iid_), byref(p))
    
    window = comDy.Dispatch(p)
    word = window.application
    cert = word.Documents(1)
    

    【讨论】:

    • 您的回答让我对AccessibleObjectFromWindow 大开眼界,我可以用VBA 解决它,即得到Office objects through VBA。非常感谢您的提问和回答。当然 Python 的方式要优雅得多。
    猜你喜欢
    • 2020-09-29
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多