Принудительная выгрузка DLL из сборки - PullRequest
11 голосов
/ 26 января 2012

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

DLL загружается с помощью LoadLibrary и удаляется с помощью FreeLibrary (с использованием DllImport s, взятых из P /Запустить сайт).Когда я вызываю 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 / C ++
  • К сожалению, мой процесс ограничен использованием только .NET 2 (поэтому нет решения WCF).
  • Я использую WinXP Pro x64 SP2, но решение должно бытьСовместимость с XP, Win7 x32 / x64 и т. Д.
  • DLL используется для связи с USB-токеном

1 Ответ

4 голосов
/ 26 января 2012

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...