views:

208

answers:

5

Hi

I have a windows service written in c# which reads the text from word documents (doc and docx) using VBA interop. However on certain documents it seems to hang on the call to the Open method. It seems that the problem documents all have macros in them. The locally installed version of word has macros disabled and the code I use to open the document is as follows:

using Word = Microsoft.Office.Interop.Word;
using OfficeCore = Microsoft.Office.Core;

Word.Application m_wordApp = new Word.ApplicationClass();
Word.Document m_wordDoc = null;

object TRUE_VALUE = true;
object FALSE_VALUE = false;
object MISSING_VALUE = System.Reflection.Missing.Value;

m_wordApp.DisplayAlerts = Microsoft.Office.Interop.Word.WdAlertLevel.wdAlertsNone; //will still fail with this line removed
m_wordApp.Visible = false; //will still fail with this line removed
m_wordApp.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable; //will still fail with this line removed
m_wordDoc = m_wordApp.Documents.Open(ref fileNameObject, ref FALSE_VALUE, ref TRUE_VALUE, ref FALSE_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref FALSE_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE);

I can process these documents manually on my dev machine. Does anyone know why this is happening or have any further questions about my question?

Thanks

K

+2  A: 

Microsoft.Office.Interop.Word uses a COM wrapper to remotely control the actual Word executable. It is absolutely horible. The setting to disable macros in the copy of Word it is using is almost certainly a user specific setting and the Windows service will be running Word as whatever user account the service is running under. The chances are it is essentially popping up some kind of macro security dialog in some theoretical netherworld that is the Windows service users desktop/ui.

Ben Robinson
I found the registry key that corresponds to the "disable all macros without notification" option in the Word trust centre and set that for the user the service runs as but this is not correct the situation
Keith K
+2  A: 

There are recommendations against server-side automation by Microsoft, but there are also plenty of resources to help you if that's what you're still going to do. These two articles should give you sufficient background into what to account for:

However, if it is as simple as your documents are hanging because of any AutoMacros, like AutoOpen, inside the VBA code behind, you'll need to use WordBasic to disable these. I could never get this to work in C#, but I did in VB.NET. See How to open document that contains AutoOpen macro with PowerShell?

A final option would be to consider a tool that is built for server-side Office automation, like Apose.Words.

Otaku
+1  A: 

Word will prompt the user when there's a minor problem with the document. That prompt will be displayed on the desktop for services in your case, where nobody can hear it scream. And preventing the Open() method call from completing.

Be sure to set the OpenAndRepair argument of the Open() method to True so this is dealt with automatically without prompting the user.

Hans Passant
I set the open and repair arguement to be TRUE_VALUE and still got the error. The call to open now looks like m_wordApp.Documents.Open(ref fileNameObject, ref FALSE_VALUE, ref TRUE_VALUE, ref FALSE_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref FALSE_VALUE, ref TRUE_VALUE, ref MISSING_VALUE, ref TRUE_VALUE, ref MISSING_VALUE)
Keith K
You got an error? That's good, what's the error?
Hans Passant
Yes, sorry made the cardinal error when posting about an error and didn't post it, d'uh! I don't have it any more but when I get some time I to try processing all the problem documents I'm sure I'll get it again.
Keith K
+1  A: 

I've hopefully finally found all the issues relating to this and have ended up with the following line to open the doc:

m_wordApp.Documents.Open(ref fileNameObject, ref FALSE_VALUE, ref TRUE_VALUE, ref FALSE_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref MISSING_VALUE, ref FALSE_VALUE, ref TRUE_VALUE, ref MISSING_VALUE, ref TRUE_VALUE, ref MISSING_VALUE);

The 4th and 2nd last parameters prevent repair and encoding dialogs from opening which fixed most of the errors.

The registry key to turn disable macros without notification is:

[HKEY_USERS\S-x-x-xx-xxxxxxxxxx-xxxxxxxxx-xxxxxxxxxx-xxx\Software\Microsoft\Office\12.0\Word\Security]
"VBAWarnings"=dword:00000004

Finally, after all that there were still docs that were crashing the service and leaking winword instances. After logging in as the service user and opening one of these documents I got this message dialog from word: "Word cannot start the converter mswrd632". This is fixed by removing a registry key as explained in http://support.microsoft.com/kb/973904.

Edit: I also found that because VBA was not installed Word opened a dialog to tell the service this which caused some of the documents to hang the service. Reinstalling it then disabling though Word itself (as explained above) got a few more documents processing. Still a few documents that can't be processed. Thinking of trying http://poi.apache.org/text-extraction.html with ikvmc to parse the documents instead.

Keith K
+1  A: 

You might also try calling the documents.OpenNoRepairDialog(...) method. It exists for office 2007 and later.

Note that I am using straight COM calls, so I am not sure that it exists in the office interop libs.

JMilnes
The method is in the vsto COM interop dlls. I do have config switch that I can use to enable the service to use it instead of the Open method, but when using it I still couldn't get any of the problem documents to open. At the moment the service is running well enough without it so I'm not going to make any changes but thanks for the suggestion.
Keith K