У меня очень простой exe и dll просто для проверки. Вот код в exe-процессе:
auto lib = ::LoadLibrary("CppDll.dll");
auto bar = (Bar)::GetProcAddress(lib, "Bar");
bar();
while (::FreeLibrary(lib));
Когда после этого я пытаюсь удалить файл dll, я вижу следующее:
Я также просмотрел модули, и я озадачен
auto lib = ::LoadLibrary("CppDll.dll");
auto bar = (Bar)::GetProcAddress(lib, "Bar");
bar();
while (::FreeLibrary(lib));
Итак, после вызова bar()
их два. А после FreeLibrary
еще остался один.
Что я могу сделать, чтобы удалить файл?
UPD: я только что обнаружил, что это происходит только в том случае, если dll поддерживает clr.
Это кажется невозможным. Приложение, в котором размещается CLR, использует CLRCreateInstance
, из которого оно может получить ICLRMetaHost
интерфейс, на котором оно может вызывать GetRuntime
для создания CLR. Но у интерфейса нет элементов для выгрузки CLR. Его метод Stop
останавливает выполнение кода в CLR, но не освобождает, не выделяет ресурсы и не выгружает домены приложений. Но чтобы выгрузить сборку, мы должны выгрузить все домены приложений, которые ее используют.
Таким образом, чтобы иметь возможность выгрузить сборку, необходимо загрузить ее в отдельный домен приложения, а затем выгрузить домен приложения. Но выгрузить DLL, загружающую CLR, нельзя, CLR можно выгрузить только при завершении процесса.
Richter, CLR via C#. Chapter 22 "CLR Hosting and AppDomains":
Первый домен приложения, созданный при инициализации среды CLR, называется доменом по умолчанию. домен приложения; этот AppDomain уничтожается только после завершения процесса Windows.
Это возможно, если вы загружаете управляемую .dll в оперативную память.
См. следующий пример: