1 место PM+WinApi или управление окнами любых других приложений

b.ihnatyshyn

Новичок
Регистрация
21.05.2020
Сообщения
5
Благодарностей
0
Баллы
1

dr.reklam

Client
Регистрация
02.06.2020
Сообщения
64
Благодарностей
15
Баллы
8
Здравствуйте, подскажите будет ли работать WinApi в многопотоке? Допустим есть одно приложение десткопное, в нем большой список проектов, при нажатии кнопки на любой проект совершается действие. Можно ли настроить чтобы одновременно в одном приложении нажималось несколько кнопок? Например сразу 20 кликов, причем команда на каждый клик будет приходить от отдельного шаблона в zennoposter
 

Master4eg

Client
Регистрация
06.04.2016
Сообщения
421
Благодарностей
122
Баллы
43
Здравствуйте, подскажите будет ли работать WinApi в многопотоке? Допустим есть одно приложение десткопное, в нем большой список проектов, при нажатии кнопки на любой проект совершается действие. Можно ли настроить чтобы одновременно в одном приложении нажималось несколько кнопок? Например сразу 20 кликов, причем команда на каждый клик будет приходить от отдельного шаблона в zennoposter
Звучит, как нет, либо я не понимаю что-то, пиши в лс
 

radv

Client
Регистрация
11.05.2015
Сообщения
3 789
Благодарностей
1 954
Баллы
113
Можно ли настроить чтобы одновременно в одном приложении нажималось несколько кнопок?
а ты в ручную можешь это повторить? нажать несколько кнопок? Что в твоем понимании многопоток? Каждый поток должен работать со своим объектом (или его копией), а если объект (содержимое на экране приложения одно) то потоки будут мешать друг другу.
 

dr.reklam

Client
Регистрация
02.06.2020
Сообщения
64
Благодарностей
15
Баллы
8
Попытаюсь проще объяснить. Например есть одно окно приложения MSWord, в нем лист с двадцатью чек-боксами. В zennoposter работает двадцать проектов и каждый соответсвует одному чек-боксу. При определенных условиях каждый проект отправляет команду "поставить галочку в чек-бокс". Вопрос, если все двадцать проектов одновременно отправят команду, сможет ли WinAPI сразу везде поставить галочки?

Вручную я не могу такое сделать, мышь только одна и одновременно кликать могу только на один чек-бокс.

MS.Word и чек-боксы это пример, по аналогии нужно нажимать кнопки в программе.
 

radv

Client
Регистрация
11.05.2015
Сообщения
3 789
Благодарностей
1 954
Баллы
113
Вручную я не могу такое сделать, мышь только одна и одновременно кликать могу только на один чек-бокс.
вот так и с автоматизацией.
Вопрос, если все двадцать проектов одновременно отправят команду, сможет ли WinAPI сразу везде поставить галочки?
одновременно нет. Работа с файлами это одно (там можно блокировки сделать, и все сделать последовательно), работа с интерфейсом это другое. Да и смысл одновременно делать разное в одной и той же программе. Это как работать с одним гуглдокументом разным пользователям, при этом один что то вводит, второй меняет текст на свой, третий вообще все удаляет и при этом все друг другу мешают. :-)
 

Anton312

Новичок
Регистрация
10.12.2019
Сообщения
20
Благодарностей
0
Баллы
1
Что я делаю не так?
Настроил проект по инструкции.
Проект запускается, но действия не выполняются.
Может я что-то не установил на пк?
 

Antoxa421

