Import DLL: Unicode kontra ANSI
Łańcuchy MQL5 są szerokoznakowe, a połowa funkcji WinAPI oczekuje bajtów. Kto odpowiada za bufor i skąd biorą się krzaki.
1 fragment kodu z tej strony przeszedł przez kompilator MetaEditor build 6090, 2026-08-05.
MQL5 to potężne narzędzie, ale czasami musi wyjść poza swoją piaskownicę (sandbox). Importowanie funkcji z zewnętrznych bibliotek DLL (zwłaszcza systemowego WinAPI z user32.dll czy kernel32.dll) pozwala na tworzenie zaawansowanych interfejsów, powiadomień i integracji. Jednak to właśnie tutaj programiści C++ i C# zapominają o najważniejszej różnicy: MQL5 wewnętrznie przechowuje stringi jako Unicode (UTF-16), podczas gdy wiele funkcji systemowych oczekuje ciągów ANSI (jednobajtowych).
Zarządzanie pamięcią: Kto jest właścicielem bufora?
W językach zarządzanych (C#, Java) string jest obiektem niemutowalnym. W MQL5 string jest tablicą znaków Unicode zakończoną zerem (null-terminated). Kiedy przekazujesz stringa do funkcji DLL jako parametr, przekazujesz wskaźnik do tego bufora w pamięci terminala. Jeśli funkcja DLL ma go modyfikować (np. pobierać tekst z okna systemowego), MQL5 musi z góry wiedzieć, jak duża jest ta pamięć. W przeciwnym razie DLL nadpisze pamięć sąsiednich zmiennych, powodując критический błąd (Access Violation) i natychmiastowe zamknięcie terminala.
Wzorzec bezpiecznego wywołania: GetWindowText
Rozważmy klasyczny przykład: chcemy pobrać tytuł okna terminala za pomocą API Windows. Funkcja GetWindowText występuje w dwóch wersjach: GetWindowTextA (ANSI) i GetWindowTextW (Unicode). Użycie wersji "W" (Wide) wydaje się naturalne dla MQL5, ale wymaga ostrożności z buforem. Jeśli użyjemy wersji ANSI, MQL5 niejawnie przekonwertuje stringa, ale musimy zadeklarować parametr odpowiednio.
// Import funkcji systemowej (Unicode)
#import "user32.dll"
int GetWindowTextW(int hWnd, string &lpString, int nMaxCount);
#import
string GetTerminalTitle() {
// 1. Inicjalizujemy pusty string o z góry zdefiniowanej długości!
// Jeśli tego nie zrobimy, string ma długość 0 i DLL nadpisze pamięć.
string title = " ";
StringInit(title, 256); // Alokujemy 256 znaków (512 bajtów w UTF-16)
// Pobieramy uchwyt okna (skrócone, w realu używa się FindWindowW)
int hwnd = (int)ChartGetInteger(0, CHART_WINDOW_HANDLE);
// 2. Wywołujemy DLL. Zwróć uwagę na operator & (referencja).
// Musimy przekazać rozmiar w ZNAKACH, nie w bajtach.
int copied = GetWindowTextW(hwnd, title, 256);
if(copied > 0) {
// 3. Odczytujemy wartość. MQL5 automatycznie ucięta stringa
// na pierwszym znaku null (0x00 0x00).
return title;
}
return "Nie udało się pobrać tytułu.";
}