Open chart programmatically, then get focus/handle

 
Hello all!

I'm trying to launch a new chart via a script like this:

hTerminal = GetAncestor(WindowHandle(Symbol(), Period()), 2);
PostMessageA(hTerminal, WM_COMMAND, 33160, 0);
then trying to change the Pair/Period of the new chart using:

hwnd = WindowHandle(Symbol(),Period());
SetWindowTextA (hwnd, sym + "," + tf); 
PostMessageA (hwnd, WM_KEYDOWN, VK_RETURN, 0 );

the problem I'm getting is the window handle belongs to the window grabbed during the creation of hTerminal,
and not the newly created chart/window.

I have attempted to activate the newly created chart by spawning the Windows dialog/popup (alt+w), then using
keybd_event to trigger alt+a ('Activate'); while this functionally works (ie. the buttons are triggered), the new chart
(which appears at the top of the Windows dialog, and is hilighted by default) does not receive focus.

I have exhausted google in searching for a solution, and found some dated options in this forum (though sadly they no
appear to function), and sadly am not versed in C++ lingo sufficiently to sort the issue out myself - any ideas?

Here's the full code:

#import "user32.dll"
   //int GetParent(int hWnd);
   int GetAncestor(int hWnd, int gaFlags);
   //int GetDlgItem(int hDlg, int nIDDlgItem);
   int PostMessageA(int hWnd, int Msg, int wParam, int lParam);
   //int GetForegroundWindow();
#import

#include <WinUser32.mqh>

#define WM_COMMAND   0x0111
#define WM_KEYDOWN   0x0100
#define VK_RETURN    0x0D
#define VK_ESCAPE    0x1B
#define VK_ALT       0x12
#define VK_TAB       0x09
#define VK_A         0x41
#define VK_W         0x57
#define PAUSE        500

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
void start()
{
   ChartWindow("USDJPY", 5);
}

//+------------------------------------------------------------------+
//| Open a new chart                                                 |
//+------------------------------------------------------------------+
/**/
int ChartWindow(string sym, int tf)
{  
   int hTerminal, hwnd, woo;
   // get root
   hTerminal = GetAncestor(WindowHandle(Symbol(), Period()), 2);
   // spawn new chart
   PostMessageA(hTerminal, WM_COMMAND, 33160, 0);
   Sleep(PAUSE);
   // spawn 'windows' dialog
   keybd_event(VK_ALT,0,0,0); // Alt
   keybd_event(VK_W,0,0,0); // w
   keybd_event(VK_W,0,KEYEVENTF_KEYUP,0);
   keybd_event(VK_ALT,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE);
   /*
   // 'Activate' chart (which is first in list and hilighted)
   keybd_event(VK_ALT,0,0,0); // Alt
   keybd_event(VK_A,0,0,0); // 'A'
   keybd_event(VK_A,0,KEYEVENTF_KEYUP,0);
   keybd_event(VK_ALT,0,KEYEVENTF_KEYUP,0);
   Sleep(1000); 
   */
   // Noticed both 'Activate' and 'Close' have focus(?),
   // tab through selection until only 'Activate' has
   // focus...
   keybd_event(VK_TAB,0,0,0); // Tab
   keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 
   keybd_event(VK_TAB,0,0,0); // Tab
   keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 
   keybd_event(VK_TAB,0,0,0); // Tab
   keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 
   keybd_event(VK_TAB,0,0,0); // Tab
   keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 
   keybd_event(VK_TAB,0,0,0); // Tab
   keybd_event(VK_TAB,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 
   // ...then return
   keybd_event(VK_RETURN,0,0,0); // Return
   keybd_event(VK_RETURN,0,KEYEVENTF_KEYUP,0);
   Sleep(PAUSE); 

   // grab 'new' chart handle (BROKEN...DOESN'T GAIN FOCUS.)
   hwnd = WindowHandle(Symbol(),Period());
   
   // change chart to desired pair/period
   SetWindowTextA (hwnd, sym + "," + tf); 
   PostMessageA (hwnd, WM_KEYDOWN, VK_RETURN, 0 ); 
   return(0);   
}
 

Alt w Alt a doesn't work manually. you have to down arrow to select an entry before the alt a.

why are you sending tabs to the terminal

Why are you trying to activate a window when the stated purpose is to create a new one (alt F N pause down enter pause enter pair,tf enter)

Do you think SetWindowTextA is the same as keyboard events?

Why are you doing any of this?

 
WHRoeder :

Alt w Alt a doesn't work manually. you have to down arrow to select an entry before the alt a.

why are you sending tabs to the terminal

Why are you trying to activate a window when the stated purpose is to create a new one (alt F N pause down enter pause enter pair,tf enter)

Do you think SetWindowTextA is the same as keyboard events?

Why are you doing any of this?



Hi WHRoeder,

First, thanks for the very fast response! You have been very helpful on many occasions over the past couple of years :)

"Alt w Alt a doesn't work manually. you have to down arrow to select an entry before the alt a."
What if I want to activate the hilighted chart?

"why are you sending tabs to the terminal"
Because I've not been able to get the functionality I desire, stumbled across this, and it worked (at least partially).

"Why are you trying to activate a window when the stated purpose is to create a new one (alt F N pause down enter pause enter pair,tf enter)"
Because I wish to create a new chart (via script) according to a predefined pair/tf. I was able to create the chart, but when changing the pair/tf,
the window in behind was receiving the event. I had (incorrectly?) assumed activating the new chart gave it focus.

Just to clarify, I wish to launch a new chart, with a specified pair/tf...nothing more, nothing less :)

"Do you think SetWindowTextA is the same as keyboard events?"
No, because you're dealing with a specified window handle, which has nothing to do with focus, whereas keyboard events target the focused window/dialog/etc.
Alas I found this option via forum (was related to https://www.mql5.com/ru/code/9951 where
someone had posted a comparatively simplified method of changing a charts pair/tf via script.

" Why are you doing any of this?"
Because while MT4 is great, it can't be everything to everyone. I have created a fractal trading system which monitors all pairs/tf's, and use
an external server/app to monitor/calculate my triggers; I review these triggers via a web interface, and require a means of spawning the
related chart programmatically...so I don't have to do so manually.

As stated, my background is not windows based (ie. c++), and while I would love to pick up another language, I don't have the requisite time
to do so...apologies in advance for the probably awful mash of code I posted; this is a very small part of the overall requirement, and the
only one needing WinAPI.

Cheers!


 
giro :


What if I want to activate the hilighted chart?
Just to clarify, I wish to launch a new chart, with a specified pair/tf...nothing more, nothing less :)

I have created a fractal trading system which monitors all pairs/tf's, and use an external server/app to monitor/calculate my triggers; I review these triggers via a web interface, and require a means of spawning the related chart programmatically...so I don't have to do so manually.

As stated, my background is not windows based

  1. Make up your mind activate a chart or launch a new chart. I saved this from some post:
    #property show_inputs
    #import "user32.dll"
    int GetParent(int hWnd);
    int SendMessageA(int hWnd, int Msg, int wParam, int lParam);
    #import
    
    #define WM_MDIACTIVATE 0x222
    #define WM_MDIMAXIMIZE 0x0225
    
    extern string symbol = "EURUSD"; 
    
    int periods[9] = {PERIOD_MN1, PERIOD_W1, PERIOD_D1, PERIOD_H4, PERIOD_H1, PERIOD_M30, PERIOD_M15, PERIOD_M5, PERIOD_M1};
    
    int Window.activate(int hwnd) {
       int p = GetParent(hwnd);
       SendMessageA(GetParent(p), WM_MDIACTIVATE, p, 0);
    }
    int Window.maximize(int hwnd) {
       int p = GetParent(hwnd);
       SendMessageA(GetParent(p), WM_MDIMAXIMIZE, p, 0);
    }
    
    int Window.getHandle(string symbol) {
       int i, hwnd;
       for (i=0; i<ArraySize(periods); i++) {
          hwnd = WindowHandle(symbol, periods[i]);
          if (hwnd != 0) break;
       }
       return (hwnd);
    }
    
    void start() {
       int hwnd = Window.getHandle(symbol);
       Window.activate(hwnd);
       Window.maximize(hwnd);
       
    }
    and from my code
       //{The PostMessage above sends the command to the main terminal. Thus it
       // only affects the active chart window. To maximize a window for example
       // must activate it first. https://www.mql5.com/en/forum/128744
       //}See also SetForgroundWindow(h) https://www.mql5.com/en/code
    
  2. You've created your set of problems because of your approach and you keep on trying to kludge mt4 to your way of thinking. Stop it. Do it the way mt4 was designed. One application on multiple open charts triggered by ticks. Simple code - one symbol. Have the app merge their data to external server/app with IPC (quick channel, named pipes files, etc.)
  3. I have no windows programming experience either.
 

Thanks for your response!

I want to launch a chart, utilizing a script (which I already employ in an open chart) which contains a function accepting 2 arguments

OpenChart(string pair, int timeframe){}

It does NOT matter whether this new chart is Activated, but it MUST spawn according to the arguments passed to OpenChart.
(To clarify, the ONLY reason I was looking to Activate, was that

PostMessageA(hTerminal, WM_COMMAND, 33160, 0);

does not pass focus to the newly created chart - which I require as I haven't found a way to pass the pair/tf BEFORE spawning. Therefore I
needed to get the handle of the newly spawned chart, to change its pair/tf. Otherwise the chart in behind - ie. the chart with focus,
is changed, stripping away any scripts running inside of it, not good.)


Sorry if I have been overly obtuse.

Cheers! :)


Reason: