AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 19.04.2011, 15:08   #1  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Lightbulb (Не)перерисовка окна клиента AX 2009 при длительных операциях - вариант решения
Помнится, давным-давно был описан косяк 2009-й, касающийся перерисовки окна клиента при длительных операциях:
Цитата:
Сообщение от mazzy Посмотреть сообщение
1. ax2009 (проверялись беты, релиз и sp1)
2. windows vista business sp1 (проверялось и без sp1)
3. выполняется какой-нибудь длительный процесс (например, обновление перекрестных ссылок)
4. некоторое время окно с прогресс-баром обновляется нормально
5. потом окно замирает, принимает характерный "сжатый" вид (см. скриншот) и больше не обновляется (не перерисовывается)
Как вариант, окно может "покрываться пеленой" и также переставать отрисовываться. Совершенно случайно было, кажется, найдено решение этой проблемы в блоге EMEA Dynamics AX Support:
Цитата:
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.
Да, на первый взгляд может показаться, что эта тема скорее ближе к обсуждениям вроде Ошибка времени выполнения в ComExcelDocument_RU.findRange(), но из моего скромного опыта описанное в блоге - лишь одна из возможных причин, и отключение Windows Ghosting не решает проблему взаимодействия с COM-объектами полностью, а вот перерисовку лечит!
Собственно, кроме предлагаемого в блоге запуска клиента 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();
}
и добавить вызов этого метода, скажем, в info.startupPost():
X++:
/*
No SYS code must exist in this method
*/
void startupPost()
{
    if (clientKind() == ClientType::Client)
    {
        // BP deviation documented
        WinAPI::disableProcessWindowsGhosting();
    }
}
Как минимум в ядре WinXP SP3 и Windows Server 2003 SP2 функция DisableProcessWindowsGhosting() есть, так что приведенный код можно использовать относительно безопасно в тех случаях, когда клиент AX 2009 запускается на WinXP и выше.
За это сообщение автора поблагодарили: 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  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
О! Здорово.
Теперь сможем увидеть нормальный прогресс бар.
Старый 19.04.2011, 17:00   #3  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Самое интересное что запись в блоге датирована 18 Jun 2009 9:33 AM
Т.е. давно об этом известно и понятно как лечить, но в MS всем пофиг. Ядро так и не пофиксено.

Просто нет слов ...
Старый 19.04.2011, 19:39   #4  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от gl00mie Посмотреть сообщение
и добавить вызов этого метода, скажем, в info.startupPost():
мне кажется, что в ax2009 лучше в info.workspaceWindowCreated()
__________________
полезное на axForum, github, vk, coub.
Старый 19.04.2011, 20:15   #5  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5798 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Насколько я могу судить из описания DisableProcessWindowsGhosting(), она выставляет некий флаг, действующий впоследствии на все окна вызывающего процесса. Все рабочие области создаются в рамках одного процесса ax32.exe, поэтому должно быть достаточно вызвать функцию один раз при запуске клиента.
Старый 09.03.2018, 00:55   #6  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от gl00mie Посмотреть сообщение
и отключение Windows Ghosting не решает проблему взаимодействия с COM-объектами полностью, а вот перерисовку лечит!
Во-первых, спасибо gl00mie - способ действенный и давно многими используемый.

Но. Он отрубает современные механизмы управления приложением со стороны менеджера приложений виндов.
Пользователи видят, что окно не закрывается и не минимизируется, не перемещается мышкой - оно не живое. И так далее.
Давно хотелось найти более изящный способ.

Предлагаю попробовать такой способ решения для 2009:
  1. убрать WinAPI::disableProcessWindowsGhosting();
  2. добавить вызов infolog.yield(); почти в конец метода SysOperationProgressBase.update()
  3. в обработках и длительных операциях на клиенте, которые НЕ используют фреймворк SysOperationProgress расставить infolog.yield();

Суть проблемы:
  • в виндах весь пользовательский интерфейс работает с сообщениями
  • (почти) у каждого окна есть своя очередь сообщений
  • по историческим причинам длина очереди ограничена размером 10000 сообщений (когда-то это казалось огромным числом)
  • если главный поток приложения не разгребает очередь, то в современных виндах очередь очень быстро (за 3-5 секунд) заполняется и переполняется
  • окна с переполненной очередью сообщений, винда помечает признаком "Не отвечает" и включает "магию" для зависших приложений. Магия была разной в разных версиях виндов. С современных виндах старая магия скорее мешает пользователям нежели помогает, а вот современная магия вроде ничё так.

метод disableProcessWindowsGhosting отрубает всю магию по работе с неотвечающим приложением. кроме того, этот метод не решает главную проблему - очередь сообщений остается переполненной. со всеми вытекающими последствиями от пропущенных виндовых сообщений.

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

в чем состоит мое предложение:

0. в длинные обработки в аксапте принято вставлять инфолог для пользователя.
1. в штатном режиме инфолог обновляет свое окошко не чаще 1 раза в секунду
2. давайте добавим вызов метода, который при обновлении окна позволит приложению обработать очередь системных виндовых сообщений. Насколько я понимаю происходящее в аксапте - это метод infolog.yield()
3. если ваша обработка не использует стандартный фреймворк, то расставьте infolog.yield() в своем коде так, чтобы он срабатывал не реже чем раз с 3-5 секунд.

=====================
пожалуйста, протестируйте на ваших системах.
на windows 10 работает неплохо.

также, если не сложно, обратите внимание ощущаете ли вы замедления/тормоза в работе приложения из-за добавленного infolog.yield?

=====================
добавлено 02.08.2020

в целом работает неплохо.
есть один звоночек о побочном эффекте (сам не видел):

если добавить infolog.yield в метод update,
то пользователь может получить доступ к интерфейсу аксапты пока работает код.
главное, что пользователь может сменить текущую компанию пока работает код обработки.
скорее всего, стоит добавить "стража" в окно где пользователь может менять компанию.
Миниатюры
Нажмите на изображение для увеличения
Название: ax2009-update.PNG
Просмотров: 541
Размер:	79.5 Кб
ID:	11848  
__________________
полезное на axForum, github, vk, coub.

Последний раз редактировалось 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  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Интересно.
А где то есть внятное описание, что же все таки делает infolog.yield() ?
Старый 09.03.2018, 17:42   #8  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
подозреваю, что в недрах документации самой 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() и главное окно, и все подчиненные аксапте остаются вполне живыми.
Миниатюры
Нажмите на изображение для увеличения
Название: 1.PNG
Просмотров: 479
Размер:	78.0 Кб
ID:	11849  
__________________
полезное на axForum, github, vk, coub.

Последний раз редактировалось mazzy; 09.03.2018 в 17:46.
За это сообщение автора поблагодарили: Logger (5).
Старый 12.06.2018, 15:08   #9  
kia is offline
kia
Участник
 
96 / 19 (1) ++
Регистрация: 07.10.2008
Адрес: Харьков
Цитата:
Сообщение от mazzy Посмотреть сообщение
с добавленным infolog.yield() и главное окно, и все подчиненные аксапте остаются вполне живыми.
Если исправленный прогрессбар в отчете, то можно продолжать работать.
НО форма прогрессбара тоже обрабатывает сообщения и закрывается по Esc, а отчет продолжает выполняться
Старый 21.02.2019, 19:34   #10  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от mazzy Посмотреть сообщение
=====================
пожалуйста, протестируйте на ваших системах.
на windows 10 работает неплохо.
В указанном примере код может исполняться и на сервере. Нужен ли тогда там вызов yield() ? Вероятно, лучше перенести его на клиентскую часть кода.
Старый 22.02.2019, 15:11   #11  
NetBus is offline
NetBus
Участник
 
200 / 85 (3) ++++
Регистрация: 08.07.2005
Адрес: Москва
Я решал данную ситуацию проще, - нажимал ctrl + break. Потом отмена и еще 3-4 минуты можно видеть актуальный progress bar.
Старый 26.02.2019, 18:32   #12  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Печалька.
А в 4-ке нет метода xInfo.yield()
Можно как-то по другому очередь сообщений очистить ?
Старый 27.02.2019, 15:03   #13  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,952 / 3230 (115) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Коллега придумал вариант для 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);
    }
}
Затем в \Classes\SysOperationProgressBase\update
делаем так
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();
        }
    }
}
P.S. При таком способе на Ctrl-break реагирует сразу, т.е. система стала более отзывчивой. Раньше из-за WindowsGhosting могло игнорировать.

Последний раз редактировалось Logger; 27.02.2019 в 15:08.
За это сообщение автора поблагодарили: gl00mie (3).
Теги
ax2009, peekmessagea, vista, yield, баг, законченный пример, окно, ошибка, полезное, прогресс

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
daxdilip: Whats New in Dynamics AX 2012 (A brief extract from the recently held Tech Conf.) Blog bot DAX Blogs 7 31.01.2011 12:35
mbsturk: Ax 2009 Rollup 4 Version Checker Blog bot DAX Blogs 0 29.04.2010 17:05
Ошибка в логе при установке клиента AX 2009 sao DAX: Администрирование 9 04.02.2010 11:56
JOPX: Why Microsoft Dynamics AX 2009 might interest SharePoint developers ... Blog bot DAX Blogs 0 21.08.2008 01:05
Dynamics AX: Dynamics AX 2009 & SQL Server 2008 Blog bot DAX Blogs 0 10.06.2008 21:08

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 10:45.