Crashes when importing Delphi DLLs ByVar

 

Hi

I'm using delphi 2010(v14) to mk DLL s for metatrder .

here is the function definition in delphi :

procedure GetSendOrder(var symbol:shortstring;var CMD:integer;var vol:double;var Price:double;var slippage:integer;var SL:double;var TP:double;var Comment:shortstring;var Magic:integer;var Expire:integer;var color:integer;Result:integer;No : integer);stdcall;
begin
  symbol := MYDatas.SendOrders[No].Symbol;
  CMD := MYDatas.SendOrders[No].TheOrderType;
  Vol := MYDatas.SendOrders[No].Size;
  Price:= MYDatas.SendOrders[No].OpenPrice;
  slippage := MYDatas.SendOrders[No].slippge;
  SL:= MYDatas.SendOrders[No].SL;
  TP:= MYDatas.SendOrders[No].TP;
  Comment:= MYDatas.SendOrders[No].Comment;
  Magic:= MYDatas.SendOrders[No].Magic;
  Expire:= MYDatas.SendOrders[No].ExpireTime;
  Color:= MYDatas.SendOrders[No].Color;
  result:= MYDatas.SendOrders[No].result;
end;
and here is what I use in mq4 :
#import "MetaServer.dll"
void GetSendOrder(string& symbol,int& CMD,double& vol,double& Price,int& slippage,double& SL,double& TP,string& comment,int& Magic,int& Expire,int& Color,int& Result,int No );
#import
.
.
.
.
.
GetSendOrder(TheSymbol,TheCMD,TheVol,ThePrice,TheSlippage,TheSL,TheTP,TheComment,TheMgic,TheExpire,TheColor,TheResult,0);
if (TheResult==1)
{
OrderSend (Symbol(),0,0.1,Ask,10,0,0,"",0,0,Red);
}
But when I use this function , my mtatrader crashes . could someone please help me solve this problem .
 

you are shure was passing correct values to dll? doouble to double, int t int ....?

Memory-Manager you was including in Delphi Dll. I am not shure with your Records, but i remember when you handle Strings you need some memory manager.

Some example: http://www.swissdelphicenter.ch/de/showcode.php?id=1745

 

strings are always passed as PChar, not shortstring. You can "cast" the PChar to String or ShortString inside your function (this will automatically allocate a Pascal string on the heap and copy the contents) and you can also cast a String or a ShortString back to PChar when you want to return it to MT4. When working with String or ShortString in Delphi the Delphi heap manager should take care of everything, there should not be anything to worry about.

int and double cannot be passed by reference (this is a bug in mql4, it will pass a null pointer if you try), you must pass them as an array (even a single element array if you want)


Read the Lazarus-MT4 Tutorial on ForexFactory for detailed explanations about what is going on inside and some examples. Also don't forget to mask the FPU exceptions (this is mentioned in one of the later posts at the end of that thread) or you might have sporadic crashes deep inside MT4 that seem unexplainable.

 
7bit:

strings are always passed as PChar, not shortstring. You can "cast" the PChar to String or ShortString inside your function (this will automatically allocate a Pascal string on the heap and copy the contents) and you can also cast a String or a ShortString back to PChar when you want to return it to MT4. When working with String or ShortString in Delphi the Delphi heap manager should take care of everything, there should not be anything to worry about.

int and double cannot be passed by reference (this is a bug in mql4, it will pass a null pointer if you try), you must pass them as an array (even a single element array if you want)


Read the Lazarus-MT4 Tutorial on ForexFactory for detailed explanations about what is going on inside and some examples. Also don't forget to mask the FPU exceptions (this is mentioned in one of the later posts at the end of that thread) or you might have sporadic crashes deep inside MT4 that seem unexplainable.



Hi

Thanks

Could you please give me an example, I would really appreciate it if you make my function work correctly, I changed the function to this :

by the way, it is possible to pass int and doubles byrefrence, I have tried it and it works fine .

procedure GetSendOrder(var symbol:pansichar;var CMD:integer;var vol:double;var Price:double;var slippage:integer;var SL:double;var TP:double;var Comment:pansichar;var Magic:integer;var Expire:integer;var color:integer;Result:integer;No : integer);stdcall;
begin
  symbol := PAnsiChar(AnsiString( MYDatas.SendOrders[No].Symbol));
  CMD := MYDatas.SendOrders[No].TheOrderType;
  Vol := MYDatas.SendOrders[No].Size;
  Price:= MYDatas.SendOrders[No].OpenPrice;
  slippage := MYDatas.SendOrders[No].slippge;
  SL:= MYDatas.SendOrders[No].SL;
  TP:= MYDatas.SendOrders[No].TP;
  Comment:=  PAnsiChar(AnsiString((MYDatas.SendOrders[No].Comment)));
  Magic:= MYDatas.SendOrders[No].Magic;
  Expire:= MYDatas.SendOrders[No].ExpireTime;
  Color:= MYDatas.SendOrders[No].Color;
  result:= MYDatas.SendOrders[No].result;
end;


but the problem is not solved yet .

 
Mehdi_Sobhani:
by the way, it is possible to pass int and doubles byrefrence, I have tried it and it works fine .

Inside MQL4 yes, but not when calling a dll unless they recently fixed this bug (what I doubt).


in mql4 you pass an array to the function by reference:

#import "foo.dll"
   void baz(double& zap[]);
#import


int start(){
   double something[1];
   something[0] = 42;
   baz(something);
   print(something[0]);  // should print 84
}



and in Pascal you declare it like this:

type
   TOneDouble = Array[0..0] of Double;

procedure baz(var zap: TOneDouble); stdcall;
begin
  zap[0] := zap[0] * 2;
end;

and while the above is more clear to the intuition since it is using the same construct (a one-element array) on both sides it must be noted that when passing an array to the DLL function by reference you are effectively passing a pointer to the first element. This means we pass a pointer to a double which is exactly what we initially wanted to do (var zap: Double) is also expecting a pointer to a double. This means for this special case of passing a one element array we can write the above Pascal function as follows:

procedure baz(var zap: Double); stdcall;
begin
  zap := zap * 2;
end;

and this is completely equivalent!

And just for the sake of completeness: Here is how we could also write it with pointer and pointer dereferencing:

procedure baz(zap: PDouble); stdcall;
begin
  zap^ := zap^ * 2;
end;

we are passing a pointer by value and access the double by dereferencing the pointer. The var syntax above did this implicitly. If you disassemble the compiler output you should see the same machine code generated in all 3 cases.

 

Here is an example which shows this, I didn't know it had been impossible before cause i'm very new in writing DLLs for importing into mettrder:

https://forum.mql4.com/26880

 
Mehdi_Sobhani:
but the problem is not solved yet .

There are more errors. You cannot assign a PChar (which is a pointer) to the var symbol. You must use move() or strcopy() or something like that to copy the contents from your ansistring to the memory location where symbol points to (and make sure the terminating zero is included and also always make sure the mql4 string you pass to the dll is long enough to receive the contents that you will copy into it).


You could also just return a PChar as your function result and in mql4 assign this to a new string, this would be much easier.


Also you should not start your experiments with a function that contains a dozen different parameters, each of them passed somehow wrongly and then wonder which of the dozen fatal errors was the one who crashed it, you should start with a simple function or procedure with only one parameter, for example a string until you get the string thing working, then an array of doubles, until you understand how to handle this, etc. Not everything at once.


You need to fully understand what the following things are:

* Pointer
* Memory
* Memory allocation
* address operator @
* Pointer dereferencing ^
* Pascal String
* C String
* PChar
* how var parameter works and how it is equivalent to passing a pointer (but only at the machine level, not at the language syntax level. You actually must fully understand what is happening here at the machine level in every detail and what everything actually represents at the lowest level of the machine (function calling mechanism, stack, memory addresses, what is pointing where and how to manipulate it etc) or you will never be able to understand why it works (or why it breaks))

All this. Thoroughly. Really. All this is not taught and learned in only 5 minutes.


Reason: