Re[12]: Запрет выгрузки dll до момента освобождения последнег
От: Aniskin  
Дата: 26.10.18 18:27
Оценка:
O>У решения с LoadLib/FreeLib с внутренне-отложенной обработкой выгрузки есть неявное усложнение: FreeLib _не_ гарантирует реальной выгрузки либы сейчас. Соответственно если вызывателю FreeLib реально нужна (чтоб удалить файл?) то таким образом рождается фундаментальный гейзенбаг.

Мне в принципе не нужна гарантия того, что FreeLib точно выгрузит dll. Мне нужно в конечном итоге только то, что бы у dll был простой контракт на использование — 1) LoadLib, 2) UseLib, 3) FreeLib. Без всяких "FreeLib можно только по вторникам".

O>А если FreeLib ему реально не нужна — почему бы не заморозить либу в АП процесса до его завершения?


Можно и так, но этому противится мой внутренний перфекционист. Если можно сделать по нормальному, то почему бы и не сделать.
Re: Запрет выгрузки dll до момента освобождения последнего о
От: Alexander G Украина  
Дата: 26.10.18 18:41
Оценка:
Здравствуйте, 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
Русский военный корабль идёт ко дну!
Отредактировано 26.10.2018 18:44 Alexander G . Предыдущая версия .
Re: Запрет выгрузки dll до момента освобождения последнего о
От: Mystic Artifact  
Дата: 26.10.18 18:47
Оценка:
Здравствуйте, Aniskin, Вы писали:

А вот в мсдн пишут, что можно вроде просто вызвать
UiaReturnRawElementProvider(hwnd, 0, 0, NULL)
— врут? (Где-нибудь в WM_DESTROY).
Отредактировано 26.10.2018 18:50 Mystic Artifact . Предыдущая версия .
Re[2]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 26.10.18 18:48
Оценка: 1 (1)
Здравствуйте, Alexander G, Вы писали:

AG>Я не думал, что такое кто-то делает в 2018.


Ключевое — "Что бы изучить получше оконную систему Windows".

AG>FreeLibrary для последнего Release


В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.
Re[2]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 26.10.18 18:58
Оценка:
Здравствуйте, Mystic Artifact, Вы писали:

MA>можно вроде просто вызвать UiaReturnRawElementProvider(hwnd, 0, 0, NULL)


Надо проверить.
Re[2]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 26.10.18 19:58
Оценка:
MA>А вот в мсдн пишут, что можно вроде просто вызвать UiaReturnRawElementProvider

Имею AV внутри UiaReturnRawElementProvider. Возможно, эта функция предназначена для тех, кто реализует полноценный UI Automation, я же реализую только Microsoft Active Accessibility.
Re[3]: Запрет выгрузки dll до момента освобождения последнего о
От: Mystic Artifact  
Дата: 26.10.18 20:25
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Имею AV внутри UiaReturnRawElementProvider. Возможно, эта функция предназначена для тех, кто реализует полноценный UI Automation, я же реализую только Microsoft Active Accessibility.


Понятно.

Тогда я бы смотрел в сторону NotifyWinEvent EVENT_OBJECT_DESTROY или как-то убедится, что это событие приходит. В любом случае трюки с FreeLibrary кажутся здесь неуместными, т.к. оно как-то должно делаться и без них. (Подозрение)
Re[4]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 26.10.18 20:30
Оценка:
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 до момента освобождения последнего о
От: Mystic Artifact  
Дата: 26.10.18 20:41
Оценка:
Здравствуйте, 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 до момента освобождения последнего о
От: Aniskin  
Дата: 26.10.18 21:07
Оценка:
MA>А посылает?

Я не знаю, я игрался с AccEvent.exe, но не смог добиться того, что бы он хотя бы для обычных окон показывал create/destroy события.

MA>Я так понимаю, она его посылает из DefWindowProc


WM_DESTROY/WM_NCDESTROY я посылаю в DefWindowProc. Ну, и не исключено, что EVENT_OBJECT_DESTROY может посылаться и из DestroyWindow.
Re: Запрет выгрузки dll до момента освобождения последнего объекта из dll
От: Mystic Artifact  
Дата: 27.10.18 05:55
Оценка:
Здравствуйте, Aniskin, Вы писали:

Другая идея — вызывать CoDisconnectObject тоже на WM_DESTROY.
Re[3]: Запрет выгрузки dll до момента освобождения последнего о
От: Alexander G Украина  
Дата: 27.10.18 16:05
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.


Тогда классический костыль с запуском потока, который вызовет FreeLibraryAndExitThread?
Русский военный корабль идёт ко дну!
Re[2]: Запрет выгрузки dll до момента освобождения последнего объекта из dll
От: Aniskin  
Дата: 27.10.18 16:25
Оценка:
MA>Другая идея — вызывать CoDisconnectObject тоже на WM_DESTROY.

Проблема в том, что после LresultFromObject я освобождаю свой объект и более не владею ссылкой на него. Т.е. на каждый WM_GETOBJECT я создаю отдельный экземпляр IAccessible. Причине в том, что помимо IAccessible я еще реализую IEnumVARIANT, которую система использует для перечисления детей. Если я буду отдавать кэшированный IAccessible, т.е. существует вероятность, что два клиента будут одновременно перечислять детей, и внутренний счетчик будут некорректен.
Re[4]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 27.10.18 16:26
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, Aniskin, Вы писали:


A>>В этом и состоит вся проблема. Если я вызываю в последнем Release FreeLibrary, то FreeLibrary, отработав свою работу, вернется обратно в мой Release, который находится в адресном пространстве моей выгруженной dll.


AG>Тогда классический костыль с запуском потока, который вызовет FreeLibraryAndExitThread?


Та же проблема. FreeLibraryAndExitThread должен быть гарантированно вызван после того, как последний Release отработал и произошел выход из него.
Re[5]: Запрет выгрузки dll до момента освобождения последнего о
От: Alexander G Украина  
Дата: 27.10.18 16:42
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Та же проблема. FreeLibraryAndExitThread должен быть гарантированно вызван после того, как последний Release отработал и произошел выход из него.


Ох, да.
Кажется, есть идея с ассемблерной вставкой. Не то, чтобы чистое решение, но может, прокатит.
Сделать, чтобы вызов FreeLibrary был хвостовым.
(Нам всё равно, что вернёт IUnknown::Release(), это ведь чисто отладочная информация)

ULONG UiAutomationImpl::Release()
{
  ...
  PUSH module_handle
  JMP FreeLibrary // вернёт уже вызвавшему Release
}
Русский военный корабль идёт ко дну!
Re: Запрет выгрузки dll до момента освобождения последнего объекта из dll
От: Vi2 Удмуртия http://www.adem.ru
Дата: 27.10.18 16:55
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>... Проблема возникает при завершении хост приложения. Хост приложение ничего не знает о том, что были запросы WM_GETOBJECT и есть живые объекты из dll, и может выгрузить dll, а лишь затем вызвать OleUninitialize. Соответственно при OleUninitialize, когда вызывается последний Release объекта, происходит AV.


A>Вопрос – как то можно это исправить в самой dll?


Посмотри тут Бага в CoUninitialize, может это твой случай.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Запрет выгрузки dll до момента освобождения последнего о
От: Aniskin  
Дата: 27.10.18 17:23
Оценка:
AG>Кажется, есть идея с ассемблерной вставкой.

Как то вы с ononim мыслите одинаково Оба прошли в этом топике практически один и тот же путь (просто FreeLibrary в Release/поток с FreeLibraryAndExitThread/асм) и оба в конечном итоге пришли к одному и тому же решению на ассемблере

Идея мне нравиться, планирую ее реализовать (правда, последний раз писал на ассемблере 20 лет назад, и это был ассемблер Z80).
Re[2]: Запрет выгрузки dll до момента освобождения последнего объекта из dll
От: Aniskin  
Дата: 27.10.18 17:33
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Посмотри тут Бага в CoUninitialize, может это твой случай.


Нет, к сожалению (к счастью?), не мой.
Re[7]: Запрет выгрузки dll до момента освобождения последнего о
От: ononim  
Дата: 27.10.18 18:42
Оценка:
A>Как то вы с ononim мыслите одинаково Оба прошли в этом топике практически один и тот же путь (просто FreeLibrary в Release/поток с FreeLibraryAndExitThread/асм) и оба в конечном итоге пришли к одному и тому же решению на ассемблере
Я не в этом топике прошел этот путь. Я это реализовывал в продакшене
Как много веселых ребят, и все делают велосипед...
Re: Запрет выгрузки dll до момента освобождения последнего объекта из dll
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.11.18 18:18
Оценка:
Здравствуйте, Aniskin, Вы писали:

A>Вопрос – как то можно это исправить в самой dll?


Я так понял, что DLL загружается минуя COM и тебе нужно чтобы COM начал опрашивать DllCanUnloadNow после того как ты из неё вернул COM-объект.

Точно уже не помню, но по-моему в COM таки есть функция, которой подсовывают HINSTANCE уже загруженной DLL, чтобы он включил её в список загруженных COM-серверов процесса.

Я несколько раз видел упоминание (или даже описание) такой функции. Так что покопайся в этом направлении. Может найдешь её

Если тут уже такое предложили, то звиняйте
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.