Задание useLegacyV2RuntimeActivationPolicy во время выполнения

Проблема загрузки сборок скомпилированных под устаревший CLR давно известна. Старые библиотеки отказываются работать в CLR 4 и выше, если принудительно не задать в app.config разрешение на выполнение этих сборок в новом райнтайме:

<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0"/>
  </startup>
</configuration>

Без этой настройки получим исключение FileLoadException:
Сборка для смешанного режима построена на основе версии «v2.0.50727» среды выполнения и не может быть загружена в среде выполнения 4.0 без дополнительных конфигурационных данных.

Что же делать, если нет желания или возможности таскать с собой app.config?
К счастью, можно задать параметр useLegacyV2RuntimeActivationPolicy во время выполнения.

Ниже код, который опубликовал Рид Копси в своём блоге:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

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

        static RuntimePolicyHelper()
        {
            var clrRuntimeInfo =
                (ICLRRuntimeInfo)RuntimeEnvironment.GetRuntimeInterfaceAsObject(
                    Guid.Empty,
                    typeof(ICLRRuntimeInfo).GUID);
            try
            {
                clrRuntimeInfo.BindAsLegacyV2Runtime();
                LegacyV2RuntimeEnabledSuccessfully = true;
            }
            catch (COMException)
            {
                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();
        }
    }
}

Использование:

if (RuntimePolicyHelper.LegacyV2RuntimeEnabledSuccessfully)
{
    // Удалось!
}
else
{
    // Не удалось =(
}

Свойство LegacyV2RuntimeEnabledSuccessfully статического класса RuntimePolicyHelper сообщает, удалось ли привязать к устаревшей сборке новый рантайм.
Привязка может не сработать, если рантайм уже был привязан ранее.

Обращаться к свойству нужно как можно раньше, до обращения к типам устаревшей сборки. Вынесите обращения к старой сборке в отдельный метод, это гарантирует, что RuntimePolicyHelper отработает раньше.

P.S.: По картинке ниже можно представить с какими версиями .NET библиотек придётся повозиться:

Задание useLegacyV2RuntimeActivationPolicy во время выполнения: 3 комментария

  1. Константин

    спасибо, помогло!) нужно было сделать такой трюк в библиотеке

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Докажи, что не бот! *