Setting useLegacyV2RuntimeActivationPolicy At Runtime

Version 4.0 of the .NET Framework included a new CLR which is almost entirely backwards compatible with the 2.0 version of the CLR.  However, by default, mixed-mode assemblies targeting .NET 3.5sp1 and earlier will fail to load in a .NET 4 application.  Fixing this requires setting useLegacyV2RuntimeActivationPolicy in your app.Config for the application.  While there are many good reasons for this decision, there are times when this is extremely frustrating, especially when writing a library.  As such, there are (rare) times when it would be beneficial to set this in code, at runtime, as well as verify that it’s running correctly prior to receiving a FileLoadException.

Typically, loading a pre-.NET 4 mixed mode assembly is handled simply by changing your app.Config file, and including the relevant attribute in the startup element:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0"/>
  </startup>
</configuration>

This causes your application to run correctly, and load the older, mixed-mode assembly without issues. For full details on what’s happening here and why, I recommend reading Mark Miller’s detailed explanation of this attribute and the reasoning behind it.

Before I show any code, let me say:

  • I strongly recommend using the official approach of using app.config to set this policy.

That being said, there are (rare) times when, for one reason or another, changing the application configuration file is less than ideal.

While this is the supported approach to handling this issue, the CLR Hosting API includes a means of setting this programmatically via the ICLRRuntimeInfo interface.  Normally, this is used if you’re hosting the CLR in a native application in order to set this, at runtime, prior to loading the assemblies.  However, the F# Samples include a nice trick showing how to load this API and bind this policy, at runtime.  This was required in order to host the Managed DirectX API, which is built against an older version of the CLR.

This is fairly easy to port to C#.  Instead of a direct port, I also added a little addition – by trapping the COM exception received if unable to bind (which will occur if the 2.0 CLR is already bound), I also allow a runtime check of whether this property was setup properly:

public static class RuntimePolicyHelper
{
    public static bool LegacyV2RuntimeEnabledSuccessfully { get; private set; }

    static RuntimePolicyHelper()
    {
        ICLRRuntimeInfo clrRuntimeInfo =
            (ICLRRuntimeInfo)RuntimeEnvironment.GetRuntimeInterfaceAsObject(
                Guid.Empty, 
                typeof(ICLRRuntimeInfo).GUID);
        try
        {
            clrRuntimeInfo.BindAsLegacyV2Runtime();
            LegacyV2RuntimeEnabledSuccessfully = true;
        }
        catch (COMException)
        {
            // This occurs with an HRESULT meaning 
            // "A different runtime was already bound to the legacy CLR version 2 activation policy."
            LegacyV2RuntimeEnabledSuccessfully = false;
        }
    }

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891")]
    private interface ICLRRuntimeInfo
    {
        void xGetVersionString();
        void xGetRuntimeDirectory();
        void xIsLoaded();
        void xIsLoadable();
        void xLoadErrorString();
        void xLoadLibrary();
        void xGetProcAddress();
        void xGetInterface();
        void xSetDefaultStartupFlags();
        void xGetDefaultStartupFlags();

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void BindAsLegacyV2Runtime();
    }
}

Using this, it’s possible to not only set this at runtime, but also verify, prior to loading your mixed mode assembly, whether this will succeed.

In my case, this was quite useful – I am working on a library purely for internal use which uses a numerical package that is supplied with both a completely managed as well as a native solver.  The native solver uses a CLR 2 mixed-mode assembly, but is dramatically faster than the pure managed approach.  By checking RuntimePolicyHelper.LegacyV2RuntimeEnabledSuccessfully at runtime, I can decide whether to enable the native solver, and only do so if I successfully bound this policy.

There are some tricks required here – To enable this sort of fallback behavior, you must make these checks in a type that doesn’t cause the mixed mode assembly to be loaded.  In my case, this forced me to encapsulate the library I was using entirely in a separate class, perform the check, then pass through the required calls to that class.  Otherwise, the library will load before the hosting process gets enabled, which in turn will fail.

This code will also, of course, try to enable the runtime policy before the first time you use this class – which typically means just before the first time you check the boolean value.  As a result, checking this early on in the application is more likely to allow it to work.

Finally, if you’re using a library, this has to be called prior to the 2.0 CLR loading.  This will cause it to fail if you try to use it to enable this policy in a plugin for most third party applications that don’t have their app.config setup properly, as they will likely have already loaded the 2.0 runtime.

As an example, take a simple audio player.  The code below shows how this can be used to properly, at runtime, only use the “native” API if this will succeed, and fallback (or raise a nicer exception) if this will fail:

public class AudioPlayer
{
    private IAudioEngine audioEngine;

    public AudioPlayer()
    {
        if (RuntimePolicyHelper.LegacyV2RuntimeEnabledSuccessfully)
        {
            // This will load a CLR 2 mixed mode assembly
            this.audioEngine = new AudioEngineNative();
        }
        else
        {
            this.audioEngine = new AudioEngineManaged();
        }
    }

    public void Play(string filename)
    {
        this.audioEngine.Play(filename);
    }
}

Now – the warning:

This approach works, but I would be very hesitant to use it in public facing production code, especially for anything other than initializing your own application.  While this should work in a library, using it has a very nasty side effect: you change the runtime policy of the executing application in a way that is very hidden and non-obvious.

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

25 Responses to “Setting useLegacyV2RuntimeActivationPolicy At Runtime”
  1. joovie says:

    I think useLegacyV2RuntimeActivationPolicy=”false” should be rather useLegacyV2RuntimeActivationPolicy=”true” in app.Config file

    sorry for wrong comments, I have bad day…

    • Reed says:

      Thanks joovie – I corrected it. I had set it to false explicitly for testing this technique, and copy/pasted from the wrong project file… Fixed now.

  2. Rushi says:

    Hi,

    I have a typical situation. I have a project that is using the mixed mode dll. I have set the option useLegacyV2RuntimeActivationPolicy = “true” in the App.config file. Now I have a set up project which is using primary output from my dll having useLegacyV2RuntimeActivationPolicy = “true” . When I install the setup, I am getting the error
    Mixed mode assembly is built against version ‘v2.0.50727′ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.

    Is there a way to change the configuration or adding a configuration to the set up file so that I can fix this error in my setup.

    Any help greatly appreciated.

    Thanks in advance

    • Reed says:

      Rushi,

      The problem is that you need to make the application that’s running set this, not your DLL. I’m not sure there’s a good way to do this for a setup project, short of moving your DLL into an executable and launching it. This post’s technique may or may not work, but it could be worth testing in this type of scenario.

  3. Kirill says:

    thank you for this post, I have big mess with my console app, when I run this on debug my sqlite db is updated, but on setup , is not, what wrong i do ? I’m use Dbfactory and static-linked binaries for 4.0 fw. Thank you for your help

  4. Kirill says:

    I’ve resolved this clue, just update provider SQlite ADO.NET to 4.0 !

  5. Kirill says:

    here is the LINK http://sqlite.phxsoftware.com/forums/p/2314/9238.aspx , IMHO this is awful, that besides thinking about Gang Of Four, I need run for CLR adventures… but any case thanks for this great post, if you can put little solution for instance(), for download(using managed/unmanaged) this will outstanding.

  6. Gary says:

    Hi Reed,

    Thanks for the article about useLegacyV2RuntimeActivationPolicy and setting it at runtime. I’m wondering if there would be a way to do this in a VSTO project as it the executable would be the MS Office application. The config method is a nuisance for deploying an addin and I’d like to set it at runtime but I fear it won’t be possible.

    • Reed says:

      I’ve never tried it. The trick would be making sure your code ran early enough that it didn’t fail. It might be possible, but it needs to be one of the first things executed to work properly…

  7. Mike says:

    Thank you for your blog.

    This works well for those apps. But I have a “portal” which contains mix mode apps and clickonce apps. So what happens is the user launches a mix mode app and then tries to load a clickonce app and the error message comes up

    An error occurred while verifying the application. Error text: A runtime has already been bound for legacy activation policy use. (Exception from HRESULT:0×80131704

    So is there a way to Unbind the legacy runtime. do you think calls to
    void SetDefaultStartupFlags();
    void GetDefaultStartupFlags();

    would help, But I don’t know how to setup those methods with parameters or their .net calls

    Thank you

    • Reed says:

      Unfortunately, the runtime policy is either one way or the other, and once it’s set, it can’t be changed. Mixing mixed-mode and click once in a single process is going to be problematic unless you make sure things are built for the correct runtime (CLR 4).

  8. rahul says:

    My question:

    Why .Net 4.0 CLR does not allow mixed mode dlls work properly without setting the flag?

  9. rahul says:

    My one more question:

    Is there any memory issues or negative impact if we set useLegacyV2RuntimeActivationPolicy=”true”. Waiting for your reply

    • Reed says:

      There’s really no issue with regards to memory usage. The main issue is that you’re using a different CLR to load assemblies than the one for which they were built/designed. This can (potentially) introduce bugs due to differences in the runtime, though that’s very rare.

      In general, there’s little downside.

      • rahul says:

        Thanks Reed for the reply .

        Could you please answer my previous query :

        Why .Net 4.0 CLR does not allow mixed mode dlls work properly without setting the flag useLegacyV2RuntimeActivationPolicy=”true”. ?

        and if this technique works why this cannot be the default behaviour implementation?

        will be eagerly for the reply….

        • Reed says:

          As I said before – it causes the assembly to be loaded using a different runtime than the one in which it was designed. This **can** introduce new bugs (there are some breaking compatibility changes in CLR 4), but in most cases, it works. Making it the default would be dangerous, as a Windows update or installing a program (which installed .NET 4) could, all of a sudden, break other existing programs.

          As such, it’s something where the designers decided to force you to opt into doing, though it’s a simple change.

          • Reed says:

            As for *why* it’s required – its because mixed mode assemblies can’t run across multiple CLR runtimes. I suspect the complexity of making that work was just to cost prohibitive.

  10. Thank you very much for this solution. It works perfectly for one dll file that I had to develop recently and I couldn’t use the app.config file to set this flag.

  11. Walid Haidari says:

    public static class RuntimePolicyHelper
    {
    public static bool LegacyV2RuntimeEnabledSuccessfully { get; private set; }

    static RuntimePolicyHelper()
    {

    I need this code but for visual basic not c#

    Please

    Thank you.

  12. Leland says:

    Excellent!!!! I needed this solution for an MSI project custom action as I could not find a way to app.config the MSI. It may exist but I could not find it. MANY THANKS for this contribution! I will be posting a link to this topic on an open issue in stackoverflow…

Trackbacks

Check out what others are saying about this post...
  1. [...] instantiates this library the CLR loads with this attribute set and everything works fine.(See this link). I cannot modify the excel.exe.config as it is denied in production [...]

  2. [...] Someone with much deeper technical knowledge than me provided this explanation of the situation, should you be interested in learning more. I wish I had found this earlier. This entry was posted [...]

  3. […] can read more about this setting and what it does here.  The discrepancy in behaviour between the test execution and BizTalk runtime is easily explained […]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!