2013-07-04 9 views
2

Я работаю с программой на C#, которая использует Microsoft Office Interop, позволяя вам по существу программным образом использовать Microsoft Word, Excel и PowerPoint.Microsoft Office Interop Timing Out

Один из неудачных аспектов, с которыми я столкнулся, заключается в том, что иногда программа поднимает диалоговое окно, которое приостанавливает код. Это может произойти, например, если вдруг код не сможет сохранить в выбранном вами месте, что означает, что вся ваша программа приостановлена, даже если эта проблема будет исправлена ​​позже.

Есть много других обстоятельств, при которых может быть поднято дополнительное диалоговое окно.

Так что я намерен реализовать какой-то механизм таймаута для этого, благодаря чему я могу убить экземпляр Interop, а не привязать всю свою программу. Может ли кто-нибудь предложить способ сделать это? На данный момент он обматывает вызовы Interop в System.Action и прерывает этот поток по истечении заданного времени, но мне интересно, есть ли лучший способ.

+2

Я делал такие вещи в прошлом. Единственное, что нужно сделать, это прочитать код VBA, который вы автоматизируете, и проверить его, чтобы вы знали, когда и где появляются диалоговые окна, и почему. Затем вы можете запрограммировать его. Поверьте мне, это облегчит вашу жизнь в долгосрочной перспективе! – JMK

+0

Кроме того, Office Interop не предназначен для использования без присмотра, идея заключается в том, что ваш конечный пользователь видит эти диалоговые окна и взаимодействует с ними соответствующим образом. Если вы хотите автоматическую автоматизацию Office, вы можете посмотреть OpenXML. – JMK

ответ

1

Вы можете сделать это, внедрив фильтр сообщений OLE. См. this answer для получения более подробной информации.

1

Многие люди не рекомендуют убивать процесс; См How to properly clean up Excel interop objects и Understanding Garbage Collection in .net

Вот код, я использую, чтобы убить экземпляр Excel, который я создал. Вам нужно будет немного реорганизовать его для удовлетворения ваших потребностей. Вы увидите, как получить идентификатор процесса, используя дескриптор окна, предоставленный Excel. Я предполагаю, что процесс будет таким же для Word или Powerpoint.

'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx 
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _ 
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _ 
    ByRef lpdwProcessId As Integer) As Integer 
End Function 

Sub Work() 

    'declare process; will be used later to attach the Excel process 
    Dim XLProc As Process 

    'start the application using late binding 
    Dim xlApp As Object = CreateObject("Excel.Application") 

    'or use early binding 
    'Dim xlApp As Microsoft.Office.Interop.Excel 

    'get the window handle 
    Dim xlHWND As Integer = xlApp.hwnd 

    'this will have the process ID after call to GetWindowThreadProcessId 
    Dim ProcIdXL As Integer = 0 

    'get the process ID 
    GetWindowThreadProcessId(xlHWND, ProcIdXL) 

    'get the process 
    XLProc = Process.GetProcessById(ProcIdXL) 


    'do some work with Excel here using xlApp 

    'be sure to save and close all workbooks when done 

    'release all objects used (except xlApp) using NAR(x) 


    'Quit Excel 
    xlApp.quit() 

    'Release 
    NAR(xlApp) 

    'Do garbage collection to release the COM pointers 
    'http://support.microsoft.com/kb/317109 
    GC.Collect() 
    GC.WaitForPendingFinalizers() 

    'I prefer to have two parachutes when dealing with the Excel process 
    'this is the last answer if garbage collection were to fail 
    If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then 
     XLProc.Kill() 
    End If 
End Sub 

Private Sub NAR(ByVal o As Object) 
    'http://support.microsoft.com/kb/317109 
    Try 
     While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0) 
     End While 
    Catch 
    Finally 
     o = Nothing 
    End Try 
End Sub 
Смежные вопросы