Stringhe ANSI vs UNICODE in MQL4

Fino alla versione 580, MQL lavorava con stringhe in formato ANSI mentre nelle versioni successive le stringhe sono in formato Unicode. Lungi dal volere fare una trattazione su vantaggi e svantaggi di una codifica rispetto all’altra, la differenza sostanziale fra le due codifiche consiste nel numero di bytes usati per rappresentare ogni singolo carattere.

A differenza della codifica ANSI che è una codifica a byte singolo e si avvale poi di tabelle di conversione (le famose CodePage) per riuscire a rappresentare i vari caratteri disponibili nelle diverse lingue, la codifica Unicode è una codifica multibyte che risulta pertanto più flessibile ed è in grado di rappresentare in maniera univoca ogni singolo carattere disponbile in ogni singola lingua. Tralascio gli eventuali problemi di conversione da un formato all’altro, per i quali sono state introdotte in MQL funzioni specifiche, e mi soffermo invece su un caso particolare usato in uno degli expert più diffusi: quello per generare le candele Renko, l’ormai storico RenkoLiveChart_v32.mq4.

In questo EA è presente la funzione UpdateChartWindow() il cui scopo è quello di tenere aggiornato il chart (che ricordo viene generato come chart offline) e simulare la ricezione di un tick, in modo che il chart generato si comporti come un normale chart.

void UpdateChartWindow() {
   static int hwnd = 0;
   if(hwnd == 0) {
      hwnd = WindowHandle(SymbolName, RenkoTimeFrame);
      if(hwnd != 0) Print("Chart window detected");
   }
   if(EmulateOnLineChart && MT4InternalMsg == 0)
      MT4InternalMsg = RegisterWindowMessageA("MetaTrader4_Internal_Message");
   if(hwnd != 0) if(PostMessageA(hwnd, WM_COMMAND, 0x822c, 0) == 0) hwnd = 0;
   if(hwnd != 0 && MT4InternalMsg != 0) PostMessageA(hwnd, MT4InternalMsg, 2, 1);
   return;
}

La funzione UpdateChartWindow() si avvale di due funzioni RegisterWindowMessageA() e PostMessageA() importate entrambe dalla libreria di sistema user32.dll. All’inizio del codice troviamo infatti

#import "user32.dll"
   int RegisterWindowMessageA(string lpString);
#import

Questa direttiva #import è necessaria perché le funzioni importate dalla user32.dll (e incluse in WinUser32.mqh tramite la direttiva #include) non comprendono la funzione RegisterWindowMessageA();

La funzione RegisterWindowMessageA() serve per registrare una stringa da usare come messaggio codificato, usato internamente da MT4 per le “comunicazioni” fra le varie finestre dell’applicazione e, nello specifico l’istruzione

PostMessageA(hwnd, MT4InternalMsg, 2, 1);

serve per forzare l’invio di un tick fittizio al chart offline e simulare quindi il comportamento di un chart reale.

Il problema è che la stringa “MetaTrader4_Internal_Message” nelle nuove versioni non è più una stringa ANSI ma viene trattata del compilatore come una stringa Unicode, pertanto non si potrà più usare la funzione RegisterWindowMessageA() (specifica per le stringhe in formato ANSI, il suffisso A sta appunto per ANSI) ma si dovrà usare la corrispettiva funzione RegisterWindowMessageW() per le stringhe in formato Unicode.

Analogamente, al posto della funzione PostMessageA() usata per trasmettere il messaggio, trattandosi di una stringa unicode, si dovrà usale la corrispettiva funzione PostMessageW().

I parametri formali usati nella definizione delle due funzioni sono esattamente gli stessi; pertanto le modifiche da fare sono veramente poche per adattare la routine UpdateChartWindow() alla nuova sintassi. La sezione #import diventerà pertanto

#import "user32.dll"
   int RegisterWindowMessageW(string lpString);
#import

e la routine UpdateChartWindow() diventerà

void UpdateChartWindow() {
   static int hwnd = 0;
   if(hwnd == 0) {
      hwnd = WindowHandle(SymbolName, RenkoTimeFrame);
      if(hwnd != 0) Print("Chart window detected");
   }
   if(EmulateOnLineChart && MT4InternalMsg == 0)
      MT4InternalMsg = RegisterWindowMessageW("MetaTrader4_Internal_Message");
   if(hwnd != 0) if(PostMessageA(hwnd, WM_COMMAND, 0x822c, 0) == 0) hwnd = 0;
   if(hwnd != 0 && MT4InternalMsg != 0) PostMessageW(hwnd, MT4InternalMsg, 2, 1);
   return;
}

Come si vede, la prima chiamata a PostMessageA() è rimasta inalterata trattandosi di un comando per l’aggiornamento video, mentre la seconda, trattandosi di una stringa ANSI è stata trasformata opportunamente.

Entrambe le funzioni PostMessageA() e PostMessageW() sono già presenti nel file WinUser32.mqh incluso all’inizio del codice.

Buon aggiornamento!

Skipper

Comments are closed.

© 2016 by    
Marco Tosoni