DCOM Config settings for Microsoft Interop Word Automation - c#

I am using Microsoft Office Interop Word to generate documents using C#. In order for the document generation to work, there should be an entry for the "Microsoft Office Word 97 - 2003 Document" under the Dcom Config Settings as shown below:
The Local Path under the General Tab has a correct path when Microsoft Office is first installed. If I then join the computer to a Domain, and then restart the system with a Domain user, the Local Path becomes blank and the application doesn't generate the documents and gives error.
Even if I join the computer to Domain first and then login with Domain user and then install the Microsoft Office, the Local Path appears correct first and then after a restart, it becomes blank again. While, at the same time, if I login with the Local User, the Path is still there.
What is causing the value of Local Path to go blank?
This all setup is on virtual machines and the word automation works on a domain account as I have seen it working on a physical machine joined to domain.
UPDATE: What my application is doing:
There are 4-5 components in my application.
The first is a VSTO Word AddIn, which integrates with Microsoft Word, where we create new documents that contain some Expressions that are also saved in the database. There are also conditions on the Expressions and they can be nested also. Expressions contain schema elements from XSD files which are saved in database. Once this type of document is created, its WordML is saved in the database. This all is done in VSTO AddIn.
The second is a Web Service which receives an input xml from another component that confirms to the XSD above from which the schema elements were embedded into the expressions in the document created through VSTO addIn. This web service checks for the validations and several other tasks. It then gets the WordML of the corresponding word document from the database and passes it to the Word Interop which using its APIs, iterates through it recursively to replace the schema elements with their actual values from the input xml. This then saves the WordML to a file as word document.
This also attaches a template to the document before saving it. It uses the SaveAs functionality of Word Interop to also save the file as PDF.
UPDATE:
I have again gone through my complete application and came to know that we are doing all things by parsing the Office Open XML (e.g. for feeding the input to the word document), but the only things that we are doing using Word Automation are following:
Using Word Interop to save the generated WordML as one of the Word Format Files.
Exporting the generated WordML to the PDF file.
Merging several WordMLs into a single word document file.
Fetching the XML for it.
All these four codes are shown below with only relevant parts of code:
Microsoft.Office.Interop.Word.Document wordDocument = null;
object templateName = "templateFile.dotm";
wordDocument = this.WordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing);
wordDocument.Range(ref missing, ref missing).Text = "";
wordDocument.set_AttachedTemplate(ref templateName);
wordDocument = this.WordApplication.Documents.Open(
ref objSourceFilePath, ref oFalse, ref oTrue,
ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing,
ref oMissing);
wordDocument.ExportAsFixedFormat(
strTargetPath,
targetFormat,
paramOpenAfterExport,
paramExportOptimizeFor,
paramExportRange,
paramStartPage,
paramEndPage,
paramExportItem,
paramIncludeDocProps,
paramKeepIRM,
paramCreateBookmarks,
paramDocStructureTags,
paramBitmapMissingFonts,
paramUseISO19005_1,
ref oMissing);
object SaveToFormat = SaveToFormat = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97;
wordDocument.SaveAs(ref objTargetFilePath, ref SaveToFormat, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
For Merging several files:
Microsoft.Office.Interop.Word.Document doc = null;
Microsoft.Office.Interop.Word.Section section = null;
object sectionBreakNextPage = (object)WdBreakType.wdSectionBreakNextPage;
WordApp.Visible = false;
doc = this.WordApplication.Documents.Add(ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing);
if (doc != null)
{
doc.Activate();
int fileCount = sourceFiles.Length;
String fileName = string.Empty;
for (int fileIndex = 0; fileIndex < fileCount; fileIndex++)
{
fileName = sourceFiles[fileIndex];
if (System.IO.File.Exists(fileName))
{
section = doc.Sections.Last;
//delink the current section's header & footer from previous section's header & footer
section.Headers[WdHeaderFooterIndex.wdHeaderFooterFirstPage].LinkToPrevious = false;
section.Footers[WdHeaderFooterIndex.wdHeaderFooterFirstPage].LinkToPrevious = false;
section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
section.Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
section.Headers[WdHeaderFooterIndex.wdHeaderFooterEvenPages].LinkToPrevious = false;
section.Footers[WdHeaderFooterIndex.wdHeaderFooterEvenPages].LinkToPrevious = false;
section.Range.InsertFile(fileName, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing);
//if it is last iteration, do'nt insert break
if (fileIndex < fileCount - 1)
{
object rangeStart = (object)(section.Range.End - 1);
doc.Range(ref rangeStart, ref paramMissing).InsertBreak(ref sectionBreakNextPage);
}
}
}
doc.SaveAs(ref targetFile, ref wordFormat, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing);
return true;
}
Right now, I am receiving the following error:
The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))
Can this all be done without using the Word Automation?

Instead of trying to fix and deal with that error, I think you should read this and then try another approach to your problem:
(...) 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, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when run in this environment. (...)
Some of the alternatives recommended in that KB are:
(...) Microsoft strongly recommends a number of alternatives that do not require Office to be installed server-side, and that can perform most common tasks more efficiently and more quickly than Automation. Before you involve Office as a server-side component in your project, consider alternatives.
Most server-side Automation tasks involve document creation or editing. Office 2007 supports new Open XML file formats that let developers create, edit, read, and transform file content on the server side. These file formats use the System.IO.Package.IO namespace in the Microsoft .NET 3.x Framework to edit Office files without using the Office client applications themselves. This is the recommended and supported method for handling changes to Office files from a service. (...)
And
(...) Microsoft provides an SDK for manipulating Open XML file formats from the .NET 3.x Framework. For more information about the SDK and about how to use the SDK to create or edit Open XML files, visit the following Microsoft Developer Network (MSDN) Web sites:
Open XML SDK Documentation
How to: Manipulate Office Open XML Formats Documents
Manipulating Word 2007 Files with the Open XML Object Model (Part 1 of 3)
Manipulating Word 2007 Files with the Open XML Object Model (Part 2 of 3)
Manipulating Word 2007 Files with the Open XML Object Model (Part 3 of 3) (...)
Note, that even if you get your problem fixed, your solution will hardly be stable... In essence what, it seems to be happening is that you messed your registry and it seems that your Word reinstallation is not fixing your registry, and that is problematic.
Based on this, I recommend you to read the above documentation and to try put together a more stable solution using the above alternatives, as Automation of Microsoft Office applications from any unattended, non-interactive client application or component, which is your case, may exhibit unstable behaviors.
UPDATE 1
You have an Hello World example here.
Creating a document with Open XML can be as easy as doing this:
public void HelloWorld(string docName)
{
// Create a Wordprocessing document.
using (WordprocessingDocument package = WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document))
{
// Add a new main document part.
package.AddMainDocumentPart();
// Create the Document DOM.
package.MainDocumentPart.Document =
new Document(
new Body(
new Paragraph(
new Run(
new Text("Hello World!")))));
// Save changes to the main document part.
package.MainDocumentPart.Document.Save();
}
}
Note
I could spent here hours, trying to solve your registry, but as you can see in this article in my blog, those problem are huge headaches, and in your case, even if you find a way to solve it, it will not be a maintainable or either scalable solution, in my opinion of course.
UPDATE 2
According to this, those configurations such as local path are extracted from the registry and are not modifiable:
(...) The General tab provides general information about the application. This tab displays the Application name, type (local server or remote server), and location (local path or remote computer). These settings are not modifiable through the DCOM Config interface.
The General Tab retrieves all of its information from subkeys of the following registry key:
HKEY_CLASSES_ROOT\CLSID{...CLSID...}
where {...CLSID...} is the unique CLSID for the Object Server currently being viewed. (...)
So! Run > regedit > Go to HKEY_CLASSES_ROOT\CLSID, then go to Edit menu and click Find, filter by key and put your ApplicationID there. You should find it this way.
Now after finding the registry entry for your DCOM, expand it, you should see a LocalServer32, the property (Default) holds your Local Path value, try change it the same path as in your new Oracle Virtual Box.
If this works, test if the value hold after restarting and logging in with you Domain User account if it does, great, if not, run a batch to run a .reg file to perform this modification, on every login.
Warning: Nevertheless, this is bad stuff, I strongly, strongly encourage you to go the other way around, this is not the way to do it.
UPDATE 3
Regarding the "MS-WORD AUTOMATION ERROR : "The message filter indicated that the application is busy", you have a very good reply to that problem here. I'll cite a bit of the above link, for further understanding of why that error happens:
(...) That issue is the fact that the Word objects you are calling into do not support multiple threading. Since they are exposed to arbitrary clients via COM, the possibility exists that multiple threads could attempt to simultaneously execute code within the object. To prevent this from happening, will serialize all incoming calls by queuing them up and only allowing one call at a time to execute. This is done by packaging up the details of each call and posting a message to Word. When Word processes, the message, the call will execute on Word's own main thread. The problem with this approach is that if Word is busy doing something else when the call comes in, the caller will have to wait. (...)
About the merging, this tool claims to be capable of merging OpenXML documents, I never used it, but I would give it a try (if I were you).
(...) PowerTools for Open XML contains source code and guidance for accomplishing various common tasks using the Open XML SDK, such as: - High-fidelity conversion of DOCX to HTML/CSS using HtmlConverter.cs; - Merging and splitting DOCX documents using DocumentBuilder.cs; - Merging and splitting PPTX presentations using PresentationBuilder.cs; - Accepting tracked revisions in DOCX documents using RevisionAccepter.cs; - Searching and replacing text in DOCX documents using TextReplacer.cs (...)
Finally to generate PDFs, from your word documents, you can use this tool here.
So as you can see, once more, you can keep dealing with Word Automation (Dark Side), or you can join the Light Side of the Force :).

