Кириллица из dll - страница 2

 
Ihor Herasko:

Здесь юникодная строка text приводится к многобайтной кодировке с потерей всей информации для нелатинских символов, потом добавляется текст уже в многобайтной кодировке и отправляется в МТ, который воспринимает все это как юникод.

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

Намного проще вот так (не проверял, но смысл должен быть понятен):

Только теперь обязательно нужно передать размер строки chtxt в символах (второй аргумент функции).

Хоть и можно разместить строку требуемой длины вызовом StringSetLength, но мне кажется, даже так лучше не делать - мы не знаем, как работает выделение памяти в мтшной string. Можно возвращать из длл адрес массива, который заведомо не разрушится до выгрузки длл, и конвертировать его в строку вызовом ShortArrayToString.
 
SeriousRacoon:
Хоть и можно разместить строку требуемой длины вызовом StringSetLength, но мне кажется, даже так лучше не делать - мы не знаем, как работает выделение памяти в мтшной string. Можно возвращать из длл адрес массива, который заведомо не разрушится до выгрузки длл, и конвертировать его в строку вызовом ShortArrayToString.
А как тогда будет правильно вызов в mql4?
 
Murat Ishakov:
А как тогда будет правильно вызов в mql4?

Как-то так получается. Тоже не проверял ))

///////////////
// вижак
_DLLAPI void __stdcall getText(wchar_t *pOutTextArray, const int nOutTextArraySize, DWORD *pdwOutLength, const wchar_t *text)
{
        wstring wst(text);
        wst += _T(" второй текст");
        wmemcpy_s(pOutTextArray, nOutTextArraySize, wst.c_str(), wst.length());
        if (pdwOutLength)
                *pdwOutLength = wst.length();
}


///////////////
// мкл
string sResult;
ushort usTextBuffer[];
uint uOutLength = 0; // uint мкл имеет размер DWORD винапи
ArrayResize(usTextBuffer, 256);
getText(usTextBuffer, 256, uOutLength, "My Text");

sResult = ShortArrayToString(usTextBuffer, 0, uOutLength);
немного поправил
*pdwOutLength = min(nOutTextArraySize, wst.length());
 
SeriousRacoon:
Хоть и можно разместить строку требуемой длины вызовом StringSetLength, но мне кажется, даже так лучше не делать - мы не знаем, как работает выделение памяти в мтшной string. Можно возвращать из длл адрес массива, который заведомо не разрушится до выгрузки длл, и конвертировать его в строку вызовом ShortArrayToString.

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

 
Murat Ishakov:
А вызов из mql4 как должен выглядеть? Там же uchar убирается? Что будет вместо wchar_t *chtxt? Тоже string?

Можно string (только перед вызовом забить в строку достаточное количество символов), а лучше - массив ushort, который потом преобразовать в string.

 
Ihor Herasko:

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

О, я этого не видел. Спасибо.

 
SeriousRacoon:

О, я этого не видел. Спасибо.

инициализируйте строку с помощью StringInit() 

так делаю давно, работает без проблем при обмене с dll, очень удобно, что могу задать конкретный размер буфера

я в два вызова получаю данные из dll, на первом вызове обрабатываю запрос и сохраняю данные в локальной статической переменной в dll и возвращаю размер требуемого буфера , на втором вызове передаю в MQL это значение

и чтобы в основном коде было удобно это использовать, делаю такую обертку:

#import "tablemt4.dll"
int  getrowszbuff(int, int, string);
void getstrbuffer(string &);
#import

//+------------------------------------------------------------------+
void OnStart()
{
   string t_row1 = TBL_getRow(t_handle, 1, ";");
}


//+------------------------------------------------------------------+
string TBL_getRow(int handle, int row, string separator)
{
   return(tblgetbuff(getrowszbuff(handle, row, separator)));
}
//+------------------------------------------------------------------+
string tblgetbuff(int sz)
{
   string result = "";
   if(sz <= 0) return(result);
   StringInit(result, sz);
   getstrbuffer(result);
   return(result);
}
//+------------------------------------------------------------------+
 
Igor Makanu:

инициализируйте строку с помощью StringInit() 

так делаю давно, работает без проблем при обмене с dll, очень удобно, что могу задать конкретный размер буфера

я в два вызова получаю данные из dll, на первом вызове обрабатываю запрос и сохраняю данные в локальной статической переменной в dll и возвращаю размер требуемого буфера , на втором вызове передаю в MQL это значение

и чтобы в основном коде было удобно это использовать, делаю такую обертку:

Да, в 2 вызова как раз весь винапи работает - передаешь 0 как адрес буфера, получаешь длину и вызываешь второй раз. По-другому тут никак.
 
Всем огромное спасибо. Получилось!
Причина обращения: