MT5 build 1035 (x64) Вызов функции из DLL, возвращающей строку wchar_t*

 

Столкнулся вот с такой проблемой. 

При вызове тривиальной функции из DLL, которая возвращает строку, MT5 валит ошибку "Access violation"

Причем если скрипт был скомпилирован в одном из предыдущих билдов, то он работает нормально. Если же перекомпилировать в 1035, то получается вот такая беда.

Такой ощущение что x64 не UTF-16 использует уже а что-то другое, хотя тот же билд 1035 x86, работает вроде как нормально.

 

Кто-то сталкивался еще с подобным ? 

Открыл кейс в сервис деск по этому поводу.

 
Приведите пример для воспроизведения, пожалуйста
 

Пример.

Скрипт для теста

#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"


#import "test.dll"
string  TestTheString();
#import

void OnStart()
{
 Print ("Testing the string, returned by DLL!");
 string result;
 
 result = TestTheString();
 Print(result);
 
 Print ("Done!");
   
}

 

Исходник DLL

#define WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers
#define MT4_EXPFUNC __declspec(dllexport)
#define _USE_INLINING
#define TRACE

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

// just for compatibility
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
        switch(ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH: break;
        case DLL_THREAD_ATTACH: break;
        case DLL_THREAD_DETACH: break;
        case DLL_PROCESS_DETACH:  break;
   }
   return(TRUE);
}

// return UTF-16 string
MT4_EXPFUNC wchar_t* __stdcall TestTheString()
{
 return (L"Wide char string was returned successful. Test Passed\x00");
}

 

Скриншот ошибки

Ошибка 

Прикреплен архив со скриптом и DLL.

Файлы:
 

А что так можно? По-моему такой код в принципе некорректен. 

 
TheXpert:

А что так можно? По-моему такой код в принципе некорректен. 

В чем некорректность? 

В MT4 начиная с 600 билда по сей день выполняется корректно. В MT5 тоже, до билда 1035.

Пробовал обернуть в структуру MqlStr c длиной строки и самой строкой - реакция та же. 

Определял глобальную строковую константу - результат тот же.

Выставил самый простой вариант, который и использовался ранее всегда и работал прекрасно.

Под x64 проект DLL компилировал в режимах MULTI BYTE и UNICODE, результат одинаков.

Я вообще всегда тщательно подхожу к отладке и проверке; и прежде чем в сервисдеск обращаться стараюсь как можно больше тестов провести самостоятельно. 

 
elugovoy:

В чем некорректность? 

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

Могу ошибаться конечно, поэтому хочется услышать комментарий разработчиков. 

 
TheXpert:

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

Могу ошибаться конечно, поэтому хочется услышать комментарий разработчиков. 

Терминал не должен заботиться о распределении памяти во внешних ресурсах. Другое дело, когда в DLL определяется локальная переменная, указатель на которую возвращается в MQL, а затем (при выходе из функции) происходит высвобождение памяти, выделенной под эту переменную.

Тогда MQL получит ссылку на часть памяти, как говорится "бывшей в употреблении". Ссылка на константу же будет ликвидной даже при выходе из функции (при загрузке DLL будет выделен участок памяти для константы и функция вернет адрес начала строки, во всяком случае в ассемблере именно так обстоят дела).

 
От сервис деска ни ответа ни привета. Уснули что ль...
 
TheXpert:

А что так можно? По-моему такой код в принципе некорректен. 

Всегда считал, что так нельзя. В справке указано, что управлением распределения памяти под строку должен заниматься сам терминал. То есть, если нужно получить/изменить строку, то сначала производится инициализация этой строки, затем передача указателя на нее в DLL. Возвращать строковый параметр из DLL, вроде как, некорректно.
 

Впервые слышу чтобы было некорректным возвращать указатель на строку из DLL.

Для того чтобы не углублялись в дебри "можно/нельзя" стандартный пример от MQ (входящий в поставку терминала 4):

MT4_EXPFUNC wchar_t* __stdcall GetStringValue(wchar_t *spar)
  {
   wprintf(L"Wide char string was received: \"%s\"\n",spar);
   return(spar);
  }

Точно так же валит ошибку. 

 
elugovoy:

В чем некорректность? 

В MT4 начиная с 600 билда по сей день выполняется корректно. В MT5 тоже, до билда 1035.

Пробовал обернуть в структуру MqlStr c длиной строки и самой строкой - реакция та же. 

Определял глобальную строковую константу - результат тот же.

Выставил самый простой вариант, который и использовался ранее всегда и работал прекрасно.

Под x64 проект DLL компилировал в режимах MULTI BYTE и UNICODE, результат одинаков.

Я вообще всегда тщательно подхожу к отладке и проверке; и прежде чем в сервисдеск обращаться стараюсь как можно больше тестов провести самостоятельно. 

Вам просто везло.

Некорректность заключается в попытке вернуть автоматически распределённую строку.

В отличие от MQL4/5, где строки являются базовым типом, в C/C++ строки не являются самостоятельным типом, а являются zero-terminated массивом символов.

Вы возвращаете указатель на массив, который после вызова функции автоматически уничтожается. Это - ошибка всех новичков (я тоже так ошибался)

Мы в свою очередь посмотрим, что мы такого поменяли, что перестал работать возврат строк...

Причина обращения: