Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > Управление чужим приложением через Spy++


Автор: zmaximka 27.5.2006, 22:59
Ребята, нужно написать прогу которая делала манипуляции с другой прогой! В инете порылся, нашел что это делается через  Spy++. Только как это сделать через С# пока представления не имею. Объясните пожалуйста, кто имел опыт работы или укажите ссылочку на данную тематика!  

Автор: mr.DUDA 28.5.2006, 15:10
Spy++ это утилита, входящая в комплект VS начиная с 6-й версии. Предназначение её состоит в том, чтобы иметь возможность посмотреть на иерархию процессов, потоков и окон. Кроме того, можно трассировать WinAPI-шные сообщения с возможностью фильтрации, а также найти окно по Handle и наоборот. Вот практически всё что она умеет. 

Автор: zmaximka 28.5.2006, 23:33
Цитата(mr.DUDA @  28.5.2006,  15:10 Найти цитируемый пост)
Spy++ это утилита ...

В MFC она помогала отлавливать сообщения других програм! 
Я вообще, если честно еще не достаточно опытем и так и не смог найти решения этой задачи! Т.е. как нажимать кнопку чужой программы из своей. Может есть какое-то другое решение?
 

Автор: mr.DUDA 29.5.2006, 12:11
Цитата(zmaximka @  28.5.2006,  22:33 Найти цитируемый пост)
В MFC она помогала отлавливать сообщения других програм! 

вот именно, поэтому первый вопрос непонятен:

Цитата(zmaximka @  27.5.2006,  21:59 Найти цитируемый пост)
нужно написать прогу которая делала манипуляции с другой прогой! В инете порылся, нашел что это делается через  Spy++.


Что касаемо собстна "нажать чужую кнопку", так это на WinAPI делается "на раз", если знать структуру чужого окна (нас интересуют имена window classes и иерархия вложенности окон). Действительно, получить эту инфу можно с пом. Spy++. На этом все возможности этой утилиты и заканчиваются, потому что посылать сообщения она не умеет. Как нажать кнопку, зная её window class и расположение в дереве окон ? Используя функцию FindWindow или FindWindowEx, получаем по имени или по window class-у "корневое" окно приложения, затем таким же образом ищем вложенное окно, пробираясь по иерархии окон. Когда добрались до кнопки, имеем её Handle (HWND), можно послать нажатие. Чтобы в точности сымитировать нажатие, можно например с помощью той же Spy++ прицепиться к кнопке и трассировать оконные сообщения с фильтрацией "только WM_LBUTTONDOWN, WM_LBUTTONUP", получив таким способом lParam и wParam. Эти значения и будут аргументами ф-ции SendMessage. 

Автор: zmaximka 29.5.2006, 12:59
Цитата(mr.DUDA @  29.5.2006,  12:11 Найти цитируемый пост)
Когда добрались до кнопки, имеем её Handle (HWND), можно послать нажатие. Чтобы в точности сымитировать нажатие, можно например с помощью той же Spy++ прицепиться к кнопке и трассировать оконные сообщения с фильтрацией "только WM_LBUTTONDOWN, WM_LBUTTONUP", получив таким способом lParam и wParam. Эти значения и будут аргументами ф-ции SendMessage.  

А можно привести пример на С#, пожалуйста!
 

Автор: mr.DUDA 29.5.2006, 13:02
Пример для какого приложения тебе нужен ? Или так, в общем ? 

Автор: zmaximka 29.5.2006, 14:20
Цитата(mr.DUDA @  29.5.2006,  13:02 Найти цитируемый пост)
Пример для какого приложения тебе нужен ? Или так, в общем ?

Ну к примеру, что б я нажимал в своем приложении кнопку, а в стандартном виндовом калькуляторе нажималась цифра 1. 

Автор: mr.DUDA 30.5.2006, 08:46
Цитата(zmaximka @  29.5.2006,  13:20 Найти цитируемый пост)
Ну к примеру, что б я нажимал в своем приложении кнопку, а в стандартном виндовом калькуляторе нажималась цифра 1. 

Вот пример, консольное приложение, при запуске находит окно калькулятора и "нажимает" в нём кнопку 1:

Код
using System;
using System.Runtime.InteropServices;

class TestProgram
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string windowName);

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

    const int WM_LBUTTONDOWN = 0x0201;
    const int WM_LBUTTONUP = 0x0202;

    static void Main()
    {
        // находим окно калькулятора, зная window class ("SciCalc")
        IntPtr calcWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "SciCalc", null);

        // находим кнопку по имени окна ("1") и имени класса ("Button")
        IntPtr button1 = FindWindowEx(calcWnd, IntPtr.Zero, "Button", "1");

        // если нашли
        if(button1 != IntPtr.Zero)
        {
            // посылаем нажатие кнопки мыши, последний параметр
            // содержит координаты мыши (скопировано из Spy++)
            SendMessage(button1, WM_LBUTTONDOWN, 1, 0x150018);
            SendMessage(button1, WM_LBUTTONUP, 0, 0x150018);
        }
    }
}
 

Автор: zmaximka 31.5.2006, 15:22
Цитата(mr.DUDA @  30.5.2006,  08:46 Найти цитируемый пост)
Вот пример, консольное приложение, при запуске находит окно калькулятора и "нажимает" в нём кнопку 1:

Вах, Шайтан!!! Спасибо!
 

Автор: VisualProgrammerNET 31.5.2006, 16:51
Давно мучал вопрос. Как из приложения C# выключить/перезагрузить комп? Ессно, через винапи, но сколько ни лазил по библиотекам... в общем, как?  smile 

Собрался написать хитрую программку, которая прячется в автозапуске и при активизации перезагружает комп  smile . Ловушка для ламеров, обладающих .NET Framework'ом  smile  

Автор: mr.DUDA 31.5.2006, 20:40
Цитата(VisualProgrammerNET @  31.5.2006,  15:51 Найти цитируемый пост)
 Как из приложения C# выключить/перезагрузить комп? Ессно, через винапи, но сколько ни лазил по библиотекам... в общем, как?

один топик = один вопрос, вообще-то...

Что касается "как выключить комп", то это делается через командную строку:

RUNDLL.EXE user.exe,exitwindows

Можно то же самое через WinExec организовать, или через Process.Start() 

Автор: zmaximka 8.6.2006, 14:03
А почему кнопка может не ловится Spy++? Я навожу на нее прицел, а виделяется только один GroupBox 

Автор: mr.DUDA 14.6.2006, 10:58
Цитата(zmaximka @  8.6.2006,  13:03 Найти цитируемый пост)
А почему кнопка может не ловится Spy++? Я навожу на нее прицел, а виделяется только один GroupBox 

Может, и не кнопка это вовсе  smile
Руками нарисованная, то есть.

З.Ы. проверить просто: находишь прицелом групбокс и в дереве смотришь, какие у групбокса внутри есть чилды. Если там кнопки нету - значит её и нет.

З.Ы.(2) извиняюсь за задержку с ответом. 

Автор: zmaximka 23.6.2006, 15:57
Цитата(mr.DUDA @  14.6.2006,  10:58 Найти цитируемый пост)
проверить просто: находишь прицелом групбокс и в дереве смотришь, какие у групбокса внутри есть чилды. Если там кнопки нету - значит её и нет.

Таки нет! И как же все таки можно ее нажать? 

Автор: jfx 23.6.2006, 16:07
Думаю вам небезинтересно будет прочесть вот эту статью:
Deliver The Power Of Spy++ To Windows Forms With Our New Tool

Цитата
Many developers use the Spy++ tool provided with Visual Studio®. With Spy++, you can understand the window layout of a running application or identify a certain window message that causes a bug. However, when you create a Microsoft® .NET Framework-based application, Spy++ becomes less useful because the window messages and classes intercepted by Spy++ don't correspond to anything a developer uses or even sees. What a developer really wants to see are managed events and property values.

This article describes how to use a new utility called ManagedSpy and its associated library ManagedSpyLib, both of which are available for download from the MSDN®Magazine Web site. Similar to how Spy++ displays Win32® information such as window classes, styles, and messages, ManagedSpy displays managed controls, properties, and events. ManagedSpyLib allows you to programmatically access Windows® Forms controls in another process. You can get and set properties and sync on events in your own code. ManagedSpyLib can also help you build test harnesses and can perform window, message, and event logging.
...


http://msdn.microsoft.com/msdnmag/issues/06/04/ManagedSpy/    

Автор: mr.DUDA 23.6.2006, 16:11
Цитата(zmaximka @  23.6.2006,  15:57 Найти цитируемый пост)
Таки нет! И как же все таки можно ее нажать? 


По простому не получается ? Ну попробуй тогда сделать так, если сможешь: 

1) начать с пом. Spy++ прослушивать сообщения WM_LBUTTONDOWN/UP/CLICK, выставить галку "All windows of same process"
2) нажать мышкой "кнопку" в окне
3) посмотреть, какие сообщения отловил Spy++
4) не меняя положения окна с "кнопкой", послать (с пом. SendMessage) окну такие же сообщения с теми же lParam и wParam, посмотреть будет ли результат

Если пункт 4 приведёт к такой же реакции, как пункт 2 (т.е. "кнопка" нажмётся), значит можно всё это делать для любого положения окна: после того как FindWindow() нашёл окно, определяем левый верхний угол окна (импортируемая функция GetWindowPos), по ним вычисляем координаты кнопки и посылаем окну WM_LBUTTONDOWN/WM_LBUTTONUP.

Добавлено @ 16:14 
Упс, пропустил сообщение jfx, скорее всего в этом и дело smile 

Автор: zmaximka 26.6.2006, 17:28
А у меня выдает ошибку! Подозреваю что lParam у меня в такой форме 0014000E, а у тебя в 0x150018! Если да, то как переконвертировать? 

Автор: mr.DUDA 26.6.2006, 17:38
Цитата(zmaximka @  26.6.2006,  17:28 Найти цитируемый пост)
0014000E

Это такое же hex-число, как и 0x150018. Только "0x" не хватает. 

Автор: zmaximka 26.6.2006, 17:44
Цитата(mr.DUDA @  26.6.2006,  17:38 Найти цитируемый пост)
Это такое же hex-число, как и 0x150018. Только "0x" не хватает. 

А можно пример?!  smile  

Автор: mr.DUDA 26.6.2006, 18:22
Цитата(zmaximka @  26.6.2006,  17:44 Найти цитируемый пост)
А можно пример?!

Пример чего ? Шестнадцатеричных чисел ? Пожалста:

0x000001
0xabcdef
0x456000
0x100000 

Автор: zmaximka 26.6.2006, 18:46
Не работает! Я посылаю этой нарисованной кнопке сообщения, а она не реагирует! Может я не тому окну посылаю?
Код

sing System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace PreWork
{
    class Program
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string windowName);

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

        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_LBUTTONUP = 0x0202;

        static void Main(string[] args)
        {
            IntPtr pillotWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "TMainForm", "Настройка и учет звонков PILOT-X                       -=  TANDEM LTD  =-");

            IntPtr Tab1 = FindWindowEx(pillotWnd, IntPtr.Zero, "TPageControl", null);

            IntPtr Tab2 = FindWindowEx(Tab1, IntPtr.Zero, "TTabSheet", "Параметры");

            IntPtr button1 = FindWindowEx(Tab2, IntPtr.Zero, "TScrollBox", null);

 
            if (button1 != IntPtr.Zero)
            {
                SendMessage(button1, WM_LBUTTONDOWN, 1, 0x001900B8);
                SendMessage(button1, WM_LBUTTONUP, 0, 0x001900B8);
            }
        }
    }
}
 

Автор: mr.DUDA 27.6.2006, 10:42
Так ты посылаешь сообщение кнопке скроллбара ? Для этого есть совсем другие сообщения - WM_VSCROLL, например. 

Автор: zmaximka 27.6.2006, 15:12
Цитата(mr.DUDA @  27.6.2006,  10:42 Найти цитируемый пост)
Так ты посылаешь сообщение кнопке скроллбара ?

Нет, я нечиго на хочу прокручивать! Я вообще не могу понять откуда там скрол бар, если его там нет. 

Автор: zmaximka 27.6.2006, 16:02
Цитата(zmaximka @  27.6.2006,  15:12 Найти цитируемый пост)
Нет, я нечиго на хочу прокручивать! Я вообще не могу понять откуда там скрол бар, если его там нет

Все!!! Эта кнопка нажимается. А если кнопка на панеле задач то же LBUTONNUP LBUTONNDOWN?
 

Автор: zmaximka 3.7.2006, 10:57
А если кнопка на панеле задач то же LBUTONNUP LBUTONNDOWN? 

Автор: mr.DUDA 3.7.2006, 11:08
Цитата(zmaximka @  3.7.2006,  10:57 Найти цитируемый пост)
А если кнопка на панеле задач то же LBUTONNUP LBUTONNDOWN?

Панель задач - отдельное окно, но в целом ничем (по поведению) не должно отличаться от обычных окон. 

Автор: zmaximka 3.7.2006, 11:15
Цитата(mr.DUDA @  3.7.2006,  11:08 Найти цитируемый пост)
Панель задач - отдельное окно, но в целом ничем (по поведению) не должно отличаться от обычных окон. 

И панель инструментов тоже? 

Автор: mr.DUDA 3.7.2006, 13:13
Цитата(zmaximka @  3.7.2006,  11:15 Найти цитируемый пост)
И панель инструментов тоже? 

ну и при чём здесь панель инструментов к панели задач ?.. 

Автор: zmaximka 3.7.2006, 14:15
А если кнопка на панеле инструментов, то же LBUTONNUP LBUTONNDOWN?  

Автор: mr.DUDA 3.7.2006, 21:48
Гм, что понимается под "панелью инструментов" ? Область окна в верхней части, где расположены мелкие кнопки типа "открыть файл", "копировать", "вставить" и т.п. ? Если да - то там кроме WM_LBUTTONDOWN/UP/CLICK есть ещё очень важное сообщение WM_COMMAND, посылаемое при выборе (нажатии/отжатии) кнопки тулбара. Можно в эту сторону покопать... 

Автор: Ch0bits 3.7.2006, 22:41
Цитата(VisualProgrammerNET @  31.5.2006,  17:51 Найти цитируемый пост)
Как из приложения C# выключить/перезагрузить комп?

Есть такая архиполезная утилита 
%systemroot%\system32\shutdown.exe -r -t 60
запускаешь и смотришь на табличку о завершении работы (такую же вызывал MSBlast)   smile 
Подробнее читай справку - ключ /?
Отмена завершения - ключ -a. 

Автор: mr.DUDA 3.7.2006, 23:33
Цитата(Ch0bits @  3.7.2006,  22:41 Найти цитируемый пост)
Есть такая архиполезная утилита 
%systemroot%\system32\shutdown.exe -r -t 60
запускаешь и смотришь на табличку о завершении работы (такую же вызывал MSBlast)    
Подробнее читай справку - ключ /?
Отмена завершения - ключ -a. 

всё это классно, конечно, но непонятно как относится к теме 

Автор: zmaximka 5.7.2006, 21:49
А какое посылать сообщение для нажатия OK/Cancel в сплывающем сообщении? 

Автор: mr.DUDA 6.7.2006, 00:57
Энтер и искейп 

Автор: zmaximka 6.7.2006, 12:05
Цитата(mr.DUDA @  6.7.2006,  00:57 Найти цитируемый пост)
Энтер и искейп 

А пример можлно? smile 
 

Автор: Nickey 26.5.2007, 22:08
Понятно что один вопрос - одна тема, но мой вопросец очень схож. Как нажать на кнопку другого прилажения из вышеприведенных примеров понятно, а вот если на форме есть объект для ввода текста, как туда послать сообщение. Интересует меня потомучто есть задача в телнет клиент кинуть пару команд, т.е. саму команду, и enter. Вот как это можно сделать?

Автор: mr.DUDA 27.5.2007, 15:57
Nickey, читайте разделы в MSDN посвещённые оконным сообщениям и в частности - функции SendMessage, PostMessage. Для замены текста в тектбоксе на новый - сообщение WM_SETTEXT. Для добавления текста придётся эмулировать нажатия клавиш (для этого есть стандартный класс SendKeys).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)