Как вернуть строку из C ++ DLL в экосистему выполнения кода MetaTrader 4?

У меня есть следующая функция

__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;
}

Эта DLL возвращается wchar_t* в MetaTrader4.

Я пробовал много способов вернуть правильное значение и избежать утечек памяти, таких как заданный тип возврата const wchar_t*, создавая свой собственный класс с деструктором с delete[] в. Но все эти попытки оказались безуспешными: я получил '??ello' вместо 'hello', Просто первые один или два символа были неверны. С созданием thread это работает правильно. Но я хочу знать, может ли быть лучшее решение?

3

Решение

Чтобы создать строку в вашей DLL и передать ее вызывающей стороне, вы должны динамически выделить часть памяти в DLL для хранения символов строки и передать указатель на эту память вызывающей стороне.

Более того, вызывающая сторона должна иметь возможность освободить эту память, когда строка больше не нужна.

Для правильной работы необходимо использовать так же диспетчер памяти / распределитель для выделения и освобождения памяти строки.

Одним из вариантов будет использование общего общесистемного распределителя, такого как COM-распределитель. Таким образом, вы можете выделить память в DLL с помощью CoTaskMemAllocи вызывающий абонент может освободить его, используя соответствующий CoTaskMemFree,

Другим вариантом будет вернуть BSTR строка, выделенная SysAllocString в DLL. И вызывающая сторона выпустит эту строку, вызывая SysFreeString,

Или вы можете предоставить пользовательскую функцию для освобождения памяти строки в вашей DLL. Например, вы можете выделить память строки в вашей DLL, используя new[]и вы могли бы предоставить MyDllFreeString функция, которая вызывает delete[],

Обратите внимание, что когда вы выделяете память для строки в стиле C, вы должны рассмотреть дополнительный слот для строки NUL-терминатор (Итак, вы должны выделить stringLength + 1 wchar_tс).

1

Другие решения

#Старые ASM хакеры всегда начинали с
#assume nothing ; mql4_string != string

Бинго, сильный удар очевиден. Принимающая сторона не предполагает, так как новыйMQL4.56789 было представлено, это представление блока байтов в виде string, но struct (!).

(Соч. 🙂 Внутреннее представление строкового типа представляет собой структуру длиной 12 байтов:

#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)

(Соч. 🙂 (Документация на стороне MQL4:)
String Type

string Тип используется для хранения текстовых строк. Текстовая строка — это последовательность символов в формате Unicode с последним нулем в конце.

1

Случайно, я сосредоточился на BOOL APIENTRY DllMain, Так что это решит мою проблему без создания темы.

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;
}
0

Другой способ сделать это (немного проще, но только для некоторых случаев):

//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();
0
По вопросам рекламы [email protected]