Passing a String/String Array reference to C++ or how to write a result handle for mysql

 

Hey all,


since a few days i am fighting with MT to pass a string reference and a string array reference to c++ in order to handle mysql results. I started here a discussion but i thought to start fresh again.

My goal is to have like the same as Russel wrote here: https://www.mql5.com/en/code/8623


I don't know what i do wrong, i guess i understand C++ and MT, but even the examples won't work on my x64 windows maschine. 

Here is what is working:

- I can pass a string ( wchar_t*, char* ) to a C++ Function in a DLL

- I can return a string ( wchar_t*, char* ) from a C++ Function in a DLL

- I can overwrite the passed pointer in C++ and display the result in MT5


But i can't pass a array or a string reference. Since i know that i have to use the "C" prefix for exporting a C++ function, MT5 can find the function, but it's return value is in a unknown character set. Within C++ it works, no error during compiling, and the checks are okay. After a month of mysql driver writing and fighting with MT5 strings i want to start writing my trading agent.

I like MT very much and i am a programmer, but i getting p***** when i stuc at a simple problem. Normaly i would fight and solve the problem by my own, but i want to trade, and not doing troubleshooting :D If you like to write me the module and solve me the problem, i will pay for it: https://www.mql5.com/en/job/71666


C++:

#ifdef MYSQLWRAPPER_EXPORTS
#define MYSQLWRAPPER_API __declspec(dllexport)
#else
#define MYSQLWRAPPER_API __declspec(dllimport)
#endif

#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif // _UNICODE

namespace std {
#ifdef _UNICODE
    typedef wstring tstring;
#else
    typedef string tstring;
#endif // _UNICODE
};

struct MqlStr {
    int               len;
    char             *string;
};

extern "C" MYSQLWRAPPER_API wchar_t*  __stdcall    returnString    ();
extern "C" MYSQLWRAPPER_API void __stdcall        changeString1    (wchar_t* &stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        changeString2    (char* &stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        changeString3    (LPWSTR &stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        changeString4    (LPWSTR stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        changeString5    (LPCSTR &stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        changeString6    (LPCSTR stringTest);
extern "C" MYSQLWRAPPER_API void __stdcall        fnReplaceString    (wchar_t* text, wchar_t *from, wchar_t *to);
extern "C" MYSQLWRAPPER_API void __stdcall        changeArrayString1(MqlStr *row);


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

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

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

void  __stdcall changeString3(LPWSTR &stringTest) {
    stringTest = L"Hello you ....";
}

void  __stdcall changeString4(LPWSTR stringTest) {
    stringTest = L"Hello you ....";
}

void  __stdcall changeString5(LPCSTR &stringTest) {
    stringTest = TEXT("Hello you ....");
}

void  __stdcall changeString6(LPCSTR stringTest) {
    stringTest = TEXT("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));
    text = cp;
}

void __stdcall changeArrayString1( MqlStr *row) {

    int pos = 1;

    for (int i = 0; i < pos; i++) {
        row[i].string = "Hello you ....";;
        row[i].len = static_cast<int>(strlen(row[i].string));
    }
}


MT5:

#import "Quantum\MySQL\mysql_wrapper.dll"
   string   returnString      ();
   void     changeString1      (string &value);
   void     changeString2     (string &value);
   void     changeString3     (string &value);
   void     changeString4     (string value);
   void     changeString5     (string &value);
   void     changeString6     (string value);
   void     fnReplaceString   (string &text,string from,string to);
   void     changeArrayString1(string& row[]);
#import


   string return_value1 = returnString();
   string return_value2 = "default...";
   string return_value3 = "default...";
   string return_value4 = "default...";
   string return_value5 = "default...";
   string return_value6 = "default...";
  
   Print("1.  Return value is: " + return_value1 );
  
   changeString1(return_value1);
   changeString2(return_value2);
   changeString3(return_value3);
   changeString4(return_value4);
   changeString5(return_value5);
   changeString6(return_value6);
  
   Print("1.1 Return value is: " + return_value1 );
   Print("2.  Return value is: " + return_value2 );
   Print("3.  Return value is: " + return_value3 );
   Print("4.  Return value is: " + return_value4 );
   Print("5.  Return value is: " + return_value5 );
   Print("6.  Return value is: " + return_value6 );
  
   //--- modify the string
   string text="A quick brown fox jumps over the lazy dog";
  
   fnReplaceString(text,"fox","cat");
   Print("Replace: ",text);
  
  // string row[];
  // ArrayResize(row, 2);
  // changeArrayString1(row);


Terminal:

2017.11.20 08:18:32.548    Test (EURUSD,M1)    1.  Return value is: this is a wchar_t string
2017.11.20 08:18:32.548    Test (EURUSD,M1)    1.1 Return value is: ㎘߾
2017.11.20 08:18:32.548    Test (EURUSD,M1)    2.  Return value is: ㎸߾
2017.11.20 08:18:32.548    Test (EURUSD,M1)    3.  Return value is: ㎘߾
2017.11.20 08:18:32.548    Test (EURUSD,M1)    4.  Return value is: default...
2017.11.20 08:18:32.548    Test (EURUSD,M1)    5.  Return value is: ㎸߾
2017.11.20 08:18:32.548    Test (EURUSD,M1)    6.  Return value is: default...
2017.11.20 08:18:32.548    Test (EURUSD,M1)    Replace: A quick brown cat jumps over the lazy dog


Passing a array, like as in the mysql_wrapper cause a panic:

2017.11.20 07:56:38.438    Test (EURUSD,M1)    Access violation at 0x000007FEF6CA10EA write to 0x0000000000000008 in 'C:\Users\tesla\AppData\Roaming\MetaQuotes\Terminal\D0E8209F77C8CF37AD8BF550E51FF075\MQL5\Libraries\Test\MySQL\mysql_wrapper.dll'
2017.11.20 07:56:38.438    Test (EURUSD,M1)       crash -->  000007FEF6CA10EA 48895008          mov        [rax+0x8], rdx
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA10EE 4883C8FF          or         rax, 0xff
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA10F2 488B11            mov        rdx, [rcx]
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA10F5 488B4A08          mov        rcx, [rdx+0x8]
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA10F9 0F1F8000000000    nop        [rax+0x0]
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA1100 48FFC0            inc        rax
2017.11.20 07:56:38.438    Test (EURUSD,M1)                  000007FEF6CA1103 803C0100          cmp        byte [rcx+rax], 0x0
2017.11.20 07:56:38.438    Test (EURUSD,M1)    
2017.11.20 07:56:38.438    Test (EURUSD,M1)    00: 0x000007FEF6CA10EA
2017.11.20 07:56:38.438    Test (EURUSD,M1)    01: 0x00000000042D212B
2017.11.20 07:56:38.438    Test (EURUSD,M1)    02: 0x000000000C405200
2017.11.20 07:56:38.438    Test (EURUSD,M1)    03: 0x000000000881113E
2017.11.20 07:56:38.438    Test (EURUSD,M1)    04: 0x0000000000000002


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...
 

Passing of string arrays is blocked by MQ.

Documentation on MQL5: Language Basics / Preprocessor / Importing Functions (#import)
Documentation on MQL5: Language Basics / Preprocessor / Importing Functions (#import)
  • www.mql5.com
directive. For compiler to be able to correctly form the imported function call and organize proper transmission parameters, the full description of functions is needed. Function descriptions immediately follow the Imported functions can have any names. Functions having the same names but from different modules can be imported at the same...
 
Christian Stern:

- I can pass a string ( wchar_t*, char* ) to a C++ Function in a DLL

- I can return a string ( wchar_t*, char* ) from a C++ Function in a DLL

- I can overwrite the passed pointer in C++ and display the result in MT5

But i can't pass a array or a string reference.

  1. When you post code please use the SRC button! Please edit your post.
              General rules and best pratices of the Forum. - General - MQL5 programming forum

  2. MT4/5 doesn't have pointers, (only handles to classes,) so you can't pass a string reference.
  3. Of course you can pass an array (as a reference.) Remember the array will not be asSeries.
  4. You can't change the pointer (array reference.) Change the passed array, don't exceed it's allocated size.
  5. Since C++ can't do anything but manipulate variables, stop making things more complicated. Just write the code in MT4/5, KISS.
Reason: