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.
I think useLegacyV2RuntimeActivationPolicy=â€false†should be rather useLegacyV2RuntimeActivationPolicy=â€true†in app.Config file
sorry for wrong comments, I have bad day…
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.
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
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.
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
I’ve resolved this clue, just update provider SQlite ADO.NET to 4.0 !
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.
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.
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…
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:0x80131704
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
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).
My question:
Why .Net 4.0 CLR does not allow mixed mode dlls work properly without setting the flag?
My one more question:
Is there any memory issues or negative impact if we set useLegacyV2RuntimeActivationPolicy=”true”. Waiting for your reply
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.
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….
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.
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.
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.
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.
Telerik’s code coverter appears to do a reasonable job of the conversion – you should be able to just feed the code through: http://converter.telerik.com/
Thank you Reed Copsey . Nice post it helps me lot 😉
Instead of using GetRuntime(), I tried EnumerateLoadedRuntimes() and later BindAsLegacyV2Runtime() on first loaded runtime:
ICLRRuntimeInfo *pRuntimeInfo = NULL;
IEnumUnknown *pEnumerator;
hr = pMetaHost->EnumerateLoadedRuntimes(GetCurrentProcess(), &pEnumerator);
if (FAILED(hr))
{
wprintf(L”ICLRMetaHost::EnumerateLoadedRuntimes failed w/hr 0x%08lx\n”, hr);
goto Cleanup;
}
hr = pEnumerator->Next(1, (IUnknown**)&pRuntimeInfo, NULL);
if (FAILED(hr))
{
wprintf(L”ICLRMetaHost::Next failed w/hr 0x%08lx\n”, hr);
goto Cleanup;
}
Do you think it is right way?
If it’s working, that should suffice. GetRuntime() does seem to work in my testing/usage scenario, however.
Hi, I wanna ask, what situation will it “”A different runtime was already bound to the legacy CLR version 2 activation ” , and it occured sometimes when I run my project… how to reslove it ?
It means the runtime has already been decided. You need to run this code prior to the assemblies being loaded, or it won’t work. I mention this in the article.
Thx so much. Was trying to use ink with xbap. useLegacyV2RuntimeActivationPolicy=”true” didn’t Work. This did!
Great article and code sample – thank you!
Thank you for sharing this code, it was really helpful.
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…