none
Issue with word document now showing in the taskbar when opening the word document from an application that is running as a service. Because of this process's MainWindowHandle is always 0

    Question

  • I am using Microsoft.Office.Interop to open the word document. While creating word application, its visible property is set to true. Once document is opened, it updates some properties and then save and close. When running this code from a windows application, I can see a word document visible on the taskbar. However when the application is run as a windows service, the word application is not visible on the taskbar. Debugging, Application.Visible is always false even when it is set to true when running as a service.

    Code snippet of what I am using...

    Dim wordApp As Microsoft.Office.Interop.Word.Application
            Dim wordDoc As Microsoft.Office.Interop.Word.Document
            Dim m_objMissing As Object = Type.Missing
            Dim m_objTrue As Object = True
            Dim m_objFalse As Object = False
            Dim m_objPassword As Object = "Password"
    
            wordApp = New Microsoft.Office.Interop.Word.Application
            wordApp.Visible = True
            wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone
            wordDoc = wordApp.Documents.Open(CObj(Sourcedocument), m_objFalse, m_objFalse, m_objFalse, m_objPassword, m_objMissing, m_objMissing, m_objMissing, m_objMissing, m_objMissing, m_objMissing, m_objMissing, m_objFalse, m_objMissing, m_objMissing)
    
            'DO SOME STUFF HERE
    
            wordDoc.Saved = False
            wordDoc.Save()
            wordDoc.Saved = True
            CType(wordDoc, Microsoft.Office.Interop.Word._Document).Close()
            wordDoc = Nothing
            If Not wordApp Is Nothing Then
                CType(wordApp, Microsoft.Office.Interop.Word._Application).Quit()
                wordApp = Nothing
            End If

    Occassionally, if a word document is not closed within a specific time, we need to close the document. For this, I am using the following code which needs the MainWindowHandle of the word process. It works fine when the application is run as a desktop application. However if the application is run as a service, it doesn't work. Reason being when running as a service, application is not visible and hence MainWindowHandle is 0 for this.

    code snippet for closing the particular document

       
    Public Sub CloseSpecificDocument(ByVal documentFullPath As String)
            Dim wdPcs As Process()
            Dim hWnd As Integer = 0
            wdPcs = Process.GetProcessesByName("WinWord")
            If wdPcs.Length > 0 Then
                    For Each pcs As Process In wdPcs
                    hWnd = pcs.MainWindowHandle
                    If hWnd <> 0 Then
                        Dim hwndChild As Integer = 0
                        Dim cb As New EnumChildCallback(AddressOf EnumChildProc)
                        EnumChildWindows(hWnd, cb, hwndChild)
                        If hwndChild <> 0 Then
                            Const OBJID_NATIVEOM As Integer = &HFFFFFFF0
                            Dim IID_IDispatch As New Guid("{00020400-0000-0000-C000-000000000046}")
                            Dim ptr As Microsoft.Office.Interop.Word.Window
                            Dim hr As Integer = AccessibleObjectFromWindow(hwndChild, OBJID_NATIVEOM, IID_IDispatch, ptr)
                            If hr >= 0 Then
                                Dim myOpenedDocuments As Word.Documents = ptr.Application.Documents
                                For Each myDoc As Word.Document In myOpenedDocuments
                                    If myDoc.FullName = documentFullPath Then
                                        myDoc.Close(Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges, Type.Missing, Type.Missing)
                                        Exit For
                                    End If
                                Next
                            End If
                        End If
                    End If
                Next
            End If
        End Sub
    
    Public Delegate Function EnumChildCallback(ByVal hwnd As Integer, ByRef lParam As Integer) As Boolean
        Private Declare Auto Function EnumChildWindows Lib "user32" (ByVal hWndParent As Integer, ByVal lpEnumFunc As EnumChildCallback, ByRef lParam As Integer) As Boolean
        Private Declare Function AccessibleObjectFromWindow Lib "oleacc" (ByVal Hwnd As Int32, ByVal dwId As Int32, ByRef riid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef ppvObject As Object) As Int32
        <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
        Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer)
    
        End Sub
        Public Function EnumChildProc(ByVal hwndChild As Integer, ByRef lParam As Integer) As Boolean
            Dim buf As New StringBuilder(128)
            GetClassName(hwndChild, buf, 128)
            If buf.ToString() = "_WwG" Then
                lParam = hwndChild
                Return False
            End If
            Return True
        End Function



    Any help on how I can fix this. (Either making application visible even when running as a service or any other way to get the specific document from the list of running word applications and close it gracefully)

    Please help.



     


    Monday, October 21, 2013 3:05 PM

All replies

  • THe Office applications were not designed to run as services or in a server environment.

    If you need to process Word documents in this manner you should consider changing your approach to leverage the Office Open XML file format. This would mean you don't run the Word application at all; it would not need to be installed on the machines performing the tasks; you would not require licenses. The files can be accessed and opened directly without using the Word application.

    For more information, your starting point would be OpenXMLDeveloper.org

    Beyond that, I'd recommend that your over-all application have a class level member for the Word.Application that you instantiate only once. Test whether the member Is Nothing to determine whether an instance of Word already exists and is running.

    Through that instance, you should be able to access the Application.Documents in order to close any specific document.


    Cindy Meister, VSTO/Word MVP, my blog

    Tuesday, October 22, 2013 6:41 AM
  • Thanks Cindy for the reply.

    Basically when it is timed out, I want to close the word application itself so that other documents in queue can be processed. In order to do that, as you have suggested, I was doing following in my close method to close the application itself.

      If Not wordApp Is Nothing Then
         wordApp.Quit()
         wordApp = Nothing
      End If

    It works fine most of the time and closes the word application that was opened to process this document.

    However if any dialog has opened on word document, it doesn't quit the application.

    Since there is no user to response to this dialog, it just hangs over there. I understand that office is not designed to work unattended, but that is the design approach the application is based on.

    Would you be able to suggest some sort of solution to close the word application in any scenario. Forcefully close the application ignoring any pop up dialog opened or so. Or if possible, kill the winword process associated with this application.

    Please help.


    • Edited by savy17 Tuesday, October 22, 2013 3:07 PM updated
    Tuesday, October 22, 2013 3:02 PM