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();
Related
I am using following code to replace image (Shape in Microsoft.Interop.Office.Word) of the word document with new image but what the requirement from client is that I need to check the 1st Image of the 1st page of the word document and then compare this image with image of the rest of the document and if match it get replaced with new image else not so need help on how can we compare two shapes(Images)
public void ReplaceWordImage(string FilePath)
{
Word.Document d = new Word.Document();
Word.Application WordApp;
WordApp = new Microsoft.Office.Interop.Word.Application();
bool headerImage = false;
try
{
object missing = System.Reflection.Missing.Value;
object yes = true;
object no = false;
object filename = #"D:/ImageToReplace/5.docx";
d = WordApp.Documents.Open(ref filename, ref missing, ref no, ref missing,
ref missing, ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref yes, ref missing, ref missing, ref missing, ref missing);
List<Word.ShapeRange> ranges = new List<Microsoft.Office.Interop.Word.ShapeRange>();
List<Word.ShapeRange> headerRanges = new List<Microsoft.Office.Interop.Word.ShapeRange>();
foreach (Word.Shape shape in d.Shapes)
{
if (shape.Type == Microsoft.Office.Core.MsoShapeType.msoPicture)
{
shape.Delete();
foreach (Word.Range r in ranges)
`enter code here` {
r.InlineShapes.AddPicture(#"D:\Untitled.jpg", ref missing, ref missing);
break;
}
}
The Word object model doesn't provide anything to compare two images. The best what you could do is to save both on the disk and then try comparing the bytes representation of both. However, there is a better way to get the job done. The answer is the Open XML SDK which allows getting the bytes representation of images on the fly without saving them to a disk before. The Open XML SDK contains a class WordprocessingDocument that can manipulate a memory stream containing a WordDocument content. And MemoryStream can be converted using ToArray() to a byte[]. See Convert Word of interop object to byte [] without saving physically for more information.
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
I'm using Microsoft Interop Word version 15.0.0.0 in order to create a new Word document, insert some text into it, and save it.
When I'm saving it using the following command:
document.SaveAs2(wordFilePath);
the document is saved in format DOCX.
But when I'm saving it using the following command:
document.SaveAs2(wordFilePath, Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97);
the document is seemingly saved as Word-97 DOC (Windows explorer display it with Word-97 DOC icon and type), but it is really internally saved as DOCX (I can see this in two ways: it has the same size of the corresponding DOCX, and when I open it with Word-2016 and select SaveAs, the default save format is DOCX!).
How can I save a document in real document-97 format?
Here's the function used to create a new Word document, whose type depends on the extension (DOC vs. DOCX) of given file path:
public static void TextToMsWordDocument(string body, string wordFilePath)
{
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.Add(ref missing, ref missing, ref missing, ref missing);
if (body != null)
{
document.Content.SetRange(0, 0);
document.Content.Text = (body + System.Environment.NewLine);
}
if (System.IO.Path.GetExtension(wordFilePath).ToLower() == "doc")
document.SaveAs2(wordFilePath, Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97);
else // Assuming a "docx" extension:
document.SaveAs2(wordFilePath);
document.Close(ref missing, ref missing, ref missing);
document = null;
winword.Quit(ref missing, ref missing, ref missing);
winword = null;
}
And here's the code used to call this function:
TextToMsWordDocument("abcdefghijklmnopqrstuvwxyz", "text.doc");
TextToMsWordDocument("abcdefghijklmnopqrstuvwxyz", "text.docx");
It's been a rather stupid error...compare ‘ == ".doc" ’ instead of ‘ == "doc"...
I didn't notice it due to the fact that when SaveAs2 received a file path with extension ".doc" and no WdSaveFormat, it - strangely enough- created a Word document file that had the problem I explained here...
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.
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.