4

I have an object created in memory using Microsoft.Office.Interop and Microsoft.Office.Word and with all created, paragraphs, tables and the like. I need this object to generate a content byte [] to feed one field of the same type in a table. The problem that I can not save it in any way physically with a oDoc.Save ("path") in order to use a FileStream and solve my problem.

Have tried several solutions and how to use the clipboard, and did not work. Any solution?

Berkay Turancı
  • 3,373
  • 4
  • 32
  • 45
Iceknight
  • 113
  • 2
  • 6
  • 1
    What error are you getting? Can you show some code? – keyboardP May 16 '11 at 20:53
  • I wonder if saving to a named pipe might work... But - writing to the TEMP are is a lot easier... – Marc Gravell May 16 '11 at 21:32
  • Marc, i dont writing in TEMP because dont have any permission to write in FS. – Iceknight May 17 '11 at 17:59
  • keyboardP, the code : object oMissing = System.Reflection.Missing.Value; Word.Application oWord; Word.Document oDoc; oWord = new Word.Application(); oDoc = oWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing); Word.Paragraph oPara1; oPara1 = oDoc.Content.Paragraphs.Add(ref oMissing); oPara1.Range.Text = "The title; oPara1.Range.InsertParagraphAfter(); byte[] content = new byte[oDoc.Content.Text.Length]; System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); content = encoding.GetBytes(oDoc.Content.Text); This return the text w/o formt – Iceknight May 17 '11 at 18:02

2 Answers2

2

Do you really have to use the Microsoft.Office.Interop and Microsoft.Office.Word?

If it is not really necessary, you could use the OpenXML SDK libraries for manipulating the content of the WordDocument.

OpenXML 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[].

As a code sample:

byte[] templateContent = File.ReadAllBytes(templateFile);

MemoryStream stream = new MemoryStream();
stream.Write(templateContent, 0, templateContent.Length);

WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true);

// When done
byte[] contentOfWordFile = stream.toArray();
George
  • 307
  • 3
  • 10
  • 1
    You actually don't even need the `File.ReadAllBytes()`, etc. part, because `WordprocessingDocument` will accept the file path, directly, instead of requiring the stream to be created outside, like that. You would do `using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filePath, true)) { using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream())) { string docText = sr.ReadToEnd(); } XmlDocument xml = new XmlDocument(); xml.LoadXml(docText); // do stuff with XmlNodes…` And then you would have `docText = xml.OuterXml;` that could then be converted to bytes. – vapcguy Nov 15 '18 at 03:03
  • 1
    The only problem with my method is you are then encoding a string of XML into bytes for the database: `byte[] bytes = Encoding.ASCII.GetBytes(docText);` , so you have to remember that if you want to reconstitute the file back to a docx you'd need to convert the bytes back to a string, then need `using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create))) { sw.Write(docText); }` – vapcguy Nov 15 '18 at 03:13
  • 1
    Talks all about it: https://learn.microsoft.com/en-us/office/open-xml/how-to-search-and-replace-text-in-a-document-part – vapcguy Nov 15 '18 at 03:15
  • Well, I also found that encoding the bytes is bad and doesn't work... it corrupts the file if you write it back out. I had to use `File.ReadAllBytes()` to read it, then `File.WriteAllBytes()` for it to be accurate. You can write the string of XML like I described, but converting bytes back to string doesn't work, because the encoding (whether you use UTF8, Unicode, Default, UTF7, ASCII, doesn't matter) will corrupt it. – vapcguy Nov 19 '18 at 19:16
  • Converting it to `byte[]` from a stream with `.ToArray()` also works, and using `using (MemoryStream stream = new MemoryStream()) { stream.Write(byteArray, 0, (int)byteArray.Length); // Save the file with the new name File.WriteAllBytes(strDocumentPath, stream.ToArray()); }` to write it back out also is a way to convert it back and forth successfully. – vapcguy Nov 26 '18 at 15:47
1

Sounds like this is a dynamically-created Word document.

Since you have the document in the form of a Document object, you should be able to get its string of XML, then bytes, by doing this:

Microsoft.Office.Interop.Word.Document d = new Microsoft.Office.Interop.Word.Document();

// All of your building of the document was here
// The object must be updated with content

string docText = d.WordOpenXML;  // this assumes content is here
byte[] bytes = Encoding.UTF8.GetBytes(docText);

I don't think that saving the object to the file system first is required, since you already have the object you have built all dynamically, in memory. It should just be a matter of accessing its WordOpenXML.

If you were grabbing the file from the file system, it would look pretty much the same, except for how the document is opened first:

string sourceFilePath = @"C:\test.docx";
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
var document = wordApp.Documents.Open(sourceFilePath);
string docText = document.WordOpenXML;
byte[] bytes = Encoding.UTF8.GetBytes(docText);

If you ever want to download these bytes back into a document, you'd need to do this:

string documentPath = @"C:\test.docx"; // can be modified with dynamic paths, file name from database, etc.
byte[] contentBytes = null;
// … Fill contentBytes from the database, then...

// Create the Word document using the path
using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(documentPath, true))
{
    // This should get you the XML string...
    string docText = System.Text.Encoding.UTF8.GetString(contentBytes);

    // Then we write it out...
    using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
    {                    
        sw.Write(docText);
    } 
}

See How can I form a Word document using stream of bytes for more information.

vapcguy
  • 7,097
  • 1
  • 56
  • 52