Возврат строки из DLL

 

Добрый вечер.

Возникла проблема при возврате строки символов из DLL написанной на Delphi 7

В DLL имеем функцию:

function SaveRateM1(Rate: PChar): PChar;
var Srs   : ShortString;
    SrDb  : TMySql;
    SrR   : TRate;
    SrSql : string;
    SrRes : ShortString;
    SrH   : HWND;
    SrCDS : COPYDATASTRUCT;
    SrQ   : IMySQLQuery;
    Srhs  : ShortString;
begin
  try
    SrDb := TMySql.Create;
    SrRes := 'OK' + #0;
    try
      if (not ConnectToMySql(SrDb)) then RaiseMySqlError('',SrDb);
      Srs := ShortString(Rate);
      SrR :=  DecodeRate(Rate);
      if (SrR.Rtype in ['M','М','H','Н']) then // Сохраняем в базу
      begin
        SrSql := Format('Call sp_NewM1 (''%s'',''%s'',''%s'',%s,%s,%s,%s,%s)',
                      [SrR.Market,                   // Дилер
                       EncodeMySqlDatetime(SrR.Dt),  // Дата время
                       SrR.Symb,                     // Символ
                       FloatToStr(SrR.O),            // Open
                       FloatToStr(SrR.H),            // High
                       FloatToStr(SrR.L),            // Low
                       FloatToStr(SrR.C),            // Close
                       IntToStr(SrR.V)               // Vol
                      ]);
        if not SrDb.ExecSQL(SrSql) then RaiseMySqlError('',SrDb);

      Srs := Srs + #0;
      SrCDS.dwData:=1;
      SrCDS.lpData:=@Srs[1];
      SrCDS.cbData:=Length(Srs)+1;

      SrSql := 'SELECT HWND, AppName FROM Applications';
      SrQ := SrDb.Query(SrSql);
      if SrQ = nil then  RaiseMySqlError('',SrDb);
      while SrQ.FetchRow = true do
      begin
        Srhs := SrQ.ValueByName['HWND'];
        if Srhs = '' then SrH := 0
        else SrH  := StrToInt(Srhs);
        if SrH <> 0 then SendMessage(SrH, wm_CopyData, 0, DWORD(@SrCDS));
      end;

    finally
      Result := PChar(SrRes + '   ');
      SrDb.Disconnect;
    end;
  except
    on e: exception do
    begin
      SrRes := 'SaveRateM1: ' + e.Message + '> '+ #0;
      Result := PChar(SrRes + '   ');
    end;
  end;
end;

в эксперте она вызывается так

#import "TestDll.dll" 
  string SaveRateM1(string Rate);
int start() {
  for (int i = 1; i < 31; i++) {
    datetime Tm = iTime(Symbol(),PERIOD_M1,1);
    string    Rt  = StringConcatenate("M",";",
                               AccountCompany(),";",
                               Symbol(),";",
                               TimeToStr(Tm,TIME_DATE)," ",TimeToStr(Tm,TIME_MINUTES),";",
                               DoubleToStr(iOpen  (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iHigh  (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iLow   (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iClose (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iVolume(Symbol(),PERIOD_M1,1),0)
                               );

    if (!(IsOptimization() || IsTesting())) {
       string res = "";
       res = SaveRateM1(Rt);
       if (res != "OK")  Print("<",res,">");
       Sleep(100);
    }   
  }  
  return(0);
}


Проблема в том что эта функция ИНОГДА ОЧЕНЬ РЕДКО возвращает мусор. Вот кусочек журнала

18:13:56 DllTest GBPJPY,M1: <d.;EURCHF;2008.05.22 15:14;1.6230;1.6232;1.6230;1.6232;16>
18:14:07 DllTest EURJPY,H1: < 15:14;1.6230;1.6232;1.6230;1.6232;16>
18:14:07 DllTest EURCHF,H1: < 15:14;1.9811;1.9811;1.9805;1.9805;16>
18:14:09 DllTest EURJPY,H1: <j>
18:14:11 DllTest GBPJPY,M1: <>
18:14:16 DllTest GBPUSD,H1: < 15:14;1.6230;1.6232;1.6230;1.6232;16>
18:14:16 DllTest GBPUSD,H1: < 15:14;1.6230;1.6232;1.6230;1.6232;16>
18:14:46 DllTest EURCHF,H1: < 15:14;1.9811;1.9811;1.9805;1.9805;16>
18:15:09 DllTest GBPUSD,H1: < 15:15;163.44;163.45;163.43;163.45;15>
18:15:09 DllTest GBPUSD,H1: < 15:15;205.85;205.91;205.84;205.91;33>
18:15:23 DllTest EURCHF,H1: < 15:15;1.5722;1.5722;1.5716;1.5717;18>
18:15:28 DllTest GBPCHF,M5: < 15:15;1.9804;1.9805;1.9802;1.9802;8>
18:15:44 DllTest EURUSD,H1: <j>
18:15:45 DllTest EURCHF,H1: < 15:15;163.44;163.45;163.43;163.45;15>
18:15:48 DllTest EURUSD,H1: < 15:15;163.44;163.45;163.43;163.45;15>
18:15:49 DllTest GBPUSD,H1: < 15:16;1.6238;1.6241;1.6237;1.6237;29>

Тестовый эксперт запущен на нескольких (8) инструментах. Может кто нибудь сказать из-за чего это происходит?

 
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

 
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

важно помнить что размер строки не должен быть превышен

т е в MQL4 задается размер

#import "TESTDLL.DLL"

string MY_STR_FROM_DLL ( string );

string mmm = "ляля ля ля ля "; // этот размер в DLL нельзя троггать больше нельзя точно - уменьшить не пробовал но по логике скорее всего сработет

string sss = MY_STR_FROM_DLL( mmm ); // MYDLL

в DLL нельзя его увеличить mmm, иначе трабл

 
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

Все остальное нужно чтобы не падал MT4. Это достигалость потом и немалым.

 
YuraZ:
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

важно помнить что размер строки не должен быть превышен

т е в MQL4 задается размер

#import "TESTDLL.DLL"

string MY_STR_FROM_DLL ( string );

string mmm = "ляля ля ля ля "; // этот размер в DLL нельзя троггать больше нельзя точно - уменьшить не пробовал но по логике скорее всего сработет

string sss = MY_STR_FROM_DLL( mmm ); // MYDLL

в DLL нельзя его увеличить mmm, иначе трабл

PChar определяет максимальный размер строки в 255 символов. При этом в DLL использую короткие строки ShortString, размер которых тоже не превышает 255 символов. при таких условиях траблы MT4 не наблюдаются даже при отсутствии в советнике явного задания длины принимающей строки. Если использовать в DLL обычные строки string то траблы иногда были.

Но проблема не в траблах, а в возвращаемом периодически мусоре.

 
lusp:
YuraZ:
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

важно помнить что размер строки не должен быть превышен

т е в MQL4 задается размер

#import "TESTDLL.DLL"

string MY_STR_FROM_DLL ( string );

string mmm = "ляля ля ля ля "; // этот размер в DLL нельзя троггать больше нельзя точно - уменьшить не пробовал но по логике скорее всего сработет

string sss = MY_STR_FROM_DLL( mmm ); // MYDLL

в DLL нельзя его увеличить mmm, иначе трабл

PChar определяет максимальный размер строки в 255 символов. При этом в DLL использую короткие строки ShortString, размер которых тоже не превышает 255 символов. при таких условиях траблы MT4 не наблюдаются даже при отсутствии в советнике явного задания длины принимающей строки. Если использовать в DLL обычные строки string то траблы иногда были.

Но проблема не в траблах, а в возвращаемом периодически мусоре.

кроме того внутри DLL необходимо формировать 0 в конце строки

 
YuraZ:
lusp:
YuraZ:
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

важно помнить что размер строки не должен быть превышен

т е в MQL4 задается размер

#import "TESTDLL.DLL"

string MY_STR_FROM_DLL ( string );

string mmm = "ляля ля ля ля "; // этот размер в DLL нельзя троггать больше нельзя точно - уменьшить не пробовал но по логике скорее всего сработет

string sss = MY_STR_FROM_DLL( mmm ); // MYDLL

в DLL нельзя его увеличить mmm, иначе трабл

PChar определяет максимальный размер строки в 255 символов. При этом в DLL использую короткие строки ShortString, размер которых тоже не превышает 255 символов. при таких условиях траблы MT4 не наблюдаются даже при отсутствии в советнике явного задания длины принимающей строки. Если использовать в DLL обычные строки string то траблы иногда были.

Но проблема не в траблах, а в возвращаемом периодически мусоре.

кроме того внутри DLL необходимо формировать 0 в конце строки

Формируется

SrRes := 'OK' + #0;

Кроме того добавляются 3 пробела. Не знаю зачем. Но когда-то для возврата строки в Exel пришлось изобрести такую конструкцию. Без нее ничего не получалось.

Result := PChar(SrRes + '   ');
 

при вызове и передачи строки в MT



формируйте размер строки в MT4



а именно

ДОПУСТИМ вы хотите получать не менее 100 символов ! поэтому в MT4 в MQL4 формируйте чуть более 100 символов . лучше с запасом


string MMM = "012345... ...100";


ее и передавайде в DLL для возврата в нее же





почитайте это

 
YuraZ:
lusp:
YuraZ:
lusp:
YuraZ:
BabyBear:
Если проблемма в возврате значения - попробуй так
function SaveRateM1(Rate: PChar): PChar;
begin
    Result := 'OK' + #0;
end;

Зачем всё остальное?

важно помнить что размер строки не должен быть превышен

т е в MQL4 задается размер

#import "TESTDLL.DLL"

string MY_STR_FROM_DLL ( string );

string mmm = "ляля ля ля ля "; // этот размер в DLL нельзя троггать больше нельзя точно - уменьшить не пробовал но по логике скорее всего сработет

string sss = MY_STR_FROM_DLL( mmm ); // MYDLL

в DLL нельзя его увеличить mmm, иначе трабл

PChar определяет максимальный размер строки в 255 символов. При этом в DLL использую короткие строки ShortString, размер которых тоже не превышает 255 символов. при таких условиях траблы MT4 не наблюдаются даже при отсутствии в советнике явного задания длины принимающей строки. Если использовать в DLL обычные строки string то траблы иногда были.

Но проблема не в траблах, а в возвращаемом периодически мусоре.

кроме того внутри DLL необходимо формировать 0 в конце строки

Формируется

SrRes := 'OK' + #0;

Кроме того добавляются 3 пробела. Не знаю зачем. Но когда-то для возврата строки в Exel пришлось изобрести такую конструкцию. Без нее ничего не получалось.

Result := PChar(SrRes + '   ');

при вызове и передачи строки в MT


формируйте размер строки в MT4


а именно

ДОПУСТИМ вы хотите получать не менее 100 символов ! поэтому в MT4 в MQL4 формируйте чуть более 100 символов . лучше с запасом

string MMM = "012345... ...100";


ее и передавайде в DLL для возврата в нее же



почитайте это

Не помогает. Попробовал такую конструкцию вызова:

int start() {
  for (int i = 1; i < 31; i++) {
    datetime Tm = iTime(Symbol(),PERIOD_M1,1);
    string    Rt  = StringConcatenate("M",";",
                               AccountCompany(),";",
                               Symbol(),";",
                               TimeToStr(Tm,TIME_DATE)," ",TimeToStr(Tm,TIME_MINUTES),";",
                               DoubleToStr(iOpen  (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iHigh  (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iLow   (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iClose (Symbol(),PERIOD_M1,1),Digits),";",
                               DoubleToStr(iVolume(Symbol(),PERIOD_M1,1),0)
                               );

    if (!(IsOptimization() || IsTesting())) {
       string res = "";
       for (int j=0; j<255; j++) res = StringConcatenate(res," ");
       res = SaveRateM1(Rt);
       if (res != "OK")  Print("<",res,">");
       Sleep(100);
    }   
  }  
  return(0);
}

Мусорок остался. Причем он бывает не всегда, а иногда.

10:30:05 DllTest EURUSD,H1: < 07:30;163.67;163.69;163.64;163.65;27>
10:30:05 DllTest EURUSD,H1: < 07:30;163.67;163.69;163.64;163.65;27>
10:30:05 DllTest EURJPY,H1: <>
10:30:06 DllTest EURUSD,H1: < 07:30;2.0424;2.0433;2.0424;2.0433;39>
10:30:10 DllTest EURCHF,H1: <j>
10:30:32 DllTest GBPUSD,H1: <j>
10:30:45 DllTest GBPJPY,M1: <>
10:31:11 DllTest EURCHF,H1: < 07:31;1.5711;1.5715;1.5710;1.5715;23>
10:31:11 DllTest EURJPY,H1: < 07:31;1.9792;1.9794;1.9790;1.9790;13>
 
lusp:

       string res = ".... тут вставьте 255 пробелов              ";
       ///  for (int j=0; j<255; j++) res = StringConcatenate(res," ");
       res = SaveRateM1(Rt);
       if (res != "OK")  Print("<",res,">");
       Sleep(100);
    }   
  }  
  return(0);
}

вы объявили res = "";


вы ее во ттак объявите



string res = "012345678901234567890... ...255 "; /// ну я не могу 255 сивмолов А вы сможете :-)

// и не надо ее динамически наращивать!

----





то есть если хотим передавать строки в эксперт из DLL то надо заранее проинициализировтаь строки максимальным значением типа

Эксперт:
 
void testStringFunc() {
  string[] strArray = {"ccccccccccccccc", "ccc"};
  dllFunc(strArray, 2);
  Print("strArray[0] = ", strArray[0]);
  Print("strArray[1] = ", strArray[1]);
}
 
DLL:
 
EXP void __stdcall dllFunc(MqlStr* strArray, int n) {
  strcpy(strArray[0].string, "maximum 14 char");
  strcpy(strArray[1].string, "123");
}

вы все таки ссылку почитайте! почитайте это

 
YuraZ:
       string res = ".... тут вставьте 255 пробелов              ";
       ///  for (int j=0; j<255; j++) res = StringConcatenate(res," ");
       res = SaveRateM1(Rt);
       if (res != "OK")  Print("<",res,">");
       Sleep(100);
    }   
  }  
  return(0);
}
вы объявили res = "";

вы ее во ттак объявите


static string res = "012345678901234567890... ...255 "; /// ну я не могу 255 сивмолов А вы сможете :-)

// и не надо ее динамически наращивать!

Все равно не помогает.

    if (!(IsOptimization() || IsTesting())) {
       string res = "0         1         2         3         4         5         6         7         8         9        10        11        12        13        14        15        16        17        18        19        20        21        22        23        24        25    5";
       string r1  = res;
       res = SaveRateM1(Rt);
       if (res != "OK")  {
         Print("StringLen(res)=",StringLen(r1), " result res= <",res,">");
       }  
       Sleep(100);
    }

Првда, чисто по ощущениям мусора стало меньше. Но он все равно есть

10:53:00 DllTest GBPJPY,M1: StringLen(res)=255 result res= < 07:53;2.0400;2.0402;2.0388;2.0390;49>
10:53:00 DllTest GBPCHF,M5: StringLen(res)=255 result res= <d.;EURJPY;2008.05.23 07:53;163.56;163.58;163.55;163.56;13>
10:53:41 DllTest GBPJPY,M1: StringLen(res)=255 result res= <jdmiral Markets Ltd.;GBPJPY;2008.05.23 07:54;205.74;205.85;205.74;205.78;50>
10:54:47 DllTest GBPUSD,H1: StringLen(res)=255 result res= <M;Admiral Markets Ltd.;GBPCHF;2008.05.23 07:54;2.0389;2.0398;2.0389;2.0391;35>
10:54:47 DllTest GBPUSD,H1: StringLen(res)=255 result res= < 07:55;2.0394;2.0395;2.0382;2.0385;50>
10:55:05 DllTest GBPCHF,M5: StringLen(res)=255 result res= < 07:55;163.57;163.57;163.53;163.55;22>
10:55:05 DllTest EURCHF,H1: StringLen(res)=255 result res= < 07:55;1.5717;1.5724;1.5717;1.5723;17>
10:56:35 DllTest GBPCHF,M5: StringLen(res)=255 result res= < 07:56;205.69;205.69;205.57;205.60;44>

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