unit ifpscall;
{
  Innerfuse Pascal Script Call unit
  You may not copy a part of this unit, only use it as whole, with
  Innerfuse Pascal Script scriptengine DLL library or Delphi Library. 

}
interface
uses
  ifspas, ifs_var, ifs_utl;

type
  TCallingConvention = (ccRegister, ccPascal, ccCdecl, ccStdcall);

function InnerfuseCall(Self, Address: Pointer; CallingConv: TCallingConvention; Params: PVariableManager; Res: PIFVariant): Boolean; // res should already have been created with the type used for it

function ReadHeader(SE: TIfPasScript; Decl: String; var FuncName, FuncParam: String; Var CC: TCallingConvention): Boolean;

implementation
function ReadHeader(SE: TIfPasScript; Decl: String; var FuncName, FuncParam: String; Var CC: TCallingConvention): Boolean;
var
  Parser: TIfPascalParser;
  CurrVar: string;
  FuncRes,
    CurrType: Longint;
  E: TIFParserError;

  function GetType(const s: string): Longint;
  var
    t: PTypeRec;
  begin
    if (S = 'BYTE') or (S = 'WORD') or (s = 'CARDINAL') or (S = 'STRING') or (s = 'LONGINT') or (s = 'INTEGER') or (S = 'SMALLINT') or (S = 'SHORTINT') then
      GetType := Longint(SE.GetType(s))
    else if (S = 'PCHAR') then
    begin
      t := SE.GetType('!PCHAR');
      if t = nil then
      begin
        t := Se.AddTypeEx('!PCHAR');
        t^.Ext := Pointer(1);
      end;
      GetType := Longint(T);
    end else 
      GetType := 0;
  end;
begin
  Parser := TIfPascalParser.Create;
  ReadHeader := False;
  if not Parser.SetText(Decl, E) then
  begin
    parser.Free;
    exit;
  end;
  if Parser.CurrTokenId = CSTII_Procedure then
    FuncRes := 0
  else
    FuncRes := 1;
  Parser.Next;
  FuncName := Parser.GetToken;
  Parser.Next;
  FuncParam := '';
  CurrVar := '';
  if Parser.CurrTokenId = CSTI_OpenRound then begin
    Parser.Next;
    while True do begin
      if Parser.CurrTokenId = CSTI_Eof then begin
        Parser.Free;
        exit;
      end;
      if Parser.CurrTokenId = CSTII_Var then begin
        CurrVar := '!';
        Parser.Next;
      end; {if}
      while True do begin
        if Parser.CurrTokenId = CSTI_Eof then begin
          Parser.Free;
          exit;
        end;
        if Parser.CurrTokenId <> CSTI_Identifier then begin
          parser.Free;
          exit;
        end;
        CurrVar := CurrVar + Parser.GetToken + '|';
        Parser.Next;
        if Parser.CurrTokenId = CSTI_Colon then break;
        if Parser.CurrTokenId <> CSTI_Comma then begin
          parser.Free;
          exit;
        end;
        Parser.Next;
      end; {while}
      Parser.Next;
      CurrType := GetType(Parser.GetToken);
      if CurrType = 0 then
      begin
        Parser.Free;
        exit;
      end;
      if Pos('!', CurrVar) = 1 then begin
        Delete(CurrVar, 1, 1);
        while Pos('|', CurrVar) > 0 do begin
          FuncParam := FuncParam + ' !' + copy(CurrVar, 1, Pos('|', CurrVar) - 1) + ' ' + inttostr(CurrType);
          Delete(CurrVar, 1, Pos('|', CurrVar));
        end; {while}
      end else begin
        while Pos('|', CurrVar) > 0 do begin
          FuncParam := FuncParam + ' ' + copy(CurrVar, 1, Pos('|', CurrVar) - 1) + ' ' + inttostr(CurrType);
          Delete(CurrVar, 1, Pos('|', CurrVar));
        end; {while}
      end; {if}
      Parser.Next;
      if Parser.CurrTokenId = CSTI_CloseRound then begin
        Parser.Next;
        break;
      end; {if}
      Parser.Next;
    end;
  end;
  if FuncRes = 1 then begin
    Parser.Next;
    FuncRes := GetType(Parser.GetToken);
    if FuncRes = 0 then begin
      Parser.Free;
      exit;
    end;
    Parser.Next;
  end;
  CC := ccRegister;
  if Parser.CurrTokenID = CSTI_Semicolon then
  begin
    Parser.Next;
    if Parser.CurrTokenId = CSTI_Identifier then
    begin
      if Parser.GetToken = 'STDCALL' then
        CC := CCStdCall
      else if Parser.GetToken = 'CDECL' then
        CC := CCCdecl
      else if Parser.GetToken = 'PASCAL' then
        CC := ccPascal;
      // Register is default.
    end;
  end;
  FuncParam := inttostr(FuncRes) + FuncParam;
  ReadHeader := True;
  Parser.Free;
end;

function  RealCall_Register(p: Pointer;
                   _EAX, _EDX, _ECX: Cardinal;
                   StackData: pointer;
                   StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
                   ResultLength: Longint):Longint; stdcall; // make sure all things are on stack
var
  r: Longint;                   
begin
  asm
    mov ecx, stackdatalen
    jecxz @@2
    mov eax, stackdata
    @@1:
    mov edx, [eax]
    push edx
    add eax,4
    dec ecx
    or ecx, ecx
    jnz @@1
    @@2:
    mov eax,_EAX
    mov edx,_EDX
    mov ecx,_ECX
    call p
    mov ecx, resultlength
    cmp ecx, 0
    je @@5
    cmp ecx, 1
    je @@3
    cmp ecx, 2
    je @@4
    mov r, eax
    jmp @@5
    @@3:
    xor ecx, ecx
    mov cl, al
    mov r, ecx
    jmp @@5
    @@4:
    xor ecx, ecx
    mov cx, ax
    mov r, ecx
    @@5:
  end;
  result := r;
end;

function  RealCall_Other(p: Pointer;
                   StackData: pointer;
                   StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
                   ResultLength: Longint): Longint; stdcall; // make sure all things are on stack
var
  R: Longint;
begin
  asm
    mov ecx, stackdatalen
    jecxz @@2
    mov eax, stackdata
    @@1:
    mov edx, [eax]
    push edx
    add eax,4
    dec ecx
    or ecx, ecx
    jnz @@1
    @@2:
    call p
    mov ecx, resultlength
    cmp ecx, 0
    je @@5
    cmp ecx, 1
    je @@3
    cmp ecx, 2
    je @@4
    mov r, eax
    jmp @@5
    @@3:
    xor ecx, ecx
    mov cl, al
    mov r, ecx
    jmp @@5
    @@4:
    xor ecx, ecx
    mov cx, ax
    mov r, ecx
    @@5:
  end;
  result := r;
end;
function RealCall_CDecl(p: Pointer;
                   StackData: pointer;
                   StackDataLen: Longint; // stack length are in 4 bytes. (so 1 = 4 bytes)
                   ResultLength: Longint): Longint; stdcall; // make sure all things are on stack
var
  R: Longint;                   
begin
  asm
    mov ecx, stackdatalen
    jecxz @@2
    mov eax, stackdata
    @@1:
    mov edx, [eax]
    push edx
    add eax,4
    dec ecx
    or ecx, ecx
    jnz @@1
    @@2:
    call p
    mov ecx, resultlength
    cmp ecx, 0
    je @@5
    cmp ecx, 1
    je @@3
    cmp ecx, 2
    je @@4
    mov r, eax
    jmp @@5
    @@3:
    xor ecx, ecx
    mov cl, al
    mov r, ecx
    jmp @@5
    @@4:
    xor ecx, ecx
    mov cx, ax
    mov r, ecx
    @@5:
    mov ecx, stackdatalen
    jecxz @@2
    @@6:
    pop edx
    dec ecx
    or ecx, ecx
    jnz @@6
  end;
  Result := R;
end;

function InnerfuseCall(Self, Address: Pointer; CallingConv: TCallingConvention; Params: PVariableManager; Res: PIFVariant): Boolean; // res should already have been created with the type used for it
var
  Stack: ansistring;
  i: Longint;
  RegUsage: Byte;
  EAX, EDX, ECX: Longint;
begin
  InnerfuseCall := False;
  if Address = nil then
    exit; // need address
  stack := '';
  case CallingConv of
    ccRegister:
    begin
      EAX := 0;
      EDX := 0;
      ECX := 0;
      RegUsage:= 0;
      if assigned(Self) then
      begin
        RegUsage := 1;
        EAX := Longint(Self);
      end;
      for i := 0 to VM_Count(Params)-1 do
      begin
        if VM_Get(Params, I)^.vtype^.atypeid = CSV_VAR then // var parameter
        begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: begin
              case RegUsage of
                0: begin EAX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UByte); inc(RegUsage);end;
                1: begin EDX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UByte); inc(RegUsage);end;
                2: begin ECX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UByte); inc(RegUsage);end;
              else
                begin
                  Stack := Stack + #0#0#0#0;
                  Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Char);
                end;
              end;
            end;
            CSV_UInt16, CSV_SInt16: begin
              case RegUsage of
                0: begin EAX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UInt16); Inc(RegUsage); end;
                1: begin EDX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UInt16); Inc(RegUsage); end;
                2: begin ECX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_UInt16); Inc(RegUsage); end;
                else
                  begin
                    Stack := Stack + #0#0#0#0;
                    Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Uint16);
                  end;
              end;
            end;
            CSV_UInt32, CSV_SInt32: begin
              case RegUsage of
                0: Begin EAX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_SInt32); Inc(RegUsage); end;
                1: Begin EDX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_SInt32); Inc(RegUsage); end;
                2: Begin ECX := Longint(@GetVarLink(VM_Get(Params, I))^.CV_SInt32); Inc(RegUsage); end;
              else
                begin
                  Stack := Stack + #0#0#0#0;
                  Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Sint32);
                end;
              end;
            end;
            CSV_String: begin
              case RegUsage of
                0: begin EAX := Longint(@(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                1: begin EDX := Longint(@(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                2: begin ECX := Longint(@(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                else begin Stack := Stack + #0#0#0#0;Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
              end;
            end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end else begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: begin
              case RegUsage of
                0: begin EAX := GetVarLink(VM_Get(Params, I))^.CV_UByte; inc(RegUsage);end;
                1: begin EDX := GetVarLink(VM_Get(Params, I))^.CV_UByte; inc(RegUsage);end;
                2: begin ECX := GetVarLink(VM_Get(Params, I))^.CV_UByte; inc(RegUsage);end;
              else
                begin
                  Stack := Stack + GetVarLink(VM_Get(Params, I))^.CV_Char + #0#0#0;
                end;
              end;
            end;
            CSV_UInt16, CSV_SInt16: begin
              case RegUsage of
                0: begin EAX := GetVarLink(VM_Get(Params, I))^.CV_UInt16; Inc(RegUsage); end;
                1: begin EDX := GetVarLink(VM_Get(Params, I))^.CV_UInt16; Inc(RegUsage); end;
                2: begin ECX := GetVarLink(VM_Get(Params, I))^.CV_UInt16; Inc(RegUsage); end;
                else
                  begin
                    Stack := Stack + #0#0#0#0; Word((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_UInt16;
                  end;
              end;
            end;
            CSV_UInt32, CSV_SInt32: begin
              case RegUsage of
                0: Begin EAX := GetVarLink(VM_Get(Params, I))^.CV_SInt32; Inc(RegUsage); end;
                1: Begin EDX := GetVarLink(VM_Get(Params, I))^.CV_SInt32; Inc(RegUsage); end;
                2: Begin ECX := GetVarLink(VM_Get(Params, I))^.CV_SInt32; Inc(RegUsage); end;
              else
                begin
                  Stack := Stack + #0#0#0#0; Longint((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_SInt32;
                end;
              end;
            end;
            CSV_String: begin
              case RegUsage of
                0: begin EAX := Longint(Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                1: begin EDX := Longint(Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                2: begin ECX := Longint(Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str)); Inc(RegUsage); end;
                else begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
              end;
            end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end;
      end;
      if Assigned(Res) then
      begin
        case Res^.VType^.atypeid of
          CSV_String: begin
            if Longint(Res^.VType^.ext) = 0 then
            begin
              case RegUsage of
              0: begin EAX := Longint(@Res^.cv_Str); end;
              1: begin EDX := Longint(@Res^.cv_Str); end;
              2: begin ECX := Longint(@Res^.cv_Str); end;
              else begin Stack := Stack + #0#0#0#0; Longint((@Stack[Length(Stack)-3])^) := Longint(@Res^.cv_Str); end;
              end;
            end;
          end;
        end;
      end;
      if assigned(Res) then
      begin
        case Res^.vtype^.atypeid of
          CSV_Char, CSV_UByte, CSV_SByte: begin
            Res^.CV_UByte := RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 1);
          end;
          CSV_UInt16, CSV_SInt16: begin
            res^.CV_UInt16 := RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 2);
          end;
          CSV_UInt32, CSV_SInt32: begin
            Res^.CV_SInt32 := RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 4);
          end;
          CSV_String: if Longint(Res^.VType^.ext) = 1 then begin
            Res^.CV_Str := PChar(RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 0));
          end else RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 0);
        else
          exit;
        end;
      end else begin
        RealCall_Register(Address, EAX, EDX, ECX, @Stack[1], Length(Stack) div 4, 0);
      end;
      Result := True;
    end;

    ccPascal:
    begin
      for i := 0 to VM_Count(Params)-1 do
      begin
        if VM_Get(Params, I)^.vtype^.atypeid = CSV_VAR then
        begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Char); end;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0;  Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt16); end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt32);end;
            CSV_String: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end else begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: Stack := Stack + GetVarLink(VM_Get(Params, I))^.CV_Char + #0#0#0;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0; Word((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_UInt16; end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Longint((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_SInt32;
            end;
            CSV_String: begin
              case Longint(GetVarLink(VM_Get(Params, I))^.vtype^.Ext) of
                0 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
                1 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := PChar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
              end;
            end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end;
      end;
      if Assigned(Res) then
      begin
        case Res^.VType^.atypeid of
          CSV_String: begin
            if Longint(Res^.VType^.ext) = 0 then
            begin
              Stack := Stack + #0#0#0#0;
              Longint((@Stack[Length(Stack)-3])^) := Longint(@Res^.cv_Str);
            end;
          end;
        end;
      end;
      if assigned(Self) then
      begin
        Stack := Stack + #0#0#0#0;
        Pointer((@Stack[Length(Stack)-3])^) := Self;
      end;
      if assigned(Res) then
      begin
        case Res^.vtype^.atypeid of
          CSV_Char, CSV_UByte, CSV_SByte: begin
            Res^.CV_UByte := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 1);
          end;
          CSV_UInt16, CSV_SInt16: begin
            res^.CV_UInt16 := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 2);
          end;
          CSV_UInt32, CSV_SInt32: begin
            Res^.CV_SInt32 := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 4);
          end;
          CSV_String: if Longint(Res^.VType^.ext) = 1 then begin
            Res^.CV_Str := PChar(RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0));
          end else RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0);
        else
          exit;
        end;
      end else begin
        RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0);
      end;
      Result := True;
    end;

    ccCdecl: begin
      if assigned(Self) then
      begin
        Stack := Stack + #0#0#0#0;
        Pointer((@Stack[Length(Stack)-3])^) := Self;
      end;
      for i := VM_Count(Params)-1 downto 0 do
      begin
        if VM_Get(Params, I)^.vtype^.atypeid = CSV_VAR then
        begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Char); end;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0;  Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt16); end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt32);end;
            CSV_String: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end else begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: Stack := Stack  + GetVarLink(VM_Get(Params, I))^.CV_Char+ #0#0#0;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0; Word((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_UInt16; end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Longint((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_SInt32;
            end;
            CSV_String: begin
              case Longint(GetVarLink(VM_Get(Params, I))^.vtype^.Ext) of
                0 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
                1 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := PChar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
              end;
            end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end;
      end;
      if assigned(Res) then
      begin
        case Res^.VType^.atypeid of
          CSV_String: begin
            if Longint(Res^.VType^.ext) = 0 then
            begin
              Stack := Stack + #0#0#0#0;
              Longint((@Stack[Length(Stack)-3])^) := Longint(@Res^.cv_Str);
              RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 0);
            end else begin
              Res^.CV_Str := Pchar(RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 0));
            end;
          end;
          CSV_Char, CSV_UByte, CSV_SByte: begin
            Res^.CV_UByte := RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 1);
          end;
          CSV_UInt16, CSV_SInt16: begin
            res^.CV_UInt16 := RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 2);
          end;
          CSV_UInt32, CSV_SInt32: begin
            Res^.CV_SInt32 := RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 4);
          end;
        else
          exit;
        end;
      end else begin
        RealCall_CDECL(Address, @Stack[1], Length(Stack) div 4, 0);
      end;
      Result := True;
    end;
    ccStdcall: begin
      if assigned(Self) then
      begin
        Stack := Stack + #0#0#0#0;
        Pointer((@Stack[Length(Stack)-3])^) := Self;
      end;
      for i := VM_Count(Params)-1 downto 0 do
      begin
        if VM_Get(Params, I)^.vtype^.atypeid = CSV_VAR then
        begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Char); end;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0;  Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt16); end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_UInt32);end;
            CSV_String: begin Stack := Stack + #0#0#0#0; Pointer((@Stack[Length(Stack)-3])^) := @(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end else begin
          case GetVarLink(VM_Get(Params, I))^.vtype^.atypeid of
            CSV_Char, CSV_UByte, CSV_SByte: Stack := Stack + GetVarLink(VM_Get(Params, I))^.CV_Char + #0#0#0;
            CSV_UInt16, CSV_SInt16: begin Stack := Stack + #0#0#0#0; Word((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_UInt16; end;
            CSV_UInt32, CSV_SInt32: begin Stack := Stack + #0#0#0#0; Longint((@Stack[Length(Stack)-3])^) := GetVarLink(VM_Get(Params, I))^.CV_SInt32;
            end;
            CSV_String: begin
              case Longint(GetVarLink(VM_Get(Params, I))^.vtype^.Ext) of
                0 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := Pchar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
                1 : begin Stack := Stack + #0#0#0#0; if GetVarLink(VM_Get(Params, I))^.cv_Str <> '' then Pointer((@Stack[Length(Stack)-3])^) := PChar(GetVarLink(VM_Get(Params, I))^.CV_Str); end;
              end;
            end;
          else
            begin
              exit; //invalid type
            end;
          end;
        end;
      end;
      if assigned(Res) then
      begin
        case Res^.VType^.atypeid of
          CSV_String: begin
            if Longint(Res^.VType^.ext) = 0 then
            begin
              Stack := Stack + #0#0#0#0;
              Longint((@Stack[Length(Stack)-3])^) := Longint(@Res^.cv_Str);
              RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0);
            end else Res^.CV_Str := Pchar(RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0));
          end;
          CSV_Char, CSV_UByte, CSV_SByte: begin
            Res^.CV_UByte := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 1);
          end;
          CSV_UInt16, CSV_SInt16: begin
            res^.CV_UInt16 := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 2);
          end;
          CSV_UInt32, CSV_SInt32: begin
            Res^.CV_SInt32 := RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 4);
          end;
        else
          exit;
        end;
      end else begin
        RealCall_Other(Address, @Stack[1], Length(Stack) div 4, 0);
      end;
      Result := True;
    end;
  end;
end;

end.
