O>У решения с LoadLib/FreeLib с внутренне-отложенной обработкой выгрузки есть неявное усложнение: FreeLib _не_ гарантирует реальной выгрузки либы сейчас. Соответственно если вызывателю FreeLib реально нужна (чтоб удалить файл?) то таким образом рождается фундаментальный гейзенбаг.
Мне в принципе не нужна гарантия того, что FreeLib точно выгрузит dll. Мне нужно в конечном итоге только то, что бы у dll был простой контракт на использование — 1) LoadLib, 2) UseLib, 3) FreeLib. Без всяких "FreeLib можно только по вторникам".
O>А если FreeLib ему реально не нужна — почему бы не заморозить либу в АП процесса до его завершения?
Можно и так, но этому противится мой внутренний перфекционист. Если можно сделать по нормальному, то почему бы и не сделать.
Re: Запрет выгрузки dll до момента освобождения последнего о
Здравствуйте, Aniskin, Вы писали:
A>Что бы изучить получше оконную систему Windows решил я написать более-менее сложный контрол на чистом WinApi. Для одного из проектов мне нужно было дерево, отображающее себя несколько иначе по сравнению со стандартным SysTreeView32, его и решил реализовать. Контрол я успешно написал, оформил по взрослому, но осталась у меня одна не решенная проблема.
Я не думал, что такое кто-то делает в 2018.
A>Проблема возникает при завершении хост приложения. Хост приложение ничего не знает о том, что были запросы WM_GETOBJECT и есть живые объекты из dll, и может выгрузить dll, а лишь затем вызвать OleUninitialize. Соответственно при OleUninitialize, когда вызывается последний Release объекта, происходит AV.
A>Вопрос – как то можно это исправить в самой dll?
Может хранить референс на DLL в объекте?
GetModuleHandleEx со своим адресом с GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS и без GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT для первого AddRef
FreeLibrary для последнего Release
Здравствуйте, Alexander G, Вы писали:
AG>Я не думал, что такое кто-то делает в 2018.
Ключевое — "Что бы изучить получше оконную систему Windows".
AG>FreeLibrary для последнего Release
В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.
Re[2]: Запрет выгрузки dll до момента освобождения последнего о
MA>А вот в мсдн пишут, что можно вроде просто вызвать UiaReturnRawElementProvider
Имею AV внутри UiaReturnRawElementProvider. Возможно, эта функция предназначена для тех, кто реализует полноценный UI Automation, я же реализую только Microsoft Active Accessibility.
Re[3]: Запрет выгрузки dll до момента освобождения последнего о
Здравствуйте, Aniskin, Вы писали:
A>Имею AV внутри UiaReturnRawElementProvider. Возможно, эта функция предназначена для тех, кто реализует полноценный UI Automation, я же реализую только Microsoft Active Accessibility.
Понятно.
Тогда я бы смотрел в сторону NotifyWinEvent EVENT_OBJECT_DESTROY или как-то убедится, что это событие приходит. В любом случае трюки с FreeLibrary кажутся здесь неуместными, т.к. оно как-то должно делаться и без них. (Подозрение)
Re[4]: Запрет выгрузки dll до момента освобождения последнего о
MA>Тогда я бы смотрел в сторону NotifyWinEvent EVENT_OBJECT_DESTROY или как-то убедится, что это событие приходит.
Про EVENT_OBJECT_DESTROY пишут следующее: An object has been destroyed. The system sends this event for the following user interface elements: ... and window object. Т.е. система самостоятельно посылает это сообщение при уничтожении окна.
Re[5]: Запрет выгрузки dll до момента освобождения последнего о
Здравствуйте, Aniskin, Вы писали:
A>Про EVENT_OBJECT_DESTROY пишут следующее: An object has been destroyed. The system sends this event for the following user interface elements: ... and window object. Т.е. система самостоятельно посылает это сообщение при уничтожении окна.
А посылает? Я так понимаю, она его посылает из DefWindowProc, который можно и не вызывать в своем контроле. Я не знаю. Просто как идея.
Там где-то между буквами у них пишут, что это обязанность сервера.
Re[6]: Запрет выгрузки dll до момента освобождения последнего о
Я не знаю, я игрался с AccEvent.exe, но не смог добиться того, что бы он хотя бы для обычных окон показывал create/destroy события.
MA>Я так понимаю, она его посылает из DefWindowProc
WM_DESTROY/WM_NCDESTROY я посылаю в DefWindowProc. Ну, и не исключено, что EVENT_OBJECT_DESTROY может посылаться и из DestroyWindow.
Re: Запрет выгрузки dll до момента освобождения последнего объекта из dll
Здравствуйте, Aniskin, Вы писали:
A>В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.
Тогда классический костыль с запуском потока, который вызовет FreeLibraryAndExitThread?
Русский военный корабль идёт ко дну!
Re[2]: Запрет выгрузки dll до момента освобождения последнего объекта из dll
MA>Другая идея — вызывать CoDisconnectObject тоже на WM_DESTROY.
Проблема в том, что после LresultFromObject я освобождаю свой объект и более не владею ссылкой на него. Т.е. на каждый WM_GETOBJECT я создаю отдельный экземпляр IAccessible. Причине в том, что помимо IAccessible я еще реализую IEnumVARIANT, которую система использует для перечисления детей. Если я буду отдавать кэшированный IAccessible, т.е. существует вероятность, что два клиента будут одновременно перечислять детей, и внутренний счетчик будут некорректен.
Re[4]: Запрет выгрузки dll до момента освобождения последнего о
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, Aniskin, Вы писали:
A>>В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.
AG>Тогда классический костыль с запуском потока, который вызовет FreeLibraryAndExitThread?
Та же проблема. FreeLibraryAndExitThread должен быть гарантированно вызван после того, как последний Release отработал и произошел выход из него.
Re[5]: Запрет выгрузки dll до момента освобождения последнего о
Здравствуйте, Aniskin, Вы писали:
A>Та же проблема. FreeLibraryAndExitThread должен быть гарантированно вызван после того, как последний Release отработал и произошел выход из него.
Ох, да.
Кажется, есть идея с ассемблерной вставкой. Не то, чтобы чистое решение, но может, прокатит.
Сделать, чтобы вызов FreeLibrary был хвостовым.
(Нам всё равно, что вернёт IUnknown::Release(), это ведь чисто отладочная информация)
Здравствуйте, Aniskin, Вы писали:
A>... Проблема возникает при завершении хост приложения. Хост приложение ничего не знает о том, что были запросы WM_GETOBJECT и есть живые объекты из dll, и может выгрузить dll, а лишь затем вызвать OleUninitialize. Соответственно при OleUninitialize, когда вызывается последний Release объекта, происходит AV.
A>Вопрос – как то можно это исправить в самой dll?
Как то вы с ononim мыслите одинаково Оба прошли в этом топике практически один и тот же путь (просто FreeLibrary в Release/поток с FreeLibraryAndExitThread/асм) и оба в конечном итоге пришли к одному и тому же решению на ассемблере
Идея мне нравиться, планирую ее реализовать (правда, последний раз писал на ассемблере 20 лет назад, и это был ассемблер Z80).
Re[2]: Запрет выгрузки dll до момента освобождения последнего объекта из dll
A>Как то вы с ononim мыслите одинаково Оба прошли в этом топике практически один и тот же путь (просто FreeLibrary в Release/поток с FreeLibraryAndExitThread/асм) и оба в конечном итоге пришли к одному и тому же решению на ассемблере
Я не в этом топике прошел этот путь. Я это реализовывал в продакшене
Как много веселых ребят, и все делают велосипед...
Re: Запрет выгрузки dll до момента освобождения последнего объекта из dll
Здравствуйте, Aniskin, Вы писали:
A>Вопрос – как то можно это исправить в самой dll?
Я так понял, что DLL загружается минуя COM и тебе нужно чтобы COM начал опрашивать DllCanUnloadNow после того как ты из неё вернул COM-объект.
Точно уже не помню, но по-моему в COM таки есть функция, которой подсовывают HINSTANCE уже загруженной DLL, чтобы он включил её в список загруженных COM-серверов процесса.
Я несколько раз видел упоминание (или даже описание) такой функции. Так что покопайся в этом направлении. Может найдешь её
Если тут уже такое предложили, то звиняйте
-- Пользователи не приняли программу. Всех пришлось уничтожить. --