This project has moved. For the latest updates, please go here.

Distributing Office AddIn with NetOffice in a single .DLL

Oct 15, 2014 at 5:18 PM
I would like to distribute my addin in a single .DLL file instead of having to create an installer that puts in all of the necessary NetOffice .DLL files -- effectively giving me a file copy deployment.

I built out my solution with NetOffice and all worked great! I modified it to combine the dependent DLLs with my addin's DLL and now I'm not getting called for the document before save event in Word. Under the debugger I am getting called for the initialization that sets up the event handler, and I also get called in the shutdown process, but the document before save event isn't firing. I didn't make any other changes to the project other than using ILMerge to pack the NetOffice DLLs into my DLL.

The addin I am playing around with here is a little utility that helps template developers utilize revision control systems. When the user saves the document template in Word, the addin creates a folder beneath the template file and serializes all of the forms, classes, and code modules to independent files so that revision control systems can manage those details at a granular level.
Coordinator
Oct 16, 2014 at 2:55 AM
no idea about your single demployment concept(i like the idea, of course because im a developer).... in fact:
what i'm understand so far is as follows:
  • your solution works fine so far on prod system
  • now you add/delete/change some reference assemblies and the before save event stop working(on same system, same office version)
true? (try MS FusionLog in this case, becaue a refrence can't resolve and the runtime stops working)

*Sebastian
Oct 16, 2014 at 3:42 PM
I work primarily with large enterprise customers in my day-to-day business. I have a software company that provide document automation solutions to large banks. In these environments, I often face some pretty strict constraints over how solutions can be deployed. I have to have a deployment procedure that does not require administrative access on the PC. The bank’s IT departments are very risk aversive so they try to thwart any possible entry points in their system that could be potential security breaches.

I can try to explain in greater detail. I created a Word AddIn .DLL file using NetOffice and with a traditional deployment, everything worked properly. The solution requires my DLL plus the dependent NetOffice DLLs so I ended up requiring 5 DLLs to install for this to work properly:
WordSourceControl.dll   <-- My Word AddIn DLL
NetOffice.dll
OfficeApi.dll
WordApi.dll
VBIDEApi.dll
Upon creating the system I wrote up a short little setup program using Inno Setup. This setup program installed my DLL along with the four NetOffice dependent DLLs. I tested the system out on several virtual machines running different versions of Office (2007, 2010, 2013) and everything worked great.

I decided that I would also like to support a single file / copy file deployment. This would enable the add in to be installed just by being copying the single .DLL file into the user’s Word STARTUP folder C:\Users{username}\AppData\Roaming\Microsoft\Word\STARTUP. When Word encounters DLLs in that folder, it will attempt to load them as a global addin.

I added ILMerge to my build process (there’s a NuGet package that makes it really easy to do.) As part of that process you simply list the assemblies that you want to combine:

this file contains the partial list of the merged assemblies in the merge order

you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build

and finetune merge order to your satisfaction

WordSourceControl.dll
NetOffice.dll
OfficeApi.dll
VBIDEApi.dll
WordApi.dll

At the end of the build process, ILmerge is invoked to combine all of the assemblies into a single assembly (the first one listed serves as the target assembly.) So far, so good. I looked at the generated assembly and it all looks to be there.

When I run the AddIn in Word, however, I am no longer receiving the BeforeDocumentSave event.

In the debugger, I traced through the execution and found that the AddIn starts up correctly. The AddIn constructor gets hit, I setup the event handlers for OnConnection and OnDisconnection and do in fact receive the events for both of those.
public class ThisAddin : COMAddin
{
    WordSourceControl wordSourceControl = null;

    public ThisAddin()
    {
        this.OnConnection += new OnConnectionEventHandler(OnConnectionEvent);
        this.OnDisconnection += new OnDisconnectionEventHandler(OnDisconnectionEvent);
    }

    private void OnConnectionEvent(object Application, ext_ConnectMode ConnectMode, object AddInInst, ref Array custom)
    {
        AutoDocsCore.WordApp = (Word.Application)this.Application;
        wordSourceControl = new WordSourceControl(AutoDocsCore.WordApp);
        wordSourceControl.Initialize();
    }

    private void OnDisconnectionEvent(ext_DisconnectMode RemoveMode, ref Array custom)
    {
        wordSourceControl.Shutdown();
        wordSourceControl = null;
        AutoDocsCore.WordApp = null;
    }
}
You’ll see that in the OnConnection event I’m creating my WordSourceCountrol object and calling into its Initialize method, which only serves to set up the event handler for the DocumentBeforeSave event:
    public void Initialize()
    {
        application.DocumentBeforeSaveEvent += new Word.Application_DocumentBeforeSaveEventHandler(DocumentBeforeSaveEvent);
    }
The issue that I’m running into is that I never receive the DocumentBeforeSave event.

I actually made no code changes to the project from the multi-file deployment. The only thing I did was pack the assemblies into a single .DLL assembly which normally works fine.

When writing .EXE files I will sometimes pack the dependent assemblies as embedded resources and add a resolver to load them up. That way I can have an executable that doesn’t require a setup program at all :-)

I’m not sure if I was better able to describe this to you but I thought I would give it a try. I will check in with FusionLog to see if that shows anything out of the ordinary.

Chad