Delphi 创建建具有“反射调用”功能的类

Delphi通过JNI调用Java类完整实战项目 Spring Boot打包的jar用了特殊的,直接FindClass是找不到的。得用反射:varbegin// 获取当前线程'));// 获取上下文类加载器'));// 反射调用loadClass');end; 阅读详情

有的时候你会希望自己定义的一个Class在运行期能增加一个property、function,或者一个方法能完全改变他的行为,又或者你希望通过方法名来调用方法(类似JAVA)。

这样的效果可以利用AutoObject的后绑定特性来实现。

第一步、模拟实现一个AutoObject。

其实关键部分是要实现IDispatch的GetIDsOfNames(通过函数(属性)名称获取函数ID),和Invoke(调用指定DispID的方法)。完成之后,TRefClass便有了后帮定特性。可以赋值给Variant变量。

第二步、用一个List 保存增加的属性名称、方法名称、方法指针。以便GetIDsOfNames能找到指定的方法。

第三步、对已知方法调用、属性赋值处理比较简单。对动态增加的方法,由于参数未知,和参数的传递方式不同,处理起来相对困难(下面的例子支持简单参数类型Stdcall。

  TRefClass = class(TInterfacedObject, IDispatch)
  private
    function CallFunction(ProcAddress: Pointer; var Params: TDispParams): variant;
  protected
    FList: TCustomList;
    function GetFieldValue(DataField: String): Variant; virtual;
    procedure SetFieldValue(DataField: String; Value: Variant); virtual;
    function ClassMapp: variant;
    procedure AddProperty(Attribute: String; Default: variant);
    function GetProperty(Attribute: String): variant;
    function FindProperty(DataField: String): boolean;
    procedure AddProcedure(ProName: string; Address: Pointer; OfObject: TObject);

    {IDispatch}
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; virtual; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; virtual; stdcall;

  public
    constructor Create(AOwner: TComponent); virtual;
    destructor Destroy; override;
    class function CreateAsAutoObject(AOwner: TComponent): variant;
  end;
 implementation
procedure TRefClass .AddProcedure(ProName: string; Address: Pointer;
  OfObject: TObject);
var
  pMethod: ^TSetPropertyProc;
begin
  pMethod := AllocMem(SizeOf(TSetPropertyProc));
  TMethod(pMethod^).Data := OfObject;
  TMethod(pMethod^).Code := Address;

  FList.Add(ProName, PointerToVariant(pMethod));
end;

procedure TRefClass .AddProperty(Attribute: String; Default: variant);
begin
  FList.Add(Attribute, Default);
end;
function TRefClass .CallFunction(ProcAddress: Pointer;
  var Params: TDispParams): variant;

  function GetParamAdrs(Value: Variant): Pointer;
  var
    s: PString;
    k: PInteger;
    F: PExtended;
  begin
    case TVarData(Value).VType of
      varInteger, varSmallint, varSingle:
        begin
          New(k);
          K^ := Value;
          Result := K;
        end;
      varOleStr, varString:
        begin
          New(S);
          s^ := Value;
          Result := S;
        end;
      varDouble, varCurrency:
        begin
          New(F);
          F^ := Value;
          Result := F;
        end;
      else
        Result := nil;
    end;
  end;
var
  i: Integer;
  pParams: array of Pointer;
  p: TMethod;
  pCount: Integer;
begin
  pCount := Params.cArgs;
  SetLength(pParams, pCount);
  FillChar(pParams[0], pCount*Sizeof(Pointer), 0);
  p := TMethod(ProcAddress^);

  for i:=pCount-1 downto 0 do
  begin
    pParams[pCount-1-i] := GetParamAdrs(Variant(DispParams(Params).rgvarg^[i]));
  end;

  asm
//    push eax
//    push ecx
//    push edx
//    //push p.Data
    cmp pCount, 1
    JB @exec
    JE @One
    cmp pCount, 2
    JE @two
    @ThreeUp:
      CLD
      mov ecx, pCount
      sub ecx, 2
      mov edx, 4
      add edx, 4
    @loop:
      mov eax, [pParams]
      mov eax, [eax]+edx
      mov eax, [eax]
      push eax
      add edx, 4
      Loop @loop
    @Two:
      mov ecx, [pParams]
      mov ecx, [ecx]+4
      mov ecx, [ecx]
    @One:
      mov edx, [pParams]
      mov edx, [edx]
      mov edx, [edx]
    @exec:
      mov eax, p.Data
      test eax, eax
      je @1
      jne @call
      @1:
        mov eax, edx
        mov edx, ecx
        pop ecx
        jmp @call
      @call:
        call P.Code
//    pop edx
//    pop ecx
//    pop eax
  end;

  for i:=0 to pCount-1 do
    Dispose(pParams[i]);
end;

function TRefClass .ClassMapp: variant;
begin
  result := Self as IDispatch;
end;

constructor TRefClass .Create(AOwner: TComponent);
begin
  inherited Create;
  FOwner := AOwner;
  FList := TCustomList.Create();
end;

class function TRefClass .CreateAsAutoObject(AOwner: TComponent): variant;
begin
  result := Create(AOwner).ClassMapp;
end;

destructor TRefClass .Destroy;
begin
  FList.free;
  inherited;
end;

function TRefClass .FindProperty(DataField: String): boolean;
begin
  result := false;
end;

function TRefClass .GetFieldValue(DataField: String): Variant;
var
  P: PPropInfo;
  V: variant;
  TypeData: PTypeData;
  PFunction: ^TGetPropertyFunction;
  k: integer;
begin
  V := FList[DataField];
  if TVarData(V).Reserved1=1 then
  begin
    P := VariantToPointer(V);
    case P^.PropType^.Kind of
      tkInteger, tkChar, tkWChar, tkClass:
        result := GetOrdProp(FOwner, P);
      tkEnumeration:
        begin
          TypeData := GetTypeData(P^.PropType^);
          if TypeData^.BaseType^ = TypeInfo(Boolean) then
            Result := Boolean(GetOrdProp(FOwner, P))
          else
            Result := GetOrdProp(FOwner, P);
        end;
      tkFloat:
        Result := GetFloatProp(FOwner, P);
      tkString, tkLString, tkWString:
        Result := GetStrProp(FOwner, P);
      tkSet:
        Result := GetSetProp(FOwner, P);
      tkMethod:
        Result := P^.PropType^.Name;
      tkVariant:
        Result := GetVariantProp(FOwner, P);
      tkInt64:
        Result := GetInt64Prop(FOwner, P) + 0.0;
      tkDynArray,
      tkArray,
      tkRecord,
      tkInterface:;
    end;
  end
  else
  begin
    k := FList.IndexOf(Format('Get%s', [DataField]));
    if k<>-1 then
    begin
      PFunction := VariantToPointer(FList.Items[k]);
      V := PFunction^;
    end;
    result := V;
  end;
end;

function TRefClass .GetIDsOfNames(const IID: TGUID; Names: Pointer;
  NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
const
  FUNCLIST: array[1..4] of String =
    ('AddProperty', 'GetProperty', 'FindProperty', 'AddProcedure');
var
  S: String;
  DispID: integer;
  i: integer;
begin
  s := WideString(POleStrList(Names)^[0]);
  DispID := 0;
  for i := 1 to 4 do
    if CompareText(S, FUNCLIST[i])=0 then
    begin
      DispID := -1*i;
      break;
    end;
  if DispID = 0 then
  begin
    DispID := FList.IndexOf(S);

    if DispID = -1 then
    begin
      result := E_NOTIMPL;
      exit;
    end;
  end;
  PDispIdList(DispIDs)^[0] := DispID;
  result := S_OK;
end;

function TRefClass .GetProperty(Attribute: String): variant;
begin
  result := GetFieldValue(Attribute);
end;

function TRefClass .GetTypeInfo(Index, LocaleID: Integer;
  out TypeInfo): HResult;
begin
  result := S_OK;
end;

function TRefClass .GetTypeInfoCount(out Count: Integer): HResult;
begin
  result := S_OK;
end;

function TRefClass .Invoke(DispID: Integer; const IID: TGUID;
  LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
  ArgErr: Pointer): HResult;
Var
  V: Variant;
  P: Pointer;
begin
  case DispID of
    -1:
      begin
        if PDispParams(@Params)^.cArgs=1 then
          AddProperty(OleVariant(PDispParams(@Params).rgvarg^[0]), NULL)
        else
          AddProperty(OleVariant(PDispParams(@Params).rgvarg^[1]), OleVariant(PDispParams(@Params).rgvarg^[0]))
      end;
    -2:
      V := FindProperty(OleVariant(PDispParams(@Params).rgvarg^[0]));
    -3:
      V := GetProperty(OleVariant(PDispParams(@Params).rgvarg^[0]));
    -4:
      if PDispParams(@Params)^.cArgs=2 then
        AddProcedure(OleVariant(PDispParams(@Params).rgvarg^[1]),
          VariantToPointer(OleVariant(PDispParams(@Params).rgvarg^[0])), nil)
      else if PDispParams(@Params)^.cArgs=3 then
        AddProcedure(OleVariant(PDispParams(@Params).rgvarg^[2]),
          VariantToPointer(OleVariant(PDispParams(@Params).rgvarg^[1])),
          VariantToPointer(OleVariant(PDispParams(@Params).rgvarg^[0])));
    else
    begin
      if (Flags and DISPATCH_PROPERTYGET) = DISPATCH_PROPERTYGET then
        V := GetFieldValue(FList.Names[DispID])
      else if (Flags and DISPATCH_PROPERTYPUT) = DISPATCH_PROPERTYPUT then
        SetFieldValue(FList.Names[DispID], OleVariant(PDispParams(@Params).rgvarg^[0]))
      else
      begin
        V := FList.Items[DispID];
        P := VariantToPointer(V);
        V := CallFunction(P, TDispParams(Params));
      end;
    end;
  end;
  if assigned(VarResult) then
    PVariant(VarResult)^ := V;
  result := S_OK;
end;

procedure TRefClass .SetFieldValue(DataField: String; Value: Variant);
  function RangedValue(const AMin, AMax: Int64): Int64;
  begin
    Result := Trunc(Value);
    if Result < AMin then
      Result := AMin;
    if Result > AMax then
      Result := AMax;
  end;
var
  PropInfo: PPropInfo;
  TypeData: PTypeData;
  V: variant;
  PProcedure: ^TSetPropertyProc;
  k: integer;
begin
  V := FList[DataField];

  if TVarData(V).Reserved1=1 then
  begin
    PropInfo := VariantToPointer(V);

    if PropInfo <> nil then
    begin
      case PropInfo.PropType^^.Kind of
        tkInteger, tkChar, tkWChar:
          begin
            TypeData := GetTypeData(PropInfo^.PropType^);
            SetOrdProp(FOwner, PropInfo, RangedValue(TypeData^.MinValue, TypeData^.MaxValue));
          end;
        tkEnumeration:
          if VarType(Value) = varString then
            SetEnumProp(FOwner, PropInfo, VarToStr(Value))
          else
          begin
            TypeData := GetTypeData(PropInfo^.PropType^);
            SetOrdProp(FOwner, PropInfo, RangedValue(TypeData^.MinValue, TypeData^.MaxValue));
          end;
        tkSet:
          if VarType(Value) = varInteger then
            SetOrdProp(FOwner, PropInfo, Value)
          else
            SetSetProp(FOwner, PropInfo, VarToStr(Value));
        tkFloat:
          SetFloatProp(FOwner, PropInfo, Value);
        tkString, tkLString, tkWString:
          SetStrProp(FOwner, PropInfo, VarToStr(Value));
        tkVariant:
          SetVariantProp(FOwner, PropInfo, Value);
        tkInt64:
          begin
            TypeData := GetTypeData(PropInfo^.PropType^);
            SetInt64Prop(FOwner, PropInfo, RangedValue(TypeData^.MinInt64Value, TypeData^.MaxInt64Value));
          end;
      else
      end;
    end;
  end
  else
  begin
    k := FList.IndexOf(Format('Set%s', [DataField]));
    if k<>-1 then
    begin
      PProcedure := VariantToPointer(FList.Items[k]);
      PProcedure^(Value);
    end;
    FList.Add(DataField, Value);
  end;
end;

realsense D455深度相机+YOLO V5结合实现目标检测(一) realsense D455深度相机+YOLO V5结合实现目标检测代码来源环境配置代码分析:1.如何用realsense在python下面调用的问题:2.对main_debug.py文件的分析:结束语 可以实现将D435,D455深度相机和yolo v5结合到一起,在识别物体的同时,还能测到物体相对与相机的距离。 说明一下为什么需要做这个事情?1.首先为什么需要用到realsense D455深度相机? 因为他是普通的相机还加了一个红外测距的东西,所以其他二维图像一样,能够得到三维世界在二维像素平面的投影 阅读详情

相关推荐

新手必看|HDevelop核心算子快速上手,为C#移植打基础

在上一篇文章中,我们完成了C#+HALCON的开发环境搭建。但在实际工业开发中,绝不会直接在C#中编写视觉算法HDevelop可视化调试算法 → 验证效果 → 导出C#代码 → 集成到上位机。HDevelop是HALCON专属的算法调试工具,支持实时预览图像、参数动态调节、零编译运行,是新手入门和工业算法调试的核心工具。本文聚焦工业场景高频使用的核心算子,从基础操作到实战案例,手把手教你使用HDevelop;同时重点讲解算法导出C#的规范,让你调试完成的算法,能无缝移植到WinForm上位机中。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 778

delphi RTTI 反射技术

unit Unit_main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, TypInfo; type TForm_main = class(TForm) Button1...

aldsot0997的博客 421

Windows系统下搭建MPI(并行计算)环境

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;W

weixin_43417960的博客 5752

反射 数据类型_Delphi反射机制初探

在Java中存在着一种强大的功能就是反射,所以我在考虑Delphi出来这么多年了,难道没有支持反射机制吗?经过翻山越岭的一顿搜索终于找到了反射的身影在Delphi中反射称为RTTI(Run-Time Type Information) 翻译过来的名称是"运行期类型信息",也就是说可以在运行期获得数据类型或类(class)的信息反射在我们普通程序开发中基本使用不到,但是在我们底层的程序设计中使用特别...

weixin_36209848的博客 607

使用GEOquery包下载原始数据

使用GEOquery包下载原始数据

m0_75172651的博客 1889

AI数字人直播带货全攻略:从零搭建到高效运营

本文提供了一份从零开始搭建与运营AI数字人直播间的完整指南。详细解析了AI数字人直播带货的核心价值与适用场景,并分步讲解了硬件准备、软件选择、数字人创建、话术编排、OBS推流设置及开播测试等关键环节。最后,文章还分享了高效运营策略与常见避坑指南,旨在帮助商家利用AI技术实现降本增效,打造24小时不间断的智能带货直播间。

weixin_29269441的博客 2233

Delphi 的消息机制浅探(2)

补充知识:TWndMethod 概述 =============================================================================== 写这段基础知识是因为我在阅读 MakeObjectInstance(MainWndProc) 这句时不知道究竟传递了什么东西给 MakeObjectInstance。弄清楚了 TWndMethod

在水一方 2319

基于openEuler配置LAMP,部署WordPress

openEuler 基于OpenEular操作系统部署WordPress,必须包含以下内容: OpenEular的安装与基本配置。 基于SSH远程管理方式开展操作。 部署LAMP环境。 部署WordPress软件。 提供个人网站服务,并通过浏览器测试应用。 简要讲授相关知识与原理。 cd /etc/yum.repos.d 欧拉系统安装后,没有配置yum源,我们需要重新配置。 [root@localhost yum.repos.d]# ls -l 总用量 4 -rw-r--r--

Axiayouqiaomu的博客 6081

Delphi反射

最近在写一个框架,需要用到反射,与C# java这些原生支持反射的语言不同,delphi对反射的支持相对要弱一些,但也够用了,其实C#的大部分的思想还是从 delphi而来,毕竟都是安德鲁斯的杰作。 这是只谈想法,不谈实现。Delphi7里其实就有对反射的支持了,typInfo,objAuto。基本上可以实现大部分的功能。但对静态方法的支持目前还没有好的解决办法。调用objectInvoke时

diligentcat的专栏 2493

超详细网安学习路线(Day1-Day2)

渗透测试(Penetration Testing),就是一种通过模拟恶意攻击者的技术与方法,挫败目标系统安全控制措施,取得访问控制权,并发现具备业务影响后果安全隐患的一种安全测试与评估方法。简单来说,就是合法去入侵别人的系统,来帮助其找出漏洞,增强防护能力。

aobulaien001的博客 3389

Android Binder的两三事--基于Android14源码

Android14-Framework-Binder

保持专注,保持热爱 1140

利用DELPHI编写IE扩展

在自己的程序中使用过WebBrowser控件的朋友都知道,WebBrowser控件定义了诸如BeforeNavigate、DownloadComplete 等事件,我们可以通过编写事件处理代码实现对WebBrowser控件的操作。那么如何实现对IE的事件响应和处理呢?同建立IE面板一样。我们需要建立一个实现IObjectWithSite接口的COM组件,不同的是,我们还需要实现IDispatch接

桂林哈秋 - 我想学编程 1384

Qt入门教程【数据类型篇】数值类型

Qt中的数值类型

小鱼酱的博客 1万+

强大的反射功能动态创建调用dll

你所说的属于“反射”的知识点,反射在 Java、.NET 都是被支持的,并不是所有语言都支持,如:C++ 就没有反射的说法。 “反射”其实就是利用程序集的元数据信息。  反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间, 假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型):  Assembly assembly = Assembly.Lo

zhaoyycit的专栏 1938

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Delphi2010强化的反射

Delphi2010强化的反射

敦格 2954

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Delphi 动态创建类

昨天在看 Java Web 开发时有看到servlet 通过反射动态创建类,想到Delphi中能否实现。 环境 Win10 x64 , Delphi 10.4 需引用System.Rtti ; 发现 private 下的function GetXY:Integer 没有获取到,why? Rtti设计就这样? unit untTest; interface uses Classes,SysUtils,Dialogs; type TTestClass = class(TPer...

xhfbx的博客 725

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

通过反射,创建类的实例二

通过反射,创建类的实例二 这次我们通过传递参数和定义接口的方式来创建实例 namespace Interface { public interface IObjcet { void Put(); void Put(string plus); } } using System; namespace NetStar.Biz {

每天进步一点点 720

Delphi2009 反射机制的使用

Delphi2009中添加了一个用于实现反射的单元,即ObjAuto,用它可以轻松的实现反射。对于原本的RTTI,只能够得到published区分符下的属性,而反射机制则可以得到拥有反射支持的类的公开方法,成员变量和属性。下面是一个小例子:首先写一个拥有反射支持的类,注意类必须继承自TPersistent,并且类声明带有MethodInfo编译预处理。MethodInfo是一个

lee576的专栏 1709

delphi 类 线程 反射 泛型 简单理解

1 unit Unit3; 2 3 interface 4 5 uses 6 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, 7 Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl....

aldsot0997的博客 286

Delphi反射传入var形式的参数

在反射调用方法时,常常会遇到var或out形式的参数,但是Delphi的ObjAuto单元却是不支持如此做的,因此,需要对反射的单元做一些修改,以使其支持var类型的参数 对于var和out两种类型,在Delphi的编译器看来,它们的处理是一样的,只不过out参数会在传入时,先进行一次clear操作。但是其本质还是var,因此,我们将这两种形式的参数放在一起讨论。 从CodeGear提

小虾米的专栏 1282

反射机制传递类_橙子的Delphi技术专区

鉴于某人说Delphi的反射不能传入或传出类,我在此纠正一下这个说法,下面的代码可以证实,类可以传入传出。 由于我已经把D2009的反射单元移去D2007,因此就不用D2009了,所以代码中暂时不考虑Unicode的问题。 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Gr

quasiceo 957
下一篇: 数据仓库定义的理解。
LocustWei
博客等级 码龄26年 1粉丝 6原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值