简体   繁体   中英

Remoting Automation of MS Office on the server

I'm warning you, that yhis question will seems to be very strange for a lot of people:) But I have to post it because my project manager is teeling me that a technical solution exist, even if for me it doesn't.

What we have:

  • A Windows 7 Console Application with no UI, with our C# application running and no Office and Interop on it
  • a Windows 2012 server, with Ms Office 2010 + Interop installed on it (also with IIS and .NET of course)

What my PM want (and I told him it is not possible) :

  • From my C# client application
  • Automate "Ms office" installed on the server
  • Automate means "Save" or "print" a doc file to a network printer.
  • Of course the Ms office process had to run on the server

This kind of solution of "remote Ms Office automation is possible" seems to be impossible for me. But maybe I am wrong, it can be possiblbe using DCOM, WCF, or something else?

Anyone can confirm I am right please ;)

As you already learned from the comments, automating the desktop version of any of the Office applications is bad for several reasons. The details can be found in the Knowledge base article KB257757 Considerations for server-side Automation of Office . The main take away from that article is:

Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.

But as you are still insisting, consider the following example as a very simple, naive, not to be used near production proof-of-concept that enables you to quickly run into all problems mentioned in the KB article.

In a fresh solution create a WCF Service application and a Console Application. In the WCF application add the following interface:

[ServiceContract]
public interface IPrintService
{
    [OperationContract]
    string Print(Stream wordDoc);
}

and have a service implement that. Make sure to add a reference to Microsoft.Office.Interop.Word that you can find in the COM tab of the Add Reference dialog.

public class PrintService : IPrintService
{
    public string Print(Stream wordDocStream)
    {
        // copy our stream to a local file
        var tempFile = Path.GetTempFileName();
        using(var file = File.Create(tempFile))
        {
            wordDocStream.CopyTo(file);
        }

        // start word
        var wordApp = new Microsoft.Office.Interop.Word.Application();
        // setup printer
        wordApp.ActivePrinter = "Canon LBP3010/LBP3018/LBP3050";
        // open, collect data, print and close
        var doc = wordApp.Documents.Open(tempFile);
        doc.PrintOut();
        var res = doc.Words.Count;
        doc.Close(false);

        // quit word
        wordApp.Quit(false);
        // delete temp file
        File.Delete(tempFile);
        return String.Format("{0} words", res);
    }
}

You can see here a barebone solution to print a document that is sent as a stream to the Service. The service copies the stream to a file, starts Word, Opens the file, prints the document, get some data from the document and tears down and cleans up hen finished.

The client is straight forward:

using(var client = new PrintService.PrintServiceClient())
{
    using(var file = File.Open(@"small.docx", FileMode.Open))
    {
        var response = client.Print(file);
        Console.WriteLine(response);
    }
}

This is technically all there is that is needed to print a Word document from a service. This runs without much problems on the dev server. If you run this on IIS you'll probably have to make sure that the account used as an identity in the AppPool is a "user" that can start Word, is allowed to access the printers etc. I already ran into one known issue: I used the XPS Print driver which caused a dialog to popup. That is something you can't have on a server and there is no real way to prevent or detect that.

Remember that this service interface only allows for a stream to be sent. If you want to add extra data you'll have to use a message contract as is explained on msdn in Large Data and Streaming . Your contract would have to look like this in that case:

[MessageContract]
public class UploadStreamMessage
{
   [MessageHeader]
   public string appRef;
   [MessageBodyMember]
   public Stream data;
} 

If you run all this, (stress)test, consider deployment and install I'm sure you'll convince anyone that this isn't a good idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM