Cette solution fonctionne sur la Build 509, mais sur la Build 600. Sur la version 600, la sortie des experts est la suivante : "DLL says : ???????????x ??????????????".
La v600 utilise des chaînes Unicode, pas des chaînes Ansi. Soit vous devez renvoyer une chaîne Unicode à partir de votre DLL (voie la plus facile), soit vous devez faire des appels assez complexes dans le code MQL4 pour manipuler la valeur de retour de la chaîne (voie la plus difficile).
Dans tous les cas, cela va provoquer une fuite de mémoire car vous allouez un bloc de mémoire pour la chaîne de caractères que MT4 ne sait pas comment libérer et ne libérera pas. Il est préférable de transmettre un tampon à la DLL, et de faire en sorte que la DLL copie la chaîne dans ce tampon. En d'autres termes, la meilleure façon de renvoyer des valeurs de chaîne à MQL4 est d'utiliser le même type de méthode que les appels de l'API Windows tels que GetWindowsDirectory() et GetTempPath().
soit vous devez faire des appels assez complexes dans le code MQL4 pour manipuler la valeur de retour de la chaîne (voie la plus difficile).
Pour mémoire, il est toujours possible d'utiliser des DLL qui renvoient des chaînes Ansi ; c'est une sorte de suivi de https://www.mql5.com/en/forum/149321. Le problème est que le retour de chaînes de caractères à partir de DLL entraîne une fuite de mémoire, à moins que le code MQL4 ne sache comment la mémoire a été allouée et ne soit capable de la libérer. L'exemple suivant suppose que la mémoire de la chaîne a été allouée dans la DLL en utilisant LocalAlloc(), ou un équivalent indirect qui correspond à 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:
Pour mémoire, il est toujours possible d'utiliser des DLL qui renvoient des chaînes Ansi ; c'est une sorte de suivi de https://www.mql5.com/en/forum/149321. Le problème est que le fait de renvoyer des chaînes à partir de DLL entraîne une fuite de mémoire, à moins que le code MQL4 ne sache comment la mémoire a été allouée et ne soit capable de la libérer. L'exemple suivant suppose que la mémoire de la chaîne a été allouée dans la DLL en utilisant LocalAlloc(), ou un équivalent indirect qui correspond à LocalAlloc().
Merci ! Cela a également fonctionné pour ma libmysql.dll. Mon MQL4 ne peut plus parler à MySQL depuis la version 600.
Enfin, je peux au moins voir ce que la dll MySql retourne...
Pourriez-vous nous donner un indice sur la façon d'implémenter la communication inverse, c'est-à-dire de passer une chaîne de caractères de MQL4 (build 600) à une dll qui ne supporte que l'ANSI ? J'ai essayé la fonction UNICODE2ANSI() trouvée ici et ici mais cela ne fonctionne pas pour moi malheureusement.Pourriez-vous nous donner un indice sur la manière d'implémenter la communication inverse, c'est-à-dire de passer une chaîne de caractères de MQL4 (build 600) à une dll qui ne supporte que l'ANSI ?
Merci ! Cela fonctionne parfaitement pour les valeurs de chaîne simples. Au moins, MQL se connecte à MySQL maintenant.
Cependant, il semble que je ne puisse pas obtenir un tableau de chaînes de caractères à partir d'une dll. Voici la fonction qui m'est fournie (il s'agit d'un wrapper MySql MQL4) :
#import "mysql_wrapper.dll" void MT4_mysql_fetch_row (int result, string& row[]);
Actuellement, je reçois l'erreur "Access violation read to 0x0..." lorsque je passe le tableau de chaînes de caractères habituel de MQL.
Toute aide est la bienvenue.
Cependant, il semble que je ne puisse pas obtenir un tableau de chaînes de caractères à partir d'une dll. Voici la fonction qui m'est fournie (il s'agit d'un wrapper MySql MQL4) :
Simuler les anciens tableaux de chaînes Ansi est un peu compliqué, mais c'est possible. (Cela va dépendre du bon comportement de la DLL, en particulier si elle renvoie des données à MQL4 en modifiant le contenu du tableau. Je n'ai testé cela que contre l'exemple de code C++ en bas de page, pas contre quelque chose de plus réaliste comme la bibliothèque 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]); } }
Par exemple, le code ci-dessus fonctionne avec la DLL suivante qui fait une boîte de message pour chaque chaîne dans un tableau et ensuite inverse la chaîne avant de retourner à 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++; } }
La simulation des anciens tableaux de chaînes de caractères Ansi est compliquée, mais toujours possible.
(Le code ci-dessus peut être simplifié si le MQL4 passe le tableau de chaînes à la DLL uniquement pour lui donner un tampon de chaînes dans lequel la DLL peut écrire. Le code ci-dessus devrait gérer ce scénario, mais il est inutilement compliqué pour un appel en réception seulement à une DLL).
Si une DLL Ansi prend un paramètre de tableau de chaînes uniquement pour pouvoir renvoyer une valeur dans arr[0], alors le code peut être beaucoup plus simple. Par exemple :
#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); }
Cela fonctionne avec une DLL qui utilise simplement array[0] comme un tampon dans lequel elle peut écrire, par exemple :
__declspec(dllexport) void WINAPI Test(MqlStr * arr) { lstrcpyA(arr->data, "The string return value from the DLL"); }
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation
Salut les codeurs !
J'ai écrit une fonction DLL en Delphi. Ce code renvoie seulement un texte PChar à l'ex4.
Mon code MQ4 :
Cette solution fonctionne sur Build 509, mais sur Build 600. Sur Build 600, la sortie Experts est : "DLL says : ???????????x ??????????????".
Pourquoi ne fonctionne-t-il pas sur B600 ? Avez-vous une idée pour faire fonctionner mon code correctement ?
Merci d'avance.
Relative