minimize/maximize a chart window in MQL5 - winapi

I found a very useful 'indicator' for MT4 that lets you maximize/minimize any chart by double/triple-clicking on it.
I've been trying to port it to MT5 unsuccessfully.
I am not sure what I am doing wrong with the Windows API.
I did change the types to ulong/uint as per MSDN.
I am also using CHART_WINDOW_HANDLE to get the hwnd.
The mouse clicking counter seems to work but I never managed to maximize or minimize a chart window with the below code.
Any help would be greatly appreciated.
//+------------------------------------------------------------------+
//| ClickMax.mq5 |
//| Copyright © 2020 | 2016, MaryJane |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020 | 2016, MaryJane"
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
#property strict
input uint clickDelay = 300;
input bool tripleClick = true;
#define SW_MAXIMIZE 3
#define SW_RESTORE 9
//+------------------------------------------------------------------------------------------------------------------------------------------------------+
// --- DLLs
#import "user32.dll"
ulong GetParent(ulong hWnd);
ulong GetWindow(ulong hWnd, uint uCmd);
bool ShowWindow(ulong hWnd, int nCmdShow);
bool IsZoomed(ulong hWnd);
#import
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(!TerminalInfoInteger(TERMINAL_DLLS_ALLOWED))
{
Alert("You have to allow DLLs for ClickMax to work");
return(INIT_FAILED);
}
else
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
return(0);
}
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
static uint clicktime = GetTickCount();
static int clickcount = 0;
bool doubleclick = false;
if(_IsX64)
{
ulong hwnd = GetParent(CHART_WINDOW_HANDLE);
//ulong hwnd = CHART_WINDOW_HANDLE;
if(id == CHARTEVENT_CLICK)
{
uint test = GetTickCount() - clicktime;
if(GetTickCount() - clicktime < clickDelay)
clickcount++;
else
clickcount = 0;
if((tripleClick && clickcount==2) ||
(!tripleClick && clickcount==1))
doubleclick = true;
clicktime = GetTickCount();
if(doubleclick)
{
if(!IsZoomed(hwnd))
ShowWindow(hwnd, SW_MAXIMIZE);
else
ShowWindow(hwnd, SW_RESTORE);
clickcount = 0;
}
}
}
}

as hinted by #dxiv in the comments, CHART_WINDOW_HANDLE is not an actual HWND.
This is: (int)ChartGetInteger(0,CHART_WINDOW_HANDLE)

Related

error adding new frame when i received data from webSocket in mql5

