• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Послать "горячие клавиши в другое приложение"

  • Автор темы Serge
  • Дата начала
Статус
Закрыто для дальнейших ответов.
S

Serge

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

Немного истории. Недавно мне понадобилось переписать программы для переводов в WORD и Stylus3.1. на Word и Promt6. Это только в PROMTе считают, что этот кошмар, "профессиональная среда для переводов". В отличие от Stylus, где весь интерфейс расписан в одной библиотеке, в Promt6 все намного сложнее. Попросил на сайде Promt справку по библиотекам типов, но меня отфутболили, потребовав регистрацию. Пожав плечами - какая может быть регистрация на библиотеки типов, если я рекламирую их продукт?

В общем, не стал брать библиотеки сразу в лоб, тем более не горело. Полазив по интернету обратил внимание на то, что много есть вопросов на то, что или не получается послать сообщение в другое приложение, или посылают накрутив гору кода, и не одного не нашел, как послать сообщение правильно в другое приложение "горячих клавиш", и оно обработалось.

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

Не открою никому Америку, что работа Windows базируется на сообщения между окнами и системой. Существует основной класс окна приложения и может быть подклассы окон приложения, и взаимодействуют они между собой с помощью сообщений, как стандартных, так и пользовательских.

А вот теперь, в интернете, я только вскользь, находил, а какими сообщениями они пользуются между собой? И почему - то все скопом мило умалчивают об этом.

Взяв два шпиона ws32.exe и spy.exe, немного поэкспериментировал и решил все свои проблемы. Хочу сразу заметить, что нижеприведенный код на искусство ни в коем мере не претендует - попросту это топор - веревка - палка, но все это работает и работает надежно.

Обратил внимание, на многих форумах народ жалуется, что посылают сообщения в приложение, а оно не обрабатывает его. Скорее всего, пытаются посылать сообщение в самое верхнее окно, но не факт, что оно пропустит сообщение на обработку, если оно предназначено для дочернего окна. Поэтому, чтобы подобные вещи делать необходимо, знать досконально Z порядок окон. И чтобы правильно послать сообщение необходимо поэкспериментировать со шпионами.

Суть, заключается в том, послав сообщение активному окну, т.е. нажав сочетание клавиш, в активном окне приложения. Окно определяет, что есть нажатие "горячих клавиш" и посылает в верхнее окно (необязательно в Z порядке) WM_COMMAND или WM_SYSCOMMAND, в основном, со стандартными сообщениями Windows, в качестве параметров. А вот после этого оконная процедура, как правило, она одна на приложение, реагирует на это сообщение.

Просто послать "сочетание" в другое приложение с помощью SendMessage или Post Message, вам не удаться никогда, если, только извернуться так, что удаться сымитировать работу драйвера клавиатуры. Но думаю, что не стоит ломать стену, если рядом не дыра, а "Бранденбурские ворота, " в которые вы можете въехать и измываться над любым приложением насколько у вас хватит фантазии.

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

Идея в следующем:

1. Переделать специализированный словарь от Stylus - в пользовательский, а затем подключить его к PROMTу

2. Созданный вновь словарь надо назвать "InfoStylus", в комментариях старался поподробней описать, на тот случай если кому - то понадобиться сделать тоже самое.

3. В командной строке запишите количество статей, которое необходимо переработать в пользовательский словарь. На практике 2000 статей обрабатывает нормально.

4. Написана на Builder6

Код:
#include <vcl.h>

#pragma hdrstop

//---------------------------------------------------------------------------



#pragma argsused

//дескриптор исходного словаря

HWND hWnd0 = NULL;

// дескриптор словаря слива статей

HWND hWnd1 = NULL;

// верхнее окно hWnd0

HWND hWnd01 = NULL;

// верхнее окно hWnd1

HWND hWnd11 = NULL;

//главное окно

HWND PAPA = NULL;

char dcv[80];

int i;

bool t6;

bool CALLBACK EnumWindowsProc(HWND, LPARAM);

bool CALLBACK EnumWinChild (HWND, LPARAM);



int main(int argc, char* argv[])

