How to return a string from a C++ DLL into a MetaTrader 4 code-execution ecosystem?

浪子不回头ぞ 提交于 2020-01-01 06:39:15

问题


I have following function

__declspec(dllexport) wchar_t* __stdcall __getJson(wchar_t * listN){
setlocale(LC_ALL, "");
//function logic
wstring ant = utf8_to_wstring(result);
const WCHAR* constRes = ant.c_str();
WCHAR* tempObj=new WCHAR[ant.length()];
wcscpy(tempObj, constRes);
thread Thread([tempObj]{
    Sleep(1000);
    delete[] tempObj;
});
Thread.detach();
return tempObj;
}

This DLL returns wchar_t* to MetaTrader4.

I tried many ways to return correct value and avoid memory leaks such as set return type const wchar_t*, creating my own class with destructor with delete[] in. But all this attempts was unsuccessful: I got '??ello' instead of 'hello'. Just first one or two symbols were incorrect. With creating thread it works right. But, I want to know, may there be better solution?


回答1:


To create a string in your DLL and pass it to the caller, you must dynamically allocate some memory in the DLL to store the string's characters, and pass a pointer to that memory to the caller.

Moreover, the caller must be able to release that memory when the string is not needed anymore.

To make it work properly, you must use the same memory manager/allocator to both allocate and free the string's memory.

One option would be to use a common system-wide allocator like the COM allocator. In this way, you can allocate the memory in the DLL using CoTaskMemAlloc, and the caller can free it using the matching CoTaskMemFree.

Another option would be to return a BSTR string, allocated with SysAllocString in the DLL. And the caller would release that string invoking SysFreeString.

Or, you could provide a custom function to free the string's memory in your DLL. For example, you could allocate the string's memory in your DLL using new[], and you could provide a MyDllFreeString function that invokes delete[].

Note that, when you allocate memory for a C-style string, you must consider an additional slot for the string's NUL-terminator (so, you must allocate stringLength + 1 wchar_ts).




回答2:


#ol' ASM hackers always used to start with
#assume nothing ; mql4_string != string

Bingo, the headbang is evident. Receiving side does not assume, since New-MQL4.56789 was introduced, it's representation of a block of bytes as a string, but a struct (!).

(cit.:) Internal representation of the string type is a structure of 12 bytes long:

#pragma pack(push,1) 
struct MqlString 
       { 
                int      size;       // 32-bit integer, contains size of the buffer, allocated for the string. 
                LPWSTR   buffer;     // 32-bit address of the buffer, containing the string. 
                int      reserved;   // 32-bit integer, reserved. 
                }; 
#pragma pack(pop,1)

(cit.:) ( MQL4-side doc: )
String Type


The string type is used for storing text strings. A text string is a sequence of characters in the Unicode format with the final zero at the end of it.




回答3:


Accidentaly, I put my mind to BOOL APIENTRY DllMain. So it solve my problem without creating threads.

vector<wchar_t*> tempObjVector;

BOOL APIENTRY DllMain(HMODULE 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: 
       while (tempObjVector.size() != 0)
       {
           delete[] tempObjVector.back();
           tempObjVector.pop_back();
       }
       break;
   }
   return TRUE;
}

__declspec(dllexport) wchar_t* __stdcall __getJson(wchar_t * listN){
    ....
    ....
    wchar_t* tempObj=new wchar_t[ant.length()+1];
    tempObj[ant.length()] = 0;
    wcscpy(tempObj, constRes);
    tempObjVector.push_back(tempObj);
    return tempObj;
}



回答4:


Another way of doing that (a little bit simpler, but for some cases only):

//C++
extern "C" __declspec(dllimport) const wchar_t *GetMessage();
const wchar_t *GetMessage()
{
    static std::wstring last_message;
    last_message = GetSomeMessage();
    return last_message.c_str();
}

//MQL
#import "MyDll.dll"
string GetMessage();
#import
string message = GetMessage();


来源:https://stackoverflow.com/questions/43320799/how-to-return-a-string-from-a-c-dll-into-a-metatrader-4-code-execution-ecosyst

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!