目的
他のインジケータやEAのアラートを盗む。
アラートとは?
この鈴がついたウィンドウです!
アラートの正体
結論から言うと,MetaTraderのアラートの正体は,ListViewです。
なぜListViewとわかったかというのは,spy++というソフトを使えばわかります。
ググればすぐでてきますが,VisualStudioに同梱されている便利ツールです。
こいつをつかって,アラートは何者なのか,スクロールできるあの窓は何で構成されているのか調べることができます。
環境によって違うのかもしれませんが,時間と共に表示されているのはListViewで,アラート自身のウィンドウは,#32770というのがキーです。
MQL4
このあたりのマクロ定義は決まったお作法のようなものなので・・・。
#define LVM_GETITEMCOUNT 0x1004
#define LVM_GETITEMW 0x1005
#define LVM_GETHEADER 0x101F
#define LVIF_TEXT 0x0001
#define HDM_GETITEMCOUNT 0x1200
#define PROCESS_VM_OPERATION 0x0008
#define PROCESS_VM_READ 0x0010
#define PROCESS_VM_WRITE 0x0020
#define MEM_RESERVE 0x2000
#define MEM_DECOMMIT 0x4000
#define MEM_RELEASE 0x8000
#define MEM_COMMIT 0x1000
#define PAGE_READWRITE 0x0004
#define BM_CLICK 0x00F5//ユーザーがボタンをクリックした。
次に,MQL側からWin32API用のDLLを呼びます。
#import "user32.dll"
int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
int SendMessageW(int hWnd,int Msg,int wParam,int lParam);
int PostMessageW(int hWnd,int Msg,int wParam,int lParam);
int FindWindowW(string lpClassName,string lpWindowName);
int FindWindowExW(int hwndParent,int hwndChildAfter,string lpClassName,string lpWindowName);
int GetWindowThreadProcessId(int hWnd, int &lpProcessId[]);
#import "kernel32.dll"
int OpenProcess(int dwDesiredAccess,bool bInheritHandle,int dwProcessId);
int ReadProcessMemory(int hProcess,int lpBaseAddress,char &lpBuffer[],int nSize,int lpNumberOfBytesRead);
int WriteProcessMemory(int hProcess, int lpBaseAddress, int &lpBuffer[], int size, int &written);
//メモリ展開 解放
int VirtualAllocEx(int hProcess,int lpBaseAddress, int dwSize, int flAllocationType,int flProtect);
int VirtualFreeEx(int hProcess,int lpAddress,int dwSize,int dwFreeType);
int CloseHandle(int hObject);
int GetCurrentProcessId();
int GetCurrentThreadId();
#import
不要なアラートを拾わないようにメンバーに以下を宣言しておきます。
input string C5="---- アラート設定 ----";//---- アラート設定 ----
input bool mtAlertEnable = false; //MetaTrader(スマホアプリ)の通知可否
input bool myAlertEnable = false; //標準アラートを自動で閉じるかどうか
input string C6="---- フィルタ設定 ----";//---- フィルタ設定 ----
input bool fileterEnable =true;//フィルタ有効?(true:有効/false:無効)
input string filter1="Line";//フィルタ1
input string filter2="";//フィルタ2
input string filter3="";//フィルタ2
まずは,アラートを取得する関数です。
void getAlert()
{
if(drows > 0)
{
hwnd = FindWindowW("#32770","アラート");
hwndList = FindWindowExW(hwnd,0,"SysListView32","List1");
rows = SendMessageA(hwndList,LVM_GETITEMCOUNT,0,0);//リストビューの行数の取得
myhwndListHeader = SendMessageA(hwndList, LVM_GETHEADER,0,0);//リストビューヘッダのハンドルを取得
colums = SendMessageA(myhwndListHeader,HDM_GETITEMCOUNT, 0, NULL);//リストビューの列数の取得
//Print("ListViewの行数の取得"+(string)rows+" 列数は"+(string)colums);
int LVITEM[10];
int qid[1];
tid = GetWindowThreadProcessId(hwnd,qid);
pid=qid[0];
//プロセスハンドラを取得する。
hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, False, pid);
////共有メモリ確保
//int lpShared1 = GetSharedMem(pid, sizeof(LVITEM), hProc);
//int lpShared2 = GetSharedMem(pid, 255, hProc);
//int lWritten=0;
//printf("OpenProcess %d",hProc);
//printf("共有メモリ確保 lpShared1_%d ,lpShared2_%d hProc %d",lpShared1,lpShared2,hProc);
uchar strBuffer[255];
for(int i=rows-drows-1; i>=0; i--)
{
string qtr="";
for(int j=1; j<colums; j++)
{
//共有メモリ確保
int lpShared1 = GetSharedMem(pid, sizeof(LVITEM), hProc);
int lpShared2 = GetSharedMem(pid, 255, hProc);
int lWritten=0;
LVITEM[0] = LVIF_TEXT;
LVITEM[1] = i;
LVITEM[2] = j;//項目のインデックス(列
LVITEM[5] = lpShared2;
LVITEM[6] = 255; // textmask
int intRc= WriteProcessMemory(hProc, lpShared1,LVITEM, sizeof(LVITEM), lWritten);//書込み
if(intRc ==0)
continue;
intRc = SendMessageW(hwndList,LVM_GETITEMW,0,lpShared1);//取得依頼
if(intRc ==0)
continue;
intRc = ReadProcessMemory(hProc,lpShared2, strBuffer, 255, 0); //読込
if(intRc ==0)
continue;
qtr += CharArrayToString(strBuffer,0,255, CP_THREAD_ACP)+" ";
//qtr = ShortArrayToString(strBuffer,0,255);
//メモリ解放
FreeSharedMem(hProc, lpShared1, sizeof(LVITEM));
FreeSharedMem(hProc, lpShared2, 255);
}
int f1,f2,f3;
int ff1,ff2,ff3;
ff1 = StringLen(filter1);
ff2 = StringLen(filter2);
ff3 = StringLen(filter3);
f1 = StringLen(filter1) > 0 ? StringFind(qtr,filter1,0):-1;
f2 = StringLen(filter2) > 0 ? StringFind(qtr,filter2,0):-1;
f3 = StringLen(filter3) > 0 ? StringFind(qtr,filter3,0):-1;
if(fileterEnable)
{
if(f1>=0||f2>=0||f3>=0)
{
myAlert(qtr);
Print("アラートをスティールしました→,",qtr);
}
}
else
{
myAlert(qtr);
Print("アラートをスティールしました→,",qtr);
}
}
////メモリ解放
//FreeSharedMem(hProc, lpShared1, sizeof(LVITEM));
//FreeSharedMem(hProc, lpShared2, 255);
}
drows = rows;
//Print("END");
}
ListViewの中身は,共有メモリ内にあるようで,そこにアクセスできればListViewの中身を取りに行けます。
共有メモリへのアクセスには,
GetSharedMem(int mypid, int memSize, int ahProc)
アクセスしたあとは,手を離さないといけないので,
FreeSharedMem(int ahProc,int MemAddress,int memSize)
を読んでいます。
それぞれの実装は次になります。
//+------------------------------------------------------------------+
//| 共有メモリ確保 |
//+------------------------------------------------------------------+
int GetSharedMem(int mypid, int memSize, int ahProc)
{
return VirtualAllocEx(ahProc, 0, memSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
//+------------------------------------------------------------------+
//| 共有メモリ解放 |
//+------------------------------------------------------------------+
int FreeSharedMem(int ahProc,int MemAddress,int memSize)
{
VirtualFreeEx(ahProc, MemAddress, memSize, MEM_RELEASE);
return CloseHandle(ahProc);
}
//+------------------------------------------------------------------+
あとは
myAlert(string msg)
で,煮るなり焼くなりすればいいわけです。
//+------------------------------------------------------------------+
//| チャート送ったり通知したりするところのまとめ |
//+------------------------------------------------------------------+
void myAlert(string msg)
{
datetime now =TimeLocal();
MqlDateTime now_struct;
TimeToStruct(now, now_struct);
string myNow = StringFormat("%4d-%02d-%02d_%02d-%02d-%2d",
now_struct.year,
now_struct.mon,
now_struct.day,
now_struct.hour,
now_struct.min,
now_struct.sec);
if(mtAlertEnable)
{
SendNotification(myNow+" "+ msg);
}
if(myAlertEnable)
{
int hwndButton = FindWindowExW(hwnd,0,"Button","OK");//アラートのウィンドウを閉じる。
PostMessageW(hwndButton,BM_CLICK,0,0);
}
}
//+------------------------------------------------------------------+
注意事項
アラートの量にもよりますが,1週間も稼働させればMetaTraderが固まります!
コード全部
#property strict
#property indicator_chart_window
#define LVM_GETITEMCOUNT 0x1004
#define LVM_GETITEMW 0x1005
#define LVM_GETHEADER 0x101F
#define LVIF_TEXT 0x0001
#define HDM_GETITEMCOUNT 0x1200
#define PROCESS_VM_OPERATION 0x0008
#define PROCESS_VM_READ 0x0010
#define PROCESS_VM_WRITE 0x0020
#define MEM_RESERVE 0x2000
#define MEM_DECOMMIT 0x4000
#define MEM_RELEASE 0x8000
#define MEM_COMMIT 0x1000
#define PAGE_READWRITE 0x0004
#define BM_CLICK 0x00F5//ユーザーがボタンをクリックした。
//
input string C5="---- アラート設定 ----";//---- アラート設定 ----
input bool mailAlertEnable = false; //メールの通知可否
input bool mtAlertEnable = false; //MetaTrader(スマホアプリ)の通知可否
input bool myAlertEnable = false; //標準アラートを自動で閉じるかどうか
input string C6="---- フィルタ設定 ----";//---- フィルタ設定 ----
input bool fileterEnable =true;//フィルタ有効?(true:有効/false:無効)
input string filter1="AUTO";//フィルタ1
input string filter2="";//フィルタ2
input string filter3="";//フィルタ2
input string C7="---- 通知除外時間はパソコンの時間です。 ----";//---- 通知除外時間 ----
input string C8="---- trueなら除外 falseなら通知します。 ----";//---- 通知除外時間 ----
input bool exclosion00 = false;//00時
input bool exclosion01 = false;//01時
input bool exclosion02 = false;//02時
input bool exclosion03 = false;//03時
input bool exclosion04 = false;//04時
input bool exclosion05 = false;//05時
input bool exclosion06 = false;//06時
input bool exclosion07 = false;//07時
input bool exclosion08 = false;//08時
input bool exclosion09 = false;//09時
input bool exclosion10 = false;//10時
input bool exclosion11 = false;//11時
input bool exclosion12 = false;//12時
input bool exclosion13 = false;//13時
input bool exclosion14 = false;//14時
input bool exclosion15 = false;//15時
input bool exclosion16 = false;//16時
input bool exclosion17 = false;//17時
input bool exclosion18 = false;//18時
input bool exclosion19 = false;//19時
input bool exclosion20 = false;//20時
input bool exclosion21 = false;//21時
input bool exclosion22 = false;//22時
input bool exclosion23 = false;//23時
#import "user32.dll"
//---- messages
int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
int SendMessageW(int hWnd,int Msg,int wParam,int lParam);
int PostMessageW(int hWnd,int Msg,int wParam,int lParam);
//lpClassName・・・クラス名
//lpWindowName・・・ウィンドウ名
//return ウィンドウハンドル
int FindWindowW(string lpClassName,string lpWindowName);
//hwndParent・・・親Windowのハンドル
//hwndChildAfter・・・検索を開始する子Windowのハンドル。「0」の場合、最初の子Windowから検索
//lpClassName・・・クラス名
//lpWindowName・・・ウィンドウ名
//return ウィンドウハンドル
int FindWindowExW(int hwndParent,int hwndChildAfter,string lpClassName,string lpWindowName);
int GetWindowThreadProcessId(int hWnd, int &lpProcessId[]);
#import "kernel32.dll"
int OpenProcess(int dwDesiredAccess,bool bInheritHandle,int dwProcessId);
int ReadProcessMemory(int hProcess,int lpBaseAddress,char &lpBuffer[],int nSize,int lpNumberOfBytesRead);
int WriteProcessMemory(int hProcess, int lpBaseAddress, int &lpBuffer[], int size, int &written);
//メモリ展開 解放
int VirtualAllocEx(int hProcess,int lpBaseAddress, int dwSize, int flAllocationType,int flProtect);
int VirtualFreeEx(int hProcess,int lpAddress,int dwSize,int dwFreeType);
int CloseHandle(int hObject);
int GetCurrentProcessId();
int GetCurrentThreadId();
#import
int hwnd ;
int hProc;//ぷろせすはんどる
int hwndList;
int rows;
int myhwndListHeader;
int colums;
int drows;
int pid;//プロセスID
int tid;//スレッドID
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
Alert("TEST_TEST_TEST_TEST_TEST_TEST_TEST");
drows=99999999;
getAlert();
//---
EventSetTimer(5);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
getAlert();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void getAlert()
{
if(drows > 0)
{
hwnd = FindWindowW("#32770","アラート");
hwndList = FindWindowExW(hwnd,0,"SysListView32","List1");
rows = SendMessageA(hwndList,LVM_GETITEMCOUNT,0,0);//リストビューの行数の取得
myhwndListHeader = SendMessageA(hwndList, LVM_GETHEADER,0,0);//リストビューヘッダのハンドルを取得
colums = SendMessageA(myhwndListHeader,HDM_GETITEMCOUNT, 0, NULL);//リストビューの列数の取得
//Print("ListViewの行数の取得"+(string)rows+" 列数は"+(string)colums);
int LVITEM[10];
int qid[1];
tid = GetWindowThreadProcessId(hwnd,qid);
pid=qid[0];
//プロセスハンドラを取得する。
hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, False, pid);
////共有メモリ確保
//int lpShared1 = GetSharedMem(pid, sizeof(LVITEM), hProc);
//int lpShared2 = GetSharedMem(pid, 255, hProc);
//int lWritten=0;
//printf("OpenProcess %d",hProc);
//printf("共有メモリ確保 lpShared1_%d ,lpShared2_%d hProc %d",lpShared1,lpShared2,hProc);
uchar strBuffer[255];
for(int i=rows-drows-1; i>=0; i--)
{
string qtr="";
for(int j=1; j<colums; j++)
{
//共有メモリ確保
int lpShared1 = GetSharedMem(pid, sizeof(LVITEM), hProc);
int lpShared2 = GetSharedMem(pid, 255, hProc);
int lWritten=0;
LVITEM[0] = LVIF_TEXT;
LVITEM[1] = i;
LVITEM[2] = j;//項目のインデックス(列
LVITEM[5] = lpShared2;
LVITEM[6] = 255; // textmask
int intRc= WriteProcessMemory(hProc, lpShared1,LVITEM, sizeof(LVITEM), lWritten);//書込み
if(intRc ==0)
continue;
intRc = SendMessageW(hwndList,LVM_GETITEMW,0,lpShared1);//取得依頼
if(intRc ==0)
continue;
intRc = ReadProcessMemory(hProc,lpShared2, strBuffer, 255, 0); //読込
if(intRc ==0)
continue;
qtr += CharArrayToString(strBuffer,0,255, CP_THREAD_ACP)+" ";
//qtr = ShortArrayToString(strBuffer,0,255);
//メモリ解放
FreeSharedMem(hProc, lpShared1, sizeof(LVITEM));
FreeSharedMem(hProc, lpShared2, 255);
}
int f1,f2,f3;
int ff1,ff2,ff3;
ff1 = StringLen(filter1);
ff2 = StringLen(filter2);
ff3 = StringLen(filter3);
f1 = StringLen(filter1) > 0 ? StringFind(qtr,filter1,0):-1;
f2 = StringLen(filter2) > 0 ? StringFind(qtr,filter2,0):-1;
f3 = StringLen(filter3) > 0 ? StringFind(qtr,filter3,0):-1;
if(fileterEnable)
{
if(f1>=0||f2>=0||f3>=0)
{
myAlert(qtr);
Print("アラートをスティールしました→,",qtr);
}
}
else
{
myAlert(qtr);
Print("アラートをスティールしました→,",qtr);
}
}
////メモリ解放
//FreeSharedMem(hProc, lpShared1, sizeof(LVITEM));
//FreeSharedMem(hProc, lpShared2, 255);
}
drows = rows;
//Print("END");
}
//+------------------------------------------------------------------+
//| 共有メモリ確保 |
//+------------------------------------------------------------------+
int GetSharedMem(int mypid, int memSize, int ahProc)
{
return VirtualAllocEx(ahProc, 0, memSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
//+------------------------------------------------------------------+
//| 共有メモリ解放 |
//+------------------------------------------------------------------+
int FreeSharedMem(int ahProc,int MemAddress,int memSize)
{
VirtualFreeEx(ahProc, MemAddress, memSize, MEM_RELEASE);
return CloseHandle(ahProc);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| チャート送ったり通知したりするところのまとめ |
//+------------------------------------------------------------------+
void myAlert(string msg)
{
datetime now =TimeLocal();
MqlDateTime now_struct;
TimeToStruct(now, now_struct);
string myNow = StringFormat("%4d-%02d-%02d_%02d-%02d-%2d",
now_struct.year,
now_struct.mon,
now_struct.day,
now_struct.hour,
now_struct.min,
now_struct.sec);
if(mailAlertEnable)
{
SendMail(myNow+" "+ msg, myNow+" "+ msg);
}
if(mtAlertEnable)
{
SendNotification(myNow+" "+ msg);
}
if(myAlertEnable)
{
int hwndButton = FindWindowExW(hwnd,0,"Button","OK");
PostMessageW(hwndButton,BM_CLICK,0,0);
}
}
//+------------------------------------------------------------------+
苦労したところも残しています!!!
REFERENCEs
さいごに
投資は自己責任!
カレンダー参加者募集してます!
Have a good MQL Life!!!