Использование инициализированных переменных типа string в DLL: как?

 

Добрый день!

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

static string params[3] = {
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
"22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"
};

Во внешней библиотеке принимаю указатель на MqlStr, заполняю массив

MqlStr* paramsArray

strcpy( paramsArray[i].string, pMyParamsStr->c_str() );

При первом вызове внешней функции в эксперте успешно получаю данные через этот массив, строки имеют необходимую длину, они корретно преобразуются в нужный тип:

int cmd = StrToInteger(params[0]);
double volume = StrToDouble(params[1]);
double price = StrToDouble(params[2]);

После этого повторно использую массив params[3] при вызове все той же функцуии в DLL.

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

paramsArray [i]. len == 0,

также

strlen(paramsArray[c].string) == 0

При этом указатель на буфер не обнулен

paramsArray[i].string != NULL

Пробовал играться модификатором static - ничего не меняется, буфер все равно обнуляется.

Из этого я сделал вывод, что после выполнения функции преобразования строковых данных (использования переменной?) используемый буфер обнуляется. После выполнения функции

int cmd = StrToInteger(params[0])

устанавливается

params[0].len == 0 и

params[0].string == 0

Подскажите, пожалуйста, каким образом можно восстанавливать буфер для string? Или может быть есть другой безопасный способ повторного использования строковых переменных для получения данных их внешних библиотек?

ЗЫ. Использую MetaTrader 4.0 Build 216.

 
Ostap:

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

Похоже услышать ответ на свой вопрос мне не доведется. :(
 
Ostap:
Ostap:

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

Похоже услышать ответ на свой вопрос мне не доведется. :(

Поиск рулит


вот пример похожей проблемы

https://forum.mql4.com/ru/12812

 
YuraZ:

вот пример похожей проблемы

https://forum.mql4.com/ru/12812

Спасибо, прочитал. У меня вроде бы так и сделано, как рекомендовано.

Проблемы с возвратом строковых параметров у меня вроде бы нет - приложение не валится, параметры передаются.

Есть проблема с повторной инициализацией (присваиванием) строки в MQL. Я объявляю массив строк в глобальном пространстве имен (MQL).

//static string params[3] = {
string params[3] = {
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
"22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"
};

После этого передаю этот массив в DLL и получаю значения.

if ( true == GetParams( params, ArraySize(params) ) )
{

...

}

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

// reinit array
params[0] = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

params[1] = "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";

params[2] = "22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222";

Является ли допустимым такое присваивание значения инициализированной MQL строке? Или так делать нельзя и нужно использовать оператор + (функцию StringConcatenate()), переписывая буфер начиная с первого символа? Не произойдет ли при этом сброс ранее выделенного буфера? Можно ли будет при этом увеличить размер буфера (не будет ли переполнения)?

 

Я написал простой проверочный скрипт, и он показал, что MQL4-функции конвертации строковых значений не меняют содержимое.

//+------------------------------------------------------------------+
//|                                             CheckStringArray.mq4 |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net"
 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void testFunction(bool show)
   {
//----
   static string params[3] = {
   "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
   "22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"
   };
   
   int cmd = StrToInteger(params[0]);
   double volume = StrToDouble(params[1]);
   double price = StrToDouble(params[2]);
   
   if (show)
      {
      Print("1 StringLen()=",StringLen(params[0]),"  string:",params[0]);
      Print("2 StringLen()=",StringLen(params[1]),"  string:",params[1]);
      Print("3 StringLen()=",StringLen(params[2]),"  string:",params[2]);
      }
   else
      {
      int f = StringLen(params[0]);
      int s = StringLen(params[1]);
      int t = StringLen(params[2]);
      if (f!=s || s!=t || f==0) Print(params[0],"|",params[1],"|",params[2]);
      }      
//----
   return;   
   }
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   Print("Первый");
   testFunction(true);
   
   Print("Второй");
   testFunction(true);
      
   for (int i=0; i<1000000;i++)
      {
      testFunction(false);
      Comment(i);
      Sleep(50);
      }
//----
   return(0);
  }
//+------------------------------------------------------------------+

Вы можете предоставить свой код? Это ускорило бы нахождение истины.

 
Ostap:


ваша проблема, скорее всего в некорректной DLL

но возможно и в некорректном коде MQL4

без кода понять будет сложно!

---

если DLL на паскале - делфи, не скажу ничего...

если на Си то вероятно подскажу

пишу в Си

 
Rosh:

Я написал простой проверочный скрипт, и он показал, что MQL4-функции конвертации строковых значений не меняют содержимое.

   for (int i=0; i<1000000;i++)
      {
      testFunction(false);
      Comment(i);
      Sleep(50);
      }

В своем коде Вы не используете повторную инициализацию (присвоение значений) для string params[3].

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

Поскольку код моего эксперта не помещается в сообщение форума, я выложил его на сайте http://homeauto.com.ua/Software/MetaBridgeSetup.msi

Куцая инструкция как им пользоваться лежит там же http://homeauto.com.ua/Software/MetaBridge_manual.doc

Код моего эксперта тестирует совместную работу MetaTrader, Excel и eSignal.

Спасибо за помощь!

 

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

static string params[10] = {
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
};
...
BridgeTick( AccountServer(), AccountNumber(), Symbol(), functionId, params, ArraySize(params) ) ;
switch(functionId[0])
{
case MarketInfoId:
{
int type = StrToInteger(params[0]);
break;
}
}
...
Print("reinit array");
Print("Init params[0] = ", params[0]);
params[0] = "x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

2008.06.09 11:27:29 MetaBridge GBPUSD,H4: Init params[0] =
2008.06.09 11:27:29 MetaBridge GBPUSD,H4: reinit array

В строке лога '2008.06.09 11:27:29 MetaBridge GBPUSD,H4: Init params[0] = ' видно что оператор присваивания не инициализирует строку (ее длина становится нулевой, хотя до инициализации она содержала значение).

// reinit array
Print("reinit array");
params[0] = "x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
Print("Init params[0] = ", params[0]);

ЗЫ. Попутно выяснилось, что можно спокойно увеличивать размер строки против инициализированной в массиве - в DLL передается буфер увеличенного размера. Не выяснял, правда, как это работает в реале.

 
Ostap писал (а) >>

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

static string params[10] = {
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
};
...
BridgeTick( AccountServer(), AccountNumber(), Symbol(), functionId, params, ArraySize(params) ) ;
switch(functionId[0])
{
case MarketInfoId:
{
int type = StrToInteger(params[0]);
break;
}
}
...
Print("reinit array");
Print("Init params[0] = ", params[0]);
params[0] = "x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

2008.06.09 11:27:29 MetaBridge GBPUSD,H4: Init params[0] =
2008.06.09 11:27:29 MetaBridge GBPUSD,H4: reinit array

В строке лога '2008.06.09 11:27:29 MetaBridge GBPUSD,H4: Init params[0] = ' видно что оператор присваивания не инициализирует строку (ее длина становится нулевой, хотя до инициализации она содержала значение).

// reinit array
Print("reinit array");
params[0] = "x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
Print("Init params[0] = ", params[0]);

ЗЫ. Попутно выяснилось, что можно спокойно увеличивать размер строки против инициализированной в массиве - в DLL передается буфер увеличенного размера. Не выяснял, правда, как это работает в реале.

Ostap, как с вами связаться ? Есть некая мысля по поводу MetaBridge.

 

> Ostap, как с вами связаться ? Есть некая мысля по поводу MetaBridge.

Пишите на vroma at users.sourceforge.net - мне перешлют (не хочу светить свое мыло спамерам).

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