diff --git a/MT5Connector/MT5Connector.cpp b/MT5Connector/MT5Connector.cpp index 89b9b39d..fa11cea0 100755 --- a/MT5Connector/MT5Connector.cpp +++ b/MT5Connector/MT5Connector.cpp @@ -9,12 +9,27 @@ #include "Mt5Handler.h" #include "MtService.h" -static void convertSystemString(wchar_t* dest, const std::string& src) +// Capacities (in wchar_t, including the null terminator) of the caller-allocated +// MQL string buffers. They must match the StringInit calls in the expert advisor: +// StringInit(_error, 1000, 0) and StringInit(payload, 5000, 0). +static const size_t ERROR_BUFFER_CAPACITY = 1000; +static const size_t PAYLOAD_BUFFER_CAPACITY = 5000; + +static std::wstring convertToWString(const std::string& src) { using convert_typeX = std::codecvt_utf8; std::wstring_convert converterX; - auto wstr = converterX.from_bytes(src); - memcpy(dest, wstr.c_str(), wcsnlen(wstr.c_str(), 1000) * sizeof(wchar_t)); + return converterX.from_bytes(src); +} + +static void convertSystemString(wchar_t* dest, const std::string& src, size_t capacity) +{ + auto wstr = convertToWString(src); + size_t len = wstr.length(); + if (len >= capacity) + len = capacity - 1; + memcpy(dest, wstr.c_str(), len * sizeof(wchar_t)); + dest[len] = L'\0'; } static std::string convertWString(const wchar_t* src) @@ -34,7 +49,7 @@ template T Execute(std::function func, wchar_t* err, T default } catch (std::exception& e) { - convertSystemString(err, e.what()); + convertSystemString(err, e.what(), ERROR_BUFFER_CAPACITY); MtService::GetInstance().LogError(e.what()); } return result; @@ -84,7 +99,26 @@ _DLLAPI int _stdcall getCommandType(int expertHandle, int& res, wchar_t* err) _DLLAPI int _stdcall getPayload(int expertHandle, wchar_t* res, wchar_t* err) { return Execute([&expertHandle, res]() { - convertSystemString(res, MtService::GetInstance().GetCommandPayload(expertHandle)); + convertSystemString(res, MtService::GetInstance().GetCommandPayload(expertHandle), PAYLOAD_BUFFER_CAPACITY); return 1; }, err, 0); +} + +// Size-aware replacement for getPayload: copies at most (capacity - 1) characters +// into res (always null-terminated) and returns the full payload length in wchar_t +// (excluding the null terminator), or -1 on error. If the returned length is +// >= capacity, the caller should re-allocate its buffer and call again. +_DLLAPI int _stdcall getPayload2(int expertHandle, wchar_t* res, int capacity, wchar_t* err) +{ + return Execute([&expertHandle, res, &capacity]() { + auto wstr = convertToWString(MtService::GetInstance().GetCommandPayload(expertHandle)); + int required = static_cast(wstr.length()); + if (capacity > 0) + { + int len = required < capacity ? required : capacity - 1; + memcpy(res, wstr.c_str(), static_cast(len) * sizeof(wchar_t)); + res[len] = L'\0'; + } + return required; + }, err, -1); } \ No newline at end of file diff --git a/MTConnector/MTConnector.cpp b/MTConnector/MTConnector.cpp index 0bf77e33..518803e2 100755 --- a/MTConnector/MTConnector.cpp +++ b/MTConnector/MTConnector.cpp @@ -9,12 +9,27 @@ #include #include -static void convertSystemString(wchar_t* dest, const std::string& src) +// Capacities (in wchar_t, including the null terminator) of the caller-allocated +// MQL string buffers. They must match the StringInit calls in the expert advisor: +// StringInit(_error, 1000, 0) and StringInit(payload, 5000, 0). +static const size_t ERROR_BUFFER_CAPACITY = 1000; +static const size_t PAYLOAD_BUFFER_CAPACITY = 5000; + +static std::wstring convertToWString(const std::string& src) { using convert_typeX = std::codecvt_utf8; std::wstring_convert converterX; - auto wstr = converterX.from_bytes(src); - memcpy(dest, wstr.c_str(), wcsnlen(wstr.c_str(), 1000) * sizeof(wchar_t)); + return converterX.from_bytes(src); +} + +static void convertSystemString(wchar_t* dest, const std::string& src, size_t capacity) +{ + auto wstr = convertToWString(src); + size_t len = wstr.length(); + if (len >= capacity) + len = capacity - 1; + memcpy(dest, wstr.c_str(), len * sizeof(wchar_t)); + dest[len] = L'\0'; } static std::string convertWString(const wchar_t* src) @@ -34,7 +49,7 @@ template T Execute(std::function func, wchar_t* err, T default } catch (std::exception& e) { - convertSystemString(err, e.what()); + convertSystemString(err, e.what(), ERROR_BUFFER_CAPACITY); MtService::GetInstance().LogError(e.what()); } return result; @@ -84,7 +99,26 @@ _DLLAPI int _stdcall getCommandType(int expertHandle, int& res, wchar_t* err) _DLLAPI int _stdcall getPayload(int expertHandle, wchar_t* res, wchar_t* err) { return Execute([&expertHandle, res]() { - convertSystemString(res, MtService::GetInstance().GetCommandPayload(expertHandle)); + convertSystemString(res, MtService::GetInstance().GetCommandPayload(expertHandle), PAYLOAD_BUFFER_CAPACITY); return 1; }, err, 0); +} + +// Size-aware replacement for getPayload: copies at most (capacity - 1) characters +// into res (always null-terminated) and returns the full payload length in wchar_t +// (excluding the null terminator), or -1 on error. If the returned length is +// >= capacity, the caller should re-allocate its buffer and call again. +_DLLAPI int _stdcall getPayload2(int expertHandle, wchar_t* res, int capacity, wchar_t* err) +{ + return Execute([&expertHandle, res, &capacity]() { + auto wstr = convertToWString(MtService::GetInstance().GetCommandPayload(expertHandle)); + int required = static_cast(wstr.length()); + if (capacity > 0) + { + int len = required < capacity ? required : capacity - 1; + memcpy(res, wstr.c_str(), static_cast(len) * sizeof(wchar_t)); + res[len] = L'\0'; + } + return required; + }, err, -1); } \ No newline at end of file diff --git a/mq4/MtApi.ex4 b/mq4/MtApi.ex4 index 1c266664..94a66265 100755 Binary files a/mq4/MtApi.ex4 and b/mq4/MtApi.ex4 differ diff --git a/mq4/MtApi.mq4 b/mq4/MtApi.mq4 index e721df62..6c576a18 100755 --- a/mq4/MtApi.mq4 +++ b/mq4/MtApi.mq4 @@ -17,6 +17,7 @@ bool getCommandType(int expertHandle, int& res, string& err); bool getPayload(int expertHandle, string& res, string& err); + int getPayload2(int expertHandle, string& res, int capacity, string& err); #import //#define __DEBUG_LOG__ @@ -533,13 +534,26 @@ JSONObject* GetJsonPayload() { string payload; StringInit(payload, 5000, 0); - - if (!getPayload(ExpertHandle, payload, _error)) + + int required = getPayload2(ExpertHandle, payload, 5000, _error); + if (required < 0) { PrintFormat("%s [ERROR]: %s", __FUNCTION__, _error); return NULL; } + if (required >= 5000) + { + //--- payload larger than the default buffer: re-allocate and fetch again + StringInit(payload, required + 1, 0); + required = getPayload2(ExpertHandle, payload, required + 1, _error); + if (required < 0) + { + PrintFormat("%s [ERROR]: %s", __FUNCTION__, _error); + return NULL; + } + } + JSONParser payload_parser; JSONValue *payload_json = payload_parser.parse(payload); diff --git a/mq5/MtApi5.ex5 b/mq5/MtApi5.ex5 index 95e17467..96a0ca0a 100755 Binary files a/mq5/MtApi5.ex5 and b/mq5/MtApi5.ex5 differ diff --git a/mq5/MtApi5.mq5 b/mq5/MtApi5.mq5 index 18c0b55e..76673cbd 100644 --- a/mq5/MtApi5.mq5 +++ b/mq5/MtApi5.mq5 @@ -18,6 +18,7 @@ bool getCommandType(int expertHandle, int& res, string& err); bool getPayload(int expertHandle, string& res, string& err); + int getPayload2(int expertHandle, string& res, int capacity, string& err); #import ///-------------------------------------------------------------------------------------- @@ -566,13 +567,26 @@ JSONObject* GetJsonPayload() { string payload; StringInit(payload, 5000, 0); - - if (!getPayload(ExpertHandle, payload, _error)) + + int required = getPayload2(ExpertHandle, payload, 5000, _error); + if (required < 0) { PrintFormat("%s [ERROR]: %s", __FUNCTION__, _error); return NULL; } + if (required >= 5000) + { + //--- payload larger than the default buffer: re-allocate and fetch again + StringInit(payload, required + 1, 0); + required = getPayload2(ExpertHandle, payload, required + 1, _error); + if (required < 0) + { + PrintFormat("%s [ERROR]: %s", __FUNCTION__, _error); + return NULL; + } + } + JSONParser payload_parser; JSONValue *payload_json = payload_parser.parse(payload);