Приложения Office являются приложениями для конечных пользователей и не оптимизированы как инструменты разработки. Это означает, что они могут зависать при ожидании пользовательского ввода, как описано в вопросе. Не существует простого, чистого способа обойти это, поэтому использование формата файла Open XML рекомендуется для требований, когда закрытие диалоговых окон является проблемой ...
Если необходимо использовать автоматизацию, я знаю о двух возможностях. Подробная информация не Python, но это документирует основные подходы.
- Используйте функцию Timer и SendKeys для автоматического закрытия диалогового окна, если код не может быть запущен. Это немного лотерея, так как невозможно узнать, какое диалоговое окно закрывается. Обычно отправляется ключ «Escape». Когда-то был набор статей KB, нацеленных на разные языки программирования, но их больше нет на сайте Microsoft. Я нахожу архив C-Bit и копирую соответствующий пример контента, который демонстрирует принцип для классического VB6:
Шаги в этом разделе демонстрируют автоматизацию Microsoft Word для
распечатать документ. Клиент автоматизации вызывает метод PrintOut для
объект Word Document. Если принтер пользователя по умолчанию настроен
для печати на порт FILE, затем вызов PrintOut производит диалог
окно, предлагающее пользователю ввести имя файла. Чтобы определить, если
Метод PrintOut вызывает это диалоговое окно, Visual Basic
Клиент автоматизации использует элемент управления Timer для определения времени простоя после
вызов метода PrintOut. До вызова PrintOut таймер
включается и запускается через пять секунд. Когда PrintOut завершается,
Таймер отключен. Поэтому, если метод PrintOut завершается в течение
пять секунд, событие Таймер никогда не происходит, и никаких дальнейших действий
приняты. Документ распечатан и выполнение кода продолжается
метод PrintOut. Однако если событие Timer происходит в пределах
с интервалом в пять секунд предполагается, что метод PrintOut не имеет
завершена и что задержка вызвана диалоговым окном, ожидающим
пользовательский ввод. Когда происходит событие Timer, клиент Automation дает
сосредоточиться на Word и использует SendKeys, чтобы закрыть диалоговое окно.
Примечание. В демонстрационных целях в этом примере используется метод PrintOut.
таким образом, что он отображает диалоговое окно намеренно, когда он
печатает на принтере, настроенном на порт FILE. Обратите внимание, что PrintOut
Метод имеет два аргумента, OutputfileName и PrintToFile, которые вы можете
обеспечить, чтобы избежать этого диалогового окна.
Кроме того, при использовании этого подхода «таймера» вы можете настроить
время ожидания должно быть больше или меньше пяти секунд, а также
настроить нажатия клавиш в диалоговом окне.
Эта демонстрация состоит из двух проектов Visual Basic:
ActiveX EXE, который предоставляет класс Timer, используемый для обнаружения задержки. Причина использования ActiveX EXE для класса Timer заключается в запуске кода Timer в отдельном процессе и, следовательно, в отдельном потоке.
Это позволяет классу Timer вызывать событие во время
приостановлена автоматизация вызова.
Стандартный EXE-файл, который использует автоматизацию для Word и вызывает метод PrintOut для печати документа. Он использует ActiveX EXE для обнаружения задержки
при вызове метода PrintOut. Создать проект ActiveX EXE
- Запустите Visual Basic и создайте проект ActiveX EXE. Class1 создан по умолчанию.
- В меню «Проект» щелкните, чтобы выбрать «Свойства», а затем измените имя проекта на «MyTimer».
- Скопируйте и вставьте следующий код в модуль Class1: Option Explicit
Public Event Timer() Private oForm1 As Form1
Private Sub Class_Initialize()
Set oForm1 = New Form1
oForm1.Timer1.Enabled = False
End Sub
Private Sub Class_Terminate()
Me.Enabled = False
Unload oForm1
Set oForm1 = Nothing
End Sub
Public Property Get Enabled() As Boolean
Enabled = oForm1.Timer1.Enabled
End Property
Public Property Let Enabled(ByVal vNewValue As Boolean)
oForm1.Timer1.Enabled = vNewValue
If vNewValue = True Then
Set oForm1.oClass1 = Me
Else
Set oForm1.oClass1 = Nothing
End If
End Property
Public Property Get Interval() As Integer
Interval = oForm1.Timer1.Interval
End Property
Public Property Let Interval(ByVal vNewValue As Integer)
oForm1.Timer1.Interval = vNewValue End Property
Friend Sub TimerEvent()
RaiseEvent Timer
End Sub
- В меню «Проект» выберите «Добавить форму», чтобы добавить новую форму в проект.
- Добавить элемент управления Timer в форму.
- Скопируйте и вставьте следующий код в модуль кода для Form1: Option Explicit
Public oClass1 As Class1
Private Sub Timer1_Timer()
oClass1.TimerEvent
End Sub
- Сохраните этот проект в новой подпапке с именем Server.
- В меню Файл выберите Создать MyTimer.Exe, чтобы создать и зарегистрировать компонент. Создайте клиент автоматизации
- Работа с Windows API для выявления и закрытия возможных проблемных диалоговых окон. Я нашел код для этого на форуме MSDN , который я копирую здесь. Присвоение имени пользователя
yet
:
Вот пример, который использует Win32 API через pinvoke в C #. я
возможность распоряжаться известными окнами Word, такими как Word-> File-> диалог настроек
окно через FindWindow и SendMessage или PostMessage. Пожалуйста иди
через образец и посмотрите, будет ли он работать для вас. С вами
знать, какие диалоговые окна вы хотите удалить, используйте spy ++ для
найдите заголовок окна и класс окна и используйте его в этом примере.
Для вашего сценария SendKeys могут не понадобиться.
Надеюсь, это поможет.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SendKeys
{
public partial class Form1 : Form
{
// For Windows Mobile, replace user32.dll with coredll.dll
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
static uint WM_CLOSE = 0x10;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// the caption and the className is for the Word -> File -> Options window
// the caption and the className are got by using spy++ application and focussing on the window we are researching.
string caption = "Word Options";
string className = "NUIDialog";
IntPtr hWnd= (IntPtr)(0);
// Win 32 API being called through PInvoke
hWnd = FindWindow(className, caption);
/*bool retVal = false;
if ((int)hWnd != 0)
{
// Win 32 API being called through PInvoke
retVal = SetForegroundWindow(hWnd);
}*/
if ((int)hWnd != 0)
{
CloseWindow2(hWnd);
//CloseWindow(hWnd); // either sendMessage or PostMessage can be used.
}
}
static bool CloseWindow(IntPtr hWnd)
{
// Win 32 API being called through PInvoke
SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return true;
}
static bool CloseWindow2(IntPtr hWnd)
{
// Win 32 API being called through PInvoke
PostMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return true;
}
}
}