powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Rtti Invoke
7 сообщений из 7, страница 1 из 1
Rtti Invoke
    #39635721
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Заметил баг, что при вызове TStyleManager.SetStyle он падает с
raised exception class EInvalidCast with message 'Invalid class typecast'.


Пример кода

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, rtti, Vcl.Themes,
  Vcl.Styles;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  rtti: TRttiContext;
  c2: TClass;
  c1: TRttiType;
  m: TRttiMethod;
  p: TRttiParameter;
  fileSkin: string;
  Args: TArray<TValue>;
begin
  c1 := rtti.GetType(TStyleManager);
  c2 := c1.handle.TypeData.ClassType;

  fileSkin := 'CharcoalDarkSlate.vsf';
  for m in c1.GetMethods do
  begin
    if (m.Name = 'SetStyle') and
      (m.GetParameters[0].ParamType.TypeKind = tkPointer) then
    begin
      SetLength(Args, 1);
      Args[0] := TStyleManager.LoadFromFile(fileSkin);
      //  Args[0] := TRttiPointerType(TStyleManager.LoadFromFile(fileSkin));
      m.Invoke(c2, Args);

      // Работает прямой вызов
      // TStyleManager.SetStyle(PPointer(Args[0].GetReferenceToRawData)^);
    end;
  end;
end;

end.




Ошибка просиходит тут
Код: pascal
1.
2.
3.
4.
5.
function TValue.Cast(ATypeInfo: PTypeInfo; const EmptyAsAnyType: Boolean): TValue;
begin
  if not TryCast(ATypeInfo, Result, EmptyAsAnyType) then
    raise EInvalidCast.CreateRes(@SInvalidCast);
end;



Этот баг фиксится ?
...
Рейтинг: 0 / 0
Rtti Invoke
    #39635723
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Падает с типом TStyleServicesHandle

Код: pascal
1.
TStyleServicesHandle = type Pointer;




По имени работает отлиычно. Но когда пытаешься загрузить по указателю на TMemoryStream то он падает
...
Рейтинг: 0 / 0
Rtti Invoke
    #39635732
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Наверно с родным твоерением - нереально баг обойти, только если свой инвок напишешь. Вот так к примеру как написал я


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
procedure TForm1.FormCreate(Sender: TObject);
  function MethodInvoke(c2: TClass; m: TRttiMethod;
    Args: TArray<TValue>): TValue;
  var
    ResultType: PTypeInfo;
    Max, Min: Integer;
    v: TValue;
  begin
    SetLength(Args, Length(Args) + 1);

    Max := High(Args);

    for Min := 0 to High(Args) - 1 do
    begin
      v := Args[Min];
      Args[Min] := Args[Max];
      Args[Max] := v;
      Dec(Max);
    end;

    Args[0] := c2;

    if m.ReturnType <> nil then
      ResultType := m.ReturnType.Handle
    else
      ResultType := nil;

    Result := System.rtti.Invoke(m.CodeAddress, Args, m.CallingConvention,
      ResultType);
  end;

var
  rtti: TRttiContext;
  c2: TClass;
  c1: TRttiType;
  m: TRttiMethod;
  p: TRttiParameter;
  fileSkin: string;
  Args: TArray<TValue>;
begin
  c1 := rtti.GetType(TStyleManager);
  c2 := c1.Handle.TypeData.ClassType;

  fileSkin := 'CharcoalDarkSlate.vsf';
  for m in c1.GetMethods do
  begin
    if (m.Name = 'SetStyle') and
      (m.GetParameters[0].ParamType.TypeKind = tkPointer) then
    begin
      SetLength(Args, 1);
      Args[0] := TStyleManager.LoadFromFile(fileSkin);

      MethodInvoke(c2, m, Args);
    end;
  end;
end;



И всё заработало
...
Рейтинг: 0 / 0
Rtti Invoke
    #39635739
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот инвок который поддерживает конструктор, в добавок теперь не надо следить за конвертированием адресса в TClass и TObject (Только надо следить за передаваемыми параметрами самому) Ну так как я уже конвертирую их из одного языка в другой, исходя из аргументов. То стандартный только двойную операцию делал, и не работал (Этот пока все тесты проходит ранние)

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
function MethodInvoke(c2: pointer; m: TRttiMethod;
  Args: TArray<TValue>): TValue;
type
  PPVtable = ^PVtable;
  PVtable = ^TVtable;
  TVtable = array [0 .. MaxInt div sizeof(pointer) - 1] of pointer;
var
  ResultType: PTypeInfo;
  Max, Min: integer;
  v: TValue;
  plus, lARGS: integer;
  alloc: Boolean;
  cls: TClass;
  obj: TObject;
  code: pointer;
  GetParameters: TArray<TRttiParameter>;
  P: TRttiParameter;
begin
  if m.IsConstructor then
    plus := 2
  else
    plus := 1;

  SetLength(Args, length(Args) + plus);

  Max := High(Args);

  GetParameters := m.GetParameters;
  lARGS := length(GetParameters);

  for Min := 0 to High(Args) - 1 do
  begin
    v := Args[Min];
    if (Min < lARGS) and v.IsEmpty then
    begin
      P := GetParameters[Min];
      if P.ParamType.Handle <> nil then
      begin
        TValue.Make(nil, P.ParamType.Handle, v);
      end;
    end;
    Args[Min] := Args[Max];
    Args[Max] := v;
    Dec(Max);
  end;

  if m.IsConstructor then
  begin
    cls := nil;
    alloc := TValue(c2).TryAsType<TClass>(cls);
    if alloc then
      obj := nil
    else
    begin
      obj := TValue(c2).AsObject;
      if obj <> nil then
        cls := obj.ClassType
      else
        cls := nil;
    end;
    if alloc then
      Args[0] := cls
    else
      Args[0] := obj;

    Args[1] := alloc;

    case m.DispatchKind of
      dkVtable:
        code := PVtable(cls)^[m.VirtualIndex];
      dkDynamic:
        code := GetDynaMethod(cls, m.VirtualIndex);
    else
      code := m.CodeAddress;
    end;
  end
  else
  begin
    Args[0] := c2;
    code := m.CodeAddress;
  end;
  if m.ReturnType <> nil then
    ResultType := m.ReturnType.Handle
  else
    ResultType := nil;

  if m.IsConstructor then
    result := System.rtti.Invoke(code, Args, m.CallingConvention, cls.ClassInfo,
      m.IsStatic, True)
  else
    result := System.rtti.Invoke(code, Args, m.CallingConvention, ResultType);
end;

...
Рейтинг: 0 / 0
Rtti Invoke
    #39635744
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Г.ы А вот целая функция, просто убрано конвертирование

function MethodInvoke(Instance: pointer; m: TRttiMethod;
Args: TArray<TValue>): TValue;
type
PPVtable = ^PVtable;
PVtable = ^TVtable;
TVtable = array [0 .. MaxInt div sizeof(pointer) - 1] of pointer;
procedure PushSelfFirst(CC: TCallConv; var argList: TArray<TValue>;
var Index: integer; const value: TValue); inline;
begin
{$IFDEF CPUX86}
if CC = ccPascal then
exit;
{$ENDIF CPUX86}
argList[Index] := value;
inc(Index);
end;

procedure PushSelfLast(CC: TCallConv; var argList: TArray<TValue>;
var Index: integer; const value: TValue); inline;
begin
{$IFDEF CPUX86}
if CC <> ccPascal then
exit;
argList[Index] := value;
{$ELSE !CPUX86}
{$ENDIF CPUX86}
end;

var
code: pointer;
argCount: integer;
parList: TArray<TRttiParameter>;
i, CurrArg: integer;
cls: TClass;
obj: TObject;
alloc: Boolean;
plus, lARGS, gg, Min, Max: integer;
P: TRttiParameter;
v: TValue;
begin
with m do
begin
argCount := length(Args);
gg := argCount;
if IsConstructor or IsDestructor then
inc(argCount);
if not IsStatic then
inc(argCount);

SetLength(Args, argCount);

lARGS := length(GetParameters);

Max := argCount - 1;

for Min := 0 to gg - 1 do
begin
v := Args[Min];
if (Min < lARGS) and v.IsEmpty then
begin
P := GetParameters[Min];
if P.ParamType.Handle <> nil then
begin
TValue.Make(nil, P.ParamType.Handle, v);
end;
end;
Args[Min] := Args[Max];
Args[Max] := v;
Dec(Max);
end;

CurrArg := 0;
cls := nil;

alloc := True; // avoid warning
obj := nil; // avoid warning

if not IsStatic then
begin
// Two jobs: handle special methods like ctor/dtor, and
// extract metaclass so that vtable lookups can occur.
if IsConstructor then
begin
alloc := TValue(Instance).TryAsType<TClass>(cls);
// flag: should allocate
if alloc then
obj := nil // not used
else
begin
obj := TValue(Instance).AsObject;
if obj <> nil then
cls := obj.ClassType
else
cls := nil;
end;
if alloc then
PushSelfFirst(CallingConvention, Args, CurrArg, cls)
else
PushSelfFirst(CallingConvention, Args, CurrArg, obj);
Args[CurrArg] := alloc;
inc(CurrArg);
end
else if IsDestructor then
begin
cls := TValue(Instance).AsObject.ClassType;
PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
Args[CurrArg] := True;
inc(CurrArg);
end
else if IsClassMethod then
begin
cls := TValue(Instance).AsClass;
PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
end
else
begin
PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
end;

end;

if IsStatic then
code := CodeAddress
else
case DispatchKind of
dkVtable:
code := PVtable(cls)^[VirtualIndex];
dkDynamic:
code := GetDynaMethod(cls, VirtualIndex);
else
code := CodeAddress;
end;

if not IsStatic then
begin
if IsConstructor then
begin
if alloc then
PushSelfLast(CallingConvention, Args, CurrArg, cls)
else
PushSelfLast(CallingConvention, Args, CurrArg, obj);
end
else
PushSelfLast(CallingConvention, Args, CurrArg, Instance);
end;

