Как получить данные из списка Алертов. WinAPI

 

Я пытаюсь получить алерты из списка.

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

Мне удалось получить хендл Listview, но никак не получается прочитать сообщение.

#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#define WM_GETTEXT        0x000D
#define WM_USER 0x0400

#import "kernel32.dll" 
   int GetCurrentThreadId();
#import    
   
#import "user32.dll"
int SendMessageA(int hWnd,int Msg,int wParam,char& lParam[]);
int  FindWindowA(uchar &lpClassName[], uchar &lpWindowName[]);

int  FindWindowExW(int    hwndParent,      // Дескриптор родительского окна.
                   int    hwndChildAfter, // Дескриптор дочернего окна.
                   string lpszClass,         // Указатель имени класса.
                   string lpszWindow);      // Указатель имени окна.

int  GetDlgItem(int hDlg,        // Блок диалога, содеpжащий оpган упpавления.
                int nIDDlgItem); // Идентификатоp оpгана упpавления.
            
#import


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   Alert("ddsdssq21 rerweeeeeeeeeeeeer");
   OnTick();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   Comment("");
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
 //  Alert("CurrentThreadId = " + GetCurrentThreadId());

 int A[7];
    uchar clN[],lpW[];

    StringToCharArray("#32770",clN);
   StringToCharArray("Alert",lpW);

   int   handleMainAlert = FindWindowA(clN, lpW);
  
   int handle=FindWindowExW(handleMainAlert,     // Дескриптор родительского окна.
                       0,                        // Дескриптор дочернего окна.
                       "SysListView32",          // Указатель имени класса.
                       "List1");                 // Указатель имени окна.
    Print(handle);
  
   char a[256],empty[];
   ArrayInitialize(a, 0);
   ArrayInitialize(empty, 0);


     int rows=SendMessageA(handle,0x1004,0,empty); //число строк
     int columns=SendMessageA(handle,0x1200,0,empty); //число столбцов

   string str = CharArrayToString(a);

    Comment(" Res : ",str,"\nСтрок : ",rows,"\nСтолбцов : ",columns);
      
  }

 
Этот список с большой долей вероятности со свойством LVS_OWNERDATA . Поэтому вряд ли получится получить содержимое - оно имеется только у самого терминала.
 
Ihor Herasko #:
Этот список с большой долей вероятности со свойством LVS_OWNERDATA . Поэтому вряд ли получится получить содержимое - оно имеется только у самого терминала.
Я пробовал наскоком написать в C#, нашел пример, но что-то не заработало.
 
Для МТ4 у меня было решение в виде библиотеки, но  в МТ5 уже не работает. OWNERDATA везде ...
 
Mikhail Dovbakh #:
Для МТ4 у меня было решение в виде библиотеки, но  в МТ5 уже не работает. OWNERDATA везде ...
Мне как раз нужно для МТ4, можете ссылку кинуть?
 
Fedor Arkhipov #:
Мне как раз нужно для МТ4, можете ссылку кинуть?

могу через фриланс продать.

 
Как я понял, но не точно, этот стиль MQ используют в таблицах с сортировкой, а в алерте вроде нет сортировки.
 
Mikhail Dovbakh #:

могу через фриланс продать.

Спасибо за предложение, но мне надо разобраться, чтобы понимать как это работает.
 

Вот нашел такой код для С. 

#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>

int main(void) {
 HWND hwnd=FindWindow(NULL, "Stealing Program's Memory: ListView");
 HWND listview=FindWindowEx(hwnd, NULL, "SysListView32", NULL);

 int count=(int)SendMessage(listview, LVM_GETITEMCOUNT, 0, 0);
 int i;

 LVITEM lvi, *_lvi;
 char item[512], subitem[512];
 char *_item, *_subitem;
 unsigned long pid;
 HANDLE process;

 GetWindowThreadProcessId(listview, &pid);
 process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
                     PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);

 _lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM),
                              MEM_COMMIT, PAGE_READWRITE);
 _item=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT,
                             PAGE_READWRITE);
 _subitem=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT,
                                PAGE_READWRITE);

 lvi.cchTextMax=512;

 for(i=0; i<count; i++) {
  lvi.iSubItem=0;
  lvi.pszText=_item;
  WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);
  SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi);

  lvi.iSubItem=1;
  lvi.pszText=_subitem;
  WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);
  SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi);

  ReadProcessMemory(process, _item, item, 512, NULL);
  ReadProcessMemory(process, _subitem, subitem, 512, NULL);

  printf("%s - %s\n", item, subitem);
 }

 VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
 VirtualFreeEx(process, _item, 0, MEM_RELEASE);
 VirtualFreeEx(process, _subitem, 0, MEM_RELEASE);

 return 0;
}
 

Фёдор, там не по-простому. Поискал в загашниках, чуток подправил под ситуацию. Всё работает.

#property version   "1.00"
#property strict

#define LVM_GETITEMCOUNT 0x1004
#define LVIF_TEXT 0x0001
#define LVM_GETITEMTEXTA 0x102D
#define LVM_GETITEMA 0x1005

#import "user32.dll"
int FindWindowW(string a0, string a1);
int FindWindowExW(int hWndParent,int hWndChildAfter,string lpszClass,string lpszWindow);
int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
int SendMessageW(int hWnd,int Msg,int wParam,int lParam);
int CharPrevW(char &lpszStart[], char &lpszCurrent[]); // используем для получения адреса строки
int CharPrevW(int &lpszStart[],int &lpszCurrent[]); // используем для получения адреса массива целых чисел
#import

void OnStart()
   {
   Alert("AAA");
   Alert("BBB");
   Alert("CCC");
   
   
   int ha=0, eCount=0;
   do
      {
      ha=FindWindowW("#32770", "Алерт");
      eCount++;
      if(eCount>100) return;
      Sleep(100);
      }
   while(ha==0);
   int ht=FindWindowExW(ha,0,"SysListView32","List1");   

   char ch[540];
   for(int i=0; i<540; i++) ch[i]=0x000;

   int arr[9];
   arr[0]=LVIF_TEXT;          //маска, какие из оставшихся полей должны быть заполнены
   arr[1]=0;                  //индекс элемента
   arr[2]=1;                  //дополнительный индекс (колонка)
   arr[3]=0;                  //текущее состояние атрибутов
   arr[4]=0;                  //новое задаваемое состояние атрибутов
   arr[5]=CharPrevW(ch,ch);   //текст(указатель на строку) элемента
   arr[6]=128;                //размер буфера на который указывает pszText
   arr[7]=0;                  //индекс значка в списке изображений
   arr[8]=0;                  //32-битное значение, ассоциируемое с записью
   int LVITEM_addr=CharPrevW(arr,arr);
   
   int ItemsCount = SendMessageA(ht, LVM_GETITEMCOUNT, 0, 0);
   
   int hs;
   string stu;
   for (int i = 0; i < ItemsCount; i++)
      {
      arr[1]=i;
      for(int j=0; j<ArraySize(ch); j++) ch[j]=0x000;
      hs=SendMessageA(ht, LVM_GETITEMTEXTA, i, LVITEM_addr);
      stu="";
      
      
      for(int r=0; r<hs; r++) stu+=CharToString(ch[r]);
      printf(">>> "+(string)hs+" : "+stu);
      Sleep(100);
      }
   }
 
А в таблицах с сортировкой таким способом не прочитать. То, что ребята говорили, LVS_OWNERDATA.
Причина обращения: