I am currently creating a c# program which uses a template.dotx containing pre-defined building blocks (with bookmarks) to insert pages of content into a new document, all working as follows
Word._Application oWord;
Word._Document oDoc;
object oMissing = System.Reflection.Missing.Value;
object bAddress = "bAddress";
oWord = new Word.Application();
object oTemplate = _template;
oDoc = oWord.Documents.Add(ref oTemplate, ref oMissing,
ref oMissing, ref oMissing);
Word.Template objTmpl = (Word.Template)oDoc.get_AttachedTemplate();
Word.BuildingBlock objBB = objTmpl.BuildingBlockEntries.Item("PageBB");
Range where = oDoc.Range(oDoc.Content.End - 1, oDoc.Content.End - 1);
var orng = objBB.Insert(where, true);
orng.Bookmarks[bAddress].Range.Text = "Address";
I would like to do this in reverse, to open created file at a later date, and read through each bookmark to get the value.
The problem is when I open the resulting DocXCreatedFromTemplate.docx, the bookmarks have disappeared. Programmatically, I receive the bookmark not in collection error, but also by allowing word to open and checking manually the bookmarks are replaced with text but the bookmark reference has gone.
Is there any way to get round this?
I have worked this out, the following text replaces and deletes the bookmark
orng.Bookmarks[bAddress].Range.Text = "Address";
The solution was to re-add the bookmark afterwards using a method as follows
private void UpdateBookmarkWithoutDeleting(object bookmark, string text, _Document document)
{
var bookmarkRange = document.Bookmarks[bookmark].Range;
bookmarkRange.Text = text;
document.Bookmarks.Add(bookmark.ToString(), bookmarkRange);
}
I found the information at the following link (in VB):
https://wordmvp.com/FAQs/MacrosVBA/InsertingTextAtBookmark.htm
Related
I work on a process that reads a Word document and appends some images to the end of it. The issue I'm running into is that the document ends with a lettered list and the images I am appending are becoming a part of that list. I can't seem to find a way to end that list before adding the images.
Microsoft.Office.Interop.Word.Application winword =
new Microsoft.Office.Interop.Word.Application();
winword.Visible = false;
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Document document = winword.Documents.Open(documentName);
object lastLine = Microsoft.Office.Interop.Word.WdGoToItem.wdGoToLine;
object lastDirection = Microsoft.Office.Interop.Word.WdGoToDirection.wdGoToLast;
document.Sections.Add(missing);
document.Sections[document.Sections.Count]
.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
document.Sections[document.Sections.Count]
.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.Text = "";
winword.Selection.GoTo(ref lastLine, ref lastDirection, ref missing, ref missing);
winword.Selection.EndKey(WdUnits.wdStory, missing);
foreach(string image in images)
{
document.Application.Selection.InlineShapes.AddPicture(image);
}
document.SaveAs2("finished.doc",
Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97);
document.Close();
winword.Quit();
Is there a way to embbed outlook mailitems into word document programatically from a Outlook Mailitem List.??
I am trying to achieve something like this
Word.Application wdApp = new Word.Application();
Word.Document wdDoc = wdApp.Documents.Add(ref missing, ref missing, ref missing,
ref missing);
foreach(Outlook.MailItem olMail in mailAttachments)
{
//Paste/embbed this olMail into the word document
}
Ya Finally i found an effective solution
I used the InlineShapes.AddOLEObject method
My solution:
static void creatDocument(List<Outlook.MailItems> mailAttachments)
{
string userprofile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
object missing = System.Reflection.Missing.Value
object start=0;
object end =0;
object classType ="{00020D0B-0000-0000-C000-000000000046}";
object fileName;
object linkToFile = false;
object displayAsIcon = true;
object iconFileName = Path.Combine(userprofile,"Pictures\MailIcon.ico");
object iconIndex =0;
object iconLabel;
object range;
Word.Application wdApp=new Word.Application();
Word.Document wdDoc = wdApp.Documents.Add(ref missing, ref missing, ref missing, ref missing);
Range rng = wdDoc.Range(ref start,ref missing);
foreach(outlook.MailItem olMail in mailAttachments)
{
olMail.SaveAs(Path.Combine(userprofile,"Documents\TemperoraySave") + CleanFileName(olMail.Subject) + ".msg" ,Outlook.OlSaveAsType.olMsg);
fileName = Path.Combine(userprofile,"Documents\TemperoraySave") + CleanFileName(olMail.Subject) + ".msg"
iconLabel = CleanFIleName(olMail.Subject) + ".msg";
rng = wdDoc.Content;
rng.Collapse(WdCollapseDirection.wdCollapseEnd);
range = rng;
wdDoc.InLineShapes.AddOLEObject(ref classType,ref fileName,ref linkToFile,ref displayAsIcon,ref iconFIleName,ref iconIndex,ref iconLabel,ref range);
var mailRanger = wdDoc.Paragraphs.Add();
mailRanger.Format.SpaceAfter =10f;
}
}
private static string CleanFileName(string fileName)
{
return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}
Nope. The Word object model doesn't provide anything for that. Instead, you may consider using the CustomDocumentPropertiesenter link description here collection for storing your custom data. For example, you may save the message as an .msg file and save the path to the file or the ID of the record in the database to a custom document property. After, when you need to open a message you can get the ID or path for retrieving the email message.
You can't embed the source text of the emails, but you can copy the MailItem.HTMLBody or MailItem.Body (text) values and insert them into the Word document.
I'm working on Word 2010 plugin and I want to copy active document with track changes (http://office.microsoft.com/en-001/word-help/turn-track-changes-on-or-off-HA010370561.aspx) to XML format and later to send it somewhere else.
This is my code:
Microsoft.Office.Interop.Word.Document documentNew = new Microsoft.Office.Interop.Word.Document();
object missing = Type.Missing;
document.Range(ref missing, ref missing).Copy();
documentNew.Range(ref missing, ref missing).PasteAndFormat(Microsoft.Office.Interop.Word.WdRecoveryType.wdFormatOriginalFormatting);
Object xmlFormat = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatXML;
documentNew.SaveAs2(file, xmlFormat);
This works, but does not include track changes in duplicate document. Anybody have idea how to also include changes?
How about saving document to the new document in XML first, then opening up the new document and make whatever changes are required? I've tested this approach and it preserves the tracked changed without having to do anything special.
Copy and pasting into a new document is not going to preserve the original tracked changes.
So the code would be:
public static void SaveAsXMLAndDoSomethingElse() {
String fn = #"C:\Users\zbook\Desktop\Track test.docx";
String fn_xml = #"C:\Users\zbook\Desktop\Track test3.xml";
Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.Application();
Documents docs = app.Documents;
Document doc = docs.Open(fn, ReadOnly:true);
//bool b = doc.TrackFormatting; // for some reason this line bombs
doc.SaveAs2(fn_xml, Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatXML);
doc.Close(false);
Marshal.ReleaseComObject(doc);
// now open up fn_xml ... and do whatever
app.Quit(false);
Marshal.ReleaseComObject(docs);
Marshal.ReleaseComObject(app);
}
I am writing a simple Word Interop application which open a .doc file in background, changes bookmarks content, then make it visible to the user :
var App = new Microsoft.Office.Interop.Word.Application();
var ParTemplate = (object)Template;
var ParVisible = (object)false;
var Doc = App.Documents.Open(
FileName: ref ParTemplate, // Template
ConfirmConversions: ref missing,
ReadOnly: ref missing,
...
Doc.Activate();
Doc.SetBookmarkValue("IssueNumber", TheIssue.IssueNo);
Doc.SetBookmarkValue("Title", TheIssue.Title);
...
App.Visible = true;
App.WindowState = WdWindowState.wdWindowStateNormal;
Actually, the Word application appears in the task tray, and the user has to switch to it manually.
What is the best way to make my application focus on the opened Word document ?
Try this App.Activate(); instead of Doc.Activate().
How can I copy contents of one word document and insert it in another pre-existing word document using C#. I've had a look around but everything looks really complicated (I'm a newbie). Surely there must be an easy solution?
I have found this code which gives me no errors but it doesnt seem to be doing anything. It's certainly not copying into the correct word doc. put it that way.
Word.Application oWord = new Word.Application();
Word.Document oWordDoc = new Word.Document();
Object oMissing = System.Reflection.Missing.Value;
oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
oWordDoc.ActiveWindow.Selection.WholeStory();
oWordDoc.ActiveWindow.Selection.Copy();
oWord.ActiveDocument.Select();
oWordDoc.ActiveWindow.Selection.PasteAndFormat(Word.WdRecoveryType.wdPasteDefault);
P.S these word docs are .doc
Word.Application oWord = new Word.Application();
Word.Document oWordDoc = new Word.Document();
Object oMissing = System.Reflection.Missing.Value;
object oTemplatePath = #"C:\\Documents and Settings\\Student\\Desktop\\ExportFiles\\" + "The_One.docx";
oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
oWordDoc.ActiveWindow.Selection.WholeStory();
oWordDoc.ActiveWindow.Selection.Copy();
oWord.ActiveDocument.Select();
// The Visible flag is what you've missed. You actually succeeded in making
// the copy, but because
// Your Word app remained hidden and the newly created document unsaved, you could not
// See the results.
oWord.Visible = true;
oWordDoc.ActiveWindow.Selection.PasteAndFormat(Word.WdRecoveryType.wdPasteDefault);
It's funny to see all the C# guys asking now the questions the VBA developers have answered since 15 years. It's worth to dig in VB 6 and VBA code samples, if you have to work with Microsoft Office automation issues.
For the point "nothing happens" it's simple: if you start Word through automation, you must set the application also to visible. If you run your code, it will work, but Word remains an invisible instance (open Windows Task Manager to see it).
For the point "easy solution", you can try to insert a document at a given range with the InsertFile method of the range, e.g. like this:
static void Main(string[] args)
{
Word.Application oWord = new Word.Application();
oWord.Visible = true; // shows Word application
Word.Document oWordDoc = new Word.Document();
Object oMissing = System.Reflection.Missing.Value;
oWordDoc = oWord.Documents.Add(ref oMissing);
Word.Range r = oWordDoc.Range();
r.InsertAfter("Some text added through automation!");
r.InsertParagraphAfter();
r.InsertParagraphAfter();
r.Collapse(Word.WdCollapseDirection.wdCollapseEnd); // Moves range at the end of the text
string path = #"C:\Temp\Letter.doc";
// Insert whole Word document at the given range, omitting page layout
// of the inserted document (if it doesn't contain section breakts)
r.InsertFile(path, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
}
NOTE: I was using framework 4.0 for this example, which allows for optional parameters.