Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 21.08.08 16:50
Оценка:
Есть такая задача — мой софт запускает чужой процесс, этот процесс очень громоздкий поэтому запуск длится долго, вдобавок он при запуске обращается к своему серверу, что тоже занимает время, при запуске этот процесс создает несколько окон, одно из которых отображается, как главное окно. Время от старта процесса и до момента когда окно процесса будет готово к работе, проходит от 30 секунд до минуты-двух.

Мне необходимо программно узнать когда процесс закончил загрузку и начал ожидание пользовательского ввода.

Процесс модифицировать нельзя, контролы основного окна судя по всему написаны на VB (имена класса окон начинается на "ThunderRT6", значение Text у окон почемуто не установлено — видимо особенность VB).
Есть мысли попробовать дождаться когда его основное окно начнет выборку сообщений в message pumping loop, но как это лучше сделать?

Как это можно сделать?? Заранее спасибо за помощь
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re: Как дождаться загрузки приложения?
От: Аноним  
Дата: 21.08.08 19:17
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>Есть такая задача — мой софт запускает чужой процесс, этот процесс очень громоздкий поэтому запуск длится долго, вдобавок он при запуске обращается к своему серверу, что тоже занимает время, при запуске этот процесс создает несколько окон, одно из которых отображается, как главное окно. Время от старта процесса и до момента когда окно процесса будет готово к работе, проходит от 30 секунд до минуты-двух.


_M_>Мне необходимо программно узнать когда процесс закончил загрузку и начал ожидание пользовательского ввода.


_M_>Процесс модифицировать нельзя, контролы основного окна судя по всему написаны на VB (имена класса окон начинается на "ThunderRT6", значение Text у окон почемуто не установлено — видимо особенность VB).

_M_>Есть мысли попробовать дождаться когда его основное окно начнет выборку сообщений в message pumping loop, но как это лучше сделать?

_M_>Как это можно сделать?? Заранее спасибо за помощь


Повесь момент загрузки на событие
Re[2]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 22.08.08 11:10
Оценка:
Здравствуйте, <Аноним>, Вы писали:

_M_>>Как это можно сделать?? Заранее спасибо за помощь


А>Повесь момент загрузки на событие


вопрос в том как определить когда этот момент произошел?

Есть идея отправить главному окну процесса какоето мусорное сообщения и дождаться когда оно будет обработано, но не уверен что это сработает, и какое сообщение выбрать, чтобы оно не влияло на работу окна...
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re: Как дождаться загрузки приложения?
От: Mr.Cat  
Дата: 22.08.08 11:21
Оценка: 6 (1)
http://msdn.microsoft.com/en-us/library/kcdbkyt4.aspx
Re[2]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 22.08.08 14:58
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>http://msdn.microsoft.com/en-us/library/kcdbkyt4.aspx


спасибо, но к сожалению почемуто этот вызов возвращает управление раньше — еще на этапе загрузки, очевидно дочерний процесс во время загрузки делает вызовы Application.DoEvents()... Из-за которых ошибочно определяется готовность к вводу...

Может есть идеи как это обойти?
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Как дождаться загрузки приложения?
От: Alyas77 США http://kids.lingresource.com/
Дата: 22.08.08 16:07
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>Может есть идеи как это обойти?

Если есть знание WinAPI то:

EnumWindows(ищем главное окно — благо есть ProcessID — по нему и сравниваем)
EnumChildWindows (ищем тот EditBox в который тайпать будут — тут Spy++ тебе поможет...)

SendMessage() — какой — смотри сам WM_GETTEXT пройдет в 90% — но если не поможет — проверь фокус даного контрола — хотя есть любители после установки фокуса еще чего-то поделать — но это уже из разряда домыслов.
ждем ответ от SendMessage()

как по другому? наверное вряд ли выйдет...
Re[4]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 26.08.08 13:26
Оценка:
Здравствуйте, Alyas77, Вы писали:

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


_M_>>Может есть идеи как это обойти?

A>Если есть знание WinAPI то:

A>EnumWindows(ищем главное окно — благо есть ProcessID — по нему и сравниваем)

A>EnumChildWindows (ищем тот EditBox в который тайпать будут — тут Spy++ тебе поможет...)

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

кстати с поиском окон есть проблемка — у окон почемуто не установлен текст, т.е. пусто, например имя класса основного окна "ThunderRT6MDIForm", а текста нет....

A>SendMessage() — какой — смотри сам WM_GETTEXT пройдет в 90% — но если не поможет — проверь фокус даного контрола — хотя есть любители после установки фокуса еще чего-то поделать — но это уже из разряда домыслов.

A>ждем ответ от SendMessage()

A>как по другому? наверное вряд ли выйдет...


попробую...
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: Как дождаться загрузки приложения?
От: Alyas77 США http://kids.lingresource.com/
Дата: 26.08.08 20:44
Оценка:
_M_>собственно перед тем как делать именно эти вызовы мне и нужно дождаться пока закончатся "переходные процессы" происходящие внутри запускаемой программы...
А что мешает энумерацию в цикле делать — пока нужное окошко(контрол) не всплывет

_M_>кстати с поиском окон есть проблемка — у окон почемуто не установлен текст, т.е. пусто, например имя класса основного окна "ThunderRT6MDIForm", а текста нет....


Ну на нет и суда нет — а оно тебе надо? задача-то дождаться загрузки.. а не текст получить А что за проблема с поиском я так и не понял. Да и зачем тебе окно — контрол "контрольный" найди на нем — как он появился и ответил — так программа и загрузилась... наверное

_M_>попробую...


Пробуй — дай знать если как что получиться — людям интересно будет...
Re[6]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 27.08.08 10:48
Оценка:
Здравствуйте, Alyas77, Вы писали:

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

A>А что мешает энумерацию в цикле делать — пока нужное окошко(контрол) не всплывет

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

_M_>>кстати с поиском окон есть проблемка — у окон почемуто не установлен текст, т.е. пусто, например имя класса основного окна "ThunderRT6MDIForm", а текста нет....


A>Ну на нет и суда нет — а оно тебе надо? задача-то дождаться загрузки.. а не текст получить А что за проблема с поиском я так и не понял. Да и зачем тебе окно — контрол "контрольный" найди на нем — как он появился и ответил — так программа и загрузилась... наверное


задача в том чтобы сделать автоматическое управление программой, дело в том что система отказывается запускаться параллельно с Rational Robot, TestComplete падает с ошибкой в kernel32 через некоторое время работы с этим приложением, вот и пытаюсь сделать свою приблуду, проблемка в том чтобы определить момент когда закончится активность процесса, вызванная очередным автоматическим кликом или клавиатурным вводом. Чтобы не кликать на кнопку в то время когда процесс занят обработкой предыдущего действия...

_M_>>попробую...


A>Пробуй — дай знать если как что получиться — людям интересно будет...


попробовал — WM_GETTEXT работает, но результат не совсем тот, что я ожидал — момента когда начинается прокачка сообщений дождаться получилось, но вот дальше этот способ не работает. Т.е. при запуске процесса вылазит диалог, моя прога кликает на диалоге, и вот тут загвоздка — через некоторое время (~5-10 сек) вылазит новый диалог, который вылазит не всегда. Задача в том чтобы определить момент когда завершились внутренние процессы и открылось окно или очередной диалог...
WM_GETTEXT тут к сожалению не помогает, очевидно в промежутке между первым и вторым диалогом вызывается чтото вроде Application.DoEvents();