websocket server node.js
mql5 websocket is :
used from this library
i give this error
enter image description here
my mq5 expert , its just for connect to server and received data .
//+------------------------------------------------------------------+
//| Websocketclient_test.mq5 |
//| Copyright 2019, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#include<WebSocketClient.mqh>
input string Address="127.0.0.1";
input int Port =3001;
input bool ExtTLS =false;
input int MaxSize=256;
input int Timeout=500;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string _msg="test webSocket";
//---
CWebSocketClient wsc;
//---
int sent=-1;
uint received=-1;
//---
// string subject,issuer,serial,thumbprint;
//---
// datetime expiration;
//---
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EventSetMillisecondTimer(500);
//---
wsc.SetMaxSendSize(MaxSize);
//---
if(wsc.Connect(Address,Port,Timeout,ExtTLS,true))
{
sent=wsc.SendString(_msg);
//--
//Print("sent data is "+IntegerToString(sent));
//---
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
Print("Deinit call");
wsc.Close();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnTimer()
{
if(wsc.Readable()>0)
{
CFrame msg_frames[];
received=wsc.Read(msg_frames);
if(received>0)
{
int ll=ArraySize(msg_frames);
Print("number of received frames is :"+IntegerToString(ll));
for(int i=0; i<ll; i++)
{
Alert("r data ",msg_frames[i].ToString());
//wsc.SendString(msg_frames[i].ToString());
}
if(msg_frames[ll-1].IsFinal())
{
Print("\n Final frame received");
//wsc.Close(NORMAL_CLOSE,"good bye");
//ExpertRemove();
}
}
}
else
{
//Print("\n Nothing readable in socket");
if(wsc.ClientState()!=CONNECTED)
{
Print("\n Client disconnected");
//ExpertRemove();
wsc.Connect(Address,Port,Timeout,ExtTLS,true);
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
Sometimes it receives the data, sometimes it gives an error in
this function for get data frames
bool CWebSocketClient::parse(CFrame& out[])
{
uint i,data_len=0,frames=0;
uint s=0;
m_total_len=0;
//---
int shift=0;
for(i=0; i<(uint)ArraySize(m_rxbuf); i+=(data_len+shift))
{
++frames;
m_socket.Log("value of frame is "+IntegerToString(frames)+" Value of i is "+IntegerToString(i),__LINE__,__FUNCTION__);
switch((uint)m_rxbuf[i+1])
{
case 126:
data_len=((uint)m_rxbuf[i+2]<<8)+((uint)m_rxbuf[i+3]);
shift=4;
break;
case 127:
data_len=((uint)m_rxbuf[i+2]<<56)+((uint)m_rxbuf[i+3]<<48)+((uint)m_rxbuf[i+4]<<40)+
((uint)m_rxbuf[i+5]<<32)+((uint)m_rxbuf[i+6]<<24)+((uint)m_rxbuf[i+7]<<16)+
((uint)m_rxbuf[i+8]<<8)+((uint)m_rxbuf[i+9]);
shift=10;
break;
default:
data_len=(uint)m_rxbuf[i+1];
shift=2;
break;
}
m_total_len+=data_len;
if(data_len>0)
{
if(ArraySize(out)<(int)frames)
{
if(ArrayResize(out,frames,1)<=0)
{
m_socket.Log("array resize error",__LINE__,__FUNCTION__);
return(false);
}
}
//---
if(!out[frames-1].Fill(m_rxbuf,i+shift,data_len))
{
**//The error occurs here ....**
m_socket.Log("Error adding new frame",__LINE__,__FUNCTION__);
return(false);
}
//---
switch((uchar)m_rxbuf[i])
{
case 0x1:
if(out[frames-1].MessageType()==0)
out[frames-1].SetMessageType(TEXT_FRAME);
break;
case 0x2:
if(out[frames-1].MessageType()==0)
out[frames-1].SetMessageType(BINARY_FRAME);
break;
case 0x80:
case 0x81:
if(out[frames-1].MessageType()==0)
out[frames-1].SetMessageType(TEXT_FRAME);
case 0x82:
if(out[frames-1].MessageType()==0)
out[frames-1].SetMessageType(BINARY_FRAME);
//m_socket.Log("received last frame",__LINE__,__FUNCTION__);
out[frames-1].SetFinal();
break;
case 0x88:
//m_socket.Log("received close frame",__LINE__,__FUNCTION__);
out[frames-1].SetMessageType(CLOSE_FRAME);
if(m_wsclient==CONNECTED)
{
ArrayCopy(m_txbuf,m_rxbuf,0,i+shift,data_len);
m_wsclient=CLOSING;
}
break;
case 0x89:
//m_socket.Log("received ping frame",__LINE__,__FUNCTION__);
out[frames-1].SetMessageType(PING_FRAME);
if(m_wsclient==CONNECTED)
ArrayCopy(m_txbuf,m_rxbuf,0,i+shift,data_len);
break;
case 0x8a:
//m_socket.Log("received pong frame",__LINE__,__FUNCTION__);
out[frames-1].SetMessageType(PONG_FRAME);
break;
default:
break;
}
}
}
//---
return(true);
}
now , help me to solve it
tanks.

How can I populate a dynamic two dimensional array in a for loop

This might seem trivial to many but it seems to be getting the better of me as I've not been able to figure out how to use the ArrayResize() (which I believe is very necessary) to solve this.
In the code below I want to populate ar[][2] when isBody is true. How can I achieve this.
int ar[][2];
void CheckBody() {
for (int i = 20; i >= 0; i--) {
if (isBody) {
int a = i + 1;
int b = i - 3*i;
// how to populate ar with [a,b] when isBody is true in this block
}
}
}
Try the following code, it's programmed to run as an EA but can easily be modified if used in an indicator (you will have to add your code for the isBody variable).
#property strict
int ar[][2];
//+------------------------------------------------------------------+
//| Initialization function of the expert |
//+------------------------------------------------------------------+
int OnInit()
{
ArrayInitialize(ar,NULL);
ArrayResize(ar,1);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Deinitialization function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| "Tick" event handler function |
//+------------------------------------------------------------------+
void OnTick()
{
for(int i=20; i>=0; i--)
{
if(isBody)
{
if(ar[0][0]!=NULL) ArrayResize(ar,ArrayRange(ar,0)+1);
int a=i+1;
int b=i-3*i;
ar[ArrayRange(ar,0)-1][0]=a; ar[ArrayRange(ar,0)-1][1]=b;
}
}
}

Converting mql4 EA to mql5

I have been trying to figure out how to change my MQL4 code to MQL5. So far I've been able to change the RSI and MACD conditions and SendOrder() but there's a lot, like the ModifyOrder() and CloseOrder() amongst other stuff that I've not been able to do to complete it. I know this is a mouthful but I would really appreciate some help in completing this.
This is the original MQL4 code:
extern int MagicNumber=112223;
extern double Lots =0.005;
extern double StopLoss=0;
extern double TakeProfit=0;
extern int TrailingStop=0;
extern int Slippage=3;
int mode_main = 0;
int mode_signal = 1;
//+------------------------------------------------------------------+
// expert start function
//+------------------------------------------------------------------+
int start()
{
double MyPoint=_Point;
if(Digits==3 || Digits==5) MyPoint=Point*10;
double TheStopLoss=0;
double TheTakeProfit=0;
if( TotalOrdersCount()==0 )
{
int result=0;
if((iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_signal,0)<iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_main,0))&&(iRSI(NULL,PERIOD_M5,2,PRICE_CLOSE,0)>84)) // Here is your open buy rule
{
result=OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,"EA",MagicNumber,0,Blue);
if(result>0)
{
TheStopLoss=0;
TheTakeProfit=0;
if(TakeProfit>0) TheTakeProfit=Ask+TakeProfit*MyPoint;
if(StopLoss>0) TheStopLoss=Ask-StopLoss*MyPoint;
OrderSelect(result,SELECT_BY_TICKET);
OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(TheStopLoss,Digits),NormalizeDouble(TheTakeProfit,Digits),0,Green);
}
return(0);
}
if((iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_main,0)<iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_signal,0))&&(iRSI(NULL,PERIOD_M5,2,PRICE_CLOSE,0)<16)) // Here is your open Sell rule
{
result=OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,"EA",MagicNumber,0,Red);
if(result>0)
{
TheStopLoss=0;
TheTakeProfit=0;
if(TakeProfit>0) TheTakeProfit=Bid-TakeProfit*MyPoint;
if(StopLoss>0) TheStopLoss=Bid+StopLoss*MyPoint;
OrderSelect(result,SELECT_BY_TICKET);
OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(TheStopLoss,Digits),NormalizeDouble(TheTakeProfit,Digits),0,Green);
}
return(0);
}
}
for(int cnt=0;cnt<OrdersTotal();cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL &&
OrderSymbol()==Symbol() &&
OrderMagicNumber()==MagicNumber
)
{
if(OrderType()==OP_BUY)
{
if((iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_signal,0)>iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_main,0))&&(iRSI(NULL,PERIOD_M5,2,PRICE_OPEN,0)<16)) //here is your close buy rule
{
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Red);
}
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>MyPoint*TrailingStop)
{
if(OrderStopLoss()<Bid-MyPoint*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-TrailingStop*MyPoint,OrderTakeProfit(),0,Green);
return(0);
}
}
}
}
else
{
if((iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_main,0)>iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,mode_signal,0))&&(iRSI(NULL,PERIOD_M5,2,PRICE_OPEN,0)>84)) // here is your close sell rule
{
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Red);
}
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(MyPoint*TrailingStop))
{
if((OrderStopLoss()>(Ask+MyPoint*TrailingStop)) || (OrderStopLoss()==0))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+MyPoint*TrailingStop,OrderTakeProfit(),0,Red);
return(0);
}
}
}
}
}
}
return(0);
}
int TotalOrdersCount()
{
int result=0;
for(int i=0;i<OrdersTotal();i++)
{
OrderSelect(i,SELECT_BY_POS ,MODE_TRADES);
if (OrderMagicNumber()==MagicNumber) result++;
}
return (result);
}
Here is what I've done so far (MQL5):
#include <indicators/indicators.mqh>
CIndicators g_indicators;
CiRSI *g_rsi;
CiMACD *g_macd;
input int MagicNumber=112223;
input double Lots =0.005;
input double StopLoss=0;
input double TakeProfit=0;
input int TrailingStop=0;
input int Slippage=3;
int OnInit() {
g_rsi = new CiRSI();
g_indicators.Add(g_rsi);
g_macd = new CiMACD();
g_indicators.Add(g_macd);
bool is_init = g_rsi.Create(_Symbol, PERIOD_M5, 2, PRICE_CLOSE);
is_init &= g_macd.Create(_Symbol, PERIOD_M5, 12, 26, 9, PRICE_CLOSE);
return is_init ? INIT_SUCCEEDED : INIT_FAILED;
}
void OnTick() {
g_indicators.Refresh();
double MyPoint=_Point;
if(_Digits==3 || _Digits==5) MyPoint=_Point*10;
double TheStopLoss=0;
double TheTakeProfit=0;
if( TotalOrdersCount()==0 )
{
int result=0;
if (g_macd.Main(0) > g_macd.Signal(0) && g_rsi.Main(0) > 84) { // Here is your open Buy rule
Print("Signal!");
MqlTradeRequest request;
MqlTradeResult result;
MqlTradeCheckResult check;
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); // Get the Ask Price
//--- parameters of request
request.action =TRADE_ACTION_PENDING; // type of trade operation
request.symbol =Symbol(); // symbol
request.volume =Lots; // volume of 0.005 lot
request.type =ORDER_TYPE_BUY; // order type
request.price = Ask; // price for opening
request.deviation=0; // allowed deviation from the price
request.magic =magicnumber; // MagicNumber of the order
request.tp = 0;
request.sl = 0;
request.type_filling=ORDER_FILLING_RETURN;
request.type_time=0;
request.expiration=0;
ObjectSetString(0,name,OBJPROP_TEXT,string(result.order));
if(!OrderSend(request,result))
{
Print(__FUNCTION__,": error ",GetLastError(),", retcode = ",result.retcode);
}
}
}
if (g_macd.Main(0) < g_macd.Signal(0) && g_rsi.Main(0) < 16) { // Here is your open Sell rule
Print("Signal!");
MqlTradeRequest request;
MqlTradeResult result;
MqlTradeCheckResult check;
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); // Get the Bid Price
//--- parameters of request
request.action =TRADE_ACTION_PENDING; // type of trade operation
request.symbol =Symbol(); // symbol
request.volume =Lots; // volume of 0.005 lot
request.type =ORDER_TYPE_SELL; // order type
request.price = Bid; // price for opening
request.deviation=0; // allowed deviation from the price
request.magic =magicnumber; // MagicNumber of the order
request.tp = 0;
request.sl = 0;
request.type_filling=ORDER_FILLING_RETURN;
request.type_time=0;
request.expiration=0;
ObjectSetString(0,name,OBJPROP_TEXT,string(result.order));
if(!OrderSend(request,result))
{
Print(__FUNCTION__,": error ",GetLastError(),", retcode = ",result.retcode);
}
}
}
}
}
Thanks in advance.
Yes, it may take long. luckily, someone wrote a library that you are welcome to download from https://www.mql5.com/ru/code/16006.
#include <MT4Orders.mqh> // if you have #include <Trade/Trade.mqh> in your MQL5 files, include this one AFTER.
int ticket = OrderSend(...);
same for `OrderModify()` and `OrderDelete` \ `OrderModify`
Keep in mind that this lib works for hedging mode only, so your MT5 must have a hedging mode.
full example below:
#include <MT45/MT4Orders.mqh>
//better to use MQL5 analogues of Ask etc for both MQL4 and MQL5, or redefine them
#define Ask SymbolInfoDouble(_Symbol,SYMBOL_ASK)
#define Bid SymbolInfoDouble(_Symbol,SYMBOL_BID)
#define Point _Point
#define Digits _Digits
// your inputs
extern int MagicNumber=112223;
extern double Lots =0.005;
extern double StopLoss=0;
extern double TakeProfit=0;
extern int TrailingStop=0;
extern int Slippage=3;
//int mode_main = 0; //probably throw this away
//int mode_signal = 1; //probably throw this away
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//initialize your indicators here
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//deinitialize your indicators here if you need to avoid memory leak
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
double MyPoint=_Point;
if(Digits==3 || Digits==5) MyPoint=Point*10;
double TheStopLoss=0;
double TheTakeProfit=0;
if( TotalOrdersCount()==0 )
{
TICKET_TYPE result=0;
if(isRule4Buy()) // Here is your open buy rule
{
result=OrderSend(Symbol(),OP_BUY,Lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),Slippage,0,0,"EA",MagicNumber,0,clrBlue);
if(result>0)
{
TheStopLoss=0;
TheTakeProfit=0;
if(TakeProfit>0) TheTakeProfit=Ask+TakeProfit*MyPoint;
if(StopLoss>0) TheStopLoss=Ask-StopLoss*MyPoint;
OrderSelect(result,SELECT_BY_TICKET);
OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(TheStopLoss,Digits),NormalizeDouble(TheTakeProfit,Digits),0,Green);
}
return;
}
if(isRule4Sell())
{
//simply copy the sell block
}
}
for(int cnt=0;cnt<OrdersTotal();cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL &&
OrderSymbol()==Symbol() &&
OrderMagicNumber()==MagicNumber
)
{
if(OrderType()==OP_BUY)
{
if(isRule4Sell())
{
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),Slippage,Red);
}
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>MyPoint*TrailingStop)
{
if(OrderStopLoss()<Bid-MyPoint*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-TrailingStop*MyPoint,OrderTakeProfit(),0,Green);
return;
}
}
}
}
else
{
//simply copy the sell block
}
}
}
}
//+------------------------------------------------------------------+
int TotalOrdersCount()
{
int result=0;
for(int i=0;i<OrdersTotal();i++)
{
OrderSelect(i,SELECT_BY_POS ,MODE_TRADES);
if (OrderMagicNumber()==MagicNumber) result++;
}
return (result);
}
//+------------------------------------------------------------------+
bool isRule4Buy()
{
#ifdef __MQL4__
return iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0)<iMACD(NULL,PERIOD_M5,12,26,9,PRICE_CLOSE,MODE_MAIN,0)
&& iRSI(NULL,PERIOD_M5,2,PRICE_CLOSE,0)>84;
#else
return true;
//replace with MT5
//g_macd.Main(0) > g_macd.Signal(0) && g_rsi.Main(0) > 84
#endif
}
bool isRule4Sell()
{
//similar for sell
return false;
}

How to inject a DLL into Adobe Reader X

I need to inject a DLL into Adobe Reader X that reads the events sent to the scrollbar (even if it is hidden). I need to do this to be able to find out what page of the document i am on.
I have tried hooking a dll using the win32 hooking API, i give a CBT hook to all processes on the desktop and listen for the creation of the Adobe Reader X window, then hooking this window with my scrollbar hook.
The problem is that i never get the scrollbar hook placed on Adobe Reader X, i dont get the create window or window activate messages for these windows when they are created. How do i get these messages and how do i hook into Adobe Reader X?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "pdfviewlib.h"
#include <sstream>
#pragma data_seg(".PDFVIEWLIB")
PDFVIEWOBJ pdfviewobj[MAX_PDFOBJS] = {NULL};
HHOOK globalhook = NULL;
BOOL debug = TRUE;
INT sSlide = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.PDFVIEWLIB,RWS")
#define DEBUG(...) if(debug) printf(__VA_ARGS__)
HINSTANCE hInstance = NULL;
static int tAttach = 0;
static int tDetach = 0;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
hInstance = (HINSTANCE)hModule;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DEBUG("PROCESS_ATTACH\n");
break;
case DLL_THREAD_ATTACH:
DEBUG("THREAD_ATTACH %i\n",tAttach++);
break;
case DLL_THREAD_DETACH:
DEBUG("THREAD_DETACH %i\n", tDetach++);
break;
case DLL_PROCESS_DETACH:
// Clean up... hopefully there is only the one process attached?
DEBUG("PROCESS_DETACH\n");
for(int i = 0; i<MAX_PDFOBJS; i++)
ClosePDF(i);
break;
}
return TRUE;
}
DllExport void SetDebug(BOOL onoff)
{
printf("SetDebug\n");
debug = onoff;
DEBUG("enabled\n");
}
//Check if Acrobat Reader is installed
DllExport BOOL CheckInstalled()
{
DEBUG("CheckInstalled\n");
char cmdline[MAX_PATH * 2];
return GetPDFViewerPath(cmdline, sizeof(cmdline));
}
// Open the PDF
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide)
{
STARTUPINFO * si = (STARTUPINFO *) malloc(sizeof(STARTUPINFO));
PROCESS_INFORMATION * pi = (PROCESS_INFORMATION*) malloc(sizeof(PROCESS_INFORMATION));
char cmdline[MAX_PATH * 2];
int id;
sSlide = startSlide;
DEBUG("OpenPDF start: %u", hParentWnd);
//First check if Acrobat Reader is installed before continuing
if(GetPDFViewerPath(cmdline, sizeof(cmdline))==FALSE)
{
DEBUG("OpenPDF: GetPDFTViewerPath failed\n");
return -1;
}
id = -1;
for(int i = 0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].state==PDF_CLOSED)
{
id=i;
break;
}
}
if(id<0)
{
DEBUG("OpenPDF: Too many PDFs\n");
return -1;
}
if (pdfviewobj[id].state == PDF_STARTED)
{
DEBUG("RERUN WHEN PDF_STARTED\n");
return -1;
}
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
strcpy_s(pdfviewobj[id].filename, MAX_PATH, filename);
pdfviewobj[id].state = PDF_CLOSED;
pdfviewobj[id].currentSlide = 0;
pdfviewobj[id].hParentWnd = hParentWnd;
pdfviewobj[id].hWnd = NULL;
pdfviewobj[id].hWnd2 = NULL;
strcat_s(cmdline, MAX_PATH * 2, "\\AcroRd32.exe /n /s /o");
strcat_s(cmdline, MAX_PATH * 2, " \"");
strcat_s(cmdline, MAX_PATH * 2, filename);
strcat_s(cmdline, MAX_PATH * 2, "\"");
si = (STARTUPINFO *)memset(si, 0, sizeof(STARTUPINFO));
pi = (PROCESS_INFORMATION *)memset(pi, 0, sizeof(PROCESS_INFORMATION));
if(globalhook!=NULL){
UnhookWindowsHookEx(globalhook);
DEBUG("Global unhooked\n");
globalhook = NULL;
}
//Set the global hook listening for Window Create/Window Activate messages
globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
if(globalhook==NULL)
{
DEBUG("OpenPDF: Global SetWindowsHookEx failed\n");
DEBUG("ERROR: %X\n", GetLastError());
globalhook = NULL;
ClosePDF(id);
return -1;
}
else DEBUG("GLOBAL HOOKED %X\n", globalhook);
pdfviewobj[id].state = PDF_STARTED;
Sleep(10);
DEBUG(cmdline);
//Run Acrobat Reader, PDF STATE SET TO STARTED
if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, si, pi))
{
DEBUG("OpenPDF: CreateProcess failed\n");
ClosePDF(id);
return -1;
}
pdfviewobj[id].dwProcessId = pi->dwProcessId;
pdfviewobj[id].dwThreadId = pi->dwThreadId;
pdfviewobj[id].hThread = pi->hThread;
pdfviewobj[id].hProcess = pi->hProcess;
//WAIT FOR GLOBAL HOOK TO DETECT Acrobat Windows and set PDF STATE TO PDF_OPENED
//For some reason the loops exits and PDFSTATE is PDF_CLOSED...
while(pdfviewobj[id].state==PDF_STARTED)
Sleep(50);
DEBUG("PDFSTATE == CLOSED = %i \n", pdfviewobj[id].state==PDF_CLOSED);
DEBUG("PDFSTATE == STARTED = %i \n", pdfviewobj[id].state==PDF_STARTED);
DEBUG("PDFSTATE == OPENED = %i \n", pdfviewobj[id].state==PDF_OPENED);
DEBUG("PDFSTATE == LOADED = %i \n", pdfviewobj[id].state==PDF_LOADED);
if (sSlide > 0){
GotoSlide(id, sSlide+1);
}
pdfviewobj[id].state = PDF_LOADED;
DEBUG("OpenPDF Done: id=%i\n", id);
return id;
}
// Get the path of Acrobat Reader X from the registry
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize)
{
HKEY hkey;
DWORD dwtype, dwsize;
LRESULT lresult;
DEBUG("GetPDFViewerPath: start\n");
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Adobe\\Acrobat Reader\\9.0\\InstallPath", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
return FALSE;
dwtype = REG_SZ;
dwsize = (DWORD)strsize;
lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pdfviewerpath, &dwsize );
RegCloseKey(hkey);
if(lresult!=ERROR_SUCCESS)
return FALSE;
DEBUG("GetPDFViewerPath: exit ok \n");
return TRUE;
}
// Unhook the Windows hook
void Unhook(int id)
{
DEBUG("Unhook: start %i\n", id);
if(pdfviewobj[id].hook!=NULL)
UnhookWindowsHookEx(pdfviewobj[id].hook);
pdfviewobj[id].hook = NULL;
DEBUG("Unhook: exit ok\n");
}
// Close the Acrobat Reader, release resources
DllExport void ClosePDF(int id)
{
DEBUG("ClosePDF: start %i\n", id);
if (globalhook != NULL) {
DEBUG("GLOBAL UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook = NULL;
}
else DEBUG("GLOBAL NOT UNHOOKED\n");
pdfviewobj[id].state = PDF_CLOSED;
Unhook(id);
if(pdfviewobj[id].hWnd==0)
TerminateThread(pdfviewobj[id].hThread, 0);
else
PostMessage(pdfviewobj[id].hWnd, WM_CLOSE, 0, 0);
CloseHandle(pdfviewobj[id].hThread);
CloseHandle(pdfviewobj[id].hProcess);
memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
DEBUG("ClosePDF: exit ok\n");
return;
}
// Return the number of the slide currently viewing
DllExport int GetCurrentSlide(int id)
{
DEBUG("GetCurrentSlide:%d\n", id);
if(pdfviewobj[id].state==0)
return -1;
else
return pdfviewobj[id].currentSlide;
}
// Take a step forwards through the show
DllExport void NextStep(int id)
{
DEBUG("NextStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
}
// Take a step backwards through the show
DllExport void PrevStep(int id)
{
DEBUG("PrevStep:%d\n", id);
SetForegroundWindow(pdfviewobj[id].hWnd);
SetFocus(pdfviewobj[id].hWnd);
PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
}
// Go directly to a slide
DllExport void GotoSlide(int id, int slideno)
{
//TODO: USE SETSCROLLINFO
}
// This hook is started with the AcroRd32.EXE process and waits for the WM_CREATEWND message.
// Release the hook as soon as we're complete to free up resources
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HHOOK hook = globalhook;
DEBUG("HOOK: %X\n", hook);
if (nCode < 0) {
return CallNextHookEx(hook, nCode, wParam, lParam);
}
else if(nCode==HCBT_CREATEWND)
{
DEBUG("CREATE WINDOW \n");
char csClassName[16];
char csCaptionName[16];
HWND hCurrWnd = (HWND)wParam;
DWORD retProcId = NULL;
GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
GetWindowText(hCurrWnd, csCaptionName, sizeof(csCaptionName));
if((strcmp(csClassName, "AcrobatSDIWindow")==0)
||(strcmp(csClassName, "AVL_AVView")==0))
{
DEBUG("%s found \n", csClassName);
int id=-1;
DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
break;
}
}
if(id>=0)
{
DEBUG("Matched threadid!\n");
if(strcmp(csClassName, "AVL_AVView")==0){
if (strcmp(csCaptionName, "AVPageView")==0){
pdfviewobj[id].hWnd2=hCurrWnd;
}
}
else
{
pdfviewobj[id].hWnd=hCurrWnd;
CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
if(pdfviewobj[id].hParentWnd!=NULL)
cw->lpcs->hwndParent = pdfviewobj[id].hParentWnd;
}
if((pdfviewobj[id].hWnd!=NULL)&&(pdfviewobj[id].hWnd2!=NULL))
{
pdfviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pdfviewobj[id].dwThreadId);
if (pdfviewobj[id].hook != NULL) {
DEBUG("Global UNHOOKED %X\n", globalhook);
UnhookWindowsHookEx(globalhook);
globalhook=NULL;
pdfviewobj[id].state = PDF_OPENED;
}
Sleep(10);
}
}
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
CWPSTRUCT *cwp;
cwp = (CWPSTRUCT *)lParam;
HHOOK hook = NULL;
DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
int id=-1;
for(int i=0; i<MAX_PDFOBJS; i++)
{
if(pdfviewobj[i].dwThreadId==windowthread)
{
id=i;
hook = pdfviewobj[id].hook;
break;
}
}
if((id>=0)&&(nCode==HC_ACTION))
{
DEBUG("CBT HC_ACTION\n");
if(cwp->message==SBM_SETSCROLLINFO)
{
DEBUG("CBT SBM_SETSCROLLINFO\n");
SCROLLINFO *scrInf;
scrInf = (SCROLLINFO *)cwp->lParam;
pdfviewobj[id].currentSlide = scrInf->nPos;
}
if((pdfviewobj[id].state != PDF_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT)){
pdfviewobj[id].state = PDF_CLOSING;
}
}
return CallNextHookEx(hook,nCode,wParam,lParam);
}
heres the header if you need it
#define DllExport extern "C" __declspec( dllexport )
enum PDFVIEWSTATE { PDF_CLOSED, PDF_STARTED, PDF_OPENED, PDF_LOADED, PDF_CLOSING};
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide);
DllExport BOOL CheckInstalled();
DllExport void ClosePDF(int id);
DllExport int GetCurrentSlide(int id);
DllExport void NextStep(int id);
DllExport void PrevStep(int id);
DllExport void GotoSlide(int id, int slideno);
DllExport void SetDebug(BOOL onoff);
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize);
void Unhook(int id);
//MAXUMUM NUMBER OF PDF-PROCESSES CURRENTLY SET TO ONE
#define MAX_PDFOBJS 1
struct PDFVIEWOBJ
{
HHOOK hook;
HWND hWnd;
HWND hWnd2;
HWND hParentWnd;
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
int currentSlide;
char filename[MAX_PATH];
PDFVIEWSTATE state;
};
Adobe Reader typically runs in protected mode. (See Edit/Preferences/Security (Enhanced). Un-check the "Enable Protected Mode at startup" checkbox.
Relaunch reader and see if you get your messages. You should. The issue is that the User Interface Privilege Isolation (UIPI) disallows many windows messages from crossing process boundaries between processes running at a different integrity level (low/medium/high). You are supposed to be able to change the windows message filter via ChangeWindowMessageFilterEx().
I am currently experiencing issues with Adobe Reader Xi where the ChangeWindowsMessageFilter and ChangeWindowMessageFilterEx do not seem to change the behavior of Adobe reader sending messages to the global hook receiver in the hooking process. I have copied noteapad.exe to notepad2.exe and lowered its integrity level to low via: icacls notepad2.exe /setintegritylevel low
(run from an elevated cmd prompt (i.e. run as admin)). When I do this my hooking works fine (using ChangeWindowMessageFilterEx()) but still does not get hooked messages from Adobe.
Also, Reader is 32-bit so make sure you are hooking it from a 32-bit hooking process otherwise you won't see messages either).

How can I be notified when a new window is created on Win32?

Is there a way using Win32, to register for notifications when a new window is created. I'm trying to keep a list of current open windows, but am now just polling the list of current windows using EnumWindows().
Anyone done something similar?
Thanks
I'm not sure if I'm doing this right, but I'm not able to get the SetWindowsHookEx method to fire.
anything come to mind?
here is my snip
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
const int HSHELL_WINDOWCREATED = 1;
private static HookProc winDelegate = ShellHookProcDelegate;
internal static void RegisterWindowCreatedEvent()
{
SetWindowsHookEx(HookType.WH_SHELL, winDelegate, IntPtr.Zero, 0);
}
private static int ShellHookProcDelegate(int code, IntPtr wParam, IntPtr lParam)
{
if (code != HSHELL_WINDOWCREATED)
{
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
//App specific code here
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
Use SetWindowsHookEx to set up a WH_SHELL hook and look for the HSHELL_WINDOWCREATED event.
Here is some code based on UI automation events. It gives window opened, closed, and focused events.
C#
[STAThread]
public static void Main(string[] args)
{
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
{
var element = (AutomationElement)sender;
var name = element.Current.Name;
Console.WriteLine("open: " + name + " hwnd:" + element.Current.NativeWindowHandle);
Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, element, TreeScope.Element, (s, e2) =>
{
Console.WriteLine("close: " + name + " hwnd:" + element.Current.NativeWindowHandle);
});
});
Automation.AddAutomationFocusChangedEventHandler((sender, e) =>
{
var element = (AutomationElement)sender;
var name = element.Current.Name;
Console.WriteLine("focused: " + name + " hwnd:" + element.Current.NativeWindowHandle);
});
Console.ReadLine();
Automation.RemoveAllEventHandlers();
}
C++ equivalent:
#include <windows.h>
#include <stdio.h>
#include <uiautomation.h>
// some useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define MYTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ MYTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }
#define CHECKWIN32(expr) {if(!(expr)){hr = HRESULT_FROM_WIN32(GetLastError()); MYTRACE(L"WIN32 FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }
#define CHECKARG(expr) {if(!(expr)){ MYTRACE(L"ARG FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_INVALIDARG; goto cleanup; } }
#define CHECKMEM(expr) {if(!(expr)){ MYTRACE(L"MEM FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_OUTOFMEMORY; goto cleanup; } }
#define CORELEASE(expr) {if(expr){ expr->Release(); expr = NULL; } }
#define HR HRESULT hr=S_OK;
class EventHandler :
public IUIAutomationEventHandler,
public IUIAutomationFocusChangedEventHandler
{
private:
LONG _ref;
IUIAutomation* _automation;
HWND _hwnd;
IUIAutomationElement* _sender;
public:
EventHandler(IUIAutomation* automation, IUIAutomationElement* sender, HWND hwnd) :
_ref(1),
_automation(automation),
_sender(sender),
_hwnd(hwnd)
{
if (sender)
{
sender->AddRef();
}
}
~EventHandler()
{
CORELEASE(_sender);
}
// IUnknown
ULONG STDMETHODCALLTYPE AddRef() { ULONG ret = InterlockedIncrement(&_ref); return ret; }
ULONG STDMETHODCALLTYPE Release() { ULONG ret = InterlockedDecrement(&_ref); if (!ret) { delete this; return 0; } return ret; }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
{
if (riid == __uuidof(IUnknown))
{
*ppInterface = (IUIAutomationEventHandler*)this;
}
else if (riid == __uuidof(IUIAutomationEventHandler))
{
*ppInterface = (IUIAutomationEventHandler*)this;
}
else if (riid == __uuidof(IUIAutomationFocusChangedEventHandler))
{
*ppInterface = (IUIAutomationFocusChangedEventHandler*)this;
}
else
{
*ppInterface = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// IUIAutomationFocusChangedEventHandler
HRESULT STDMETHODCALLTYPE HandleFocusChangedEvent(IUIAutomationElement* sender)
{
HWND hwnd = NULL;
sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
wprintf(L"Window focused hwnd:%p'\n", hwnd);
return S_OK;
}
// IUIAutomationEventHandler
HRESULT STDMETHODCALLTYPE HandleAutomationEvent(IUIAutomationElement* sender, EVENTID eventID)
{
HR;
HWND hwnd = NULL;
EventHandler* windowHandler;
switch (eventID)
{
case UIA_Window_WindowOpenedEventId:
sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
wprintf(L"Window opened hwnd:%p\n", hwnd);
// register for close on this window
// we build a new handler, this is the only way to remember the hwnd (the close event doesn't have anything)
windowHandler = new EventHandler(_automation, sender, hwnd); // implicit addref
CHECKMEM(windowHandler);
CHECKHR(_automation->AddAutomationEventHandler(UIA_Window_WindowClosedEventId, sender, TreeScope_Element, NULL, windowHandler));
break;
case UIA_Window_WindowClosedEventId:
wprintf(L"Window closed hwnd:%p\n", _hwnd);
CHECKHR(_automation->RemoveAutomationEventHandler(UIA_Window_WindowClosedEventId, _sender, this));
Release(); // we release our own reference, 'this' we be deleted sometime when all COM references are gone. don't do 'delete this'!
break;
}
cleanup:
return hr;
}
};
int main()
{
HR;
IUIAutomationElement* root = NULL;
EventHandler* handler = NULL;
IUIAutomation* automation = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CHECKHR(CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&automation));
CHECKHR(automation->GetRootElement(&root));
handler = new EventHandler(automation, NULL, NULL);
CHECKMEM(handler);
CHECKHR(automation->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, root, TreeScope_Subtree, NULL, handler));
CHECKHR(automation->AddFocusChangedEventHandler(NULL, handler));
wprintf(L"Press any key to stop listening for events.\n");
getchar();
cleanup:
if (automation != NULL)
{
automation->RemoveAllEventHandlers();
CORELEASE(automation);
}
CORELEASE(handler);
CORELEASE(root);
CoUninitialize();
return hr;
}
Sure - you can write a CBT hook and watch for HCBT_CREATEWND. See also SetWindowsHookEx().
Note that this will allow you to be notified of all window creation, before the windows being created are even fully initialized. If all you need are unowned, top-level windows, RichieHindle's suggestion may work better...
Detours will permit you to attach hooks to arbitrary Win32 functions. However, polling is probably a more reliable way to approach the problem: you don't have to worry about whether you've missed a particular window-creation method (how many are there in Win32? I bet more than one!), and, of course, you won't be rewriting the machine code for windows functions at runtime.
But, you know, your call.
You could try WinEventHook library for autohotkey.
Try modifying the notepad popup blocker example with the following:
HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime )
{
if Event ; EVENT_SYSTEM_FOREGROUND = 0x3
{
WinGetTitle, title, ahk_id %hWnd%
If (title = "your_window_name"
msgbox, your window has been created
}
}

Resources