Related

Open Microsoft word document from web project to any local machine

Below is my code on click to button. If I will run project using localhost it will open word document very well but when I am going to host this project on IIS and try to open it from another machine by IP it will transfer my page to error message.
Microsoft.Office.Interop.Word.ApplicationClass wordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
object file = "D:\\poForM.docx";
object objFalse = false;
object objTrue = true;
object missing = System.Reflection.Missing.Value;
object emptyData = string.Empty;
object readOnly = false;
object visible = true;
wordApp.Visible = true;
Microsoft.Office.Interop.Word.Document aDoc = wordApp.Documents.Open(ref file, ref missing, ref readOnly, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, visible, ref missing, ref missing, ref missing, ref missing);
aDoc.Activate();
Your code is relying on there being an instance of Microsoft Word on the server (Microsoft.Office.Interop.Word.ApplicationClass)... and having the object file at a specified location on the server.
If I understand correctly what you are trying to do you want to host the Word document on your IIS server but download it onto the local machine for editing..
You can do this by providing a link in your Web page to where the Word doc is, for example:
Open Word Document
Then when you click the link the browser will download the doc and open it in Word (assuming it's installed locally)
Of course if I've completely misunderstood what you're trying to do feel free to comment....
I believe you want to achieve SharePoint alike behaviour where the user can open the file and then save it back to server. Here is a similar thread Possible for Word to edit documents directly off an web server without Sharepoint? . The only bad thing about this solution is that AFAIK it is working only in IE. You can also try new ActiveXObject("Word.Application");instead of the new ActiveXObject("SharePoint.OpenDocuments");

using Microsoft.Office.Interop Word and Excel

I am using Microsoft.Office.Interop, for scanning word and excel files using C#,I am taking file as input from user, saving it on local directory then scanning it Interop library.
Its working fine on my local publish, However when I published it on server its not scanning Word or Excel Files.
I have MS-Office installed on my Server, the same version which I have on my PC.
What else I need to do? I have copied the required DLL's in my bin Directory.
This is how I am reading word file
public static string word_to_text(string source)
{
Word.Application newApp = new Word.Application();
object Source = source;
object Unknown = Type.Missing;
object miss = System.Reflection.Missing.Value;
object readOnly = true;
Microsoft.Office.Interop.Word.Document docs = newApp.Documents.Open(ref Source, ref miss, ref readOnly, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss, ref miss);
string totaltext = "";
for (int j = 0; j < docs.Paragraphs.Count; j++)
{
totaltext += " \r\n " + docs.Paragraphs[j + 1].Range.Text.ToString();
}
docs.Close();
newApp.Quit();
return totaltext;
}
I was getting this exception
Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the following error: 80070005 Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).
I fixed it by following this post
However now I am having issue with excel and word files.
In case of Word files,its not reading the file from above code,docs object is appearing to be null.
In case of Excel Its showing exception
Microsoft Office Excel cannot access the file 'myfile path'. There are several possible reasons: • The file name or path does not exist. • The file is being used by another program. • The workbook you are trying to save has the same name as a currently open workbook.
I read solution to give rights to folder, and also create Desktop folder inside system32 Here,both solutions not worked for me :(
The issue is arising only when I am publishing it
You should not use Office automation in a server. Only one thread can access Word at a time, it's very slow relative to other options, and Word is not made for server-side execution.
Much better to use OpenXML SDK:
http://www.microsoft.com/en-us/download/details.aspx?id=5124
Or some other wrapper:
http://docx.codeplex.com/
http://www.codeproject.com/Articles/87711/Manipulate-Docx-with-C-without-Microsoft-Word-inst
If you feel you absolutely must use Office automation on a server (and you shouldn't), then at least put it in a separate process and enque requests to the other process. That way you can ensure only one request is being processed at a time, you can safely grant the other process the permissions needed, and if Word halts you can kill it and the secondary process.

Office 2007 PIA - Embed non-text files

I am working with the Office 2007 PIAs and am trying to generate a large document from x number of user selected documents. Most of these documents will likely be word docs, but we want to support any file type.
Text documents work fine when inserted using InsertFile. Pictures can be inserted using InlineShapes.AddPicture. How do I embed other document types? I am looking for the functionality equivalent to drag and dropping any file into Word. If I try to use the InsertFile method, it just writes out the binary content of non text files.
To embed non-text files in Word via Interop, you use InlineShapes.AddOLEObject
I am looking for the functionality equivalent to drag and dropping any file into Word.
This does the trick for me:
public void InsertFile(Microsoft.Office.Interop.Word.Selection CurrentSelection, string FileName)
{
object FileName = fileName;
object missing = Type.Missing;
CurrentSelection.InlineShapes.AddOLEObject(ref missing, ref FileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
}
Hope this helps.

How do I save this object to a file?

I have some word documents with objects inside them. I am testing one that has 3 pdf-files (the wordApp.Selection.InlineShapes.Count matches this), But else I have trouble getting any info from the objects. How do I save it to a disk? Any help is appreciated, because the inlineShape.OLEFormat.IconLabel is an empty string in all 3 instances.
var wordApp = new Word.Application();
object confirmConversions = false;
object readOnly = true;
object missing = Type.Missing;
this.document = wordApp.Documents.Open(
ref fn, ref confirmConversions, ref readOnly,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing);
string applicationName = null;
foreach (Microsoft.Office.Interop.Word.InlineShape inlineShape in this.document.InlineShapes)
{
applicationName = inlineShape.OLEFormat.IconLabel;
}
Here's a snippet from a post which I found here which explains the approach you need to take in order to do this:
Any file that can be embedded in a
document as an OLE object can be
extracted. However, we may not be
able to provide you with a simple code
example if the technology doesn't
belong to us (such as Adobe Acrobat
files).
What we are doing with Office objects
is activating the object and then
taking advantage of the exposed
IDispatch interface so that we can use
COM interop to communicate directly
with the object's programming model.
As it happens, the Office applications
generally expose SaveAs methods that
we can call to save the files in
question. Going through the Office
programming model in this fashion is a
handy shortcut that enables saving
embedded objects with very little
code.
I suspect that Adobe Acrobat exposes a
similar programming model because
there is an Adobe Acrobat Type
Library. You will have to browse the
Type Library to see if it exposes some
sort of Save or Save as method. If it
does, you can add it as a reference to
your project (via the COM References
tab of the Add Reference dialog in
Visual Studio) and take a similar
approach as Ji suggests in his post
above.
(continues...)
If you are open to using 3rd party controls, this can be easily accomplished using Aspose.Words:
Aspose.Words.Document d = new Document(#"C:\users\john\desktop\embeddedPDF.docx");
foreach (Aspose.Words.Drawing.Shape shp in d.GetChildNodes(NodeType.Shape, true))
{
shp.OleFormat.Save(#"C:\Temp\testoutput.pdf");
}

Close MS Office C# Console

I'm writing an automated test to determine whether or not rtf files are successfully opened by MS Word. So far I looping through all the rtfs within a given directory and opening them. Later I will have to catch exceptions to generate a report (log the file name that crashed word).
I am processing a large number of files. My application is currently opening a new instance of Word for each file. Can someone tell me how to close Word?
public class LoadRTFDoc
{
private object FileName;
private object ReadOnly;
private object isVisible;
private object Missing;
private ApplicationClass WordApp;
private object Save;
private object OrigFormat;
private object RouteDoc;
public LoadRTFDoc(object filename)
{
this.WordApp = new ApplicationClass();
this.FileName = filename;
ReadOnly = false;
isVisible = true;
Missing = System.Reflection.Missing.Value;
Save = System.Reflection.Missing.Value;
OrigFormat = System.Reflection.Missing.Value;
RouteDoc = System.Reflection.Missing.Value;
}
public void OpenDocument()
{
WordApp.Visible = true;
WordApp.Documents.Open(ref FileName, ref Missing, ref ReadOnly, ref Missing, ref Missing,
ref Missing, ref Missing, ref Missing, ref Missing, ref Missing, ref Missing,
ref isVisible, ref Missing, ref Missing, ref Missing, ref Missing);
WordApp.Activate();
}
public void CloseDocument()
{
WordApp.Documents.Close(ref Save, ref OrigFormat, ref RouteDoc);
}
}
I am executing the CloseDocument() method after each document is opened. Anyone have some insight for me on this?
WordApp.Quit()
will exit the application.
However, the safest way is to get a handle to the process and kill the winword process. In C# the following code would do that:
foreach (Process p in Process.GetProcessesByName("winword"))
{
if (!p.HasExited)
{
p.Kill();
}
}
The reason is that it will happen frequently (I assume, especially since you are testing documents created not by Word) that Word will hang with an open message box, e.g. a repair dialog. In that case killing the process is the easiest way to close the application.
I would suggest that you first try to close Word using Application.Quit. If this does not work it indicates a problem with your input file (most likely because a repair dialog is blocking Word). You should record this as an error in your log and then proceed killing the winword process.
Another problem you might face is Word's document recovery feature blocking the application on startup (and thus preventing a document from being opened until the recovery dialog box is clicked away). Document recovery can be disabled by deleting the following registry key under both HKCU and HKLM prior to starting Word (replace 12.0 with 11.0 for Word 2003 and 10.0 for Word XP):
Software\Microsoft\Office\12.0\Word\Resiliency
It goes without saying that killing Word is a rather rude approach, however, it is simple and rather robust. The code above will just kill any instance of Word for a user. If you want to kill only a specific instance things get more difficult. You would have to retrieve the process id of a specific Word instance. Typically this can be done by searching for the window title of the instance, e.g. using WinAPI functions like FindWindowByCaption and GetWindowThreadProcessId.
WordApp.Quit followed by ReleaseComObect as said by dance2die.
Use System.Runtime.InteropServices.ReleaseComObject and pass it the reference of your word object instance, WordApp.
You are all correct. My problem what that I was creating an instance of ApplicationClass within a loop. Whoops. I then used the Quit() after closing each document to kill the winword.exe process.
Thanks you guys!
-Nick

Categories