base_event.pas

来自「Delphi脚本控件」· PAS 代码 · 共 704 行 · 第 1/2 页

PAS
704
字号
////////////////////////////////////////////////////////////////////////////
// PAXScript Interpreter
// Author: Alexander Baranovsky (ab@cable.netlux.org)
// ========================================================================
// Copyright (c) Alexander Baranovsky, 2003-2005. All rights reserved.
// Code Version: 3.0
// ========================================================================
// Unit: BASE_EVENT.pas
// ========================================================================
////////////////////////////////////////////////////////////////////////////


{$I PaxScript.def}
{$B-}

unit BASE_EVENT;
interface
uses
   Classes,
   TypInfo,
   SysUtils,
   BASE_SYS,
   BASE_CLASS,
   BASE_EXTERN;

type
  TPAXEventHandler = class
  public
    Scripter: Pointer;
    SubID: Integer;
    This: Variant;
    ParamCount: Integer;
    Parameters: array of TVarRec;
    ParamTypes: TStringList;
    _EAX, _EDX, _ECX: Integer;
    _P: Pointer;
    RetSize: Integer;
    DelphiInstance: TObject;
    PropInfo: PPropInfo;

    HostHandler: TMethod;
    OverrideHandlerMode: Integer;

    constructor Create(Scripter: Pointer;
                       pti: PTypeInfo;
                       SubID: Integer;
                       const This: Variant);
    destructor Destroy; override;
    procedure Invoke;
    procedure HandleEvent;
  end;

 TPAXEventHandlerList = class(TList)
   procedure ClearHandlers;
   destructor Destroy; override;
 end;

implementation

uses
  BASE_SCRIPTER,
  BASE_CALL;

destructor TPAXEventHandlerList.Destroy;
begin
  ClearHandlers;
  inherited;
end;

procedure TPAXEventHandlerList.ClearHandlers;
var
  I: Integer;
  M: TMethod;
  H: TPAXEventHandler;
begin
  M.Code := nil;
  M.Data := nil;
  for I:=0 to Count - 1 do
  begin
    H := TPAXEventHandler(Items[I]);

    if IsDelphiObject(H.DelphiInstance) then
      SetMethodProp(H.DelphiInstance, H.PropInfo, M);

    H.Free;
  end;
  Clear;
end;

constructor TPAXEventHandler.Create(Scripter: Pointer;
                                    pti: PTypeInfo;
                                    SubID: Integer;
                                    const This: Variant);
type
  TParamData = record
    Flags: TParamFlags;
    ParamName, TypeName: ShortString;
  end;
  PParamData = ^TParamData;
var
  ptd: PTypeData;
  PParam: PParamData;
  PTypeString: ^ShortString;
  I: Integer;
begin
  inherited Create;

  OverrideHandlerMode := 0;

  with TPAXBaseScripter(Scripter) do
  begin
    if SymbolTable.Kind[SubID] = KindTYPE then
      while SymbolTable.Kind[SubID] <> KindSUB do
        Inc(SubID);
  end;

  Self.SubID := SubID;
  Self.Scripter := Scripter;
  Self.This := This;

  ptd := GetTypeData(pti);
  ParamCount := ptd^.ParamCount;
  SetLength(Parameters, ParamCount);
  ParamTypes := TStringList.Create;

  PParam := PParamData(@(ptd^.ParamList));
  for I:=0 to ParamCount - 1 do
  begin
    PTypeString := ShiftPointer(PParam, SizeOf(TParamFlags) + Length(PParam^.ParamName) + 1);
    ParamTypes.Add(PTypeString^);
    PParam := ShiftPointer(PTypeString, Length(PTypeString^) + 1);
  end;
end;

destructor TPAXEventHandler.Destroy;
begin
  ParamTypes.Free;
  inherited Destroy;
end;

var
  PThis: PVariant;

procedure TPAXEventHandler.Invoke;

type
  PWord = ^Word;
  PShortInt = ^ShortInt;
  PSmallInt = ^SmallInt;
  PByte = ^Byte;

procedure Adjust(var Val: Integer);
type
  T = array[1..4] of Byte;
begin
  T(Val)[2] := 0;
  T(Val)[3] := 0;
  T(Val)[4] := 0;
end;

var
  I, J, Index: Integer;
  S: String;
  R, V: Variant;
  SO: TPAXScriptObject;
  ClassRec: TPAXClassRec;
  RTTITypeDefinition: TPAXRTTITypeDefinition;
  pti: PTypeInfo;
  ptd: PTypeData;
  SZ: Integer;
  Variants: array[0..30] of Variant;
  IsDelphiObject: Boolean;
  TypeID, ParamID: Integer;
  ByRef: Boolean;

  Ptrs: array[0..30] of Pointer;
  CreatedRecords: TList;

  Pointers: array of Pointer;
  Types, ExtraTypes, Sizes: array of Integer;
  ByRefs: array of Boolean;
  Integers: array[0..30] of Integer;

  InstanceClassRec: TPAXClassRec;
