How to access the menu bar in word programatically using c# - c#

We have created a VSTO ribbon and installed under my machine. Whenever I open a word document I can see my ribbon available in the menu bar. Now I have created a console application and open the existing document but I am unable to access the VSTO menu item dynamically. Can anyone help me how to approach to access the menu items dynamically in c#
I have created a console application and opening the existing document using word interop but I am unable to find the menu lists. I have tried in VSTO but none of those worked out
Now I would like to access the VM form designer dynamically and click on the save button using c#:
I have this code:
Application wordApp = new Application
{
Visible = false
};
DirectoryInfo directoryInfo = new DirectoryInfo("D:\\WordPlugin\\AutomationApp\\AutomationApp\\Content\\Templates");
string tempFile = "D:\\WordPlugin\\AutomationApp\\AutomationApp\\Content\\Templates";
FileInfo[] fileInfo = directoryInfo.GetFiles();
object missing = Missing.Value;
object readOnly = false;
object isVisible = false;
foreach (FileInfo info in fileInfo)
{
object filename = info.FullName;
Document doc = 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);
doc.Activate();
//if (!info.Name.Contains(".docx"))
string newFileName = string.Format("{0}\\{1}", tempFile, info.Name.Replace(".doc", ".docx"));
doc.SaveAs2(newFileName, WdSaveFormat.wdFormatXMLDocument,
CompatibilityMode: WdCompatibilityMode.wdWord2013);
var documentAddIn = doc.Application.ActiveDocument;
}
I am hoping to find out how I can access the menu bar items - Home, Insert, Design and my VSTO menu item.

Related

Why Word page count always returns 1 in Japanese Operating System

But it is works fine in English OS.
Also it is returns the correct value for Excel and Power point document in English OS as well as Japanese OS.
Only the problem am facing page count for Word document in Japanese OS
I have tried three type of code but still i'm getting total Page count as 1 only.
References version: Microsoft.Office.Interop.Word Version 15.0.0.0
Visual studio : 2013
Microsoft office : 2016
Method :1:-
Microsoft.Office.Interop.Word.ApplicationClass appWordPageCount = new Microsoft.Office.Interop.Word.ApplicationClass();
Microsoft.Office.Interop.Word.Document DocPageCount = null;
Microsoft.Office.Interop.Word.WdStatistic staticPages = Microsoft.Office.Interop.Word.WdStatistic.wdStatisticPages;
object missing = System.Reflection.Missing.Value;
DocPageCount = appWordPageCount.Documents.Open(fileNames);
wordPageCount = DocPageCount.ComputeStatistics(staticPages, ref missing); // fetches page count of word files
Method :2
Microsoft.Office.Interop.Word.Application appWordPageCount = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document DocPageCount = null;
DocPageCount = appWordPageCount.Documents.Open(wordFile);
wordPageCount = DocPageCount.ActiveWindow.ActivePane.Pages.Count;
Method :3
Microsoft.Office.Interop.Word.ApplicationClass appWordPageCount = new Microsoft.Office.Interop.Word.ApplicationClass();
Microsoft.Office.Interop.Word.Document DocPageCount = null;
Microsoft.Office.Interop.Word.WdStatistic staticPages = Microsoft.Office.Interop.Word.WdStatistic.wdStatisticPages;
object encoding = Microsoft.Office.Core.MsoEncoding.msoEncodingUTF8;
DocPageCount = appWordPageCount.Documents.Open(ref fileNames, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
ref encoding, ref missing, ref missing, ref missing, ref missing, ref missing);
wordPageCount = DocPageCount.ComputeStatistics(staticPages, ref missing);
Thanks in advance for your guidances.
When Word application view mode is "Web layout" then, it always returning page count as 1.
there are three three view mode in it, Read,Print Layout, Web Layout.
So while getting page count of word document , the mode should be in Print Layout.

Checkbox disabled for Word document created using Microsoft.Office.Interop.Word