Client
Регистрация
19.03.2020
Сообщения
11
Благодарностей
3
Баллы
3
Всем привет! У меня появилась вот такая ошибка
Код:
Компиляция кода  Ошибка в действии "CS0122" ""ZennoLab.OwnCode.CommonCode.FindWindow(string, string)" недоступен в силу его уровня защиты". [Строка: 0; Cтолбец: 26]
Я прочитал тему, там тоже у кого-то была такая-же ошибка. Сказали поставить findwindow на public я поставил потом у меня появилась вот такая ошибка точнее ошибки:
Код:
Компиляция кода  Ошибка в действии "CS1513" "ожидалась }". [Строка: 0; Cтолбец: 2]
Компиляция кода  Ошибка в действии "CS1519" "Недопустимый токен "return" в объявлении класса, структуры или интерфейса". [Строка: 2; Cтолбец: 1]
Компиляция кода  Ошибка в действии "CS1519" "Недопустимый токен ";" в объявлении класса, структуры или интерфейса". [Строка: 2; Cтолбец: 12]
Компиляция кода  Ошибка в действии "CS1022" "Ожидалось определение типа или пространства имен, либо признак конца файла". [Строка: 2; Cтолбец: 1]
Если что я вот так изменил:
C#:
public IntPtr hwnd = CommonCode.FindWindow("Qt5QWindowIcon", null);

return hwnd;
Может кто помочь? Буду благодарен.
 

Serjio Leone

Client
Регистрация
20.09.2017
Сообщения
114
Благодарностей
84
Баллы
28
  • Спасибо
Реакции: Antoxa421

Antoxa421

Client
Регистрация
19.03.2020
Сообщения
11
Благодарностей
3
Баллы
3

Rahul0076

Новичок
Регистрация
07.10.2020
Сообщения
3
Благодарностей
0
Баллы
1
Всем доброго дня! Сегодня я бы хотел раскрыть такую крутую тему как WinApi функции, благодаря которым мы можем творить с окнами других приложений все что душе угодно.

Самый главный инструмент, который нам понадобится- это SPY++(прикрепил) , он позволяет отслеживать какие сообщения отправляются окну приложения для совершения с ним того или иного действия, следовательно наша задача сводится к тому чтобы правильно сформировать сообщение и отправить его нужному окну.

Итак, начинаем исследование, в качестве подопытного я выбрал клиент Viber'a для ПК, сделаем с вами авторассыльщик по списку номеров, погнали:

Для работы с WinApi из языка С# я выделил для себя три основных источника:
а) Это конечно же всеми любимый https://msdn.microsoft.com - там можно получить инструктаж для любой апишной функции, а так же необходимые для них значения констант. Документация для С++

б) http://www.firststeps.ru - на этом сайте можно посмотреть русскоязычное описание всех основных функций. Документация тоже для С++

в) http://www.pinvoke.net - на этом сайте через поиск можно найти любую WinApi функцию именно для С#, что нам и нужно

Первое что нам нужно сделать это получить хендл (уникальный идентификатор) окна вайбера, за это отвечает функция FindWindow, идем на pinvoke и находим ее:

Код:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Куда же ее вставлять? Все просто:



Так же необходимо добавить директиву, как на скрине (именно туда, а не во вкладку Директивы using):

Код:
using System.Runtime.InteropServices;
Еще заметьте что саму функцию FindWindow я сделал публичной, чтобы к ней можно было обращаться из экшена "Свой С# код".

Как мы видим данная функция на вход получает имя класс и имя заголовка окна, со вторым все понятно, он всегда написан в верхней шапке окна, а где же взять имя класса? На помощь приходит наш spy++, качаем, запускаем его:

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




После того как наведете прицел на нужное окно и отпустите его, у вас заполнятся поля Handle(уникальный идентификатор), Caption(заголовок окна) и искомое имя Class'a - копируем его и идем обратно в PM, теперь можно уже протестировать как работает наша функция:

Создаем экшен своего С# кода и вставляем туда:

Код:
IntPtr hwnd = CommonCode.FindWindow("Qt5QWindowIcon", null);

return hwnd;
Как видите второй параметр я поставил null, т.к. он не обязателен, и нужен только в тех случаях, когда присутствуют окна с таким же именем класса. Так же в некоторых случаях можно не указывать имя класса, но указать заголовок окна.

Отправляем результат в какую нибудь переменную и смотрим:



Работает!! К сожалению, зенка преобразовывает наш IntPtr сразу в тип string и мы не можем посмотреть его value, где это число будет именно в формате IntPtr, тогда бы мы смогли по поиску в spy++ сразу найти это окно и убедиться верно ли мы нашли идентификатор.