begin
  if not TPAXBaseScripter(Scripter).AllowedEvents then
    Exit;

  CreatedRecords := TList.Create;
  try
    SetLength(Pointers, ParamCount + 1);
    SetLength(Types, ParamCount + 1);
    SetLength(ExtraTypes, ParamCount + 1);
    SetLength(Sizes, ParamCount + 1);
    SetLength(ByRefs, ParamCount + 1);
    for I:=0 to ParamCount do
    begin
      Types[I] := typeCLASS;
      ExtraTypes[I] := 0;
      Sizes[I] := 4;
      Pointers[I] := Self;
    end;
    Types[ParamCount] := 0;

    SZ := 4;
    RetSize := 0;
    _P := ShiftPointer(_P, SZ*(ParamCount - 2));
    SetLength(Parameters, ParamCount);

    if ParamCount > 2 then
    case ParamCount - 2 of
      1: RetSize := 4;
      2: RetSize := 8;
      3: RetSize := 12;
      4: RetSize := 16;
      5: RetSize := 20;
      6: RetSize := 24;
      7: RetSize := 28;
    else
      raise Exception.Create('Too many parameters in event call - scripter limitation');
    end;

    for I:=0 to ParamCount - 1 do
    begin
      with TPAXBaseScripter(Scripter) do
      begin
        ParamID := SymbolTable.GetParamID(SubID, I + 1);
        ByRef := SymbolTable.ByRef[ParamID] = 1;

        ByRefs[I] := ByRef;
      end;

      if ByRef then
        case I of
          0:
          begin
            J := _EDX;
            Ptrs[I + 1] := Pointer(J);
            J := Integer(Ptrs[I + 1]^);
          end;
          1:
          begin
            J := _ECX;
            Ptrs[I + 1] := Pointer(J);
            J := Integer(Ptrs[I + 1]^);
          end;
        else
          begin
            // Set up the variable out of the stack
            J := Integer(_P^);
            Ptrs[I + 1] := Pointer(J);
            J := Integer(Ptrs[I + 1]^);

            // Shift the pointer so we get the right spot next time...
            _P := ShiftPointer(_P, -SZ);
            SZ := 4;
          end;
        end
      else
        case I of
          0: J := _EDX;
          1: J := _ECX;
        else
          begin
            J := Integer(_P^);
            _P := ShiftPointer(_P, -SZ);
            SZ := 4;
          end;
        end;

      S := ParamTypes[I];
      ClassRec := TPAXBaseScripter(Scripter).ClassList.FindClassByName(S);

      IsDelphiObject := ClassRec <> nil;
      if StrEql(S, 'Boolean') or StrEql(S, 'String') then
        IsDelphiObject := false;

      if IsDelphiObject then
        IsDelphiObject := ClassRec.ck in [ckClass];

      if (Assigned(ClassRec)) and (ClassRec.ck = ckStructure)
      then begin
        SO := ClassRec.CreateScriptObject;
        Parameters[I].VType := vtObject;
        Parameters[I].VObject := SO;

        if (ByRef)
        then begin
          SO.ExtraPtr := Ptrs[I + 1];  // We're pointing *right* at the structure, not a reference to it...  J's not.
          SO.ExternalExtraPtr := TRUE; // We don't want to free the memory ourselves...
        end
        else begin
          // OK, we need to create some new memory - otherwise we'll be pointing at the existing one...
          SO.ExtraPtr := AllocMem(SO.ExtraPtrSize);
          Move(Pointer(J)^, SO.ExtraPtr^, SO.ExtraPtrSize);
        end;

        CreatedRecords.Add(SO);

        Types[I] := typeRECORD;
        Pointers[I] := SO.ExtraPtr;
      end
      else if (ClassRec <> nil) and ClassRec.isSet then
      begin
        Integers[I] := J;

//        pti := ClassRec.PtiSet;

        Adjust(J);
//        Variants[I] := SetToVariantArray(J, pti);
        Variants[I] := ByteSetToPaxArray(TByteSet(J), Scripter);

        Parameters[I].VType := vtVariant;
        Parameters[I].VVariant := @Variants[I];

        Types[I] := typeSET;
        Pointers[I] := @ Integers[I];
      end
      else if (ClassRec <> nil) and (ClassRec.ck = ckInterface) then
      begin
        SO := InterfaceToScriptObject(IUnknown(J), Scripter, S);

        Parameters[I].VType := vtObject;
        Parameters[I].VObject := SO;

        Types[I] := typeCLASS;
        Pointers[I] := @ SO.Instance;
      end
      else if (IsDelphiObject)
      then begin
        SO := nil;
        Index := TPAXBaseScripter(Scripter).ScriptObjectList.IndexOfDelphiObject(TObject(J));
        if Index = -1 then
        begin
          if J = 0 then
          begin
            Integers[I] := 0;
            Parameters[I].VType := vtObject;
            Parameters[I].VObject := nil;

            Types[I] := typeCLASS;
            Pointers[I] := @ Integers[I];

            continue;
          end
          else
          begin

            InstanceClassRec :=
              TPaxBaseScripter(Scripter).ClassList.FindClassByName(TObject(J).ClassName);
            if InstanceClassRec = nil then
              InstanceClassRec := ClassRec;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?