SendMessage для имитации щелчка правой кнопкой мыши приводит к сбою целевого приложения - PullRequest
5 голосов
/ 28 июня 2011

Я пишу инструмент автоматизации C #.

Поскольку Microsoft UI Automation не позволяет имитировать щелчки правой кнопкой мыши или вызывать контекстные меню, я вместо этого использую SendMessage. Я бы предпочел не использовать SendInput, потому что я не хочу захватывать фокус.

Однако, когда я звоню SendMessage, целевое приложение вылетает.

Вот мой код:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    public void RightClick<T>(T element) where T: AutomationElementWrapper
    {
        const int MOUSEEVENTF_RIGHTDOWN = 0x0008; /* right button down */
        const int MOUSEEVENTF_RIGHTUP = 0x0010; /* right button up */

        var point = element.Element.GetClickablePoint();
        var processId = element.Element.GetCurrentPropertyValue(AutomationElement.ProcessIdProperty);
        var window = AutomationElement.RootElement.FindFirst(
            TreeScope.Children,
            new PropertyCondition(AutomationElement.ProcessIdProperty,
                                  processId));
        var handle = window.Current.NativeWindowHandle;

        var x = point.X;
        var y = point.Y;

        var value = ((int)x)<<16 + (int)y;

        SendMessage(new IntPtr(handle), MOUSEEVENTF_RIGHTDOWN, IntPtr.Zero, new IntPtr(value));
        SendMessage(new IntPtr(handle), MOUSEEVENTF_RIGHTUP, IntPtr.Zero, new IntPtr(value));
    }

Есть идеи, что я делаю не так?

Ответы [ 4 ]

4 голосов
/ 28 июня 2011

Вы смешиваете свои типы.Вы используете SendMessage, который принимает оконное сообщение (которое по соглашению называется WM_ ...), но вы передаете ему значение MOUSEINPUT.dwFlags, предназначенное для SendInput (которое называется MOUSEEVENTF_ ...).Вы в основном пропускаете бред.

На самом деле ваш код делает отправку оконного сообщения, числовое значение которого равно 8 (что в сообщениях окна означает WM_KILLFOCUS), за которым следует оконное сообщение 0x10 == 16 (WM_CLOSE).Последнее, вероятно, вызывает у вас проблемы - вы говорите, чтобы окно закрылось.Я не уверен, почему произошел сбой, но он наверняка завершится.

Если вы используете SendMessage, вам нужно передать ему сообщения окна (WM_, например WM_RBUTTONDOWN и WM_RBUTTONUP).

1 голос
/ 30 июня 2011

Этот ответ достаточно длинный, я положу его в слот для ответов.Я думаю, что мой ответ в основном состоит в том, что вопрос, который вы задаете, основан на неверном предположении.

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

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

Фундаментальная проблемазаключается в том, что некоторые ресурсы пользовательского интерфейса, в частности указатель мыши и фокус клавиатуры, являются общими для всех приложений на рабочем столе.И многие (большинство? Все?) Приложения предполагают, что, когда с ними взаимодействуют, они могут делать с ними что угодно.

Иногда вы можете сойти с рук, «лгая» приложению и отправляя ему сообщенияобычно это будет конечный результат ввода (например, отправка WM_LBUTTONDOWN вместо выполнения sendinput), но если приложение в конечном итоге просматривает глобальное состояние мыши, вы получите несогласованность.

Например, приложение может ответить на WM_LBUTTONDOWN, используя координаты, переданные в качестве параметров.Или он может игнорировать их и вместо этого вызывать GetCursorPos - и это может привести к действительно странному поведению, если мышь действительно находится над вашей почтовой программой вместо приложения.

Или вы можете отправить WM_LBUTTONDOWN, и приложение ответит наэто путем вызова некоторой вспомогательной функции.Вспомогательная функция использует GetKeyState (VK_LBUTTON), чтобы проверить, нажата ли кнопка мыши на самом деле - замечает, что это не так, поэтому запускается рано.

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

Если приложение использует SetCapture () - чтоочень часто встречаются такие вещи, которые можно нажимать, например кнопки и т. п. - произойдет сбой, если приложение не имеет фокуса.Вам может повезти, и приложение проигнорирует неудачу и удачу - или нет.Элементы управления типа меню часто предполагают, что приложение имеет фокус, и будут отклонять себя, если заметят, что фокус на самом деле находится в другом месте ...

Если у вас есть приложение, которое тестируется, вы можете принять это вучтите и запишите его так, чтобы его можно было «протестировать» в фоновом режиме: но имейте в виду, что он больше не работает таким образом, который согласуется с фактическим взаимодействием с пользователем - так что, возможно, это не действительный эквивалентный пользователю тестовый пример!- это зависит от вас, учитывая ваши требования к тестированию.

Короче говоря: вы могли бы получить что-то для работы здесь в этом конкретном случае, но помните, что здесь скрывается целая куча проблеми обратите внимание, что это определенно не считается лучшей практикой тестирования пользовательского интерфейса!

0 голосов
/ 28 июня 2011

Вы не опубликовали подробности аварии (тип исключения? Местоположение?), Но мое первое подозрение - проблема повторного входа.Я бы попробовал использовать PostMessage вместо SendMessage.SendMessage является синхронным и ожидает обработки сообщения перед его возвратом, поэтому все выполняется во время его вызова.PostMessage просто помещает сообщение в очередь, а затем возвращается, и обработка происходит позже.

0 голосов
/ 28 июня 2011

Какие именно сообщения вы отправляете, можете ли вы дать их определение Windows? По данным MSDN:

#define WM_RBUTTONDOWN                  0x0204
#define WM_RBUTTONUP                    0x0205
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...