Office Interop Does Not Work in Windows Service

最后都变了- 提交于 2019-11-29 09:53:19

问题


I have a very weird issue with Microsoft Office.

I have a common library whose sole purpose is to open whatever word document file type is passed to it (by a full file path...) and save that opened word document as a pdf file.

The weird issue is that if I consume that library from a windows service, whenever it attempts to open the word document, I get a null... aka, the word document never got opened.

If however I consume the library from a WPF or Windows Form application I never have any issues. I am aware that there are issues with threading, (Single Thread Appartment) however I have no idea how to fix it to work out of the windows service. :( :( :(

I would appreciate any help! The Error I get Is the following:

Exception Message: {"Object reference not set to an instance of an object."} (Referring to the word document). Inner Exception: Null; HResult: -2147467261. Data: ListDictionaryInternal with 0 entries; Stack Trace: at DocumentConverter.ToPdf(String currentWorkingFolderPath, String pathToDocumentToConvert) in c:\Project Files...\DocumentConverter.cs:line 209

So here is the library function. It requires the Microsoft Office reference, which is created by the Visual Studio Tools for Office.

private string ToPDF(string currentWorkingFolderPath, string pathToDocumentToConvert)
{
    string temporaryPdfFolderPath = Path.GetFullPath(currentWorkingFolderPath + "\\pdf\\");
    string temporaryPdfFilePath = Path.GetFullPath(temporaryPdfFolderPath + "\\pdffile.pdf");

    if (!FileSystem.CreateDirectory(temporaryPdfFolderPath))
    {
        return null;
    }

    try
    {
        Microsoft.Office.Interop.Word.Application wordApplication = new Microsoft.Office.Interop.Word.Application();

        object objectMissing = System.Reflection.Missing.Value;

        wordApplication.Visible = false;
        wordApplication.ScreenUpdating = false;

        FileInfo wordFile = new FileInfo(pathToDocumentToConvert);

        Object fileName = (Object)wordFile.FullName;

        // This is where it breaks when called from windows service. Use the dummy value as a placeholder for optional arguments
        Document wordDocument = wordApplication.Documents.Open(ref fileName, ref objectMissing,            
            true, ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing,            
            ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing,            
            ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing);



        object outputFileName = (object)temporaryPdfFilePath;
        object fileFormat = WdSaveFormat.wdFormatPDF ;

        // Save document into PDF Format
        wordDocument.SaveAs(ref outputFileName,
            ref fileFormat, ref objectMissing, ref objectMissing,
            ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing,
            ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing,
            ref objectMissing, ref objectMissing, ref objectMissing, ref objectMissing);

        // Close the Word document, but leave the Word application open.
        // doc has to be cast to type _Document so that it will find the
        // correct Close method.                
        object saveChanges = WdSaveOptions.wdDoNotSaveChanges;
        ((_Document)wordDocument).Close(ref saveChanges, ref objectMissing, ref objectMissing);

        wordDocument = null;

        // word has to be cast to type _Application so that it will find
        // the correct Quit method.
        ((Microsoft.Office.Interop.Word._Application)wordApplication).Quit(ref objectMissing, ref objectMissing, ref objectMissing);

        wordApplication = null;

    }
    catch (Exception ex)
    {
        //logging code
        return null;
    }

    return temporaryPdfFilePath;
}

回答1:


Per @Sameer S in his post: Is Office 2003 interop supported on Windows server 2008 ..?

Officially Microsoft Office 2003 Interop is not supported on Windows server 2008 by Microsoft.

But after a lot of permutations & combinations with the code and search, we came across one solution which works for our scenario.

The solution is to plug the difference between the way Windows 2003 and 2008 maintains its folder structure, because Office Interop depends on the desktop folder for file open/save intermediately. The 2003 system houses the desktop folder under systemprofile which is absent in 2008.

So when we create this folder on 2008 under the respective hierarchy as indicated below; the office Interop is able to save the file as required. This Desktop folder is required to be created under

C:\Windows\System32\config\systemprofile

AND

C:\Windows\SysWOW64\config\systemprofile

Thanks Guys..!




回答2:


Once these folders have been created:

C:\Windows\System32\config\systemprofile\Desktop C:\Windows\SysWOW64\config\systemprofile\Desktop

Make sure the schedule task is running with a profile having access to these folders.




回答3:


Office Interop is not supported by MS in server-like scenarios (like ASP.NET or Windows Service or similar) - see http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757#kb2 !

You will need to use some library to achieve what you want:

  • MS provides the OpenXML SDK V 2.0 (free)
  • Aspose.Words (commercial)



回答4:


Is your windows service have the 'run in interactive mode' option enabled? It may be failing because Word is attempting to display a UI, which for reasons which seem obvious, it cannot do.

Another possibility (and a pretty common problem people have) is that your Windows Service is running under an account that doesn't have permissions to access the file/folder you're attempting to pass to it. A WPF/Winforms program by contrast runs under the user's credentials.

If that is not the problem, are there any errors being thrown? Check the Windows Event Log and/or add some logging to see if there are some errors being silently thrown.

EDIT: I glanced through the MSDN documention (for Word Interop) and it doesn't appear that using VSTO is required. Can you attempt to do this using pure word interop and see if it works? This post has an example




回答5:


My ASP.net 2.0 office automation application work well in Windows 2008 Server 64 bits after follow the instruction from the link below. Hope it could help everyone.

http://emalvass.blogspot.com/2010/01/how-to-use-office-2007-automation-in.html

My sample program as below:

Imports Microsoft.Office.Interop.Word


Dim Result As Boolean = False

    Dim appWord As New Microsoft.Office.Interop.Word.Application
    Dim wordDocument As Microsoft.Office.Interop.Word.Document

    Try
        Dim oFile As New FileInfo(sPDFFile), sFilePath As String, sFileName As String, sFileNameArr() As String
        Dim sActualFileName As String

        sFileName = oFile.Name
        sFileNameArr = sFileName.Split(".")
        sActualFileName = sFileNameArr(0)
        sFilePath = oFile.DirectoryName & "\" & sActualFileName & ".pdf"

        wordDocument = appWord.Documents.Open(sPDFFile)

        wordDocument.ExportAsFixedFormat(sFilePath, WdExportFormat.wdExportFormatPDF)
        'wordDocument.ExportAsFixedFormat(sFilePath, 17)

        Result = True
        oFile = Nothing

    Catch ex As COMException
        sErrMsg = ex.InnerException.ToString
        Result = False
    Finally
        wordDocument.Close()
        wordDocument = Nothing
        appWord.Application.Quit()
        appWord = Nothing



    End Try


    Return Result


来源:https://stackoverflow.com/questions/13479164/office-interop-does-not-work-in-windows-service

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!