(не постоянно) "западает" модальное окно, в видимости остается главная форма MainForm, а модального окна ModalForm не видно.
Отлавливаю WM_ACTIVATE разные.
Как это происходит у меня на компьютере: при показывании модального окна ModalForm.ShowModal сначала приходит WM_ACTIVATE(0, ...) главной форме, что она потеряла активность, потом модальной форме приходит WM_ACTIVATE(1, ...) что она получила активность. Всё. Больше WM_ACTIVATE нету.
Как это происходит у клиента, когда баг НЕ воспроизводится: сначала приходит WM_ACTIVATE(0, ...) главной форме, что она потеряла активность, потом модальной форме приходит WM_ACTIVATE(1, ...) что она получила активность, буквально через 100 мс активность переходит на TApplication окно, потом возвращается на модальное окно, баг не визуализируется.
Уже странно, почему есть это перепрыгивание фокуса на TApplication и обратно (а у меня нет).
Как это происходит у клиента, когда баг воспроизводится: сначала приходит WM_ACTIVATE(0, ...) главной форме, что она потеряла активность, потом модальной форме приходит WM_ACTIVATE(1, ...) что она получила активность, буквально через 100 мс активность переходит на MainForm (!!!), баг визуализируется. Вместо модального окна видно главную форму (которая зависла конечно как бы). Если кликнуть на приложение в панели задач - то всплывает и начинает визуализироваться модальное окно.
Почему ТАКОЕ может происходить? Есть подозрение, что все это происходит на достаточно слабых и тормозных компьютерах, но это только предположение.
Кто-нибудь может хотя бы предположить что происходит?
linux ?
windows
Стикер
ХР? У меня на ней только такие глюки бывали. ЕМНИП, на скруле этот вопрос поднимался. Выше ссылка на форум от @nikron79 была, можно поискать
там от версии Делфи зависит, они несколько лет назад сильно переписали весь этот механизм
Надо, но как Я вижу что приходит сообщение от винды, но я же не знаю что послужило этому
И на win 10 повторяется
с какой стати винда будет посылать твоему окну ACTIVATE ? проблема у тебя
Что значит с какой, винда так работает, рассылает всем сообщения о происходящих событиях
каких событиях? я имел ввиду повторную посылку
попробуй у модальной формы установить PopupParent := главная форма
Я еще давно с похожей хренью сталкивался, но не помню уже решение. Вроде был какой-то VclFix или что-то вроде. Но я потом сделал проще и лучше - отказался от модальных форм.
А подробностей нет?..
Были проблемы с формами из dll, решается передачей в dll дескриптора Application и главной формы. Только перед закрытием dll нужно дескриптор вернуть как было.
Ну тут фокусов быть не может. Нужно трамплином встать на SetWindowPos причем не в таблице импорта а на точке входа и прологировать, желательно со стеком вызова откуда она дергается. Только там и можно будет понять откуда идет паразитная передача фокуса с модалки на левое окно. Скорее всего используется какой-то левый контрол на модалке, который криво написан который лезет к Application и неявно активирует либо его либо главное окно. Пример трамплина можешь взять из примеров к статье о его применении (в архиве пример к шестой главе): https://rouse.drkb.ru/winapi.php#splice2
А ты уверен что SetWindowPos, остальные апи вызывают его? Поэтому и трамплин на точку входа?
Ну все такие функции (SetWindowPos/BringWindowToTop/) вызывают NtUserSetWindowPos, но на ней будет много ненужных старатываний.
А почему тогда именно SetWindowPos рекомендуешь? Если вдруг "вредоносный" код вызывает BringToFront или типа того? Или не может этого быть?
Потому что VCL использует SetWindowPos
что-то фейл... Воспользовался примером из "4. Вызов перехваченной функции без снятия кода перехвата" Перехватываю InitHotPatchSpliceRec(user32, 'SetWindowPos', @InterceptedSetWindowPos, HotPathSpliceRec); SpliceNearJmp(PAnsiChar(HotPathSpliceRec.FuncAddr) - NearJmpSpliceRecSize, HotPathSpliceRec.SpliceRec); SpliceLockJmp(HotPathSpliceRec.FuncAddr, LOCK_JMP_OPKODE); когда вызываю оригинальную: @ASetWindowPos := PAnsiChar(HotPathSpliceRec.FuncAddr) + LockJmpOpcodeSize; Result := ASetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags); то попадаю на первый скрин там переход jmp dword ptr [$7670ab5c] попадаю на второй скриншот Потом на третий, далее на четвертый и там уже хана :(
не работает (( Делаю: OrigAddr := GetProcAddress(GetModuleHandle(user32), 'SetWindowPos'); ReplaceIATEntry(OrigAddr, @InterceptedSetWindowPos); дальше в ReplaceIATEntry ImageBase := GetModuleHandle(user32); в результате в цикле Pointer(Thunk^._function) = OldProc не выполняется, не находит...
Ну потому что ты ищешь адрес в своей таблице импорта, причем не той функции. SetWindowPos это шлюз на win32u.NtUserSetWindowPos через таблицу импорта поэтому искать надо вот так OrigAddr := GetProcAddress(GetModuleHandle('win32u.dll'), 'NtUserSetWindowPos');
все заработало, спасибо! 🥳🙏
Ну а кто сказал что будет легко? Если разбираешся там конечно нет ничего сложного, но если нет - то повозиться конечно придется капитально чтобы понять что за чем идет и как это всё связано друг с другом
Ну нет бы единообразно, а то эта функция подходит для hotpatch, а эта вот нет, по другому сделано...
Ты кстати пишешь в статье что с вин64 не разбирался, а сейчас уже разобрался? вы перешли на 64 бита или для всего хватает 32 бита?
А, ты про это... ну да - тут нужно следить что подходит а что нет. Но с учетом что это чисто отладочный метод и его крайне не желательно применять в боевом приложении, то в таких случаях быстрее просто глазками посмотреть на реализацию и выбрать нужный тип перехвата
Ну разобрался, но там тоже есть нюансы, не все применительное к перехвату в 32 битах подойдет для применения в 64 битах.
Эээ... Если я правильно понял, просто не хватает 32 битов для указания своей точки входа?
Да, поэтому там приходится извращаться
Хм, странно зачем так сделали... Совместимость? И винда знает что все ее библиотеки точно влезут в диапазон 4гб?
Они гарантированно туда не влезут, им это и не надо т.к. нам RVA оффсеты и они в 64 биитах не совсем приспособлены под перехват
Обсуждают сегодня