I am trying to create a Word document with checkboxes in it using Microsoft.Office.Interop.Word. I have used the following references to do so:
Create a Word document in C#
Create and edit a CheckBox in Word with c#
I have successfully generated a Word document with a checkbox but unfortunately it is disabled. What I am trying to achieve is to have a checkbox that can be checked/unchecked.
In the screenshot below, you can see that I have 3 checkboxes. The 1st one is generated using Microsoft.Office.Interop.Word and the 2nd and 3rd ones were created manually in Word 2016. The first one cannot be marked as checked/unchecked while the 2nd and 3rd ones behave just like a normal checkboxes
And this is the code I used to generate the Word document.
private void btnCreateWordInterop_Click(object sender, EventArgs e)
{
Word._Application word_app = new Word.ApplicationClass();
word_app.Visible = true;
object missing = Type.Missing;
Word._Document word_doc = word_app.Documents.Add(ref missing, ref missing, ref missing, ref missing);
Word.Paragraph para = word_doc.Paragraphs.Add(ref missing);
para.Range.Text = "Chrysanthemum Curve";
object style_name = "Heading 1";
para.Range.set_Style(ref style_name);
para.Range.InsertParagraphAfter();
//Microsoft.Office.Interop.Word.Range range =
para.Range.Collapse(ref missing);
Word.FormField checkBox = word_doc.FormFields.Add(para.Range, Word.WdFieldType.wdFieldFormCheckBox);
para.Range.InsertAfter(" Checkbox generated by Microsoft.Office.Interop.Word");
// Save the document.
object filename = #"C:\Users\Username\Desktop\InteropWord.docx";
word_doc.SaveAs(ref filename, 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, ref missing,
ref missing);
//Close.
object save_changes = false;
word_doc.Close(ref save_changes, ref missing, ref missing);
word_app.Quit(ref save_changes, ref missing, ref missing);
MessageBox.Show("Saved");
}
How can I make the generated checkbox enabled?
Instead of using FormFields I'd recommend using Content Controls for this. These are more 'User Friendly' and easier to work with in general.
Change this line:
Word.FormField checkBox = word_doc.FormFields.Add(para.Range, Word.WdFieldType.wdFieldFormCheckBox);
Using a Content Control it would be something like (from the top of my head)
Word.ContentControl checkbox = para.Range.ContentControls.Add(Word.WdContentControlType.wdContentControlCheckBox);

How to link document to different structured template

I am try to automate a process for changing the document templates of word files.
If the templates are similar structure, ie they both use heading1, then when the document is linked to the new template, it works.
However, the template structure is completely different, heading1 is no longer used, it is now section1. How can I change these section titles with code? Something along the lines of if(heading1) rename to section1;
I am using Interop.Word to perform these operations.
Below is the code I'm using:
public string UpdateDocumentWithNewTemplate(string document, string theme, string template, Word.Application wordApp)
{
try
{
object missing = System.Reflection.Missing.Value;
Word.Document aDoc = null;
object notReadOnly = false;
object isVisible = false;
wordApp.Visible = false;
// create objects from variables for wordApp
object documentObject = document;
// open existing document
aDoc = wordApp.Documents.Open(ref documentObject, ref missing, ref notReadOnly, 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);
aDoc.Activate();
// set template and theme to overwrite the existing styles
aDoc.CopyStylesFromTemplate(template);
aDoc.ApplyDocumentTheme(theme);
aDoc.UpdateStyles();
// save the file with the changes
aDoc.SaveAs(ref documentObject, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
// close the document
aDoc.Close(ref missing, ref missing, ref missing);
if (aDoc != null)
System.Runtime.InteropServices.Marshal.ReleaseComObject(aDoc);
aDoc = null;
return documentObject.ToString();
}
catch (Exception exception)
{
return "Error: " + exception;
}
}
For the specific example you need to first import the styles from the other template, then do a Find/Replace to replace the styles applied. I see from your code that you've got the first part (aDoc.CopyStylesFromTemplate(template); aDoc.ApplyDocumentTheme(theme); aDoc.UpdateStyles();).
What many don't realize about Word's Find/Replace functionality is that it can also work with formatting. The best way to get the necessary syntax is to record a successful Find/Replace in a macro, then port the VBA to C#. In the UI:
Ctrl+H to open the Replace dialog box
With the cursor in the "Find what" box, click "More" then "Format" and choose "Style"
Select the name of the style you want to find and have replaced
Click in the "Replace with" box
Use Format/Style, again, to choose the style you want to use
Click "Replace All".
Here's the result I get:
Selection.Find.ClearFormatting
Selection.Find.Style = ActiveDocument.styles("Heading 1")
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Style = ActiveDocument.styles("section2")
With Selection.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.CorrectHangulEndings = False
.HanjaPhoneticHangul = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
You should use Range, not Selection. So the C# code would look something like the following code block. Note how
I get the Range of the entire document
Create a Find object for the Range and use that
To reference Styles for the Find; I show two possibilities
You can list almost all the properties for Find before using Find.Execute. It would also be possible to create object objects for each of these, with only one necessary for true and false then list these "by ref" in Find.Execute. As far as I know, this is simply a matter of personal preference. I did it this way to the most literal "translation" of the VBA to C# code.
In any case, Find.Execute "remembers" these settings, so ref missing can then be used for all the parameters you don't set specifically. In this case, only the "replace all" command is used specifically in the method.
Word.Document doc = wdApp.ActiveDocument;
Word.Range rngFind = doc.Content;
Word.Find fd = rngFind.Find;
fd.ClearFormatting();
Word.Style stylFind = doc.Styles["Heading 1"];
fd.set_Style(stylFind);
fd.Replacement.ClearFormatting();
fd.Replacement.set_Style(doc.Styles["section2"]);
fd.Text = "";
fd.Replacement.Text = "";
fd.Forward = true;
fd.Wrap = Word.WdFindWrap.wdFindStop;
fd.Format = true;
fd.MatchCase = false;
fd.MatchWholeWord = false;
fd.MatchByte = false;
fd.CorrectHangulEndings = false;
fd.HanjaPhoneticHangul = false;
fd.MatchWildcards = false;
fd.MatchSoundsLike = false;
fd.MatchAllWordForms = false;
object replaceAll = Word.WdReplace.wdReplaceAll;
object missing = Type.Missing;
fd.Execute(ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref replaceAll, ref missing, ref missing, ref missing, ref missing);

programmatically insert mail mergefield into hyperlink in a word document

I'm trying to figure out how to programmatically insert mail mergefield into hyperlink in a word document.
In ms word application this is easily accomplished with the following code when in code-view(ALT+F9):
{HYPERLINK "http://example.com?id={MERGEFILED ID}"}
I consulted stackoverflow and google but came up empty-handed.
How could I accomplish something like above snippet via C# word interoperability library?
Right now this is what I have:
using mso = Microsoft.Office.Interop.Word;
public class Test
{
public void GenerateDynamicHyperlinkWithMergeField()
{
mso.Application app = new mso.Application();
object missing = System.Reflection.Missing.Value;
mso.Document doc = app.Documents.Add(ref missing, ref missing, ref missing, ref missing);
mso.Range range = app.Selection.Range;
// this is hyperlinked correctly
mso.Hyperlink hl = document.Hyperlinks.Add(range, "http://example.com?id=", ref missing, ref missing, "textToDisplay", ref missing);
// this mergfield is outside of hyperlink
mso.MailMerge merge = app.ActiveDocument.MailMerge;
mso.MailMergeField mf = merge.Fields.Add(range, "id");
// inserts mergefield code into hyperlink, but not as recognizable code by word application
mso.Hyperlink hl2 = document.Hyperlinks.Add(range, "http://example.com?id=" + mf.Code.Text, ref missing, ref missing, "textToDisplay", ref missing);
}
}
Any help would be much appreciated.
UPDATE:
To clarify what result is expected in word document;
I want this: {HYPERLINK "http://example.com?id={MERGEFILED ID}"}
But I get this with the above function: {HYPERLINK "http://example.com?id="}{MERGEFILED ID}
Try this:
string myLink = "http://example.com?id=" + mf.Code.Text;
mso.Hyperlink hl2 = document.Hyperlinks.Add(range, myString, ref missing, ref missing, "textToDisplay", ref missing);
This might be a red herring, but have you noticed it says MERGEFILED and not MERGEFIELD?
I only bring it up because it's in all instances you mention it.

Need suggestions on how to extract data from .docx/.doc file then into SQL Server

I'm suppose to develop an application for my project, it will load past-year examination / exercises paper (word file), detect the sections accordingly, extract the questions and images in that section, and then store the questions and images into the database. (Preview of the question paper is at the bottom of this post)
So I need some suggestions on how to extract data from a word file, then inserting them into a database. Currently I have a few methods to do so, however I have no idea how I could implement them when the file contains textboxes with background image. The question has to link with the image.
Method One (Make use of ms office interop)
Load the word file -> Extract image,
save into a folder -> Extract text,
save as .txt -> Extract text from .txt then store in db
Questions:
How do I detect the section and question?
How do I link the image to the question?
Extract text from word file (Working):
private object missing = Type.Missing;
private object sFilename = #"C:\temp\questionpaper.docx";
private object sFilename2 = #"C:\temp\temp.txt";
private object readOnly = true;
object fileFormat = Word.WdSaveFormat.wdFormatText;
private void button1_Click(object sender, EventArgs e)
{
Word.Application wWordApp = new Word.Application();
wWordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
Word.Document dFile = wWordApp.Documents.Open(ref sFilename,
ref missing, 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);
dFile.SaveAs(ref sFilename2, ref fileFormat, 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,ref missing);
dFile.Close(ref missing, ref missing, ref missing);
}
Extract image from word file (doesn't work on image inside textbox):
private Word.Application wWordApp;
private int m_i;
private object missing = Type.Missing;
private object filename = #"C:\temp\questionpaper.docx";
private object readOnly = true;
private void CopyFromClipbordInlineShape(String imageIndex)
{
Word.InlineShape inlineShape = wWordApp.ActiveDocument.InlineShapes[m_i];
inlineShape.Select();
wWordApp.Selection.Copy();
Computer computer = new Computer();
if (computer.Clipboard.GetDataObject() != null)
{
System.Windows.Forms.IDataObject data = computer.Clipboard.GetDataObject();
if (data.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
{
Image image = (Image)data.GetData(System.Windows.Forms.DataFormats.Bitmap, true);
image.Save("C:\\temp\\DoCremoveImage" + imageIndex + ".png", System.Drawing.Imaging.ImageFormat.Png);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
wWordApp = new Word.Application();
wWordApp.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 missing, ref missing,
ref missing, ref missing, ref missing);
try
{
for (int i = 1; i <= wWordApp.ActiveDocument.InlineShapes.Count; i++)
{
m_i = i;
CopyFromClipbordInlineShape(Convert.ToString(i));
}
}
finally
{
object save = false;
wWordApp.Quit(ref save, ref missing, ref missing);
wWordApp = null;
}
}
Method Two
Unzip the word file (.docx) -> Copy the media(image) folder, store somewhere -> Parse the XML file -> Store the text in db
Any suggestion/help would be greatly appreciated :D
Preview of the word file:
(backup link: http://i.stack.imgur.com/YF1Ap.png)
The answer is choice #3 - the OpenXML SDK. First let me explain why you don't want the choices listed above.
Running Office on the server is a bad idea. Microsoft specifically says don't do it. It's slow and you will hit "issues" where it throws exceptions or just fails to find things.
Parsing the XML file will work but the XPath to find every possible case where the images, etc. are located adds up. You would probably have to iterate on sections, which come at the end of each section, then handle all cases of in a cell, in a textbox, positioned, inline, etc.
If you go with the OpenXML SDK you have a LINQ interface where you can then use the Descendents and get everything that is an image (or whatever you need). It also gives you sections by the SectPr node so you can easily iterate over sections.

Categories