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

Serkser

Client
Регистрация
26.01.2015
Сообщения
90
Реакции
344
Баллы
53
Всем доброго дня! Сегодня я бы хотел раскрыть такую крутую тему как 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);

Куда же ее вставлять? Все просто:

img


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

Код:
Развернуть Свернуть Копировать
using System.Runtime.InteropServices;

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

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

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


img


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

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

Код:
Развернуть Свернуть Копировать
IntPtr hwnd = CommonCode.FindWindow("Qt5QWindowIcon", null);

return hwnd;

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

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

img


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

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

img


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

img


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

img


Среди всяких сообщений о передвижении мыши и установкой курсора (их названия говорят сами за себя) можно увидеть нажатия кнопки мыши по координатам окна, значит нужно определенно отправить эти два сообщения, а еще по своему опыту я скажу что нужно отправить 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 и видим:

img


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

Код:
Развернуть Свернуть Копировать
public static UInt32 WM_LBUTTONDOWN = 0x0201;

Дальше видим, что описываются интересующие нас параметры wParam в нашем случае нужен вот такой:

img


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

Код:
Развернуть Свернуть Копировать
public static UInt32 MK_LBUTTON = 0x0001;

А вот с lParam не все так просто, мсдн нам говорит что он должен содержать low-order - координата Y и high-order - координата X:
img

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

Код:
Развернуть Свернуть Копировать
   public static IntPtr MakeLParam(int LoWord, int HiWord)
        {
            return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
        }

Снова пихаем ее в общий код:

img


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

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

Код:
Развернуть Свернуть Копировать
public static UInt32 WM_MOUSEMOVE = 0x0200;

Ну вот, все данные для отправки сообщения мы наскребли, можем формировать вызов функции в нашем экшене:

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

img


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

img


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

img


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

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

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

img


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

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

img


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

img


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

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

Код:
Развернуть Свернуть Копировать
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++ и смотрим что отправляется окну вайбера при нажатии любой циферки:

img


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

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

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

Код:
Развернуть Свернуть Копировать
public static UInt32 WM_CHAR = 0x0102;

Читаем на мсдн, что wParam - это есть char код символа, а lParam расписан вот так:

img


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

Из всего этого списка нам нужно только лишь сформировать верный 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));

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

img


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

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

Код:
Развернуть Свернуть Копировать
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++, скорее всего что то пропустили:

img


Попалась! Не хватает 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...


Если у кого то возникнут вопросы, то пишите на почту serkser2014@yandex.ru

Всем спасибо за внимание, надеюсь вы все разберетесь в этом нелегком направлении! =)
 
Номер конкурса статей
  1. Пятый конкурс статей
Тема статьи
  1. Другое

Вложения

  • Spy++.rar
    Spy++.rar
    649,6 KB · Просмотры: 2 525
  • testim.xmlz
    testim.xmlz
    16,2 KB · Просмотры: 1 770
О! Это тема. Многие просят такое в функционале Зенно.
Хотя, как мне кажется, каким-нибудь AutoIt или MouseRobot все это можно сделать намного проще и быстрее.
 
Последнее редактирование:
  • Спасибо
Реакции: MORENO
супер-круто..
я в шоке от проделанной работы.. :dm:
 
  • Спасибо
Реакции: Andrew Shell
Это ТВОРЕНИЕ заслуживает пристального внимания - автор НОВАТОР - свежее принёс на форум - ЛАЙКАЮ
Очень приятно! Я на самом деле был удивлен, что данная тема еще не была разобрана на этом форуме =)
 
О! Это тема. Многие просят такое в функционале Зенно.
Хотя, как мне кажется, каким-нибудь AutoIt или MouseRobot все это можно сделать намного проще и быстрее.
Чем меньше оберток на пути к результату, тем быстрее и красивее работает решение =)
 
  • Спасибо
Реакции: Oleg_M и Sergodjan
Просто круть. Реально возможности этого гайда безграничны)
 
Чем меньше оберток на пути к результату, тем быстрее и красивее работает решение =)
Хорошо сказано) Только оберток меньше именно в AutoIt.
Это не умаляет достоинств статьи. Методика хоть и сложная, но может использоваться во многих кейсах.
 
Просто круть. Реально возможности этого гайда безграничны)
Но это лишь малая часть базовой информации, для разных приложений понадобятся новые функции/ сообщения
 
Сильная заявка на победу). Аплодисменты)
 
  • Спасибо
Реакции: Gfoblin
О! Это тема. Многие просят такое в функционале Зенно.
Хотя, как мне кажется, каким-нибудь AutoIt или MouseRobot все это можно сделать намного проще и быстрее.
Я так и делаю! Работаю в связке зенка+MouseRobot !
ТС молодеТС тема норм но для меня проще через MouseRobot. В С+ вообще тупой Я!
 
  • Спасибо
Реакции: MORENO
Красота! Будет чем теперь заняться! =)
 
Отличная статья.
Возможности применения реально безграничны.
Конечно попотеть придется работая со spy++, и не каждый осилит.
Но таким способом можно настроить взаимодействие с любой прогой, если других вариантов нет и очень надо.:-)
 
Отличная статья.
Возможности применения реально безграничны.
Конечно попотеть придется работая со spy++, и не каждый осилит.
Но таким способом можно настроить взаимодействие с любой прогой, если других вариантов нет и очень надо.:-)


Это не так сложно как кажется, просто нужно собраться с мыслями и действовать =)
 
Это не так сложно как кажется, просто нужно собраться с мыслями и действовать =)
Да для меня то это не сложно.))

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

А если использовать твой мануал, надо гуглить, читать msdn, ковыряться в WinApi функциях, тестить, пробовать.
В общем мозг нагружает основательно.:D

Конечно дорогу осилит идущий и нет ничего невозможного, было бы желание.;-)
 
Да для меня то это не сложно.))

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

А если использовать твой мануал, надо гуглить, читать msdn, ковыряться в WinApi функциях, тестить, пробовать.
В общем мозг нагружает основательно.:D

Конечно дорогу осилит идущий и нет ничего невозможного, было бы желание.;-)
Но в итоге игра будет стоить свеч :-)
 
Статья не понятная как для меня.
Не понятна связь зенно +решения выше.
Библиотеки зенно не задействованы, с браузером не работаем....

С такми успехом можно было написать еще две функции , взять тел и текст из файла и оформить нейтив приложение
Сомнительна целесообразность использования кубика C# как IDE , когда экосистема кубика никак не задействована )

За кейс 5-, разобрался с хендлами, дескрипторами...
За выбор среды исполнения кода 2)

п.с. забыл закрыть хендл что не айс для винды, все что поломал, верни обратно)
 
Статья не понятная как для меня.
Не понятна связь зенно +решения выше.
Библиотеки зенно не задействованы, с браузером не работаем....

С такми успехом можно было написать еще две функции , взять тел и текст из файла и оформить нейтив приложение
Сомнительна целесообразность использования кубика C# как IDE , когда экосистема кубика никак не задействована )

За кейс 5-, разобрался с хендлами, дескрипторами...
За выбор среды исполнения кода 2)

п.с. забыл закрыть хендл что не айс для винды, все что поломал, верни обратно)
По поводу закрытия учтем)
С IDE понятно что все это должно делаться в вижаке на нормальном десктоп приложении, но конкурс проводит зенка и поэтому хотелось показать новые не открытые ее возможности
 
Статья не понятная как для меня.
Не понятна связь зенно +решения выше.
думаю для другой задачи можно будет связать и библиотеки и броузер

Могу даже предложить вариант где такое может пригодится.
К примеру есть сайты, где идет двух факторная аутентификация.
Надо вбить логин/пасс + пароль из мобильного приложения.
И под этот сайт надо бота. Как быть?
Если например портировали это приложение под винду на C# или сделали какой то аналог, то хорошо.
Можно покопаться в исходниках(если есть, или декомпильнуть), и вытащить что надо, перекинув в шаблон.
А если такой возможности нет, только через какой нибудь левый эмулятор. Или влом ковыряться в исходниках.
То тогда такой способ вполне подходит.
 
Могу даже предложить вариант где такое может пригодится.
К примеру есть сайты, где идет двух факторная аутентификация.
...

С этим еще проще чем с хендлами))))
G=>rfc 6238 + c#

 
Последнее редактирование:
С этим еще проще чем с хендлами))))
G=>rfc 6238 + c#
Прикольно.))
Погуглил что за либы юзаются по using - ам.
В общем концепция понятна.
Не понятно как на винт попадат qr-код.
Ну как бы догадки есть, но это догадки.))

И еще название шаба интересное - 2StepAuthExample.))
Это спецом шаб сделал чтобы видос записать?
 
голосую за эту тему=) Автору респект и уважуха, и первго места в конкурсе=)
Будет 1 место - будут новые статьи с еще большими возможностями зенки, материала за время фриланса накопилось огромное кол- во )))
 
  • Спасибо
Реакции: samsonnn и Gfoblin
Работа, видно, проведена нехилая, спасибо за статью..сложно для обычного юзера, но главное маневры.
 
  • Спасибо
Реакции: Gfoblin и Serkser

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