Passing a string to a DLL Function

To add comments, please log in or register
Christian Stern
285
Christian Stern  

Hey all,


maybe you could help me solving this problem. I have create a simple DLL, like as described here:

https://www.mql5.com/en/articles/18


The DLL work when i use as parameter a Integer but when i switch to string, MT5 come up with the message, he couldn't find the method:

2017.11.18 11:24:35.507    Test(EURUSD,M1)    Cannot find 'testWchar_Ref' in 'Test\variableTest.dll'


This is my import in MT5:

#import "Test\variableTest.dll"
   void testInt_Ref   (int    &intTest_ref);
   void testWchar_Ref (string &wchar_tTest_Ref);
#import  



Implementation in MT5:

   string stringTest = "Hello you...";  
   int    myInt = 0;
   
   testInt_Ref(myInt);
   Print("New INT: ", myInt );
   
   Print("PRE: " + stringTest);
   testWchar_Ref(u_stringTest);
   Print("POST: " + stringTest);



Export in DLL:

#ifdef VARIABLETEST_EXPORTS  
#define QVAR_API __declspec(dllexport)   
#else  
#define QVAR_API __declspec(dllimport)   
#endif

extern QVAR_API void testInt_Ref(int &intTest_ref);
extern QVAR_API void testWchar_Ref(wchar_t &wchar_tTest_Ptr);



DLL Function:

// Include header files
#include "stdafx.h"

using namespace std;

// add new INT value
void testInt_Ref(int &intTest_ref) {
    intTest_ref = 222;
}

// add new WCHAR_T value
void testWchar_Ref(wchar_t &wchar_tTest) {

    wchar_t *msg = L"This is cool.....";
    wchar_t *wchar_tTest_Ref = &wchar_tTest;

    //--- replace it
    memcpy(wchar_tTest_Ref, msg, wcslen(msg) * sizeof(wchar_t));
}



Result:

2017.11.18 11:24:35.507    Test(EURUSD,M1)    New INT: 222
2017.11.18 11:24:35.507    Test(EURUSD,M1)    PRE: Hello you...
2017.11.18 11:24:35.507    Test(EURUSD,M1)    Cannot find 'testWchar_Ref' in 'Test\variableTest.dll'
2017.11.18 11:24:35.507    Test(EURUSD,M1)    unresolved import function call



it's compiled correctly. In my c++ Testprogram it works. Even when i leave the DLL Method empty it appears. It must be the parameter.


How can i pass a string to a DLL, modify it and use it back in MT5 ?


Thanks in Advanced

How to Exchange Data: A DLL for MQL5 in 10 Minutes
How to Exchange Data: A DLL for MQL5 in 10 Minutes
  • 2010.01.27
  • MetaQuotes
  • www.mql5.com
As a matter of fact, there are not many developers who remember exactly how to write a simple DLL library and what are features of binding different systems. Using several examples, I will try to show the entire process of the simple DLL's creation in 10 minutes, as well as to discuss some technical details of our binding implementation. We...
Stanislav Korotky
24612
Stanislav Korotky  

What you're asking for is not passing a string to DLL, but getting a string from DLL!

To pass a string to DLL just declare a function with LPWSTR parameter (not a reference!) in DLL and call it with a string.

To read a string you can allocate a uchar buffer in MQL and pass it as a pointer to the DLL (something like GetString(/*in|out*/uchar *buffer, /*in*/const int bufferLen) in MQL import), which will fill it with chars. Then you can reconstruct the string using CharArrayToString.

Or you can have a static (or preallocated) buffer in the DLL and return wchar_t* (LPWSTR) for it from a function (like string GetString() in MQL import). Probably you can find a solution in this source codes (unfortunately, the description is in Russian only).

Mikhail Dovbakh
5681
Mikhail Dovbakh  

In the standard delivery of MT4 (\ MQL4 \ Scripts \ Examples \ DLL) there is an example ( & it works fine in MT5) :

//+------------------------------------------------------------------+

#include <windows.h>

#include <stdlib.h>

#include <stdio.h>

//---

#define MT4_EXPFUNC __declspec(dllexport)

//+------------------------------------------------------------------+

#pragma pack(pop)

//---

struct MqlStr

  {

   int               len;

   char             *string;

  };

static int CompareMqlStr(const void *left,const void *right);

//+------------------------------------------------------------------+

//|                                                                  |

//+------------------------------------------------------------------+

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)

  {

//---

   switch(ul_reason_for_call)

     {

      case DLL_PROCESS_ATTACH:

      case DLL_THREAD_ATTACH:

      case DLL_THREAD_DETACH:

      case DLL_PROCESS_DETACH:

         break;

     }

//---

   return(TRUE);

  }

//+------------------------------------------------------------------+

MT4_EXPFUNC wchar_t* __stdcall GetStringValue(wchar_t *spar)

  {

   spar=L" it ...";

   return(spar);

  }

#import "DLLSample.dll"

string GetStringValue(string);

#import

//+------------------------------------------------------------------+

int init()

  {

   string sret;

   int    cnt;

//--- simple dll-functions cal

   sret=GetStringValue("some string");

   Print("Returned value is ",sret);

//---

   return(0);

  }



2017.11.18 23:08:23.306 DLL_Sample (EURUSD,M1) Returned value is  it ...

MetaQuotes Software Corp.
MetaQuotes Software Corp.
  • www.metaquotes.net
Миллионы трейдеров и сотни брокеров не могут ошибаться — они выбрали MetaTrader 5 для торговли на Форексе и финансовых рынках! Узнать больше
Files:
Christian Stern
285
Christian Stern  
Hi Mikhail ,Thank you.  Yeah i know that but it doesn't match my needings. I have a mysql string result which i want to handover to MT. I dont know what i do wrong...see below my full replay



Mikhail Dovbakh:

In the standard delivery of MT4 (\ MQL4 \ Scripts \ Examples \ DLL) there is an example ( & it works fine in MT5) :

...

Christian Stern
285
Christian Stern  
Stanislav Korotky:

What you're asking for is not passing a string to DLL, but getting a string from DLL!

To pass a string to DLL just declare a function with LPWSTR parameter (not a reference!) in DLL and call it with a string.

To read a string you can allocate a uchar buffer in MQL and pass it as a pointer to the DLL (something like GetString(/*in|out*/uchar *buffer, /*in*/const int bufferLen) in MQL import), which will fill it with chars. Then you can reconstruct the string using CharArrayToString.

Or you can have a static (or preallocated) buffer in the DLL and return wchar_t* (LPWSTR) for it from a function (like string GetString() in MQL import). Probably you can find a solution in this source codes (unfortunately, the description is in Russian only).


Hi Stanislav , thank you and thank you for the hint. Yes you are right, i want to pass a string reference to a DLL function and within the DLL i want to assign data, like a mysql result. Which means i need to refer a string array. After all that reading i had some problems sorting my mind :D ...I understand what you are saying but somehow it won't work. I guess more, i have some compiler settings missing, because also the examples found here or the mysql_wrapper from russell ( https://www.mql5.com/en/code/8623 ) wont work.


He just provides a 32bit version and i compiled it for 64bit with VS2017. But also very very simple function where you just pass the arument won't work. I dont have problems passing a string, this works. I also can return a wchar_t value but i can't handle a string reference.


In MT4 there use, so far i know, char and in mt5 wchar_t

I tried all this:

#pragma pack(push,1)
struct MqlStr_mt4 {
    int      len;       // 32 bit integer, contains the size of the buffer allocated for the string
    char*    string;     // 32 bit address of the buffer that contains the string
    int      reserved;   // 32 bit integer, reserved, do not use
};

struct MqlStr_mt5 {
    int      len;        // 32 bit integer, contains the size of the buffer allocated for the string
    wchar_t* string;     // 32 bit address of the buffer that contains the string
    int      reserved;   // 32 bit integer, reserved, do not use
};
#pragma pack(pop,1)


extern MYSQLWRAPPER_API wchar_t* MT5_mysql_wrapper_version    (); << works

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (int &foobar); << int works

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (wchar_t *foobar); << Passing only

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (wchar_t *&foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (MqlStr_mt4 &foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (MqlStr_mt4 *&foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (MqlStr_mt5 &foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (MqlStr_mt5 *&foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (LPWSTR &foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (LPWSTR *&foobar); << Error in MT

extern MYSQLWRAPPER_API void     MT5_mysql_wrapper_version    (wchar_t &foobar); << Error in MT



The function also has been exported with "C" but it wont change.

Also the example from Mikhail don't work. I spend the entiere weekend with MT documentary, google and coffee and i have no clue what i do wrong.  Within C++ it works. NO Errors, no NULL Pointer Exception ....all fine.

MySQL wrapper
MySQL wrapper
  • votes: 8
  • 2008.12.15
  • Russell
  • www.mql5.com
There are a few solutions around for reading and writing to MySQL databases. Writing to MySQL is in general not a big problem in MT4. But the reading part is kinda hard. MT4 can't handle C++ structures very well, only the native types such as int, double and string are supported. Other solutions use a SELECT statement CONCATing the wanted...
Mikhail Dovbakh
5681
Mikhail Dovbakh  
Hello Christian !
If you do not have the DLL that I packed into the attachment, then you have a 32 bit MT5.
If this is not the case, I can not reason why this assembly of DLL (by the way it was made directly in the META Editor) does not work.
Christian Stern
285
Christian Stern  
Mikhail Dovbakh:
Hello Christian !
If you do not have the DLL that I packed into the attachment, then you have a 32 bit MT5.
If this is not the case, I can not reason why this assembly of DLL (by the way it was made directly in the META Editor) does not work.

Hi Mikhail ,

no, your DLL get's loaded and it works. I meaned the DLL from the one documentation i mention. But as i said, i need to pass a string reference in order to handle mysql results.

Christian Stern
285
Christian Stern  

Now, somehow i am a bit futher but still not at the goal. Current this works but the string is displayed incorretly:


Since i export the function as "C", MT stops showing me the unresolve able error message.


C++:

extern "C" MYSQLWRAPPER_API wchar_t*    returnString    ();
extern "C" MYSQLWRAPPER_API void        changeString    (wchar_t* &stringTest);
extern "C" MYSQLWRAPPER_API void        changeString1   (char* &stringTest);
extern "C" MYSQLWRAPPER_API void        fnReplaceString (wchar_t *text, wchar_t *from, wchar_t *to);


wchar_t* __stdcall returnString() {
    return(L"this is a wchar_t string");
}

void  __stdcall changeString(wchar_t* &stringTest) {
    stringTest = L"Hello you ....";
}

void  __stdcall changeString1(char* &stringTest) {
    stringTest = "Hello you ....";
}

void __stdcall fnReplaceString(wchar_t *text, wchar_t *from, wchar_t *to) {
    wchar_t *cp;
    //--- parameters check
    if (text == NULL || from == NULL || to == NULL) return;
    if (wcslen(from) != wcslen(to))             return;
    //--- search for substring
    if ((cp = wcsstr(text, from)) == NULL)         return;
    //--- replace it
    memcpy(cp, to, wcslen(to) * sizeof(wchar_t));
}


MT5:

#import "Quantum\MySQL\mysql_wrapper.dll"
   string   returnString   ();
   void     changeString   (string &value);
   void     changeString1   (string &value);
#import  


string return_value1 = returnString();
string return_value2 = "";
   
Print("1. Return value is: " + return_value1 );
   

// wchar_t
changeString(return_value1);

// char
changeString1(return_value2);


Print("2. Return value is: " + return_value1 );
Print("3. Return value is: " + return_value2 );


//--- modify the string
string text="A quick brown fox jumps over the lazy dog";
  
fnReplaceString(text,"fox","cat");
Print("Replace: ",text);


Result:

2017.11.19 20:40:55.816    Test (EURUSD,M1)    1. Return value is: this is a wchar_t string
2017.11.19 20:41:06.085    Test (EURUSD,M1)    2. Return value is: ㎘߾
2017.11.19 20:41:07.636    Test (EURUSD,M1)    3. Return value is: ㎸߾
2017.11.19 20:41:11.343    Test (EURUSD,M1)    Replace: A quick brown fox jumps over the lazy dog



Also in the example, from a example ( https://www.mql5.com/en/articles/18 ) , the hasn't changed. 


But since i overwrite the pointer at the end in the DLL function fnReplaceString:

void __stdcall fnReplaceString(wchar_t* text, wchar_t *from, wchar_t *to) {
    wchar_t *cp;
    //--- parameters check
    if (text == NULL || from == NULL || to == NULL) return;
    if (wcslen(from) != wcslen(to))             return;
    //--- search for substring
    if ((cp = wcsstr(text, from)) == NULL)         return;

    //--- replace it
    memcpy(cp, to, wcslen(to) * sizeof(wchar_t));
    text = cp;
}



The result looks great:

2017.11.19 20:50:34.581    QuantumEA (EURUSD,M1)    Replace: A quick brown cat jumps over the lazy dog

How to Exchange Data: A DLL for MQL5 in 10 Minutes
How to Exchange Data: A DLL for MQL5 in 10 Minutes
  • 2010.01.27
  • MetaQuotes
  • www.mql5.com
As a matter of fact, there are not many developers who remember exactly how to write a simple DLL library and what are features of binding different systems. Using several examples, I will try to show the entire process of the simple DLL's creation in 10 minutes, as well as to discuss some technical details of our binding implementation. We...
To add comments, please log in or register