home *** CD-ROM | disk | FTP | other *** search
Wrap
{Classes runtime unit} unit ifpiclassruntime; { Innerfuse Pascal Script III Copyright (C) 2000-2002 by Carlo Kok (ck@carlo-kok.com) } {$I ifps3_def.inc} interface uses ifps3, ifps3utl, ifps3common, ifpicall; type {TIFPSRuntimeClass is one class at runtime} TIFPSRuntimeClass = class private FClassName: string; FClassNameHash: Longint; FClassItems: TIFList; FClass: TClass; FEndOfVmt: Longint; public {Register a constructor} procedure RegisterConstructor(ProcPtr: Pointer; const Name: string); {Register a virtual constructor} procedure RegisterVirtualConstructor(ProcPtr: Pointer; const Name: string); {Register a method} procedure RegisterMethod(ProcPtr: Pointer; const Name: string); {Register a virtual method} procedure RegisterVirtualMethod(ProcPtr: Pointer; const Name: string); {Register an abstract virtual method} procedure RegisterVirtualAbstractMethod(ClassDef: TClass; ProcPtr: Pointer; const Name: string); {Register a property helper} procedure RegisterPropertyHelper(ReadFunc, WriteFunc: Pointer; const Name: string); {Register a property helper that is an event} procedure RegisterEventPropertyHelper(ReadFunc, WriteFunc: Pointer; const Name: string); {create} constructor Create(aClass: TClass); {destroy} destructor Destroy; override; end; {TIFPSRuntimeClassImporter is the runtime class importer} TIFPSRuntimeClassImporter = class private FClasses: TIFList; public {create} constructor Create; {destroy} destructor Destroy; override; {Add a class} function Add(aClass: TClass): TIFPSRuntimeClass; {Clear} procedure Clear; {Search for a class} function FindClass(const Name: string): TIFPSRuntimeClass; end; {Register the classes at runtime} procedure RegisterClassLibraryRuntime(SE: TIFPSExec; Importer: TIFPSRuntimeClassImporter); {Set a runtime variant} procedure SetVariantToClass(V: PIFVariant; Cl: TObject); {Return the RPFuncs for other libraries} function ClassRuntimeGetRPFuncs: PResourcePtrSupportFuncs; {Internal function: Script Event Handler} procedure MyAllMethodsHandler; {Internal Function: Returns the Data pointer of a TMethod for a ProcNo} function GetMethodInfoRec(SE: TIFPSExec; ProcNo: Cardinal): Pointer; implementation uses SysUtils, TypInfo, ifpidelphiruntime; type TIFPSExecHack = class (TIFPSExec) end; PScriptMethodInfo = ^TScriptMethodInfo; TScriptMethodInfo = record Se: TIFPSExecHack; ProcNo: Cardinal; end; procedure PFree(Sender: TIFPSExec; P: PScriptMethodInfo); begin Dispose(p); end; function GetMethodInfoRec(SE: TIFPSExec; ProcNo: Cardinal): Pointer; var I: Longint; pp: PScriptMethodInfo; begin I := 0; repeat pp := Se.FindProcResource2(@PFree, I); if (i <> -1) and (pp^.ProcNo = ProcNo) then begin Result := Pp; exit; end; until i = -1; New(pp); pp^.Se := TIFPSExecHack(Se); pp^.ProcNo := Procno; Se.AddResource(@PFree, pp); Result := pp; end; function DummyResourceFree(FMode: TVRFMode; P, IntoP: PIFVariant): Boolean; begin if FMode = vrfDuplicate then begin IntoP.tResourceP1 := p.tResourceP1; IntoP.tResourceFreeProc := p.tResourceFreeProc; end; Result := True; end; function ResourcePtrToStr(PSelf: PResourcePtrSupportFuncs; Sender: TIFPSExec; P: PIFVariant): string; begin SetLength(Result, 4); Pointer((@Result[1])^) := P^.tResourceP1; end; function VarResourcePtrToStr(PSelf: PResourcePtrSupportFuncs; Sender: TIFPSExec; P: PIFVariant): string; begin SetLength(Result, 4); Pointer((@Result[1])^) := @P^.tResourceP1; p^.tResourceFreeProc := DummyResourceFree; end; procedure ResultToResourcePtr(PSelf: PResourcePtrSupportFuncs; Sender: TIFPSExec; Data: Longint; P: PIFVariant); begin if Data = 0 then begin p^.tResourceP1 := nil; p^.tResourceFreeProc := nil; end else begin p^.tResourceP1 := Pointer(Data); p^.tResourceFreeProc := DummyResourceFree; end; end; const ResourcePtrSupport: TResourcePtrSupportFuncs = ( ptr: nil; PtrToStr: ResourcePtrToStr; VarPtrToStr: VarResourcePtrToStr; ResultMethod: rmRegister; ResToPtr: ResultToResourcePtr); function ClassRuntimeGetRPFuncs: PResourcePtrSupportFuncs; begin Result := @ResourcePtrSupport; end; type TPtrArr = array[0..1000] of Pointer; PPtrArr = ^TPtrArr; TByteArr = array[0..1000] of byte; PByteArr = ^TByteArr; PPointer = ^Pointer; function VirtualMethodPtrToPtr(Ptr, FSelf: Pointer): Pointer; begin Result := PPtrArr(PPointer(FSelf)^)^[Longint(Ptr)]; end; function VirtualClassMethodPtrToPtr(Ptr, FSelf: Pointer): Pointer; begin Result := PPtrArr(FSelf)^[Longint(Ptr)]; end; procedure CheckPackagePtr(var P: PByteArr); begin if (word((@p[0])^) = $25FF) and (word((@p[6])^)=$C08B)then begin p := PPointer((@p[2])^)^; end; end; function FindVirtualMethodPtr(Ret: TIFPSRuntimeClass; FClass: TClass; Ptr: Pointer): Pointer; // Idea of getting the number of VMT items from GExperts var p: PPtrArr; I: Longint; begin p := Pointer(FClass); CheckPackagePtr(PByteArr(Ptr)); if Ret.FEndOfVMT = MaxInt then begin I := {$IFDEF VER90}-48{$ELSE}vmtSelfPtr{$ENDIF} div SizeOf(Pointer) + 1; while I < 0 do begin if I < 0 then begin if I <> ({$IFDEF VER90}-44{$ELSE}vmtTypeInfo{$ENDIF} div SizeOf(Pointer)) then begin // from GExperts code if (Longint(p^[I]) > Longint(p)) and ((Longint(p^[I]) - Longint(p)) div 4 < Ret.FEndOfVMT) then begin Ret.FEndOfVMT := (Longint(p^[I]) - Longint(p)) div SizeOf(Pointer); end; end; end; Inc(I); end; if Ret.FEndOfVMT = MaxInt then begin Ret.FEndOfVMT := 0; // cound not find EndOfVMT Result := nil; exit; end; end; I := 0; while I < Ret.FEndOfVMT do begin if p^[I] = Ptr then begin Result := Pointer(I); exit; end; I := I + 1; end; Result := nil; end; type PClassItem = ^TClassItem; TClassItem = record FName: string; FNameHash: Longint; b: byte; case byte of 0: (Ptr: Pointer); {Method} 1: (PointerInList: Pointer); {Virtual Method} 3: (FReadFunc, FWriteFunc: Pointer); {Property Helper} 4: (Ptr2: Pointer); {Constructor} 5: (PointerInList2: Pointer); {virtual constructor} 6: (); {Property helper, like 3} end; function ClassCallProc01(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var i: Integer; MyList: TIfList; n: PIFVariant; FSelf: Pointer; CurrStack: Cardinal; cc: TCallingConvention; s: string; begin s := p^.ExportDecl; if length(S) < 2 then begin Result := False; exit; end; cc := TCallingConvention(s[1]); delete(s, 1, 1); if s[1] = #0 then n := Stack.GetItem(Stack.Count -1) else n := Stack.GetItem(Stack.Count -2); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) or (n^.tresourcep1 = nil) then begin result := false; exit; end; FSelf := n^.tResourceP1; CurrStack := Stack.Count - Cardinal(length(s)) -1; if s[1] = #0 then inc(CurrStack); MyList := tIfList.Create; for i := 2 to length(s) do begin MyList.Add(nil); end; for i := length(s) downto 2 do begin n :=Stack.GetItem(CurrStack); if s[i] <> #0 then begin n^.RefCount := n^.RefCount or IFPSAddrStackStart; end; MyList.SetItem(i - 2, n); inc(CurrStack); end; try if s[1] <> #0 then begin n := Stack.GetItem(CurrStack + 1); end else n := nil; if p^.Ext2 = nil then InnerfuseCall(Caller, FSelf, p^.Ext1, cc, MyList, n, @ResourcePtrSupport) else InnerfuseCall(Caller, FSelf, VirtualMethodPtrToPtr(p^.Ext1, FSelf), cc, MyList, n, @ResourcePtrSupport); result := true; except result := false; end; MyList.Free; end; const IntType: TIFTypeRec = (BaseType: btU32); IntVal: TIFVariant = (FType: @IntType; RefCount: 1; tu32: 1); function ClassCallProc04(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var i, h: Longint; MyList: TIfList; n: PIFVariant; FSelf: Pointer; CurrStack: Cardinal; cc: TCallingConvention; s: string; FType: PIFTypeRec; x: TIFPSRuntimeClass; begin n := Stack.GetItem(Stack.Count -2); if (n = nil) or (n^.Ftype^.BaseType <> btU32) then begin result := false; exit; end; FType := Caller.GetTypeNo(N^.tu32); if (FType = nil) then begin Result := False; exit; end; h := MakeHash(FType^.ExportName); FSelf := nil; for i := 0 to TIFPSRuntimeClassImporter(p^.Ext2).FClasses.Count -1 do begin x:= TIFPSRuntimeClassImporter(p^.Ext2).FClasses.GetItem(i); if (x.FClassNameHash = h) and (x.FClassName = FType^.ExportName) then begin FSelf := x.FClass; end; end; if FSelf = nil then begin Result := False; exit; end; s := p^.ExportDecl; if length(S) < 2 then begin Result := False; exit; end; cc := TCallingConvention(s[1]); delete(s, 1, 1); CurrStack := Stack.Count - Cardinal(length(s)) -1; //CurrStack := Stack.Count - Cardinal(length(s)); if s[1] = #0 then inc(CurrStack); MyList := tIfList.Create; MyList.Add(@IntVal); for i := 2 to length(s) do begin MyList.Add(nil); end; for i := length(s) downto 2 do begin n :=Stack.GetItem(CurrStack); if s[i] <> #0 then begin n^.RefCount := n^.RefCount or IFPSAddrStackStart; end; MyList.SetItem(i - 1, n); inc(CurrStack); end; try if s[1] <> #0 then begin n := Stack.GetItem(CurrStack +1); end else n := nil; InnerfuseCall(Caller, FSelf, p^.Ext1, cc, MyList, n, @ResourcePtrSupport); result := true; except result := false; end; MyList.Free; end; function ClassCallProc05(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var i, h: Longint; MyList: TIfList; n: PIFVariant; FSelf: Pointer; CurrStack: Cardinal; cc: TCallingConvention; s: string; FType: PIFTypeRec; x: TIFPSRuntimeClass; begin n := Stack.GetItem(Stack.Count -2); if (n = nil) or (n^.Ftype^.BaseType <> btU32) then begin result := false; exit; end; FType := Caller.GetTypeNo(N^.tu32); if (FType = nil) then begin Result := False; exit; end; h := MakeHash(FType^.ExportName); FSelf := nil; for i := 0 to TIFPSRuntimeClassImporter(p^.Ext2).FClasses.Count -1 do begin x:= TIFPSRuntimeClassImporter(p^.Ext2).FClasses.GetItem(i); if (x.FClassNameHash = h) and (x.FClassName = FType^.ExportName) then begin FSelf := x.FClass; Break; end; end; if FSelf = nil then begin Result := False; exit; end; s := p^.ExportDecl; if length(S) < 2 then begin Result := False; exit; end; cc := TCallingConvention(s[1]); delete(s, 1, 1); CurrStack := Stack.Count - Cardinal(length(s)) -1; if s[1] = #0 then inc(CurrStack); MyList := tIfList.Create; MyList.Add(@IntVal); for i := 2 to length(s) do begin MyList.Add(nil); end; for i := length(s) downto 2 do begin n :=Stack.GetItem(CurrStack); if s[i] <> #0 then begin n^.RefCount := n^.RefCount or IFPSAddrStackStart; end; MyList.SetItem(i - 1, n); inc(CurrStack); end; try if s[1] <> #0 then begin n := Stack.GetItem(CurrStack + 1); end else n := nil; InnerfuseCall(Caller, FSelf, VirtualClassMethodPtrToPtr(p^.Ext1, FSelf), cc, MyList, n, @ResourcePtrSupport); result := true; except result := false; end; MyList.Free; end; function CastProc(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var TypeNo, InVar, ResVar: PIFVariant; FSelf: TClass; FType: PIFTypeRec; H, I: Longint; x: TIFPSRuntimeClass; begin TypeNo := Stack.GetItem(Stack.Count-3); InVar := Stack.GetItem(Stack.Count-2); ResVar := Stack.GetItem(Stack.Count-1); if (TypeNo = nil) or (InVar = nil) or (ResVar = nil) or (InVar^.FType^.BaseType <> btResourcePointer) or (ResVar^.FType^.BaseType <> btResourcePointer) or (TypeNo^.FType^.BaseType <> btu32) then begin Result := False; Exit; end; if InVar^.tResourceP1 = nil then begin ResVar^.tResourceP1 := nil; ResVar^.tResourceFreeProc:= nil; result := True; exit; end; FType := Caller.GetTypeNo(TypeNo^.tu32); if (FType = nil) then begin Result := False; exit; end; h := MakeHash(FType^.ExportName); FSelf := nil; for i := 0 to TIFPSRuntimeClassImporter(p^.Ext2).FClasses.Count -1 do begin x:= TIFPSRuntimeClassImporter(p^.Ext2).FClasses.GetItem(i); if (x.FClassNameHash = h) and (x.FClassName = FType^.ExportName) then begin FSelf := x.FClass; end; end; if FSelf = nil then begin Result := False; exit; end; ResVar^.tResourceFreeProc := DummyResourceFree; try resVar^.tResourceP1 := TObject(InVar^.tResourceP1) as FSelf; except Result := False; exit; end; result := True; end; function CompareProc(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var p1, p2, pres: PIFVariant; begin p1 := Stack.GetItem(Stack.Count -3); p2 := Stack.GetItem(Stack.Count -2); pres := Stack.GetItem(Stack.Count -1); if (p1=nil) or (p2=nil) or (pres = nil) or (p1^.FType^.BaseType <> btResourcePointer) or (p2^.FType^.BaseType <> btResourcePointer) or (pres^.FType^.BaseType <> btu8) then begin Result := False; exit; end; if (p1^.tResourceP1 = p2^.tResourceP1) and (@p1^.tResourceFreeProc = @p2^.tResourceFreeProc) then pres^.tu32 := 1 else pres^.tu32 := 0; Result := True; end; function NilProc(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var n: PIFVariant; begin n := Stack.GetItem(Stack.Count-1); if (n = nil) or (n^.FType^.BaseType <> btResourcePointer) then begin Result := False; Exit; end; n^.tResourceP1 := nil; n^.tResourceFreeProc := nil; result := True; end; function MkMethod(FSE: TIFPSExec; No: Cardinal): TMethod; begin if no = 0 then begin Result.Code := nil; Result.Data := nil; end else begin Result.Code := @MyAllMethodsHandler; Result.Data := GetMethodInfoRec(FSE, No); end; end; function getMethodNo(P: TMethod): Cardinal; begin if (p.Code <> @MyAllMethodsHandler) or (p.Data = nil) then Result := 0 else begin Result := PScriptMethodInfo(p.Data)^.ProcNo; end; end; function ClassCallProc2(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var n: PIFVariant; FSelf: Pointer; begin if p^.Ext2 = Pointer(0) then begin n := Stack.GetItem(Stack.Count -1); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; n := Stack.GetItem(Stack.Count -2); if (PPropInfo(p^.Ext1)^.PropType^.Kind = tkMethod) and (n^.FType^.BaseType = btu32) then begin SetMethodProp(TObject(FSelf), PPropInfo(p^.Ext1), MkMethod(Caller, n^.tu32)); end else case n^.FType^.BaseType of btU8: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.tu8); btS8: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.ts8); btU16: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.tu16); btS16: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.ts16); btU32: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.tu32); btS32: SetOrdProp(TObject(FSelf), PPropInfo(p^.Ext1), n^.ts32); btSingle: SetFloatProp(TObject(FSelf), p^.Ext1, n^.tsingle); btDouble: SetFloatProp(TObject(FSelf), p^.Ext1, n^.tdouble); btExtended: SetFloatProp(TObject(FSelf), p^.Ext1, Extended(n^.textended)); btString: SetStrProp(TObject(FSelf), p^.Ext1, string(n^.tstring)); btPChar: SetStrProp(TObject(FSelf), p^.Ext1, string(n^.tstring)); btResourcePointer: begin if (@n^.tResourceFreeProc = nil) then SetOrdProp(TObject(FSelf), p^.Ext1, Longint(n^.tResourceP1)) else if @n^.tResourceFreeProc = @DummyResourceFree then SetOrdProp(TObject(FSelf), p^.Ext1, Longint(n^.tResourceP1)) else begin Result := False; exit; end; end; else begin Result := False; exit; end; end; Result := true; end else begin n := Stack.GetItem(Stack.Count -2); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; n := Stack.GetItem(Stack.Count -1); if (PPropInfo(p^.Ext1)^.PropType^.Kind = tkMethod) and (n^.FType^.BaseType = btu32) then begin n^.tu32 := GetMethodNo(GetMethodProp(TObject(FSelf), PPropInfo(p^.Ext1))); end else case n^.FType^.BaseType of btU8: n^.tu8 := GetOrdProp(TObject(FSelf), p^.Ext1); btS8: n^.tS8 := GetOrdProp(TObject(FSelf), p^.Ext1); btU16: n^.tu16 := GetOrdProp(TObject(FSelf), p^.Ext1); btS16: n^.tS16 := GetOrdProp(TObject(FSelf), p^.Ext1); btU32: n^.tu32 := GetOrdProp(TObject(FSelf), p^.Ext1); btS32: n^.tS32 := GetOrdProp(TObject(FSelf), p^.Ext1); btSingle: n^.tsingle := GetFloatProp(TObject(FSelf), p^.Ext1); btDouble: n^.tdouble := GetFloatProp(TObject(FSelf), p^.Ext1); btExtended: n^.textended := GetFloatProp(TObject(FSelf), p^.Ext1); btString: string(n^.tstring) := GetStrProp(TObject(FSelf), p^.Ext1); btPChar: string(n^.tstring) := GetStrProp(TObject(FSelf), p^.Ext1); btResourcePointer: begin n^.tResourceP1 := Pointer(GetOrdProp(TObject(FSelf), p^.Ext1)); n^.tResourceFreeProc := DummyResourceFree; end; else begin Result := False; exit; end; end; Result := True; end; end; function ClassCallProc3(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; var I, ParamCount: Longint; Params: TIfList; n: PIfVariant; FSelf: Pointer; begin if Length(P^.ExportDecl) < 4 then begin Result := False; exit; end; ParamCount := Longint((@P^.ExportDecl[1])^); if Longint(Stack.Count) < ParamCount +1 then begin Result := False; exit; end; Dec(ParamCount); if p^.Ext1 <> nil then // read begin n := Stack.GetItem(Longint(Stack.Count) - 2); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; Params := TIfList.Create; n := Stack.GetItem(Longint(Stack.Count) - 1); // Result n^.RefCount := n^.RefCount or IFPSAddrStackStart; Params.Add(n); for i := Stack.Count -3 downto Longint(Stack.Count) - ParamCount -2 do begin n := Stack.GetItem(I); Params.Add(n); end; InnerfuseCall(Caller, FSelf, p^.Ext1, ccRegister, Params, nil, @ResourcePtrSupport); Params.Free; Result := True; end else begin n := Stack.GetItem(Stack.Count -1); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; Params := TIfList.Create; Params.Add(Stack.GetItem(Longint(Stack.Count) - ParamCount - 2)); for i := Stack.Count -2 downto Longint(Stack.Count) - ParamCount -1 do begin Params.Add(Stack.GetItem(I)); end; InnerfuseCall(Caller, FSelf, p^.Ext2, ccregister, Params, nil, @ResourcePtrSupport); Params.Free; Result := True; end; end; const TMethodType: TIFTypeRec = (Ext: nil; BaseType: btDouble); function ClassCallProc06(Caller: TIFPSExec; p: PIFProcRec; Global, Stack: TIfList): Boolean; {Event property helper} var I, ParamCount: Longint; Params: TIfList; n, n2: PIfVariant; FSelf: Pointer; begin if Length(P^.ExportDecl) < 4 then begin Result := False; exit; end; ParamCount := Longint((@P^.ExportDecl[1])^); if Longint(Stack.Count) < ParamCount +1 then begin Result := False; exit; end; Dec(ParamCount); if p^.Ext1 <> nil then // read begin n := Stack.GetItem(Longint(Stack.Count) - 2); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; n := Stack.GetItem(Longint(Stack.Count) - 1); // Result if n^.FType^.BaseType <> btU32 then begin Result := False; exit; end; Params := TIfList.Create; new(n2); n2^.FType := @TMethodType; n2^.RefCount := 1 + IFPSAddrStackStart; TMethod(n2^.tdouble).Code := nil; TMethod(n2^.tdouble).Data := nil; Params.Add(n2); for i := Stack.Count -3 downto Longint(Stack.Count) - ParamCount -2 do begin n := Stack.GetItem(I); Params.Add(n); end; InnerfuseCall(Caller, FSelf, p^.Ext1, ccRegister, Params, nil, @ResourcePtrSupport); n^.tu32 := getMethodNo(TMethod(n2^.tdouble)); Params.Free; Result := True; end else begin n := Stack.GetItem(Stack.Count -1); if (n = nil) or (n^.Ftype^.BaseType <> btResourcePointer) or (@n^.tResourceFreeProc <> @DummyResourceFree) then begin result := false; exit; end; FSelf := n^.tResourceP1; n := Stack.GetItem(Longint(Stack.Count) - ParamCount - 2); if n^.FType^.BaseType <> btu32 then begin result := false; exit; end; new(n2); n2^.FType := @TMethodType; n2^.RefCount := 1; TMethod(n2^.tdouble) := MkMethod(Caller, n^.tu32); Params := TIfList.Create; Params.Add(n2); for i := Stack.Count -2 downto Longint(Stack.Count) - ParamCount -1 do begin Params.Add(Stack.GetItem(I)); end; InnerfuseCall(Caller, FSelf, p^.Ext2, ccregister, Params, nil, @ResourcePtrSupport); Dispose(n2); Params.Free; Result := True; end; end; {'class:'+CLASSNAME+'|'+FUNCNAME+'|'+chr(CallingConv)+chr(hasresult)+params For property write functions there is an '@' after the funcname. } function SpecImport(Sender: TIFPSExec; p: PIFProcRec; Tag: Pointer): Boolean; var H, I: Longint; S, s2: string; CL: TIFPSRuntimeClass; Px: PClassItem; pp: PPropInfo; IsRead: Boolean; begin s := p^.ExportDecl; delete(s, 1, 6); if s = '-' then {nil function} begin p^.ProcPtr := NilProc; Result := True; exit; end; if s = '+' then {cast function} begin p^.ProcPtr := CastProc; p^.Ext2 := Tag; Result := True; exit; end; if s = '*' then {compare function} begin p^.ProcPtr := CompareProc; p^.Ext2 := Tag; Result := True; exit; end; s2 := copy(S, 1, pos('|', s)-1); delete(s, 1, length(s2) + 1); H := MakeHash(s2); ISRead := False; cl := nil; for I := TIFPSRuntimeClassImporter(Tag).FClasses.Count -1 downto 0 do begin Cl := TIFPSRuntimeClassImporter(Tag).FClasses.GetItem(I); if (Cl.FClassNameHash = h) and (cl.FClassName = s2) then begin IsRead := True; break; end; end; if not isRead then begin Result := False; exit; end; s2 := copy(S, 1, pos('|', s)-1); delete(s, 1, length(s2) + 1); if (s2 <> '') and (s2[length(s2)] = '@') then begin IsRead := False; Delete(S2, length(s2), 1); end else isRead := True; H := MakeHash(s2); for i := cl.FClassItems.Count -1 downto 0 do begin px := cl.FClassItems.GetItem(I); if (px^.FNameHash = h) and (px^.FName = s2) then begin p^.ExportDecl := s; case px^.b of {0: ext1=ptr} {1: ext1=pointerinlist} {2: ext1=propertyinfo} {3: ext1=readfunc; ext2=writefunc} 4: begin p^.ProcPtr := ClassCallProc04; p^.Ext1 := px^.Ptr; p^.Ext2 := Tag; end; 5: begin p^.ProcPtr := ClassCallProc05; p^.Ext1 := px^.Ptr; p^.Ext2 := Tag; end; 6: begin p^.ProcPtr := ClassCallProc06; if IsRead then begin p^.Ext1 := px^.FReadFunc; p^.Ext2 := nil; end else begin p^.Ext1 := nil; p^.Ext2 := px^.FWriteFunc; end; end; 0: begin p^.ProcPtr := ClassCallProc01; p^.Ext1 := px^.Ptr; p^.Ext2 := nil; end; 1: begin p^.ProcPtr := ClassCallProc01; p^.Ext1 := px^.PointerInList; p^.ext2 := pointer(1); end; 3: begin p^.ProcPtr := ClassCallProc3; if IsRead then begin p^.Ext1 := px^.FReadFunc; p^.Ext2 := nil; end else begin p^.Ext1 := nil; p^.Ext2 := px^.FWriteFunc; end; end; else begin result := false; exit; end; end; Result := true; exit; end; end; pp := GetPropInfo(cl.FClass.ClassInfo, s2); if pp <> nil then begin p^.ProcPtr := ClassCallProc2; p^.Ext1 := pp; if IsRead then p^.Ext2 := Pointer(1) else p^.Ext2 := Pointer(0); Result := True; end else result := false; end; procedure RegisterClassLibraryRuntime(SE: TIFPSExec; Importer: TIFPSRuntimeClassImporter); begin SE.AddSpecialProcImport('class', SpecImport, Importer); end; { TIFPSRuntimeClass } constructor TIFPSRuntimeClass.Create(aClass: TClass); begin inherited Create; FClass := AClass; FClassName := FastUpperCase(aClass.ClassName); FClassNameHash := MakeHash(FClassName); FClassItems:= TIfList.Create; FEndOfVmt := MaxInt; end; destructor TIFPSRuntimeClass.Destroy; var I: Longint; P: PClassItem; begin for i:= FClassItems.Count -1 downto 0 do begin P := FClassItems.GetItem(I); Dispose(p); end; FClassItems.Free; inherited Destroy; end; procedure TIFPSRuntimeClass.RegisterVirtualAbstractMethod(ClassDef: TClass; ProcPtr: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 1; p^.PointerInList := FindVirtualMethodPtr(Self, ClassDef, ProcPtr); FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterConstructor(ProcPtr: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 4; p^.Ptr := ProcPtr; FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterMethod(ProcPtr: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 0; p^.Ptr := ProcPtr; FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterPropertyHelper(ReadFunc, WriteFunc: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 3; p^.FReadFunc := ReadFunc; p^.FWriteFunc := WriteFunc; FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterVirtualConstructor(ProcPtr: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 5; p^.PointerInList := FindVirtualMethodPtr(Self, FClass, ProcPtr); FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterVirtualMethod(ProcPtr: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 1; p^.PointerInList := FindVirtualMethodPtr(Self, FClass, ProcPtr); FClassItems.Add(p); end; procedure TIFPSRuntimeClass.RegisterEventPropertyHelper(ReadFunc, WriteFunc: Pointer; const Name: string); var P: PClassItem; begin New(P); p^.FName := Name; p^.FNameHash := MakeHash(Name); p^.b := 6; p^.FReadFunc := ReadFunc; p^.FWriteFunc := WriteFunc; FClassItems.Add(p); end; { TIFPSRuntimeClassImporter } function TIFPSRuntimeClassImporter.Add(aClass: TClass): TIFPSRuntimeClass; begin Result := TIFPSRuntimeClass.Create(aClass); FClasses.Add(Result); end; procedure TIFPSRuntimeClassImporter.Clear; var I: Longint; begin for i := 0 to FClasses.Count -1 do begin TIFPSRuntimeClass(FClasses.GetItem(I)).Free; end; FClasses.Clear; end; constructor TIFPSRuntimeClassImporter.Create; begin inherited Create; FClasses := TIfList.Create; end; destructor TIFPSRuntimeClassImporter.Destroy; begin Clear; FClasses.Free; inherited Destroy; end; procedure SetVariantToClass(V: PIFVariant; Cl: TObject); begin if v <> nil then begin v^.tResourceP1 := cl; if cl <> nil then v^.tResourceFreeProc := DummyResourceFree else v^.TResourceFreeProc := nil; end; end; { } function BGRFW(var s: string): string; var l: Longint; begin l := Length(s); while l >0 do begin if s[l] = ' ' then begin Result := copy(s, l + 1, Length(s) - l); Delete(s, l, Length(s) - l + 1); exit; end; Dec(l); end; Result := s; s := ''; end; function MyAllMethodsHandler2(Self: PScriptMethodInfo; const Stack: PPointer; _EDX, _ECX: Pointer): Integer; forward; procedure MyAllMethodsHandler; // On entry: // EAX = Self pointer // EDX, ECX = param1 and param2 // STACK = param3... paramcount asm push ecx push edx mov edx, esp add edx, 12 pop ecx call MyAllMethodsHandler2 mov edx, [esp] add esp, eax mov [esp], edx end; function MyAllMethodsHandler2(Self: PScriptMethodInfo; const Stack: PPointer; _EDX, _ECX: Pointer): Integer; var Decl: string; I, C, regno: Integer; Params: TIfList; // VarParams: TIfList; Tmp: PIFVariant; cpt: PIFTypeRec; fmod: char; s,e: string; FStack: pointer; begin Decl := PIFProcRec(Self^.Se.FProcs.GetItem(Self^.ProcNo))^.ExportDecl; FStack := Stack; Params := TIfList.Create; // VarParams := TIfList.Create; s := decl; grfw(s); while s <> '' do begin Params.Add(nil); grfw(s); end; c := Params.Count; regno := 0; I := C -1 ; Result := 0; s := decl; grfw(s); while I >= 0 do begin e := grfw(s); fmod := e[1]; delete(e, 1, 1); cpt := Self.Se.GetTypeNo(StrToInt(e)); if fmod = '!' then begin case cpt.BaseType of btResourcePointer: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); Tmp^.tResourceP1:= Pointer(Pointer(_EDX)^); tmp^.tResourceFreeProc := DummyResourceFree; end else if regno = 1 then begin Inc(regno); Tmp^.tResourceP1:= Pointer(Pointer(_ECX)^); tmp^.tResourceFreeProc := DummyResourceFree; end; // VarParams.Add(tmp); Params.SetItem(I, Tmp); end; btString, btPChar: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); string(Tmp^.tString):= string(Pointer(_EDX)^); end else if regno = 1 then begin Inc(regno); string(Tmp^.tstring):= string(Pointer(_ECX)^); end; // VarParams.Add(tmp); Params.SetItem(I, Tmp); end; btDouble{$IFNDEF NOINT64}, btS64{$ENDIF}: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); Move(Pointer(_EDX)^, tmp^.tDouble, 8); end else if regno = 1 then begin Inc(regno); Move(Pointer(_ECX)^, tmp^.tDouble, 8); end; // VarParams.Add(tmp); Params.SetItem(I, Tmp); end; btExtended: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); Move(Pointer(_EDX)^, tmp^.textended, 10); end else if regno = 1 then begin Inc(regno); Move(Pointer(_ECX)^, tmp^.textended, 10); end; // VarParams.Add(tmp); Params.SetItem(I, Tmp); end; btSingle, btU8, btS8, Btu16, bts16, btu32, bts32: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); Tmp^.ts32 := Longint(Pointer(_EDX)^); end else if regno = 1 then begin Inc(regno); Tmp^.ts32:= Longint(Pointer(_ECX)^); end; // VarParams.Add(tmp); Params.SetItem(I, Tmp); end; else begin FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF} Params); // FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF} VarParams); end; end; end else begin case cpt.BaseType of btResourcePointer: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt);; if regno = 0 then begin Inc(regno); Tmp^.tResourceP1 := _EDX; tmp^.tResourceFreeProc := DummyResourceFree; end else if regno = 1 then begin Inc(regno); Tmp^.tResourceP1 := _ECX; tmp^.tResourceFreeProc := DummyResourceFree; end; Params.SetItem(I, Tmp); end; btString: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); string(Tmp^.tstring) := string(_EDX); end else if regno = 1 then begin Inc(regno); string(Tmp^.tstring) := string(_ECX); end; Params.SetItem(I, Tmp); end; btU8, btS8, Btu16, bts16, btu32, bts32: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); if regno = 0 then begin Inc(regno); Tmp^.ts32 := Longint(_EDX); end else if regno = 1 then begin Inc(regno); Tmp^.ts32 := Longint(_ECX); end; Params.SetItem(I, Tmp); end; end; end; dec(i); if regno = 2 then break; end; s := decl; grfw(s); for I := 0 to C-1 do begin e := BGRFW(s); if Params.GetItem(I) = nil then begin fmod := e[1]; Delete(e, 1, 1); cpt := Self.Se.GetTypeNo(StrToInt(e)); if fmod = '!' then begin case cpt.BaseType of btResourcePointer: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Tmp^.tResourceP1 := Pointer(Pointer(FStack^)^); tmp^.tResourceFreeProc := DummyResourceFree; FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); // VarParams.Add(Tmp); Params.SetItem(I, Tmp); end; btString: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); String(Tmp^.tstring) := string(FStack^); FStack := Pointer(Pointer(Longint(FStack) + 4)^); Inc(Result, 4); // VarParams.Add(Tmp); Params.SetItem(I, Tmp); end; btDouble{$IFNDEF NOINT64}, bts64{$ENDIF}: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Move(Pointer(FStack^)^, Tmp^.tDouble, 8); FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); // VarParams.Add(Tmp); Params.SetItem(I, Tmp); end; btExtended: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Move(Pointer(FStack^)^, Tmp^.tExtended, 10); FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); // VarParams.Add(Tmp); Params.SetItem(I, Tmp); end; btSingle, btS8, btu8, bts16, btu16, bts32, btu32: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Move(Pointer(FStack^)^, Tmp^.ts32, 4); FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); // VarParams.Add(Tmp); Params.SetItem(I, Tmp); end; else begin FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}Params); // VarParams.Free; exit; end; end; end else begin case cpt.BaseType of btResourcePointer: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); tmp^.tResourceP1 := Pointer(FStack^); tmp^.tResourceFreeProc := DummyResourceFree; FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); Params.SetItem(I, tmp); end; btString: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); string(Tmp^.tstring):= string(FStack^); FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); Params.SetItem(I, tmp); end; btDouble{$IFNDEF NOINT64}, bts64{$ENDIF}: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Move(FStack^, Tmp^.tDouble, 8); FStack := Pointer(Longint(FStack) + 8); Inc(Result, 8); Params.SetItem(I, tmp); end; btExtended: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Move(FStack^, Tmp^.tExtended, 10); FStack := Pointer(Longint(FStack) + 12); Inc(Result, 12); Params.SetItem(I, tmp); end; btSingle, bts8, btu8, bts16, btu16, bts32, btu32: begin Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Tmp^.ts32 := Longint(FStack^); Params.SetItem(I, tmp); FStack := Pointer(Longint(FStack) + 4); Inc(Result, 4); end; else begin FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}Params); // VarParams.Free; exit; end; end; end; end; end; s := decl; e := grfw(s); (* if e <> '-1' then begin cpt := Self.Se.GetTypeNo(StrToInt(e)); Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Params.Add(tmp); end; *) Self.Se.RunProc(Params, Self.ProcNo); (* if e <> '-1' then begin cpt := Self.Se.GetTypeNo(StrToInt(e)); Tmp := CreateVariant({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}cpt); Params.Add(tmp); end; *) FStack := Stack; regno := 0; I := C-1; while I >= 0 do begin e := grfw(s); fmod := e[1]; delete(e, 1, 1); cpt := Self.Se.GetTypeNo(StrToInt(e)); if fmod = '!' then begin case cpt.BaseType of btResourcePointer: begin tmp := Params.GetItem(I); if regno = 0 then begin Inc(regno); Pointer(Pointer(_EDX)^) := Tmp^.tResourceP1; end else if regno = 1 then begin Inc(regno); Pointer(Pointer(_ECX)^) := Tmp^.tResourceP1; end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); Params.SetItem(I, nil); end; btString: begin tmp := Params.GetItem(I); if regno = 0 then begin Inc(regno); string(Pointer(_EDX)^) := string(Tmp^.tstring); end else if regno = 1 then begin Inc(regno); string(Pointer(_ECX)^) := string(Tmp^.tstring); end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); Params.SetItem(I, nil); end; btDouble{$IFNDEF NOINT64}, bts64{$ENDIF}: begin tmp := Params.GetItem(I); if regno = 0 then begin Inc(regno); Move(tmp^.tDouble, Pointer(_EDX)^, 8); end else if regno = 1 then begin Inc(regno); Move(tmp^.tDouble, Pointer(_ECX)^, 8); end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); Params.SetItem(I, nil); end; btExtended: begin tmp := Params.GetItem(I); if regno = 0 then begin Inc(regno); Move(tmp^.tExtended, Pointer(_EDX)^, 10); end else if regno = 1 then begin Inc(regno); Move(tmp^.tExtended, Pointer(_ECX)^, 10); end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); Params.SetItem(I, nil); end; btSingle, bts8, btu8, bts16, btu16, bts32, btu32: begin tmp := Params.GetItem(I); if regno = 0 then begin Inc(regno); Longint(Pointer(_EDX)^) := Tmp^.ts32; end else if regno = 1 then begin Inc(regno); Longint(Pointer(_ECX)^) := Tmp^.ts32; end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); Params.SetItem(I, nil); end; else begin FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}Params); // VarParams.Free; exit; end; end; end else begin case cpt.BaseType of btResourcePointer, btString, bts8, btu8, bts16, btu16, bts32, btu32: begin Inc(regno); DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}Params.GetItem(I)); Params.SetItem(I, nil); end; end; end; Dec(i); end; s := Decl; grfw(s); for I := 0 to C - 1 do begin e := BGRFW(s); fmod := e[1]; delete(e, 1, 1); cpt := Self.Se.GetTypeNo(StrToInt(e)); tmp := Params.GetItem(i); if tmp <> nil then begin if (fmod = '!') then begin case cpt.BaseType of btResourcePointer: begin Pointer(Pointer(FStack^)^) := tmp^.tResourceP1; FStack := Pointer(Longint(FStack) + 4); end; btString: begin string(FStack^) := string(Tmp^.tstring); FStack := Pointer(Pointer(Longint(FStack) + 4)^); end; btDouble{$IFNDEF NOINT64}, bts64{$ENDIF}: begin Move(Tmp^.tDouble, Pointer(FStack^)^, 8); FStack := Pointer(Longint(FStack) + 4); end; btExtended: begin Move(Tmp^.tExtended, Pointer(FStack^)^, 10); FStack := Pointer(Longint(FStack) + 4); end; btSingle, bts8, btu8, bts16, btu16, bts32, btu32: begin Longint(Pointer(FStack^)^) := Tmp^.ts32; FStack := Pointer(Longint(FStack) + 4); end; else begin FreePIFVariantList({$IFNDEF NOSMARTMM}Self.Se.MM, {$ENDIF}Params); exit; end; end; end; DisposeVariant({$IFNDEF NOSMARTMM}Self.Se.mm, {$ENDIF}tmp); end; end; Params.Free; end; function TIFPSRuntimeClassImporter.FindClass(const Name: string): TIFPSRuntimeClass; var h, i: Longint; p: TIFPSRuntimeClass; begin h := MakeHash(Name); for i := FClasses.Count -1 downto 0 do begin p := FClasses.GetItem(i); if (p.FClassNameHash = h) and (p.FClassName = Name) then begin Result := P; exit; end; end; Result := nil; end; initialization DelphiRPFunc := ClassRuntimeGetRPFuncs; end.