if ReturnType <> nil then
result := System.rtti.Invoke(code, Args, CallingConvention,
ReturnType.Handle, IsStatic)
else if IsConstructor then
result := System.rtti.Invoke(code, Args, CallingConvention, cls.ClassInfo,
IsStatic, True)
else
result := System.rtti.Invoke(code, Args, CallingConvention, nil);
end;
end;

[SRC delphi][/SRC]
...
Рейтинг: 0 / 0
Rtti Invoke
    #39635746
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
function MethodInvoke(Instance: pointer; m: TRttiMethod;
  Args: TArray<TValue>): TValue;
type
  PPVtable = ^PVtable;
  PVtable = ^TVtable;
  TVtable = array [0 .. MaxInt div sizeof(pointer) - 1] of pointer;
  procedure PushSelfFirst(CC: TCallConv; var argList: TArray<TValue>;
    var Index: integer; const value: TValue); inline;
  begin
{$IFDEF CPUX86}
    if CC = ccPascal then
      exit;
{$ENDIF CPUX86}
    argList[Index] := value;
    inc(Index);
  end;

  procedure PushSelfLast(CC: TCallConv; var argList: TArray<TValue>;
    var Index: integer; const value: TValue); inline;
  begin
{$IFDEF CPUX86}
    if CC <> ccPascal then
      exit;
    argList[Index] := value;
{$ELSE !CPUX86}
{$ENDIF CPUX86}
  end;

var
  code: pointer;
  argCount: integer;
  parList: TArray<TRttiParameter>;
  i, CurrArg: integer;
  cls: TClass;
  obj: TObject;
  alloc: Boolean;
  plus, lARGS, gg, Min, Max: integer;
  P: TRttiParameter;
  v: TValue;
begin
  with m do
  begin
    argCount := length(Args);
    gg := argCount;
    if IsConstructor or IsDestructor then
      inc(argCount);
    if not IsStatic then
      inc(argCount);

    SetLength(Args, argCount);

    lARGS := length(GetParameters);

    Max := argCount - 1;

    for Min := 0 to gg - 1 do
    begin
      v := Args[Min];
      if (Min < lARGS) and v.IsEmpty then
      begin
        P := GetParameters[Min];
        if P.ParamType.Handle <> nil then
        begin
          TValue.Make(nil, P.ParamType.Handle, v);
        end;
      end;
      Args[Min] := Args[Max];
      Args[Max] := v;
      Dec(Max);
    end;

    CurrArg := 0;
    cls := nil;

    alloc := True; // avoid warning
    obj := nil; // avoid warning

    if not IsStatic then
    begin
      // Two jobs: handle special methods like ctor/dtor, and
      // extract metaclass so that vtable lookups can occur.
      if IsConstructor then
      begin
        alloc := TValue(Instance).TryAsType<TClass>(cls);
        // flag: should allocate
        if alloc then
          obj := nil // not used
        else
        begin
          obj := TValue(Instance).AsObject;
          if obj <> nil then
            cls := obj.ClassType
          else
            cls := nil;
        end;
        if alloc then
          PushSelfFirst(CallingConvention, Args, CurrArg, cls)
        else
          PushSelfFirst(CallingConvention, Args, CurrArg, obj);
        Args[CurrArg] := alloc;
        inc(CurrArg);
      end
      else if IsDestructor then
      begin
        cls := TValue(Instance).AsObject.ClassType;
        PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
        Args[CurrArg] := True;
        inc(CurrArg);
      end
      else if IsClassMethod then
      begin
        cls := TValue(Instance).AsClass;
        PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
      end
      else
      begin
        PushSelfFirst(CallingConvention, Args, CurrArg, Instance);
      end;

    end;

    if IsStatic then
      code := CodeAddress
    else
      case DispatchKind of
        dkVtable:
          code := PVtable(cls)^[VirtualIndex];
        dkDynamic:
          code := GetDynaMethod(cls, VirtualIndex);
      else
        code := CodeAddress;
      end;

    if not IsStatic then
    begin
      if IsConstructor then
      begin
        if alloc then
          PushSelfLast(CallingConvention, Args, CurrArg, cls)
        else
          PushSelfLast(CallingConvention, Args, CurrArg, obj);
      end
      else
        PushSelfLast(CallingConvention, Args, CurrArg, Instance);
    end;

    if ReturnType <> nil then
      result := System.rtti.Invoke(code, Args, CallingConvention,
        ReturnType.Handle, IsStatic)
    else if IsConstructor then
      result := System.rtti.Invoke(code, Args, CallingConvention, cls.ClassInfo,
        IsStatic, True)
    else
      result := System.rtti.Invoke(code, Args, CallingConvention, nil);
  end;
end;

...
Рейтинг: 0 / 0
Rtti Invoke
    #39635747
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Даже TStyleManager::GetStyle заработал
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Rtti Invoke
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]