{   //определение PAPA

  EnumWindows((WNDENUMPROC)EnumWindowsProc, 0);



if (t6 == 1)

{

//да, закройте все окна в Stylus, программа особенно не тестировалась, а нижняя функция нужна на случай, если забыли это сделать

  EnumChildWindows(GetTopWindow(GetTopWindow(PAPA)), (WNDENUMPROC)EnumWinChild, 0);

//Определение дескрипторов словарей

EnumChildWindows(GetNextWindow(GetTopWindow(GetTopWindow(PAPA)), GW_HWNDNEXT), (WNDENUMPROC)EnumWinChild, 0);

//определение дескриптора старшего окна исходного словаря

hWnd01 = GetParent(GetParent(hWnd0));

//определение дескриптора старшего окна слива словаря

  hWnd11 = GetParent(GetParent(hWnd1));

//записать в командную строку количество статей, которые хотите скопировать  

//практически перегонял словарь, то выявились некоторые заморочки:

//пользовательский словарь должен быть < 300 kb,

// сразу ставить не более 2000 статей, иначе у Stylus съезжает крыша

 for (i == 0; i < atoi(argv[1]); i++)

  {

// переход в окно словаря слива

PostMessage (hWnd11, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);

/*задержка, все-таки PostMessage функция неуправляемая, а динамический приоритет у этой программы на данный момент самый высокий из выполняющихся программ, приходится делать задержку или менять приоритет, что труднее. Цифры взяты с потолка, они не факт*/

 Sleep(10);

//в определениях можно найти определение e122, что-то WM_COPY, легче так вставить, не проверял

PostMessage(PAPA, WM_COMMAND, 0x1e122, 0);

 Sleep(10);

// постановка сообщения в окно "Стрелка вниз"

//кстати послать нажатие клавиши можно, но не получиться просто так послать сочетание

//чем вызвано не знаю, скорее всего, какими-то временными интервалами в оконной процедуре

// если кто может подсказать напишите "finkeviche@yandex.ru"

PostMessage (hWnd0, WM_KEYDOWN, 0x28, 0);

PostMessage (hWnd0, WM_KEYUP, 0x28, 0);

Sleep(10);

// переход в словарь слива (помните, что все остальные окна должны быть закрыты)

//словарь должен быть назван "InfoStylus.udc"(потом можно его переименовать и вообще, что хотите, то и сделать и конвертировать его в PROMT6)

//и имя его должно тоже быть "InfoStylus", иначе не определится дескриптор

PostMessage (hWnd01, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);

Sleep(10);

// вставить из буфера обмена статью в словарь слива

//в определениях можно найти определение "e125", что-то вроде ID_EDIT_PASTE,

//а 1 в старшем слове определяет, что используется клавиатура

//ну и все такое, кому интересно

PostMessage(PAPA, WM_COMMAND, 0x1e125, 0);

 Sleep(100);

  }

}

  return 1;



}

//---------------------------------------------------------------------------



bool CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)

{

 GetClassName(hWnd, dcv, 60);

  int ptr;

  ptr = strcmp(dcv, "TStylusWindow");

   if (ptr == 0)

  {

   PAPA = hWnd;

   t6 = true;

   return false;

  }

  t6 = false;

  return true;

};



bool CALLBACK EnumWinChild (HWND hWnd, LPARAM lp)

{

   int ptr;

   GetClassName(hWnd, dcv, 60);

   ptr = strcmp(dcv, "SysListView32");

   GetWindowText(hWnd, dcv, 70);

   if (ptr == 0 && strcmp(dcv, "List1") == 0)

   {

   GetWindowText(GetParent(GetParent(hWnd)), dcv, 80);

   if (strncmpi(dcv, "InfoStylus:", 11) == 0)

   {

      hWnd1 = hWnd;

   }

   else

   {

      hWnd0 = hWnd;

   }



   }

   return true;

}



//=============================================

А ниже приведен код на VBA, чтобы заставить PROMT6 переводить в Wordе. Необходимость этого в том, что если задействовать стандартные средства переводчика и предоставленный интерфейс в редакторе(Word), не получатся слитное выполнение общей программы, т.к. в памяти от переводчика болтается сервисная программа и ей фиолетово, что делается в редакторе, и связки не получатся. Пробовал отлавливать потоки на количество, но в сервисной программе, кажется, идет подсчет ссылок и отказывается переводить вообще. В сервисном модуле постоянно присутствует 4 потока, и она отшивает все, что не зарегистрировано PROMTом.

Программа переводит выделенный текст и возвращает перевод из переводчика и оставляет его выделенным

