Выгрузка разгрузки DLL из сборки

Я пытаюсь выгрузить неверную версию сторонней DLL из моего .NET-процесса, поскольку она, похоже, вызывает проблему, которая всегда разрешается перезагрузкой моего приложения. Вместо перезапуска приложения я бы хотел удалить и перезагрузить DLL.

DLL загружается с помощью LoadLibrary и удаляется с помощью FreeLibrary (используя DllImport, взятый с веб-сайта P/Invoke). Когда я вызываю LoadLibrary(), я вижу, что DLL появляется в списке DLL в Process Explorer, а когда я вызываю FreeLibrary(), я вижу, что DLL исчезает из списка DLL - как и ожидалось.

Однако, как только я вызвал функцию Initialize() сторонней библиотеки, FreeLibrary() больше не удаляет DLL из списка, даже если я вызываю соответствующий метод Deinit() заранее. Вызов другой функции в библиотеке не имеет этой проблемы. Тем не менее, я должен Initialise() использовать библиотеку перед использованием!

Я попытался изолировать DLL, создав его в своем собственном AppDomain, а затем выгрузив этот домен после освобождения библиотеки DLL.

Я не получаю коды возврата или исключения из Initialize() или Deinit(), из LoadLibrary() или FreeLibrary() или от создания или выгрузки AppDomain.

Я использовал следующий код для создания AppDomain и инициализации:

string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
m_Domain = AppDomain.CreateDomain("MyAppDomain", null, new AppDomainSetup { PrivateBinPath = pathToDll });
m_Module = (ThirdPartyModule)m_Domain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ThirdPartyModule).FullName);
m_Module.Init();

Чтобы деинициализировать и выгрузить AppDomain:

m_Module.Free();
m_Module = null;
if (m_Domain != null)
{
    AppDomain.Unload(m_Domain);
    m_Domain = null;
}

Наконец, мой класс сборки ThirdPartyModule:

internal class ThirdPartyModule : MarshalByRefObject
{
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    internal static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool FreeLibrary(IntPtr hModule);

    public IntPtr Module { get; set; }

    public ThirdPartyModule()
    {
        Module = LoadLibrary("Misbehaving.dll");
    }

    public void Free()
    {
        FreeLibrary(Module);
        Module = IntPtr.Zero;
    }

    // ...
}

Означает ли это, что он должен вести себя так, как я ожидал? Если нет, есть ли другой способ гарантировать, что эта DLL полностью выгружена моим процессом?

Изменить: Подробнее

  • DLL содержит собственный код, вероятно, скомпилированный из C/С++
  • К сожалению, мой процесс ограничивается только использованием .NET 2 (поэтому нет решения WCF).
  • Я использую WinXP Pro x64 SP2, но решение должно быть совместимо с XP, Win7 x32/x64 и т.д.
  • DLL используется для связи с токеном USB

Ответ 1

Я бы рекомендовал реализовать отдельный процесс (EXE), который запускает ваше приложение и которое, в свою очередь, загружает DLL.

Это позволяет вам убивать процесс, когда это необходимо...

Я вижу несколько вариантов взаимодействия - например:

  • вы можете использовать COM (если вы реализуете его как COM-сервер вне процесса)
  • вы можете использовать общую память (очень высокую производительность, см. this для прохода и this для оболочки .NET 2)

Поскольку вы пишете, что этот метод должен быть совместим с несколькими версиями Windows, а некоторые из них поставляются с настольным брандмауэром, я бы воздержался от использования чего-либо "сетевого" для IPC.