Search code examples
c#ms-wordvstoword-2010

VSTO: how to save an interop doc (with custom parts and metadata) to memory


In order to create some custom metadata and back up what a user is doing in a word document to a server/database, I have created a VSTO application-level add-in, and used the DocumentBeforeSave event to hijack Word's default save functionality.

I would like to convert the current document into a binary blob or a complete openXML representation that contains the document, custom xml part, and with all the data that would be necessary to seamlessly open the same document from the server copy. I therefore need not just any custom XML parts I add, but information on Change Tracking and other metadata that is saved inside the document. My idea, accordingly, was to simply grab the saved blob that is created:

private void ThisAddIn_Startup(object sender, EventArgs e)
{
    Application.DocumentBeforeSave += application_DocumentBeforeSave;
}

private void application_DocumentBeforeSave(Document doc, ref bool saveAsUI, ref bool cancel)
{
    // generate some xml
    string customPart = @"<foo>some xml here</foo>";

    Office.CustomXMLPart rangeListXmlPart = doc.CustomXMLParts.Add(customPart, missing);

    // suppress default save functionality           
    saveAsUI = false;
    cancel = true;

    // manually generate save dialog
    Dialog dlg = Application.Dialogs[WdWordDialog.wdDialogFileSaveAs]
    object oDlg = dlg;
    object[] oArgs = new object[1];
    oArgs[0] = @"C:\";
    oDlg.GetType().InvokeMember("Name", BindingFlags.SetProperty, null, dlg, oArgs);
    dlg.Show(ref missing);

    // read in file blob
    byte[] data = null;

    FileInfo fileDetails = new FileInfo(doc.FullName);
    long fileSize = fileDetails.Length;

    FileStream fStream = new FileStream(path, FileMode.Open, FileAccess.Read);

    BinaryReader bReader = new BinaryReader(fStream);
    data = bReader.ReadBytes((int) fileSize);

    // send data up to the server, along with the file type
}

... but there has to be a more elegant solution to the problem, that doesn't require saving the document to disk, and then reading it back into memory, as this approach is inherently flawed: the document saving may happen many times, and it is not desirable to keep reading from the hard drive multiple times. It also would be helpful to implement this functionality at other times without saving the document to disk at all! Any thoughts would be greatly appreciated.


Solution

  • Get the WordOpenXML property from the document or range (it contains the flat OPC format of the document), then convert it to a DocX package as shown in http://blogs.msdn.com/b/ericwhite/archive/2008/09/29/transforming-flat-opc-format-to-open-xml-documents.aspx.

    The result should be equivalent to saving as DocX, but can be done entirely in memory.