Это решение работает на Build 509, но не работает на Build 600. На Build 600 эксперты выводят следующее: "DLL says: ???????????x??????????????".
v600 использует строки Unicode, а не Ansi. Вам нужно либо вернуть строку Unicode из вашей DLL (более простой путь), либо сделать несколько довольно сложных вызовов в коде MQL4 для манипулирования возвращаемым значением строки (более сложный путь).
В любом случае, это приведет к утечке памяти, потому что вы выделяете блок памяти для строки, который MT4 не знает, как освободить, и не освободит. Лучше передать DLL буфер, а DLL скопирует строку в этот буфер. Другими словами, для возврата строковых значений в MQL4 лучше использовать методы, аналогичные вызовам Windows API, таким как GetWindowsDirectory() и GetTempPath().
либо вам придется делать довольно сложные вызовы в коде MQL4, чтобы манипулировать возвращаемым значением строки (более сложный путь).
К сведению, по-прежнему можно использовать DLL, возвращающие строки Ansi; это своего рода продолжение https://www.mql5.com/en/forum/149321. Проблема заключается в том, что при возврате строк из DLL происходит утечка памяти, если только код MQL4 не знает, как была выделена память, и не может ее освободить. В следующем примере предполагается, что память для строк была выделена в DLL с помощью LocalAlloc() или какого-либо косвенного эквивалента, который отображается на LocalAlloc().
#import "SomeDllWhichReturnsAnsiStrings.dll" // Declare the Ansi function as returning int rather than string int Test(); // NOT string Test(); #import #import "kernel32.dll" int lstrlenA(int); void RtlMoveMemory(uchar & arr[], int, int); int LocalFree(int); // May need to be changed depending on how the DLL allocates memory #import void OnStart() { // Call the DLL function and get its block of string memory as an int pointer to the // memory rather than as a string int ptrStringMemory = Test(); // Get the length of the string int szString = lstrlenA(ptrStringMemory); // Create a uchar[] array whose size is the string length (plus null terminator) uchar ucValue[]; ArrayResize(ucValue, szString + 1); // Use the Win32 API to copy the string from the block returned by the DLL // into the uchar[] array RtlMoveMemory(ucValue, ptrStringMemory, szString + 1); // Convert the uchar[] array to a MQL string string strValue = CharArrayToString(ucValue); // Free the string memory returned by the DLL. This step can be removed but, without it, // there will be a memory leak. // The correct method for freeing the string *depends on how the DLL allocated the memory* // The following assumes that the DLL has used LocalAlloc (or an indirect equivalent). If not, // then the following line may not fix the leak, and may even cause a crash. LocalFree(ptrStringMemory); // Done... Print(strValue); }
gchrmt4:
К сведению, по-прежнему можно использовать DLL, возвращающие строки Ansi; это своего рода продолжение https://www.mql5.com/en/forum/149321. Проблема заключается в том, что при возврате строк из DLL происходит утечка памяти, если только код MQL4 не знает, как была выделена память, и не может ее освободить. Следующий пример предполагает, что память для строк была выделена в DLL с помощью LocalAlloc() или какого-либо косвенного эквивалента, который отображается на LocalAlloc().
Спасибо! Это также сработало для моей libmysql.dll. Мой MQL4 больше не может общаться с MySQL после сборки 600.
Наконец-то я могу хотя бы увидеть, что возвращает MySql dll...
Подскажите, пожалуйста, как реализовать обратную связь, т.е. передать строку из MQL4 (билд 600) в dll, которая поддерживает только ANSI? Я пробовал использовать функцию UNICODE2ANSI(), найденную здесь и здесь, но она, к сожалению, не работает.Подскажите, пожалуйста, как реализовать обратную связь, т.е. передать строку из MQL4 (build 600) в dll, которая поддерживает только ANSI?
Спасибо! Это работает для простых строковых значений просто идеально. По крайней мере, MQL теперь подключается к MySQL.
Однако похоже, что я не могу получить массив строк из dll. Вот функция, которую мне предоставляют (это обертка MQL4 MySql):
#import "mysql_wrapper.dll" void MT4_mysql_fetch_row (int result, string& row[]);
В настоящее время я получаю ошибку "Access violation read to 0x0..." при передаче обычного массива строк MQL.
Любая помощь будет высоко оценена.
Однако похоже, что я не могу получить массив строк из dll. Вот функция, которую мне предоставили (это обертка MQL4 MySql):
Имитация старых строковых массивов Ansi муторна, но все же возможна. (Это зависит от того, насколько хорошо ведет себя DLL, особенно если она передает данные обратно в MQL4, изменяя содержимое массива. Я проверил это только на примере C++ кода внизу, а не на чем-то более реалистичном, как библиотека MySql).
#import "SomeDllWhichTakesAStringArray.dll" // Old Ansi function which takes a string array plus a parameter telling it // the size of the array void Test(int & arr[], int); // NOT void Test(string & arr[], int) #import #import "kernel32.dll" int LocalAlloc(int,int); int LocalFree(int); int lstrcpyA(int,uchar & arr[]); int lstrlenA(int); void RtlMoveMemory(uchar & arr[], int, int); #import void OnStart() { // Example array of strings... string MyStringArray[] = {"String 1", "String 2"}; int SizeOfStringArray = ArraySize(MyStringArray); // A string array (received by the DLL as an array of MqlStr structures) corresponds // to an int array where the even-numbered members are string lengths, and the odd-numbered // members are pointers to string memory. // We start by creating an int array, which needs to have twice as many members as the // string array int i; int arrMqlStr[]; ArrayResize(arrMqlStr, SizeOfStringArray * 2); // Populate the array which simulates MqlStr[]. For each string, we allocate // a block of memory using LocalAlloc() and copy the MQL4 string into that for (i = 0; i < SizeOfStringArray; i++) { // Get the length of the string and store it int szString = StringLen(MyStringArray[i]); arrMqlStr[i * 2] = szString; // Allocate a block of memory to hold the string int ptrMem = LocalAlloc(0x40 /* LPTR */, szString + 1); arrMqlStr[(i * 2) + 1] = ptrMem; // Convert the MQL4 string to a uchar[] array uchar ucString[]; StringToCharArray(MyStringArray[i], ucString); // Copy the uchar[] array into the block of memory allocated above lstrcpyA(ptrMem, ucString); } // Call the DLL function Test(arrMqlStr, SizeOfStringArray); // We now need to free the memory which was allocated above to hold // a copy of each string. In addition, DLLs can alter strings which // are passed to them in arrays. Therefore, for completeness, we // should read the strings back and put them into the original // array for (i = 0; i < SizeOfStringArray; i++) { // Get the size of the string now contained in the memory block int NewSizeofString = lstrlenA(arrMqlStr[(i * 2) + 1]); // Copy the contents of the memory block into a uchar[] array uchar ucReceive[]; ArrayResize(ucReceive, NewSizeofString + 1); RtlMoveMemory(ucReceive, arrMqlStr[(i * 2) + 1], NewSizeofString + 1); // Put the uchar[] back into the original string array MyStringArray[i] = CharArrayToString(ucReceive); // Free the memory for the string allocated above LocalFree(arrMqlStr[(i * 2) + 1]); } }
Например, приведенный выше код работает со следующей DLL, которая делает окно сообщения для каждой строки в массиве, а затем меняет строку на противоположную перед возвратом в MT4:
__declspec(dllexport) void WINAPI Test(MqlStr * arr, int sz) { for (int i = 0; i < sz; i++) { MessageBoxA(NULL, arr->data, "String", 48); strrev(arr->data); arr++; } }
Имитация старых строковых массивов Ansi - дело муторное, но все же возможное.
(Приведенный выше код может быть упрощен, если MQL4 передает строковый массив в DLL только для того, чтобы дать ей строковый буфер для записи в DLL. Приведенный выше код должен справиться с этим сценарием, но он неоправданно сложен для вызова DLL только на прием).
Если Ansi DLL принимает параметр строкового массива только для того, чтобы передать обратно значение в arr[0], то код может быть намного проще. Например:
#import "AnsiDllWhichPassesBackAStringValueViaAnArray.dll" // Old Ansi function which takes a string array parameter **solely** so that // it can **pass back** a value in arr[0] void Test(int & arr[]); // NOT void Test(string & arr[]) #import #import "kernel32.dll" int LocalAlloc(int,int); int LocalFree(int); void RtlFillMemory(int, int, int); int lstrlenA(int); void RtlMoveMemory(uchar & arr[], int, int); #import void OnStart() { // Maximum size of string which the DLL is expected to return in arr[0] int MaxReturnValueLength = 10000; // Allocate a block of memory of the desired size int ptrMem = LocalAlloc(0x40 /* LPTR */, MaxReturnValueLength + 1); // Fill the memory with spaces so that the length is <whatever> if // the DLL checks it by doing strlen() RtlFillMemory(ptrMem, MaxReturnValueLength, 32); // Create a pseudo-MqlStr array which corresponds to a string array with one member int arrMqlStr[2]; arrMqlStr[0] = MaxReturnValueLength; arrMqlStr[1] = ptrMem; // Call the DLL Test(arrMqlStr); // Get the size of the string contained in the memory block int NewSizeofString = lstrlenA(ptrMem); // Copy the contents of the memory block into a uchar[] array uchar ucReceive[]; ArrayResize(ucReceive, NewSizeofString + 1); RtlMoveMemory(ucReceive, ptrMem, NewSizeofString + 1); // Free the memory for the string allocated above LocalFree(ptrMem); // Convert the uchar[] array to a string string strReturnValueFromDLL = CharArrayToString(ucReceive); }
Это работает с DLL, которая просто использует array[0] в качестве буфера, в который она может записывать, например:
__declspec(dllexport) void WINAPI Test(MqlStr * arr) { lstrcpyA(arr->data, "The string return value from the DLL"); }
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Привет кодеры!
Я написал DLL функцию в Delphi. Этот код возвращает только текст PChar в ex4.
Мой код для MQ4:
Это решение работает на Build 509, но на Build 600. На Build 600 вывод экспертов: "DLL says: ???????????x??????????????".
Почему не работает на B600? Есть ли у вас идеи, как сделать так, чтобы мой код работал правильно?
Заранее благодарю.
Relative