'StylusMacros

'объявления на уровне модуля

Dim Doc As Object

Dim Promt As Object

Dim rfgt55 As Integer

Option Explicit

'так удобно передавать в другие модули

'параметры мои и особенно не обращайте внимание на них

Sub StylusFlaish_t(SrtingProgramm$, yj As Long, dc As String)



Select Case SrtingProgramm$

 Case "TransSelection"

   TransSelection (yj)

 Case "TransDocument"

   TransDocument

 Case "PromViz"

   PromViz

 Case "PromNoViz"

 PromNoViz

End Select

Private Sub TransSelection(yj As Long)

Dim myTask As Task

Dim Ran As Object

If Doc Is Nothing Then

'параметра можно откапать из реестра

 Set Promt = CreateObject("Promt.Application")

' делать PROMT видимым, если 0, то скрытым

 Promt.Visible = 1

 Set Doc = Promt.PromtDocuments.Add(1, "PROMT.Document")

Else

'переход в окно английского текста на всякий случай

   For Each myTask In Tasks

     If InStr(myTask.Name, "PROMT") > 0 Then
'H111 код по определению WM_COMMAND, а 8007 переход в окно исходного текста

'ну, 1 в старшем слове, я уже объяснял

       myTask.SendWindowMessage &H111, &H18007, 0

       Exit For

     End If

   Next myTask

'см. справку по библиотекам типов (описание пользование макросами), которая поступает с PROMT

'разработчики все - таки разжалобились

   Doc.Text = ""
End If


Set Ran = Selection.Range

Ran.Copy

Doc.Paste

'вообще-то из-за этой функции и пришлось использовать COM интерфейс переводчика

Doc.Translate
'переход в окно перевода

 For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H18008, 0

    End If

 Next myTask

'все выделить

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H1E12A, 0

    End If

 Next myTask

'скопировать в буфер

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H1E122, 0

     Exit For

    End If

 Next myTask



Ran.Paste

Ran.Select

'на случай если необходимо сохранить исходный текст, yj =1

'то переход в окно исходного текста

If yj = 1 Then

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H18007, 0

     Exit For

    End If

 Next myTask

'все выделить  

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H1E12A, 0

    End If

 Next myTask

'скопировать в буфер обмена

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H1E122, 0

     Exit For

    End If

 Next myTask

End If

'PROMT накапливает буфер обмена, вот его и очищаем

'может и сам очищает, но не проверял

rfgt55 = rfgt55 + 1

If rfgt55 > 5 Then

  For Each myTask In Tasks

   If InStr(myTask.Name, "PROMT") > 0 Then

     myTask.SendWindowMessage &H111, &H8513, 0

     Exit For

    End If

 Next myTask

 rfgt55 = 0

End If

Set Ran = Nothing

End Sub





' если запустили PROMT в скрытом виде, то так можно его увидеть

Private Sub PromViz()

 Promt.Visible = 1

End Sub

'а так скрыть, но не советую

Private Sub PromNoViz()

 Promt.Visible = 0

End Sub



//======================================================



/*Ниже приведен реализ выше написанного кода, но в C++

Все - таки Word дремуче работает с памятью и лишний раз дергать его за 

усы не стоит. 

Могут быть накладки, в том смысле, что среди 30 файлов

найти все объявления и описания, мог и пропустить, но кому надо, тот поймет*/

RETPromt.cpp

//---------------------------------------------------------------------------

#include <vcl.h>

#include <windows.h>

#include <Vcl\utilcls>



#pragma hdrstop



#include "SekFill.h"

//---------------------------------------------------------------------------



#pragma package(smart_init)





extern "C" __declspec(dllexport) void __stdcall ManipPROMT()

{

try{

  if (VarIsEmpty(Stek->RetOLE()))

  {

   Stek->SetOLE1();

   Stek->SetOLE();

   EnumWindows((WNDENUMPROC)EnumWindowsProcA, 0);

      }

  else

      {

//в отличие от ДОС выриатиа можно использовать SendMessage, т.к. сообщения поступаю все в верхнее окно

SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x18007, 0);

Stek->RetOLE().OlePropertySet("Text", "");

      }

  Stek->RetOLE().OleProcedure("Paste");

  Stek->RetOLE().OleProcedure("Translate");

  SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x18008, 0);

  SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x1E12A, 0);

  SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x1E122, 0);

  Stek->y = Stek->y + 1;

  if (Stek->y > 4)

  {

SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x8513, 0);

Stek->y = 0;

  }



}

catch(const Exception &E)

{

  ShowMessage(AnsiString(E.ClassName())+ E.Message);



}

return;

}

//функция на тот случай если надо сохранить исходный текст в буфере

extern "C" __declspec(dllexport) void __stdcall REtClipboard()

{

 SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x18007, 0);

 SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x1E12A, 0);

 SendMessage(Stek->REtHWND(), (UINT)0x111, (WPARAM)0x1E122, 0);



}

//------------------------------------------------------------------------------------------------

 SekFill.h
//---------------------------------------------------------------------------



#ifndef SekFillH

#define SekFillH

#include <vcl.h>

class TsekFill

{

private:

//закрытые т.к. стоит CpuIdlePro для XP и часто класс открывает буфер и закрывает его

//переводчик иногда глючил

//объяснений нет, но сейчас перестал, а так наверно не обязательно закрывать

 //вариант для документа PROMT

 Variant V;

 //вариант для самого приложения PROMT

 Variant V1;

 //хэндл для основного окна

 HWND hwnd;

public:

//счетчик буфера переводчика

int y;

TSekFill();

//возвращает интерфейс документа PROMT

Variant RetOLE();

//назначает интерфейс документа на вариант

void SetOLE();

//назначает интерфейс приложения на вариант

void SetOLE1();

//возвращает хэндл главного окна

HWND REtHWND();

//назначает хэндл на основное окно

void SetHWHD(HWND&);

virtual ~TSekFill();

};

extern TSekFill* Stek;

//функция повторного вызова для определения главного окна

bool CALLBACK EnumWindowsProcA(HWND, LPARAM);



//---------------------------------------------------------------------------

#endif



//=================================================

 SekFill.cpp



//#include <vcl.h>

#include <windows.h>

//#include <sysvari.h>

#include <Clipbrd.hpp>

#include <Vcl\utilcls>

#pragma hdrstop

#include "SekFill.h"





//---------------------------------------------------------------------------

#pragma package(smart_init)



TSekFill::TSekFill()

{

 y = 0;

}



//---------------------------------------------------------------------

 TSekFill::~TSekFill()

 {

   V = Unassigned;

   V1 = Unassigned;

 }





 //---------------------------------------------------------------

Variant TSekFill::RetOLE()

{

 return V;

}

void TSekFill::SetOLE()

{

V = V1.OlePropertyGet("PromtDocuments");

V1.OlePropertySet("Visible", true);

V = V.OleFunction("Add", 1, "PROMT.Document");

}



void TSekFill::SetOLE1()

//коряво, но это часть класса и он распределяется в динамической памяти,

//держит в памяти много параметров на время сессии Word и при любом сбое

// выгружается, записывая параметры и стек посещения документов в файл,

// а при загрузке восстанавливает все данные

{

if (VarIsEmpty(V1))

{

  V1 = OleVariant::CreateObject("Promt.Application");

}

else

{

  V1 = Unassigned;

  V1 = OleVariant::CreateObject("Promt.Application");

}

}

HWND TSekFill::REtHWND()

{

   return hwnd;

}



void TSekFill::SetHWHD(HWND& hWnd)

{

   hwnd = hWnd;



}



bool CALLBACK EnumWindowsProcA(HWND hWnd, LPARAM lp)

{

   char asd[60];

//проверяется имя класса окна, и название окна

   GetClassName(hWnd, asd, 60);

   int ptr = strncmpi(asd, "Afx:400000:", 11);

   GetWindowText(hWnd, asd, 60);

   int ptrz = strncmpi(asd, "PROMT - [", 9);

   if (ptr == 0 && ptrz == 0)

 {

   Stek->SetHWHD(hWnd);

   return false;

 }

  return true;

}


Сергей Финкевич.
 
G

Guest

Я не понял. Ты хочешь сделать глобальные хоткеи?
 
S

Serge

<!--QuoteBegin-QUOTE+Guest-->
<span class="vbquote">(QUOTE @ Guest)</span><!--QuoteEBegin-->Я не понял. Ты хочешь сделать глобальные хоткеи?[/quote]
Нет, это я к тому, что справку скрывать - пошло.
 
Статус
Закрыто для дальнейших ответов.
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!