Хендл нужного окна получили, дальше нужно отправить ему какое нибудь сообщение, чтобы с ним что то произошло, для этого снова идем в spy++, снова прицелом находим окно viber' a и в этот раз после поиска жмем ОК, щелкаем ПКМ по выделенной строке и выбираем Messages, после этого нас перекидывает в новое пустое окно spy++, НО стоит нам навести мышью на окно вайбера, как тут же мы увидим как сыпятся сообщения:



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



По нашему плану, нам первым делом нужно нажать на иконку с шариками, чтобы была возможность набора номера, смотрим в spy++ что для этого действия отправляется окну вайбера:



Среди всяких сообщений о передвижении мыши и установкой курсора (их названия говорят сами за себя) можно увидеть нажатия кнопки мыши по координатам окна, значит нужно определенно отправить эти два сообщения, а еще по своему опыту я скажу что нужно отправить WM_MOUSEMOVE на эти же координаты, т.к. без него клик может не сработать, давайте разбираться как это делается. Во- первых, сообщения окнам отправляются двумя способами это при помощи функций SendMessage и PostMessage, разница между ними только в том что первая ожидает ответа от приложения и чисто теоретически если приложение вайбера повиснет в момент отправки сообщения, то наше приложение тоже зависнет в ожидании, вторая функция ничего не ожидает, но я все равно буду юзать SendMessage =)

Идем на pinvoke.nеt и ищем эту функцию, я нашел:

Код:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
Пихаем ее в общий код в нашем проекте, так же делаем ее публичной для доступа из экшена.

Смотрим что эта функция принимает на вход, это хендл окна, которому отправляем сообщение (его мы находили выше), само сообщение в типе Uint32 - эту константу найдем на msdn, wParam - что это такое вообще тоже узнаем на msdn , lParam аналогично. Вбиваем в поисковик название нашего сообщения (WM_LBUTTONDOWN), попадаем на msdn и видим:



Это есть наше сообщение в типе UInt32, сразу закидываем его в общий код, снова делая публичным, вот так:

Код:
public static UInt32 WM_LBUTTONDOWN = 0x0201;
Дальше видим, что описываются интересующие нас параметры wParam в нашем случае нужен вот такой:



Если вы посмотрите на сообщение в spy++ вы поймете почему =)
Аналогичным способом добавляем ее в общий код

Код:
public static UInt32 MK_LBUTTON = 0x0001;
А вот с lParam не все так просто, мсдн нам говорит что он должен содержать low-order - координата Y и high-order - координата X:

Эти low и high ордеры еще называют младшим и старшим словом, т.е. нам нужно из двух этих параметров получить один в типе IntPtr, для этого есть функция MakelParam, на пинвоке ее нету, но я ее нашел в интернетах, держите:

Код:
   public static IntPtr MakeLParam(int LoWord, int HiWord)
        {
            return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
        }
Снова пихаем ее в общий код:



Если кому интересно что в ней происходит, то вам сюда ТЫК

Не забываем про WM_MOUSEMOVE и его тоже цепляем в общий код проекта:

Код:
public static UInt32 WM_MOUSEMOVE = 0x0200;
Ну вот, все данные для отправки сообщения мы наскребли, можем формировать вызов функции в нашем экшене:

Код:
CommonCode.SendMessage(hwnd /*хендл нужного окна (вайбера)*/, CommonCode.WM_MOUSEMOVE /* сам код сообщения*/, IntPtr.Zero /*wParam, spy++ показал что он заполнен нулями*/, CommonCode.MakeLParam(238, 78) /* сформированный из координатов для клика lParam */ );


Код:
CommonCode.SendMessage(hwnd /*хендл нужного окна (вайбера)*/, CommonCode.WM_LBUTTONDOWN /* сам код сообщения*/, (IntPtr)CommonCode.MK_LBUTTON /*wParam, с явным приведением к  IntPtr*/, CommonCode.MakeLParam(238, 78) /* сформированный из координатов для клика lParam */ );


По идее уже сейчас если запустить наш проект, то в spy++ мы увидим, в каком виде пришло наше сообщение окну вайбера:



Замечательно, сообщение о передвижении мыши на координаты и нажатии ЛКМ по этим координатам вайбера успешно отправилось, да еще и в правильном виде!

Давайте теперь отправим сообщение о том что ЛКМ отпустили в этих же координатах, т.е. отправим WM_LBUTTONUP.

Снова на msdn находим значение этого сообщения и добавляем в общий код:



И формируем вызов функции:

Код:
CommonCode.SendMessage(hwnd /*опять же нужный идентификатор нашего окна */, CommonCode.WM_LBUTTONUP /* само значение сообщения */, IntPtr.Zero /* если внимательно посмотреть в spy++ на это сообщение, то видно что wParam там заполнен нулями, я так и сделал */, CommonCode.MakeLParam(238, 78) /* по старой схеме формируем lParam из координатов*/);


В теории сейчас должна успешно нажаться кнопка для набора номера в вайбере, даже в свернутом состоянии окна, проверяем:



У меня все прекрасно сработало, даже в свернутом вайбере!

Не отступаем от нашего плана и следующим пунктом у нас стоит ввод номера телефона, но надо понимать, что в не активном окне скорее всего при переходе на номеронабератель каретка не будет в нужном месте, давайте ее туда поставим обычным кликом по полю набора номера, точно так же как мы только что выбрали номеронабиратель:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(177, 155));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(177, 155));
Тут практика показала, что можно обойтись без WM_MOUSEMOVE.

Отлично, теперь можно набирать текст, лезем в spy++ и смотрим что отправляется окну вайбера при нажатии любой циферки:



Я выделил самое подходящее для нас сообщение о нажатии клавиши, однако, в некоторых случаях его может и не быть, тогда вам нужно будет смотреть на сообщения WM_KEYDOWN и WM_KEYUP.

Так вот, это сообщение говорит окну о том что пользователь нажал какой либо символ, значит мы должны сделать так же, в путь:

Сгугливаем значение WM_CHAR и кидаем в общий код:

Код:
public static UInt32 WM_CHAR = 0x0102;
Читаем на мсдн, что wParam - это есть char код символа, а lParam расписан вот так:



Это означает что придется немного поиграться с побитовыми операциями, юхууу!

Из всего этого списка нам нужно только лишь сформировать верный scan code клавиши и выполнить сдвиг на 16 бит влево и запихать туда единичку, т.к. в spy++ сказано что cRepeat: 1 - это мы и сделаем, но для получения scan code воспользуемся функцией:

Код:
 [DllImport("user32.dll")]
public static extern uint MapVirtualKey(uint uCode, uint uMapType);
Которую тоже нужно положить в общий код. Если вы загуглите что это за функция, то поймете что по сути она возвращает scan code клавиши, получая на входе ее virtual code и тип преобразования.

Формируем сообщение для нажатия клавиши 5 например:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_CHAR, (IntPtr)'5' /*явное преобразование char в IntPtr*/, (IntPtr)(CommonCode.MapVirtualKey('5', 0)<<16|1) /*это и есть получение scan code клавиши , выполнение сдвига влево на 16 бит и запихивание туда 1*/ );
Но нам же нужно набрать целый номер, поэтому будем печатать посимвольно из всей строки по циклу:
Код:
string number = "500092511";

for(int i=0; i< number.Length ;i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_CHAR, (IntPtr)number[i], (IntPtr)(CommonCode.MapVirtualKey('6', 0)<<16|1));
Правильней конечно было бы написать функцию, которая на вход получает любой текст и набирает его в нашем окне вайбера, ну да ладно, так нагляднее, проверяем:



Как видно, все работает, сообщения шлются, текст набирается, прекрасно! Осталось пару штрихов =)

По уже знакомой нам методике жмем кнопку, при помощи сообщений о нажатии ЛКМ, меняем только координаты:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEMOVE, IntPtr.Zero, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd,
CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(190,503));
Пробуем иии, не работает :(
Но мы же не отчаиваемся и смотрим в spy++, скорее всего что то пропустили:



Попалась! Не хватает WM_MOUSEACTIVATE, давайте попробуем его добавить:

Код:
public static UInt32 WM_MOUSEACTIVATE = 0x0021;
Это в общий код. Так же на мсдн находим значение переменное HTCLIENT и она равна 1, поэтому я ее добавлять не буду, а запишу прямо в формировании сообщения:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEACTIVATE, hwnd /*по документации msdn сказано что wParam это родительское окно, в нашем случае же это главное окно, поэтому сюда снова передаем hwnd*/, CommonCode.MakeLParam(1 /*это наша HTCLIENT*/, (int)CommonCode.WM_LBUTTONDOWN )/*так формируется lParam согласно инструкциям*/);
Важно понимать порядок передачи сообщений, т.е. сначала мы наводим курсор (WM_MOUSEMOVE), дальше активируется элемент (WM_MOUSEACTIVATE) потом идет нажатие мышкой (WM_LBUTTONDOWN), в коде это выглядит так:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEMOVE, IntPtr.Zero, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEACTIVATE, hwnd, CommonCode.MakeLParam(1, (int)CommonCode.WM_LBUTTONDOWN));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(190,503));
Следующий пункт - это ввод текста сообщения для рассылки, опять же не забываем поставить каретку в нужное место, но как? Если вы еще не заметили, то до этого момента, пока мы работали с левой панелькой вайбера, мы могли спокойно забирать координаты из spy++ и пользоваться ими, т.к. элементы на этой панельке не меняют свои координаты относительно всего окна, в отличии от поля, в которое нужно вводить текст сообщения, если мы возьмем для него координаты, а потом небрежный пользователь изменит размеры окна вайбера, то все сломается, нужно это как то учесть...

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

В общий код кидаем вот эти функции:

Код:
    [DllImport("user32.dll")]
        static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct Rectangle
        {
            public readonly int Left;
            public readonly int Top;
            public readonly int Right;
            public readonly int Bottom;
            public readonly int Height;
            public readonly int Width;

            public Rectangle(int width, int height) : this()
            {
                this.Height = height;
                this.Width = width;
            }
        }

        public static Rectangle GetWindowRectEx(IntPtr hWnd)
        {
            if (IntPtr.Zero == hWnd) return default(Rectangle);

            Rectangle lprect;
            GetWindowRect(hWnd, out lprect);
            return new Rectangle(lprect.Right - lprect.Left, lprect.Bottom - lprect.Top);
        }
В этой статье я уже не буду мучать вас понятиями структур и как они работаю, так что если интересно узнать как это работает, то гуглите или пишите.

Теперь мы можем получить в своем коде размеры окна, вызвав функцию GetWindowRectEx:

Код:
var rect =  CommonCode.GetWindowRectEx(hwnd);
Из этой переменной нас интересует только высота, она достигает максимального значения на нижней границе окна вайбера, значит мы должны из нее отнимать примерно 100, чтобы всегда попадать кликом на поле ввода текста, координата X будет примерно 570, именно при таком размере щелчек всегда будет попадать, вот что получается:

Код:
var rect =  CommonCode.GetWindowRectEx(hwnd);
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(570,rect.Height-100));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(570,rect.Height-100));
И теперь это работает с любым размером окна, нештяк! =)

Вводим наш текст по старой схеме:

Код:
string text = "Это добрый спам по вайберу! Никакой рекламы, только добро! Всем добра!";
for(int i=0; i< text.Length ;i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_CHAR, (IntPtr)text[i], (IntPtr)(CommonCode.MapVirtualKey(text[i], 0)<<16|1));
Все работает на УРА! Остался последний шаг - отправить сообщение, но так просто кликнуть на стрелочку мы опять не можем потому что у него каждый раз могут быть разные координаты относительно всего окна, по оси Y можно опять таким же макаром высчитать, но вот по оси X не получится, благо есть отправка по нажатию кнопки ENTER, действуем:

Сразу скажу что сообщение WM_CHAR с кодом кнопки enter вайбер видимо не обрабатывает, поэтому будем отправлять сообщение WM_KEYDOWN

