Insight of Add-in Express Loader

How it works

Add-in Express Loader is an unmanaged dll developed with the Visual C++ Active Template Library (ATL). It acts as a proxy between a host application and the real .NET library.

The loader itself is never registered and it shouldn’t be. It is just specified as a dll to be loaded for managed classes. To specify the loader as a dll to load, you need to write a full path to the loader in the Default variable of the InprocServer32 key in the registry. For example:

Writing a full path to the loader

Add-in Express Registrator registers CLSID and ProgId of all public classes in the add-in assembly. For classes that implement IDTExtensibility2, ISmartTagRecognizer, ISmartTagRecognizer2, ISmartTagAction, ISmartTagAction2 and IRtdServer, the registrator indicates the loader as a dll to load. When an Office application loads the loader, a proxy class is created, which by-turn loads the Microsoft .NET Framework common language runtime (CLR). Then the proxy class creates a separate domain for the managed extension assembly and loads the assembly there. In accordance with the proxy class, an instance of the managed class is created and a pointer to that class is stored within the proxy. Subsequently, any calls from the host application into the loader are handled first by the proxy class. The proxy class passes those calls on through the pointer of the managed class to the actual extension class in the managed extension assembly. In case of COM add-ins, the developer can get a pointer to the proxy class by using the Object property of the Office.COMAddin interface. This enables calling public methods of the add-in from VBA, other add-ins or applications.

Initialization of CLR (Common Language Runtime)

A very important point is initialization of the CLR. Before creating an instance of the managed extension class, the loader identifies the CLR’s version that was used during the compilation of the managed extension assembly. After that the loader will attempt to initialize exactly that version. If it is not found, then the most recent version installed on the PC is used.

As of today, Microsoft has two versions of hosting API that can be used for initialization of the .NET Framework.

  1. .NET Framework 1.1 and 2.0 Hosting API
  2. .NET Framework 4.0 Hosting API.

Before the release of .NET Framework 4.0, to initialize the CLR the loader used the CorBindToRuntimeEx function from the .NET Framework 1.1 and 2.0 Hosting API (see the sample code below):

hr = CorBindToRuntimeEx((LPTSTR)szRuntimeVersion, L"wks",
    STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN | STARTUP_LOADER_SAFEMODE,
    CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (LPVOID*) &m_pHost);
if (FAILED(hr))
{
    hr = CorBindToRuntimeEx((LPTSTR)szLatestRuntimeVersion, L"wks",
        STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN | STARTUP_LOADER_SAFEMODE,
        CLSID_CorRuntimeHost, IID_ICorRuntimeHost, (LPVOID*) &m_pHost);
}
GetCorVersion(pstrLoadedCLR, 255, &dwlength);
m_pHost->Start();

With release of .NET Framework 4.0, .NET Framework 1.1 and 2.0 Hosting API was declared obsolete and it was superseded by a new API, which allows initializing CLR 2.0 and 4.0 in one process. Below you can see the sample code used by the loader for initialization of CLR v2.0 – v4.0:

hr = _CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&lpMetaHost);
if (hr == S_OK)
{
    if (FAILED(hr = lpMetaHost->GetRuntime((LPTSTR)szRuntimeVersion,
        IID_ICLRRuntimeInfo, (LPVOID*)&lpRuntimeInfo)))
        {
            IfFailReturn(lpMetaHost->GetRuntime((LPTSTR)szLatestRuntimeVersion,
                IID_ICLRRuntimeInfo, (LPVOID*)&lpRuntimeInfo));
        }
    IfFailReturn(lpRuntimeInfo->GetInterface(CLSID_CorRuntimeHost,
        IID_ICorRuntimeHost, (LPVOID*)&m_pHost));
    if (SUCCEEDED(hr = m_pHost->Start()))
    {
        lpRuntimeInfo->GetVersionString(pstrLoadedCLR, &dwlength);
    }
}

Always use the latest version of Loader

I want to draw your attention to that fact the before releasing .NET Framework 4.0 Microsoft published a few intermediate versions of Visual Studio 2010 and accordingly a few versions of .NET Framework 4.0. Every time, in each of those intermediate versions, modifications were made in the Hosting API, which resulted in performance failures of add-ins using the loader that targeted a previous version of the API. For example, the Add-in Express loader in version 5.0.x – 5.2.x used the Hosting API from .NET Framework v4.0 Beta 1 and Beta 2. With the public release of .NET Framework 4.0 those loader versions stopped loading add-ins. Trying to keep pace with Microsoft, we continuously updated and will keep updating the loader to get it to support all their changes. This is the reason why we always recommend using the latest version of the Add-in Express loader in your products.

Downloads

Add-in Exploress Loader – latest version

12 Comments

  • Dennis Wallentin says:

    Sergey,

    Thanks for taking the time to explain the functionality of the loader dll, especially why we always should use the latest version of it.

    If we compare an Add-in Express COM add-in with a native shimmed managed COM add-in; is there any differences in performance?

    Kind regards,
    Dennis

  • Sergey Grischenko (Add-in Express Team) says:

    Thank you for your comment, Dennis.

    Frankly speaking, I did not compare the performance of native shimmed managed COM add-ins and that of our add-ins. In fact the code of Microsoft C++ shim doesn’t differ much from the code of Add-in Express loader. Which is why I don’t think they have any substantial differences in performance.

  • Minh Nguyen says:

    Hi Sergey,

    We are using Add-in Express to developer the add-in for Outlook. In our project we use MAPI33 (it’s .NET 2.0 wrapper) and now we want to migrate our add-in project to use .NET 4.0. Unfortunately system error as runtime because of mix mode and i found a setting in app.config to fix that problem (from Microsoft doc)

    startup useLegacyV2RuntimeActivationPolicy=”true”

    I tried to put that setting in app.config of our Add-in project and also put in adxloader.dll.manfest but no luck

    After look around i found another way to set that but it’s too later to call that API (ICLRRuntimeInfo.BindAsLegacyV2Runtime) since the our add-in managed code is in difference AppDomain with host application. The only way to inject that setting is inside adxloader.dll before it created Add-in AppDomain

    I already sent email to Add-in Express support team but they answer no. Hopefully you could give me any about this situation or that will stop us to migrate to .NET 4.0

    Many thanks and wait for your feedback,
    Minh Nguyen

  • Sergey Grischenko (a member of the Add-in Express team) says:

    Hi Minh,

    Thank you for the suggestion. Please put the useLegacyV2RuntimeActivationPolicy attribute to the outlook.exe.config file. I believe it should fix the issue. You can see an example here: https://msdn.microsoft.com/en-us/library/bbx34a2h.aspx
    I will see if we can add the BindAsLegacyV2Runtime method to the code of the loader. Most likely it will be an option in the adxloader.dll.manifest file.

  • Mulugheta says:

    Hi Sergey

    What are the impact of converting existing com-addin project, which is targeting .net 2.0 to .net 4.0?

    Thank you!

  • Sergey Grischenko (a member of the Add-in Express team) says:

    Hi Mulugheta,

    So far, I have not faced any issues with converting existing COM add-ins to .NET v4.0. If you have any difficulties, please let me know the details.

  • TonyG says:

    As seen through Excel Options > Add-Ins, the name of the add-in assembly is “adxloader.assemblyname.dll”. Is there any way to safely change the name of the DLL, to just assemblyname.dll, or to rebrand the namespace to “MyCorp.assemblyname.dll” ? Thanks!

  • Eugene Astafiev says:

    Hi Tony,

    Thank you for your feedback! The current version of Add-in Express does not allow renaming the adxloader.dll. We have added this issue to our bug-tracking system and we will consider adding such a feature in one of the future builds.

  • Perry says:

    Hi Sergey,

    I meet a problem which as Minh Nguyen describe at March 17, 2011 at 4:50 am, and you give an advice that set useLegacyV2RuntimeActivationPolicy attribute to the outlook.exe.config file. Also you said it may add the BindAsLegacyV2Runtime method to the code of the loader, most likely it will be an option in the adxloader.dll.manifest file, so what I want know is that the BindAsLegacyV2Runtime method is available in adxloader now? Or could you give any advice to solve the problem without set useLegacyV2RuntimeActivationPolicy attribute to the outlook.exe.config file?
    Thanks!

  • Sergey says:

    Hi Perry,

    Yes, the option is available now (see the example below). But we added it for add-ins which are registered via adxloader.dll. I am not sure if it works properly for Office applications. Please test it. Of course, you can rebuild the mixed code with .NET Framework v4.x in order to fix this issue.

  • Sergey says:

    Perry, for some reason I can’t post the example of the adxloader.dll.manifest file. To enable the BindAsLegacyV2Runtime option you need to add the useLegacyV2RuntimeActivationPolicy=”true” attribute to the loaderSettings element in the adxloader.dll.manifest file. Also the adxregistrator.exe tool has the ‘/uselegacyv2runtimeactivationpolicy=true’ option.

  • Perry says:

    Hi Sergey,

    Very thanks for your advice, it worked well now. And I found it’s will work in both .NET 4 only or .NET4+.NET2, when RuntimeVersion=”v2.0.50727″ in HKEY_CLASSES_ROOT\CLSID\{***}\InprocServer32 key.

    Thanks!

Post a comment

Have any questions? Ask us right now!