Передача параметра по ссылке

 

Здравствуйте,

Имеется dll, написанная на Delphi. В ней функция типа:

function get_data(var p_text: PChar): boolean; stdcall;
begin
  p_text := 'test';
end;

 Есть скрипт, в котором эта функция определена вот так:

bool get_data(string &p_fin_list);

 Вызываю эту функцию в скрипте вот так:

string lv_text;
get_data(lv_text);

 Однако в переменной lv_text в результате абракадабра.

Далее переделал функцию в Delphi вот так:

function get_data: PChar; stdcall;
begin
  result := 'test';
end;

 

Соответственно исправил описание в скрипте и все заработало как надо.

Почему когда я передаю строку как параметр и возвращаю ее, то результатом является абракадабра, а когда в качестве результата функции, то все в порядке? 

 
В этой статье https://www.mql5.com/ru/articles/96, есть ответ на ваш вопрос. 
Руководство по написанию DLL для MQL5 на Delphi
Руководство по написанию DLL для MQL5 на Delphi
  • 2010.05.26
  • Andrey Voytenko
  • www.mql5.com
Статья рассматривает механизм написания модудя DLL на популярном языке программирования ObjectPascal в среде разработки Delphi. Изложенный в статье материал ориентирован в первую очередь на начинающих программистов, решающих задачи, выходящие за рамки встроенного языка программирования MQL5, путем подключения внешних DLL модулей.
 
avoitenko:
В этой статье https://www.mql5.com/ru/articles/96, есть ответ на ваш вопрос. 

Да, я понял, сделал выделение StringInit в MQL, а в Delphi написал StrCat + убрал var. Спасибо.

Может быть не совсем уместный вопрос, но как в таком случае можно осуществлять вызов этой же функции из программы на C++, если выходной параметр в C++ объявлен как wchar_t*.

То есть:

// Объявление
typedef bool (__stdcall *t_get_data) (wchar_t* &p_text);

// Вызов
wchar_t *lv_fin_list;
// Здесь нужно инициализировать lv_fin_list, но как?
m_get_data(lv_fin_list);

Точнее интересует как сделать что-то подобное StringInit(lv_text, 100, 0) в C++? 

Заранее благодарен.

 
Здесь нужно инициализировать lv_fin_list, но как?
wchar_t *lv_fin_list = new wchar_t[255];

 
avoitenko:

Попробовал. После вызова dll-функции в отладчике строка = <Bad ptr>.

Может быть что-то еще нужно выполнить? 

 

Если в DLL передается юникод строка, то тип данных должен быть PWideChar.

function m_get_data(const p_text: PWideChar): boolean; stdcall; 
Документация по MQL5: Основы языка / Типы данных
Документация по MQL5: Основы языка / Типы данных
  • www.mql5.com
Основы языка / Типы данных - Документация по MQL5
 
avoitenko:

Если в DLL передается юникод строка, то тип данных должен быть PWideChar.

У меня Delphi XE2, там PChar = PWideChar, но я все-таки попробовал то, что вы посоветовали, результат такой же :(

Что-то еще можно сделать? 

 

Delphi DLL

library Project2;

uses Windows;

function m_get_data(p_text: PWideChar): boolean; stdcall;
var AnsiStr: AnsiString;
begin
AnsiStr:= 'Transmitted wide string';//наша строка
MultiByteToWideChar(CP_ACP, 0, @AnsiStr[1], Length(AnsiStr), p_text, Length(AnsiStr)*2);
end;

exports m_get_data;

begin
end.

 Visual Studio Console application

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

// тип указателя на функцию 
typedef bool (__stdcall *m_get_data) (wchar_t* p_text);

int _tmain(int argc, _TCHAR* argv[])
{
        HMODULE hDll = LoadLibraryA("Project2.dll");
        //указатель на функцию m_get_data
        m_get_data ProcAddr = NULL;
        
        if( hDll != NULL )
        {
                // получение адреса функции
                ProcAddr = (m_get_data) GetProcAddress(hDll, "m_get_data");
                if(ProcAddr != NULL )
                {        
                        // инициализация буфера
                        wchar_t *lv_fin_list = new wchar_t[255];
                        // вычищаем мусор
                        ZeroMemory(lv_fin_list,255*sizeof(wchar_t));
                        // вызов функции
                        (ProcAddr)(lv_fin_list);
                        // вывод результата
                        wprintf(lv_fin_list);
                        // удаление буфера
                        delete [] lv_fin_list;
                }
                
                FreeLibrary(hDll); 
        }    
        getchar();      
        return 0;
}
Result

 

MQL5 Script

#import "Project2.dll"
   bool m_get_data(string &data);
#import

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   string data;
   StringInit(data,255);
   m_get_data(data);
   Print(data);
  }
//+------------------------------------------------------------------+

Result

2012.04.19 18:45:42 StringDLL (EURUSD,H1) Transmitted wide string

 
avoitenko:

Delphi DLL

 Visual Studio Console application

Result

 

 

 

 

 

Спасибо огромное, добавил ZeroMemory и все заработало. Огромное спасибо еще раз!
 
papaklass:
 Спасибо Андрей, за такие ответы. Вы редкое исключение из числа профи. Была бы кнопочка, повышающая Ваш рейтинг, я бы нажал ее даже, если бы с моего рейтинга улетучилась эквивалентная сумма. Такие ответы достойны этого

Вот и сделайте предложение MQ по развитию сообщества.

Типа прикрутить возможность отдавать свой рейтинг за толковые ответы.

 
papaklass:
  Спасибо Андрей, за такие ответы.
Вам спасибо, Александр, за похвалу. Однако, платить рейтингом за правильные ответы - это уже лишнее. Достаточно слов благодарности от того, кому помог.
Причина обращения: