19.04.2011, 15:08 | #1 |
Участник
|
(Не)перерисовка окна клиента AX 2009 при длительных операциях - вариант решения
Помнится, давным-давно был описан косяк 2009-й, касающийся перерисовки окна клиента при длительных операциях:
Цитата:
Сообщение от mazzy
1. ax2009 (проверялись беты, релиз и sp1)
2. windows vista business sp1 (проверялось и без sp1) 3. выполняется какой-нибудь длительный процесс (например, обновление перекрестных ссылок) 4. некоторое время окно с прогресс-баром обновляется нормально 5. потом окно замирает, принимает характерный "сжатый" вид (см. скриншот) и больше не обновляется (не перерисовывается) Цитата:
One reason for running into this issue can be if the Windows Operating System is replacing the Dynamics AX application window by a ghost window. When Dynamics AX starts a lengthy COM operation, it is not responding to messages sent by the Windows Operating System in time. So Windows supposes Dynamics AX has stopped responding. When this happens the Dynamics AX application window is replaced by a ghost window until Dynamics AX resumes. Window ghosting is a nice feature that allows the user to minimize, move or close the main window even if the application is not responding. You can easily identify a ghost window as it shows (Not responding) in the window title. Unfortunately the replacement of the Dynamics AX application window by the ghost window can interfere the COM operation and result in the above error message.
Собственно, кроме предлагаемого в блоге запуска клиента AX 2009 в режиме совместимости с WinXP SP2 схожего эффекта можно добиться средствами приложения - добавить новый метод в класс WinAPI X++: /// <summary> /// Call user32.DisableProcessWindowsGhosting /// </summary> /// <remarks> /// Disables the window ghosting feature for the calling GUI process. Window ghosting is a Windows Manager feature /// that lets the user minimize, move, or close the main window of an application that is not responding. /// </remarks> public static client void disableProcessWindowsGhosting() { DLL dll = new DLL( #UserDLL ); DLLFunction dllFunc = new DLLFunction( dll, @"DisableProcessWindowsGhosting" ); ; dllFunc.returns( ExtTypes::void ); dllFunc.arg(); dllFunc.call(); } X++: /* No SYS code must exist in this method */ void startupPost() { if (clientKind() == ClientType::Client) { // BP deviation documented WinAPI::disableProcessWindowsGhosting(); } } |
|
|
За это сообщение автора поблагодарили: mazzy (5), KiselevSA (5), db (4), sukhanchik (7), Logger (15), Ivanhoe (5), MikeR (9), S.Kuskov (5), someOne (3), mikki_messer (1), Veter (1). |
19.04.2011, 16:59 | #2 |
Участник
|
О! Здорово.
Теперь сможем увидеть нормальный прогресс бар. |
|
19.04.2011, 17:00 | #3 |
Участник
|
Самое интересное что запись в блоге датирована 18 Jun 2009 9:33 AM
Т.е. давно об этом известно и понятно как лечить, но в MS всем пофиг. Ядро так и не пофиксено. Просто нет слов ... |
|
19.04.2011, 19:39 | #4 |
Участник
|
мне кажется, что в ax2009 лучше в info.workspaceWindowCreated()
|
|
19.04.2011, 20:15 | #5 |
Участник
|
Насколько я могу судить из описания DisableProcessWindowsGhosting(), она выставляет некий флаг, действующий впоследствии на все окна вызывающего процесса. Все рабочие области создаются в рамках одного процесса ax32.exe, поэтому должно быть достаточно вызвать функцию один раз при запуске клиента.
|
|
09.03.2018, 00:55 | #6 |
Участник
|
Цитата:
Но. Он отрубает современные механизмы управления приложением со стороны менеджера приложений виндов. Пользователи видят, что окно не закрывается и не минимизируется, не перемещается мышкой - оно не живое. И так далее. Давно хотелось найти более изящный способ. Предлагаю попробовать такой способ решения для 2009:
Суть проблемы:
метод disableProcessWindowsGhosting отрубает всю магию по работе с неотвечающим приложением. кроме того, этот метод не решает главную проблему - очередь сообщений остается переполненной. со всеми вытекающими последствиями от пропущенных виндовых сообщений. современные практики программирования предполагают, что у каждого приложения есть основной поток, в котором крутится только пользовательский интерфейс, а вся реальная работа должна выполняться в отдельных потоках. но эта рекомендация не для старых приложений, которые были созданы в допотопные однопроцессорные времена. в чем состоит мое предложение: 0. в длинные обработки в аксапте принято вставлять инфолог для пользователя. 1. в штатном режиме инфолог обновляет свое окошко не чаще 1 раза в секунду 2. давайте добавим вызов метода, который при обновлении окна позволит приложению обработать очередь системных виндовых сообщений. Насколько я понимаю происходящее в аксапте - это метод infolog.yield() 3. если ваша обработка не использует стандартный фреймворк, то расставьте infolog.yield() в своем коде так, чтобы он срабатывал не реже чем раз с 3-5 секунд. ===================== пожалуйста, протестируйте на ваших системах. на windows 10 работает неплохо. также, если не сложно, обратите внимание ощущаете ли вы замедления/тормоза в работе приложения из-за добавленного infolog.yield? ===================== добавлено 02.08.2020 в целом работает неплохо. есть один звоночек о побочном эффекте (сам не видел): если добавить infolog.yield в метод update, то пользователь может получить доступ к интерфейсу аксапты пока работает код. главное, что пользователь может сменить текущую компанию пока работает код обработки. скорее всего, стоит добавить "стража" в окно где пользователь может менять компанию. Последний раз редактировалось mazzy; 02.08.2020 в 10:35. |
|
|
За это сообщение автора поблагодарили: raz (5), Ace of Database (3), kitty (1), alex55 (3), Corel (1), Logger (5). |
09.03.2018, 15:19 | #7 |
Участник
|
Интересно.
А где то есть внятное описание, что же все таки делает infolog.yield() ? |
|
09.03.2018, 17:42 | #8 |
Участник
|
подозреваю, что в недрах документации самой java.
https://docs.oracle.com/javase/7/doc...ng/Thread.html https://stackoverflow.com/questions/...oin-and-interr https://habrahabr.ru/post/164487/ http://www.quizful.net/interview/jav...ait-difference поиск на страницах по ключевому слову yield. Цитата:
yield() имеет довольно туманный контракт, он останавливает поток и говорит шедулеру, чтобы тот пропустил вперед другие потоки, и насколько можно верить интернету, то что он на самом деле делает зависит не только от операционки, но и от версии jvm. Если кратко, то "дам-ка я соседям подышать"
я видел в комментариях в ax2012 (см. скриншот) ========================= кстати, в ax2012 способ "добавить infolog.yield()" тоже работает. оказывается в стандартной 2012 "улучшили" только активное окно, а главное окно с самой аксаптой по-прежнему остается в статусе "не работает" а с добавленным infolog.yield() и главное окно, и все подчиненные аксапте остаются вполне живыми. Последний раз редактировалось mazzy; 09.03.2018 в 17:46. |
|
|
За это сообщение автора поблагодарили: Logger (5). |
12.06.2018, 15:08 | #9 |
Участник
|
|
|
21.02.2019, 19:34 | #10 |
Участник
|
|
|
22.02.2019, 15:11 | #11 |
Участник
|
Я решал данную ситуацию проще, - нажимал ctrl + break. Потом отмена и еще 3-4 минуты можно видеть актуальный progress bar.
|
|
26.02.2019, 18:32 | #12 |
Участник
|
Печалька.
А в 4-ке нет метода xInfo.yield() Можно как-то по другому очередь сообщений очистить ? |
|
27.02.2019, 15:03 | #13 |
Участник
|
Коллега придумал вариант для 4-ки.
Он универсальный и подходит для ax 3.0 - 2012 И мне нравится больше чем вариант с infolog.yield() Делаем в global пару методов X++: // Для предотвращения создания операционкой окна-призрака поверх окна клиента АХ // что выглядит как повисание системы, даже если в это время идет перерисовка прогресса // Данную функцию следует вызывать не реже чем #TimeInterval секунд (объявлено в preventWindowsGhostingClient_MRC()) // JEV003298 "Оптимизация работы отчета "Остатки в открытом заказе (расширенный)"", shai 26.02.2019 public static void preventWindowsGhosting_MRC() { ; if (hasGUI()) { preventWindowsGhostingClient_MRC(); } } X++: // JEV003298 "Оптимизация работы отчета "Остатки в открытом заказе (расширенный)"", shai 26.02.2019 client private static void preventWindowsGhostingClient_MRC() { Binary message; DLL winApiDLL; DLLFunction peekMessage; Struct cachedData; SysGlobalCache globalCache; timeOfDay lastTime; timeOfDay newTime; #define.DLL("USER32") #define.DLLFunctionPeekMessageA("PeekMessageA") #define.GlobalCacheOwner("Global_preventWindowsGhosting_MRC") #define.messageBinary_30(30) #define.PM_NOREMOVE(0) #define.TimeInterval(2) ; newTime = timenow(); globalCache = infolog.globalCache(); cachedData = globalCache.get(#GlobalCacheOwner, "cachedData", cachedData); if (!cachedData) { winApiDLL = new DLL(#DLL); peekMessage = new DLLFunction(winApiDLL, #DLLFunctionPeekMessageA); peekMessage.arg(ExtTypes::Pointer, ExtTypes::DWord, ExtTypes::DWord, ExtTypes::DWord, ExtTypes::DWord); message = new Binary(#messageBinary_30); cachedData = new Struct(); cachedData.add("lastTime", -#TimeInterval - 1); cachedData.add("peekMessage", peekMessage); cachedData.add("messageBuf", message); globalCache.set(#GlobalCacheOwner, "cachedData", cachedData); } lastTime = cachedData.value("lastTime"); if (abs(newTime - lastTime) > #TimeInterval) { peekMessage = cachedData.value("peekMessage"); message = cachedData.value("messageBuf"); peekMessage.call(message, 0, 0, 0, #PM_NOREMOVE); cachedData.value("lastTime", newTime); globalCache.set(#GlobalCacheOwner, "cachedData", cachedData); } } делаем так X++: ... } // JEV003298 "Оптимизация работы отчета "Остатки в открытом заказе (расширенный)"", shai 27.02.2019 --> preventWindowsGhosting_MRC(); // JEV003298 "Оптимизация работы отчета "Остатки в открытом заказе (расширенный)"", shai 27.02.2019 <-- if (conlen(progress)) { t1 = WinAPI::getTickCount(); this.sendProgress(progress); if ((WinAPI::getTickCount() - t1)/*milliseconds*/ div 100 >= updateInterval /*seconds*/) updateInterval++; } this.updateTime(); } } } Последний раз редактировалось Logger; 27.02.2019 в 15:08. |
|
|
За это сообщение автора поблагодарили: gl00mie (3). |
Теги |
ax2009, peekmessagea, vista, yield, баг, законченный пример, окно, ошибка, полезное, прогресс |
|
|