Word Automation Deployment
It’s always tricky to get applications that you’ve written and built on your own PC to run on the target environment. One of the big reasons is that during development any problem that you encounter you overcome, but that doesn’t mean the target solution will have the same environment, the same tools installed or have some kind of resource contention you weren’t planning for.
My attempt to deploy a Word Automation Service that I built was no different. The first thing that I noticed when I went to the target box was that I didn’t have any applications competing for using Word. Since I was replacing an application that had many different consumers of Word– and I was only replacing one of them– I noticed that another application was opening and closing Word while I was trying to use it.
Semaphores
In Computer Science class in college there was the illustration of two trains that had to share one track that went through a tunnel. My current job has an even more pertinent analogy. We have three keys to the restroom. If all the keys are gone, you’re going to have to hold it!
In any case, my solution was to implement a text file semaphore. I have each of the two applications check the file before proceeding to execute. After they’ve completed executing, they leave a message in the file for the other person to use Word. If the file doesn’t exist, the new service creates the file and gives the old routine control.
It’s clunky, and hopefully the need for semaphores will go away, but for now, it gets around a sticky problem.
Word Versions
The next problem I ran into was that I was running Word 2007 locally and the deployment box is using Word 2003. I didn’t think it’d be a problem, but with the debugging flag on1 I noticed that I was getting the error “Attempted to read or write protected memory. This is often an indication that other memory is corrupt.†when the system tried to use Document.Open to open the document.
What I eventually found, after a lot of internet searching, was the following code:
Microsoft.Office.Interop.Word.Application WordApp = null; Microsoft.Office.Interop.Word.Document WordDoc = null; try { WordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); //("Word instantiated, version is: " + WordApp.Version); } catch (Exception e) { //("Error instantiating Word instance: " + e.Message); } WordApp.DisplayAlerts = Microsoft.Office.Interop.Word.WdAlertLevel.wdAlertsNone; try { WordDoc = WordApp.Documents.Open(ref strFile, ref objFalse, ref objTrue, ref objFalse, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing); //("Word document opened correctly."); } catch { //("Error opening Word document in compiled version - trying office 2000."); try { WordDoc = WordApp.Documents.Open2000(ref strFile, ref objFalse, ref objTrue, ref objFalse, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing); //("Word document opened correctly using office 2000."); } catch { //("Error opening Word document in office 2000 - trying compatibility mode."); try { WordDoc = WordApp.Documents.OpenOld(ref strFile, ref objFalse, ref objTrue, ref objFalse, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing, ref objMissing); //("Word document opened correctly using compatibility mode."); } catch (Exception e) { WordDoc = null; //("Error unable to open Word document in any mode: " + e.Message); } } }
Which I found at this site that was dealing with a Problem with Word Automation. This code tries to open the file using both the latest Open command as well as the others, and this one worked great.
The only thing after this was making sure that I produced output like Customer Support wanted it, but now it’s running fine!
- I’m using the Event Viewer to track what’s going on in the service and I have different levels of logging that you can enable with a configuration file. The idea is that if I’m troubleshooting, I can be pretty specific about what is going on. If I’m running normally, I can just show errors if I want to. [↩]