Опять кидаем его значение в общий код:
Код:
public static UInt32 WM_KEYDOWN = 0x0100;
Гуглим эту функцию и видим, что wParam у нас виртуальный код клавиши, забираем нужный нам в исходный код:

Код:
public static UInt32 VK_RETURN = 0x0D;
lParam опять стряпаем из битов, не проблема, сделано:

Код:
CommonCode.SendMessage(hwnd, CommonCode.WM_KEYDOWN, (IntPtr)CommonCode.VK_RETURN, (IntPtr)(CommonCode.MapVirtualKey(CommonCode.VK_RETURN, 0)<<16|1));
Все по аналогии с примером на WM_CHAR.

Хотел уже сказать что все готово, но не тут то было)) Оказывается поле для ввода номера не отчищается автоматически, поэтому придется после каждого нажатия на номеронабиратель отчищать это поле, последний рывок:

В виду того что вайбер не хочет принимать сообщения нажатий Ctrl+A (хотя я уверен что это можно сделать, просто я уже туплю) я принял брутальное решение, просто 100 раз отправлю нажатие Backspace :D:

Код:
for(int i=0; i<100; i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_KEYDOWN, (IntPtr)CommonCode.VK_BACK, (IntPtr)(CommonCode.MapVirtualKey(CommonCode.VK_BACK, 0)<<16|1));
И чисто и быстро =)

Остается только все скомпоновать и можно запускать нашу адскую машинку, полный листинг сниппета:

Код:
IntPtr hwnd = CommonCode.FindWindow("Qt5QWindowIcon", null); // получаем хендл окна вайбера
var all_number = project.Lists["Номера для рассылки"];// лист, в котором лежат номера для рассылки

foreach(string a in all_number) // идем по циклу по всем номерам
{
    //клик мышкой по номеронаберателю
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEMOVE, IntPtr.Zero, CommonCode.MakeLParam(243,76));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(238, 78));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(238, 78));
    //

    //клик по полю ввода номера (установка каретки)
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(177, 155));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(177, 155));
//
  
    //супер кастыль для отчищения поля от остатков предыдущего номера
for(int i=0; i<100; i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_KEYDOWN, (IntPtr)CommonCode.VK_BACK, (IntPtr)(CommonCode.MapVirtualKey(CommonCode.VK_BACK, 0)<<16|1));
//

// текущую итерацию цикла складываем в переменную number и посимвольно отправляем соответствующие нажатия в окно вайбера
string number = a;
for(int i=0; i< number.Length ;i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_CHAR, (IntPtr)number[i], (IntPtr)(CommonCode.MapVirtualKey(number[i], 0)<<16|1));
//

// Клик по кнопке перехода в чат с номером
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEMOVE, IntPtr.Zero, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEACTIVATE, hwnd, CommonCode.MakeLParam(1, (int)CommonCode.WM_LBUTTONDOWN));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(190,503));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(190,503));
//

// Пауза для того чтобы вайбер успел прорисовать элементы после перехода в чат
Thread.Sleep(1000);
//получаем текущий размер окна
var rect =  CommonCode.GetWindowRectEx(hwnd);
//кликаем по полю ввода сообщения с учетом размеров окна
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(570,rect.Height-100));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(570,rect.Height-100));
//

//текст, который будет рассылаться
string text = "Это добрый спам по вайберу! Никакой рекламы, только добро! Всем добра!";
//по циклу печатаем каждый символ текста в окно вайбера
for(int i=0; i< text.Length ;i++)
CommonCode.SendMessage(hwnd, CommonCode.WM_CHAR, (IntPtr)text[i], (IntPtr)(CommonCode.MapVirtualKey(text[i], 0)<<16|1));
CommonCode.SendMessage(hwnd, CommonCode.WM_KEYDOWN, (IntPtr)CommonCode.VK_RETURN, (IntPtr)(CommonCode.MapVirtualKey(CommonCode.VK_RETURN, 0)<<16|1));
}

return hwnd;

Демонстрация этого чуда


Вообще область применения таких функций довольно таки обширная, не забывайте про эмуляторы Android, которыми так же без проблем можно управлять из PM...


Если у кого то возникнут вопросы, то пишите на почту [email protected]

Всем спасибо за внимание, надеюсь вы все разберетесь в этом нелегком направлении! =)
сэр, когда мышь находится в экземпляре (в приложении viber), тогда работает только winapi.
когда он выходит из-под контроля, win api не работает.
есть ли какое-либо решение, чтобы исправить эту проблему.
 

colcefer

Новичок
Регистрация
20.01.2016
Сообщения
20
Благодарностей
0
Баллы
1
Вопрос к знатокам)
C#:
CommonCode.SetCursorPos(452,434);
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEMOVE, IntPtr.Zero, CommonCode.MakeLParam(452,434));
CommonCode.SendMessage(hwnd, CommonCode.WM_MOUSEACTIVATE, hwnd, CommonCode.MakeLParam(1, (int)CommonCode.WM_LBUTTONDOWN));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONDOWN, (IntPtr)CommonCode.MK_LBUTTON, CommonCode.MakeLParam(452,434));
CommonCode.SendMessage(hwnd, CommonCode.WM_LBUTTONUP, IntPtr.Zero, CommonCode.MakeLParam(452,434));
Это работает в кубике, но только если после запуска Telegram клиента нажать руками на его окно. Если запустить клиент из кубика C# и следом попробовать выполнить код, он не работает. Spy++ не видит сообщений, пока не нажмешь на окно клиента Telegram руками)
 

ezotonal

Client
Регистрация
13.01.2014
Сообщения
819
Благодарностей
231
Баллы
43
Так запусти из кубика запуск программы. Хотя тут дело в другом

C#:
CommonCode.SetCursorPos(452,434);
Не привязывается к нашему IntPtr
 
Последнее редактирование:

morpheus93

Client
Регистрация
25.01.2012
Сообщения
1 058
Благодарностей
244
Баллы
63
Отличная статья! Большое спасибо! Как я не говорю по-русски, это было немного сложно, но освоило это :-)

Один вопрос возникл: как я могу получить текст из QT-приложения, такого как Viber (например, сообщения, которые я получил как ответ), и обработать его дальше в ZP?

Большое спасибо!

Перевод с Google.
 

morpheus93

Client
Регистрация
25.01.2012
Сообщения
1 058
Благодарностей
244
Баллы
63
И любая идея о том, как сделать двойной щелчок на элементе SyslistView32 (например, 4-й элемент или выбор по тексту)?

Спасибо.
 

popkizapah

Новичок
Регистрация
22.08.2021
Сообщения
2
Благодарностей
0
Баллы
1
Serkser
Привет а как спарсить программу exe? не вкурсе куда копать?
 

Radzhab

Client
Регистрация
23.05.2014
Сообщения
1 500
Благодарностей
1 268
Баллы
113

popkizapah

Новичок
Регистрация
22.08.2021
Сообщения
2
Благодарностей
0
Баллы
1
Есть приложение покерный клиент написано на ActionScript формат swf нужно определить имена игроков через process explorer (strings) найти не удалось, через wireshark перехватить не получилось.. может как то можно сделать по-другому?
 

valeron

Новичок
Регистрация
03.10.2020
Сообщения
8
Благодарностей
1
Баллы
3
Здравствуйте, подскажите почему функция FindWindowEx не находит окно и возвращает ноль?
C#:
IntPtr contactsd= CommonCode.FindWindowEx(contacts, IntPtr.Zero, "WindowsForms10.Window.8.app.0.1b0118c_r6_ad1", null);
 
  • Спасибо
Реакции: seodamage

Vasyl1

Client
Регистрация
11.12.2016
Сообщения
203
Благодарностей
23
Баллы
18
Помогите решить проблему, не ищет око, никакое, пишет постоянно ошибка в лог

Компиляция кода Ошибка в действии "CS0122" ""ZennoLab.OwnCode.CommonCode.FindWindow(string, string)" недоступен в силу его уровня защиты". [Строка: 0; Cтолбец: 26]

Как решить помогите?
 

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)