dotnet / Open-XML-SDK

Open XML SDK by Microsoft
https://www.nuget.org/packages/DocumentFormat.OpenXml/
MIT License
3.99k stars 545 forks source link

Macro-enabled document created with CreateFromTemplate() cannot be opened by Word #1314

Open ThomasBarnekow opened 1 year ago

ThomasBarnekow commented 1 year ago

Describe the bug

As described in this stackoverflow question and my answer, Microsoft Word does not open a macro-enabled document (.docm) created from a macro-enabled template (.dotm) with the WordprocessingDocument.CreateFromTemplate() method. When using the same code to create a "normal" document (.docx) from a template (.dotx), Word opens the document without any issue.

When validating both documents (i.e., .docm and .docx) with the OpenXmlValidator, no validation errors are reported (unless the template is attached, in which case one validation error related to the attached template is emitted in each case).

To Reproduce

public sealed class CreateFromTemplateTests
{
    private readonly ITestOutputHelper _output;

    public CreateFromTemplateTests(ITestOutputHelper output)
    {
        _output = output;
    }

    [Theory]
    [InlineData("c:\\temp\\MacroEnabledTemplate.dotm", "c:\\temp\\MacroEnabledDocument.docm")]
    [InlineData("c:\\temp\\Template.dotx", "c:\\temp\\Document.docx")]
    public void CanCreateDocmFromDotm(string templatePath, string documentPath)
    {
        // Let's not attach the template, which is done by default. If a template is attached, the validator complains as follows:
        // The element has unexpected child element 'http://schemas.openxmlformats.org/wordprocessingml/2006/main:attachedTemplate'.
        using (var wordDocument = WordprocessingDocument.CreateFromTemplate(templatePath, false))
        {
            // Validate the document as created with CreateFromTemplate.
            ValidateOpenXmlPackage(wordDocument);

            // Save that document to disk so we can open it with Word, for example.
            wordDocument.SaveAs(documentPath).Dispose();
        }

        using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(documentPath, true))
        {
            // Validate the document that was opened from disk, just to see what Word would open.
            ValidateOpenXmlPackage(wordDocument);
        }
    }

    private void ValidateOpenXmlPackage(OpenXmlPackage openXmlPackage)
    {
        OpenXmlValidator validator = new(FileFormatVersions.Office2019);
        List<ValidationErrorInfo> validationErrors = validator.Validate(openXmlPackage).ToList();

        foreach (ValidationErrorInfo validationError in validationErrors)
        {
            _output.WriteLine(validationError.Description);
        }

        if (validationErrors.Any())
        {
            // Note that Word will most often be able to open the document even if there are validation errors.
            throw new Exception("The validator found validation errors.");
        }
    }
}

The above unit tests pass and no validation errors are reported.

I could not attach the templates. However, I only created super-simple templates with one line of text and a hello world macro in the case of the macro-enabled template.

Observed behavior

The Word document (.docx) created by the test can be opened as expected. The macro-enabled document (.docm) cannot be opened. In my case, Word neither displays the document nor reports any error. In the case of the original poster of the stackoverflow question, a runtime error seems to occur (which I could not reproduce).

Expected behavior

Using WordprocessingDocument.CreateFromTemplate(), the Open XML SDK should be able to create a macro-enabled document (.docm) from a valid, macro-enabled template (.dotm) that can be opened by Microsoft Word.

Desktop (please complete the following information):

diaboliq7 commented 1 year ago

I am attaching the problematic .dotm files from my case. The difference between them is that one has a module with a macro and the other does not. A file created from a template with VBA code does not open.

TemplatesAndFiles.zip

mikeebowen commented 1 year ago

Thanks for sending the files from your case. I'm seeing the same issue you, are and I also don't receive an errors, the file just doesn't open. I will try and see if I can find the underlying issue.

sixareen commented 1 year ago

Some observations posted as comments by me on StackOverflow with some additions:

"When Word creates a new document from a .dotm it creates a macro-free document. The file created by CreateFromTemplate from a .dotm has VBA-related parts but the type specified in [Content_Types].xml for the main document is for a regular .docx. If you change it to a .docm type (i.e. ). the document opens, but does not find its macros. CreateFromTemplate should probably be creating a .docx and should not be creating the macro-related parts and relationships."

When I looked at the documentation for CreateFromTemplate on the relevant Microsoft site it wasn't at all clear what the expectation should be. As @ThomasBarnekow mentioned, when CreateFromTemplate is passed a .dotm, perhaps the result should be a .docm with macros, linked to the .dotm. Perhaps this is actually specified somewhere in some other, more complete, version of the documentation.

The other (probably unrelated) thing I noticed when looking at the .docx/.docm package was that the [Content_Types].xml file for the document created by CreateFromTemplate specifies a default content type for the .xml extention that is a very specific type, rather than a general type.

i.e. it has <Default Extension="xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml/>

IMO you might expect that as an Override for the core-properties part, but not as a Default - elsewhere, I think the following is more typical:

<Default Extension="xml" ContentType="application/xml"/> Probably not a big deal if every xml part has a suitable override, but perhaps the code is working harder than it needs to.