NetOfficeFw / NetOffice

🌌 Create add-ins and automation code for Microsoft Office applications.
MIT License
697 stars 143 forks source link

Exception when accessing merge fields in a Word document #3

Closed frankfajardo closed 8 years ago

frankfajardo commented 8 years ago

I modified the Example03 in the Examples and created a new document from an existing document with merge fields. If I try to access the merge fields via a for-loop, I get the exception Factory is not initialized with NetOffice assemblies.

I ran a debug and noticed that NetOffice.Core was not getting the FactoryInfo from NetOffice.WordApi, and this is because the code _appDomain.LoadFrom(fullFileName) is returning null, despite the WordApi.dll being present on the directory it was searching in. And this is because, what I believe is this bug on CurrentAppDomain.LoadFrom() method: if LoadAssembliesUnsafe is false, it is issuing Assembly.Load when it should be issuing Assembly.LoadFrom, since you are passing the assembly's full path, rather than the assembly's fully qualified name.

frankfajardo commented 8 years ago

Also, I think the CurrentAppDomain.Load(string) should accept the assembly's fully qualified name, rather than the assembly's file path, to align with .NET's Assembly.Load(string)

frankfajardo commented 8 years ago

Having looked into this further, I think the CurrentDomain_AssemblyResolve() should be calling CurrentAppDomain.LoadFrom() instead of CurrentAppDomain.Load(), and the latter can be removed.

I have submitted a pull request for this issue. Thanks!

jozefizso commented 8 years ago

/cc @SebastianDotNet, @caioproiete

jozefizso commented 8 years ago

@frankfajardo do you have some reproduction code?

I tried this and it worked in Word 2016:

var wordApplication = new Application();
wordApplication.DisplayAlerts = WdAlertLevel.wdAlertsNone;

// add a new document
var templateFilename = Path.Combine(Environment.CurrentDirectory, "LetterTemplate.docx");
var templateDoc = wordApplication.Documents.OpenNoRepairDialog(templateFilename);

var fields = templateDoc.MailMerge.Fields;
Console.WriteLine($"Merge fields count: {fields.Count}");

foreach (var field in fields)
{
    var range = field.Code;
    Console.WriteLine($"Field: {range.Text}");
}

wordApplication.Documents.Close(false);
wordApplication.Quit();
wordApplication.Dispose();

Output:

Merge fields count: 4
Field:  GREETINGLINE \f "<<_BEFORE_ Dear >><<_TITLE0_>><< _LAST0_>>
<<_AFTER_ ,>>" \l 1033 \e "Mr.,"
_COUNTRY_>>" \l 1033 \c 2 \e "US" \d SUFFIX0_>>
Field:  MERGEFIELD First_Name
Field:  MERGEFIELD Last_Name
Done.
frankfajardo commented 8 years ago

@jozefizso , It could be because I'm using Word 2010? Although I'm not sure if it is related to the Office version. The bug is on NetOffice.CurrentAppDomain, when it tries to load the ProjectInfo (IFactoryInfo) from WordApi.dll. The exception happens in the for-loop. It does not reach the code inside the for-loop. It fails because the app is passing a file path to Assembly.Load(string) and it is unable to load the assembly by the path, because it thinks the string is the assembly's qualified name. The actual exception is:

Could not load file or assembly '{path to the WordApi.dll}' or one of its dependencies. 
The given assembly name or codebase was invalid. `

Is your Settings.LoadAssembliesUnsafe set to false? It is false by default. But if you somehow have it set to true, you will not see the bug.

jozefizso commented 8 years ago

I've tried the sample with Word 2010 and it works without problems.

frankfajardo commented 8 years ago

Not sure mate. I downloaded the Github package as is, and it failed on this line after it was called from by Core.cs on here. It was passing a file path, and Assembly.Load(string) definitely accepts an assembly qualified name.

Maybe you can run it on debug and see if you execute that line of code. I'm definitely not dreaming.

Anyway, I have decided to use OpenXml SDK, so if you think this does not need fixing, up to you.

jozefizso commented 8 years ago

Do you have sample project where is it crashing?

frankfajardo commented 8 years ago

It's on my work laptop in the office. But I modified Example03.cs to create a document from my template and loop through the MailMerge.Fields. My for loop at the beginning with the reported exception.

jozefizso commented 8 years ago

I tested the latest 1.7.4-pre build of the NetOffice library and it does contain bug in CurrentAppDomain.Load() methods as you reported.

I could not reproduce it because the bug was introduced after 1.7.3 release.

jozefizso commented 8 years ago

Fixed in latest 1.7.4-pre release.

You can try it by downloading prelease package from https://www.myget.org/gallery/netofficefw-dev