Download MetaTrader 5
To add comments, please log in or register
Do you know that MQL5 can create custom graphical tools?
florentjustin
15
florentjustin 2015.09.10 08:34 

Hi,

To pass mql4 string to dll in C I see this articles:

https://docs.mql4.com/basis/types/stringconst

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

so in my dll I do this :

struct MqlString
{
        int size;       // 32 bit integer, contains the size of the buffer allocated for the string
        LPWSTR buffer_mt4;     // 32 bit address of the buffer that contains the string
        int reserved;   // 32 bit integer, reserved, do not use
};



bool fn_print_Gvar(char *functionName, char *message){
        FILE * pfilehandle;
        wchar_t buffer[80], filename[250] = L"";

        swprintf_s(filename, 250, L"%ls%mylog.log", Gpath);

        _wfopen_s(&pfilehandle,filename, L"a");
        
        if (pfilehandle != NULL){
                fprintf_s(pfilehandle, "(%s) %s\n", functionName, message);
                fclose(pfilehandle);
                return true;
        }
        else return false;

}


_DLLAPI int __stdcall fn_Test_stringMT4(MqlString *mystringmt4){

        char buffer[2000];
        wchar_t *Symbol = L"TEST_Symbol";

        sprintf_s(buffer, "Symbol = %ls, Size = %d, reserved = %d", Symbol, mystringmt4->size, mystringmt4->reserved);
        fn_print_Gvar("fn_Test_stringMT4", buffer);

        sprintf_s(buffer, "MQLSTring = %ls, Size = %d, reserved = %d", &mystringmt4->buffer_mt4, mystringmt4->size, mystringmt4->reserved);
        fn_print_Gvar("fn_Test_stringMT4", buffer);
        
        return 0;

}


and in mql4 :


#import "mydll.dll"
int fn_Test_stringMT4(string mystringmt4);
#import


 int start(){
    string teststr;
    
    teststr = "EURUSD";
    fn_Test_stringMT4(teststr);

}


When I print the string in mql4 I have the output: EURUSD

but when I print in C I have the ouput :

Symbol = TEST_Symbol, Size = 6619242, reserved = 7536741
MQLSTring = RUSD, Size = 6619242, reserved = 7536741

the first 2 characters of my mql4 string are not printed. I have RUSD instead of EURUSD

Where is the problem ?

JC
1389
JC 2015.09.10 08:48  
florentjustin:

[...] Where is the problem ?

Strings are not passed to a DLL using MT4's internal MqlString structure. They are simply passed as a pointer (to a Unicode string). Therefore, the function definition should be:

 _DLLAPI int __stdcall fn_Test_stringMT4(LPWSTR mystringmt4)

From https://docs.mql4.com/runtime/imports:

When a string is passed, the address of the buffer of the copied string is passed; if a string is passed by reference, the address of the buffer of this string without copying it is passed to the function imported from DLL. 

(This means that strings passed to DLLs cannot contain null characters, and do not have an explicit size. If you need the size, then you simply use wcslen or lstrlenW in the usual way.)

florentjustin
15
florentjustin 2015.09.10 09:29  
jjc:

When a string is passed, the address of the buffer of the copied string is passed; if a string is passed by reference, the address of the buffer of this string without copying it is passed to the function imported from DLL. 

ok but is it sure that buffer means the buffer of the string in the struct in mql ? or buffer means the pointer on the structure.

because on https://www.mql5.com/en/articles/1391 they said in 2.4. Unicode strings and their use in a DLL: The internal structure of strings has changed in MQL4 (now it takes 12 bytes), and the MqlString structure should be used when passing strings to DLL.

and the link on MqlString is https://www.mql5.com/ru/forum/150672. It seems they use the mqlstring structure in their dll.

JC
1389
JC 2015.09.10 10:01  
florentjustin:

[...] and the MqlString structure should be used when passing strings to DLL.

That bit of documentation is wrong. And it makes no sense: if MT4/MT5 passed strings as a MqlStr structure then it would be impossible to call Win32 functions which expect strings to be passed as char*/wchar*.

[EDIT...] 

MT4/MT5 don't in fact just pass a pointer to a string buffer. The four bytes below the string contain the int size of the number of characters in the string.

In other words, using the following MQL4 code...

#import "MyDll.dll"
   void Test(string);
#import

void OnStart()
{
   string x = "ABCDEF";
   Test(x);
}

... you can then do the following in a DLL:

extern "C" void __stdcall Test(WCHAR * x)
{
        // Get the string length which is contained in an int in the four bytes
        // immediately preceding the string pointer referenced by x
        int lStringLength = *(((int*)x) -1);

        WCHAR tmp[30];
        _swprintf(tmp, L"String length: %i", lStringLength);

        MessageBoxW(NULL, x, tmp, 64);
}

But getting the string length this way is not what is documented at https://docs.mql4.com/runtime/imports, and it could potentially break in future. MT4/MT5 could simply start passing a WCHAR* without breaching the documentation.

For confirmation, MT4/5 is not passing a MqlStr structure. MqlStr is as follows:

int size;
WCHAR * buffer;
int reserved;

What MT4/5 are passing to a DLL is:

int size;
WCHAR buffer[];

... with the pointer which the DLL receives being the address of the buffer member, not the address of the size member. It's very like a Windows BSTR in that respect. 

florentjustin
15
florentjustin 2015.09.10 16:08  
ok thank you for your help. :-)
/
To add comments, please log in or register