В результате мой метод WaitForInputIdle для окна возвращает управление раньше чем появляется диалог или окно будет готово к очередному вводу:
    public class WindowItem
    {
        private IntPtr _hwnd; // Это хэндл на основное окно процесса
        
        //.........
        //.........
        //.........

        public bool WaitForInputIdle(int milliseconds)
        {
            uint lpResult;
            int result = SendMessageTimeout(_hwnd, Messages.GETTEXT, 2, new byte[256], SendMessageTimeoutFlags.SMTO_ABORTIFHUNG | SendMessageTimeoutFlags.SMTO_NORMAL, (uint)milliseconds, out lpResult);
            if (result == 0) return false;
            return true;        
        }
        
        private enum Messages : uint
        {
            /// <summary>
            /// This message is sent by an application to simulate the user clicking a button. This message causes the button to receive a WM_LBUTTONDOWN and a WM_LBUTTONUP message, and the button's parent window to receive a BN_CLICKED message.
            /// </summary>
            BM_CLICK = 0x00F5,

            /// <summary>
            /// An application sends a WM_GETTEXT message to copy the text that corresponds to a window into a buffer provided by the caller.
            /// </summary>
            GETTEXT = 0x000D,
            /// <summary>
            /// An application sends a WM_GETTEXTLENGTH message to determine the length, in characters, of the text associated with a window.
            /// </summary>
            GETTEXTLENGTH = 0x000E,
        }

        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
        private static extern int SendMessageTimeout(IntPtr hWnd, Messages Msg, int wParam, byte[] lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out uint lpdwResult);

        [Flags]
        private enum SendMessageTimeoutFlags : uint
        {
            /// <summary>
            /// The calling thread is not prevented from processing other requests while waiting for the function to return.
            /// </summary>
            SMTO_NORMAL = 0x0000,
            /// <summary>
            /// Prevents the calling thread from processing any other requests until the function returns.
            /// </summary>
            SMTO_BLOCK = 0x0001,
            /// <summary>
            /// Returns without waiting for the time-out period to elapse if the receiving thread appears to not respond or "hangs."
            /// </summary>
            SMTO_ABORTIFHUNG = 0x0002,
            /// <summary>
            /// Microsoft Windows 2000/Windows XP: Does not return when the time-out period elapses if the receiving thread stops responding.
            /// </summary>
            SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
        }
    }


вот как я его использую:
    local exitButton;
    while(true) do

        -- функция checkDialogs проверяет наличие открытых диалогов и если находит известный диалог, обрабатывает его
        local dlg = checkDialogs(proc);  
        wait(1000);
        mainWnd.WaitForInputIdle(60000);
        
        exitButton = FindChildWindowByText(mainWnd, "Exit");

        if(dlg==nil and exitButton ~= nil) then
            mainWnd.WaitForInputIdle(60000);
            break;
        end
    end
    exitButton:ClickLeft();
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re: Как дождаться загрузки приложения?
От: Константин Л.  
Дата: 27.08.08 11:00
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

[]

как тут уже советовали, ищи окно по имени класса FindWindow/EnumChildWindows
Re[2]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 27.08.08 11:11
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>как тут уже советовали, ищи окно по имени класса FindWindow/EnumChildWindows


вопрос не в этом. Попробую описать более детально суть задачи.

Есть hwnd окна. Задача состоит в том чтобы выполнить такую последовательность действий:

1. Дождаться когда окно завершит инициализацию и перейдет в режим ожидания ввода от пользователя
2. Программно кликнуть по этому окну
3. Дождаться когда окно обработает клик (этот процесс занимает некоторое неопределенное время в диапазоне от 1 сек до 2 минут)
4. Проверить не открылся ли во время обработки клика диалог, если открылся, то кликнуть по нужной кнопке в диалоге и перейти к п.3
5. программно кликнуть на кнопку "Exit" в окне
6. Дождаться когда окно закроется.

Нет вопроса в том чтобы найти HWND нужного окна и сделать программный клик.
Вопрос состоит в том, как определить, что окно закончило обработку предыдущего события и находится в ожидании очередного действия пользователя?
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Как дождаться загрузки приложения?
От: Константин Л.  
Дата: 27.08.08 11:53
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>Здравствуйте, Константин Л., Вы писали:


КЛ>>как тут уже советовали, ищи окно по имени класса FindWindow/EnumChildWindows


_M_>вопрос не в этом. Попробую описать более детально суть задачи.


_M_>Есть hwnd окна. Задача состоит в том чтобы выполнить такую последовательность действий:


_M_>1. Дождаться когда окно завершит инициализацию и перейдет в режим ожидания ввода от пользователя


что за инициализация? после того, как окно создано (те есть HWND), оно инициализировано.

_M_>2. Программно кликнуть по этому окну


нет проблем

_M_>3. Дождаться когда окно обработает клик (этот процесс занимает некоторое неопределенное время в диапазоне от 1 сек до 2 минут)


засабкласить?

_M_>4. Проверить не открылся ли во время обработки клика диалог, если открылся, то кликнуть по нужной кнопке в диалоге и перейти к п.3


хук

_M_>5. программно кликнуть на кнопку "Exit" в окне


нет проблем

_M_>6. Дождаться когда окно закроется.


тоже

_M_>Нет вопроса в том чтобы найти HWND нужного окна и сделать программный клик.

_M_>Вопрос состоит в том, как определить, что окно закончило обработку предыдущего события и находится в ожидании очередного действия пользователя?

м?
Re[4]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 27.08.08 12:50
Оценка:
Здравствуйте, Константин Л., Вы писали:

_M_>>1. Дождаться когда окно завершит инициализацию и перейдет в режим ожидания ввода от пользователя

КЛ>что за инициализация? после того, как окно создано (те есть HWND), оно инициализировано.

инициализация это время которое проходит от момента когда создано окно (т.е. появился HWND) и до момента когда поток начнет прокачку сообщений. В это время поднимаются сервисы, создаются громоздкие инстансы объектов и т.п., короче это время уходит на разворачивание приложения и потому занимает некоторое, в данном случае немалое, время...


_M_>>2. Программно кликнуть по этому окну


КЛ>нет проблем


_M_>>3. Дождаться когда окно обработает клик (этот процесс занимает некоторое неопределенное время в диапазоне от 1 сек до 2 минут)


КЛ>засабкласить?


что значит засабкласить? можно поподробнее?

есть hwnd, как дождаться когда поток создавший окно с этим hwnd начнет прокачку оконных сообщений, обработает текущие сообщения и перейдет в режим ожидания нового сообщения?


_M_>>4. Проверить не открылся ли во время обработки клика диалог, если открылся, то кликнуть по нужной кнопке в диалоге и перейти к п.3


КЛ>хук


не знаю зачем тут хук? я проверяю наличие диалогов без хуков — это проще и позволяет реализовать линейное исполнение алгоритма

_M_>>6. Дождаться когда окно закроется.

КЛ>тоже

вот об этом тоже хотелось бы спросить, как правильнее дождаться закрытия окна связанного с заданным HWND?
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: Как дождаться загрузки приложения?
От: Константин Л.  
Дата: 27.08.08 14:43
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>Здравствуйте, Константин Л., Вы писали:


_M_>>>1. Дождаться когда окно завершит инициализацию и перейдет в режим ожидания ввода от пользователя

КЛ>>что за инициализация? после того, как окно создано (те есть HWND), оно инициализировано.

_M_>инициализация это время которое проходит от момента когда создано окно (т.е. появился HWND) и до момента когда поток начнет прокачку сообщений. В это время поднимаются сервисы, создаются громоздкие инстансы объектов и т.п., короче это время уходит на разворачивание приложения и потому занимает некоторое, в данном случае немалое, время...


т.е. так:

CreateWindow(...);
SomeLongOperation(...);
MessageLoop(...);


Кхм...

Что там хоть за SomeLongOperation? Ивенты? Мьютексы? Окна? Мож есть к чему привязаться?

_M_>>>2. Программно кликнуть по этому окну


КЛ>>нет проблем


_M_>>>3. Дождаться когда окно обработает клик (этот процесс занимает некоторое неопределенное время в диапазоне от 1 сек до 2 минут)


КЛ>>засабкласить?


_M_>что значит засабкласить? можно поподробнее?


это для того, чтобы точно знать когда клик обработался. Но этот момент можно поскипать

_M_>есть hwnd, как дождаться когда поток создавший окно с этим hwnd начнет прокачку оконных сообщений, обработает текущие сообщения и перейдет в режим ожидания нового сообщения?


надо подумать в сторону хука WH_GETMESSAGE, но пока ничего в голову не приходит

_M_>>>4. Проверить не открылся ли во время обработки клика диалог, если открылся, то кликнуть по нужной кнопке в диалоге и перейти к п.3


КЛ>>хук


_M_>не знаю зачем тут хук? я проверяю наличие диалогов без хуков — это проще и позволяет реализовать линейное исполнение алгоритма


как проверяешь? просто с хуком WH_CBT (вроде так) проще всего отслеживать появление окон

_M_>>>6. Дождаться когда окно закроется.

КЛ>>тоже

_M_>вот об этом тоже хотелось бы спросить, как правильнее дождаться закрытия окна связанного с заданным HWND?


Ну дык вариантов масса. От сабклассинга окна до хуков.

Ты как-нить в этот процесс внедриться можешь? Исходники есть?
Re[6]: Как дождаться загрузки приложения?
От: _Morpheus_  
Дата: 27.08.08 15:14
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>
КЛ>CreateWindow(...);
КЛ>SomeLongOperation(...);
КЛ>MessageLoop(...);
КЛ>


КЛ>Кхм...

КЛ>Что там хоть за SomeLongOperation? Ивенты? Мьютексы? Окна? Мож есть к чему привязаться?

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

_M_>>что значит засабкласить? можно поподробнее?


КЛ>это для того, чтобы точно знать когда клик обработался. Но этот момент можно поскипать


и всетаки что значит "засабкласить"? Мне какраз и нужно узнать когда клик обработался...

_M_>>не знаю зачем тут хук? я проверяю наличие диалогов без хуков — это проще и позволяет реализовать линейное исполнение алгоритма


КЛ>как проверяешь? просто с хуком WH_CBT (вроде так) проще всего отслеживать появление окон


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


КЛ>Ты как-нить в этот процесс внедриться можешь? Исходники есть?


исходников нет, ReadProcessMemory/WriteProcessMemory юзать можно
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[7]: Как дождаться загрузки приложения?
От: Константин Л.  
Дата: 27.08.08 16:32
Оценка:
Здравствуйте, _Morpheus_, Вы писали:

_M_>Здравствуйте, Константин Л., Вы писали:


КЛ>>
КЛ>>CreateWindow(...);
КЛ>>SomeLongOperation(...);
КЛ>>MessageLoop(...);
КЛ>>


КЛ>>Кхм...

КЛ>>Что там хоть за SomeLongOperation? Ивенты? Мьютексы? Окна? Мож есть к чему привязаться?

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


мдя... ну может там какое окно "Loading..." исчезает? Смотри тогда асм

_M_>>>что значит засабкласить? можно поподробнее?


КЛ>>это для того, чтобы точно знать когда клик обработался. Но этот момент можно поскипать


_M_>и всетаки что значит "засабкласить"? Мне какраз и нужно узнать когда клик обработался...


Subclassing
общая инфа
как это сделать на .net

_M_>>>не знаю зачем тут хук? я проверяю наличие диалогов без хуков — это проще и позволяет реализовать линейное исполнение алгоритма


КЛ>>как проверяешь? просто с хуком WH_CBT (вроде так) проще всего отслеживать появление окон


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


и где-же тут линейное исполнение?

КЛ>>Ты как-нить в этот процесс внедриться можешь? Исходники есть?


_M_>исходников нет, ReadProcessMemory/WriteProcessMemory юзать можно


желательно без этого. плагин там написать?
Re[7]: Как дождаться загрузки приложения?
От: Alyas77 США http://kids.lingresource.com/
Дата: 27.08.08 19:40
Оценка:
_M_>попробовал — WM_GETTEXT работает, но результат не совсем тот, что я ожидал — момента когда начинается _M_>WM_GETTEXT тут к сожалению не помогает, очевидно в промежутке между первым и вторым диалогом вызывается чтото вроде Application.DoEvents();
А ты зачем его в основное окно пинаешь? ты же знаешь и кнопку и возможный диалог с ошибкой — их ищи — и их проверяй на присутиствие и наличие на экране — как обявились — пни для приличия — и считай что все прогрузилось.

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