Wywoływanie metod z nieznanymi parametrami

0

Próbuję wykombinować, w jaki sposób wywoływać metodę obiektu jeśli w momencie pisania kodu nie znam listy parametrów tej metody.
Po prostu stworzyć prosty język skryptowy, gdzie użytkownik może samemu rejestrować własne metody...
Próbowałem w ten sposób, że w liście published formy1 dodaję:

 procedure MyShowMsg(s:string);

To oczywiście tylko testy - tu znam listę parametrów ;)
potem piszę

 PProcMethod = ^TProcMethod;
 TProcMethod = procedure(const value:Variant) of object;

a potem odwołuje się w ten sposób:

var
  PAddr: PProcMethod;
  M: TMethod;
begin
  try
  PAddr := MethodAddress(aMethodName);
  If PAddr <> Nil then
  Begin
    M.Code := PAddr;
    M.Data := Self;
    TProcMethod(M)('MyShowMsg');
  End;
  except
  end;

niestety, w funkcji MyShowMsg wszystko wskazuje na to że "s" jest PUSTE!!!
Czy ktoś może mi pomóc?

0

A może stwórz strukturę:

TYP_PARAMETRU: liczbowy
WARTOŚĆ: wskaźnik
NASTĘPNYPARAMETR: wskaźnik

I niech twoja funkcja przyjmuje 1 parametr: wskaźnik na parametr pierwszy wywołania.

0
Szczawik napisał(a)

A może stwórz strukturę:

TYP_PARAMETRU: liczbowy
WARTOŚĆ: wskaźnik
NASTĘPNYPARAMETR: wskaźnik

> 
> I niech twoja funkcja przyjmuje 1 parametr: wskaźnik na parametr pierwszy wywołania.

Chyba mnie nie zrozumiałeś(albo ja Ciebie): ja chcę to zrobić tak, aby stworzyć unit który będzie obsługiwał każdą funkcję, czyli np. programista napisze 
```delphi
procedure Proc1(costam:integer;Costam2:string);
begin
...
end;

...

ZarejestrujMetodę(@proc1,'int|str');

a unit by wczytywał jakiego typu dane mają następować i wywoływal metodę na podstawie wskaźnika, podając pierwszy parametr jako integer, drugi jako string. Rozumiesz?
Tak żeby użytkownik nie musiał dostosowywać funkcji napisanych przez siebie do formatu obsługiwanego przez unit.

0
procedure A(n:array of const);
var i:integer;
    s:string;
begin
s:='';
for i:=low(n) to high(n) do
  begin
  with n[I] do
    case VType of
      vtInteger:    s := s + IntToStr(VInteger);
      vtBoolean:    s := s + BoolToStr(VBoolean);
      vtChar:       s := s + VChar;
      vtExtended:   s := s + FloatToStr(VExtended^);
      vtString:     s := s + VString^;
      vtPChar:      s := s + VPChar;
      vtObject:     s := s + VObject.ClassName;
      vtClass:      s := s + VClass.ClassName;
      vtAnsiString: s := s + string(VAnsiString);
      vtCurrency:   s := s + CurrToStr(VCurrency^);
      vtVariant:    s := s + string(VVariant^);
      vtInt64:      s := s + IntToStr(VInt64^);
    end;
  end;
  messagebox(0, pchar(s),'',MB_OK);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
A(['ai',1]);
end;

Temat w helpie: Variant open array parameters

0

No i...? Powiedz mi co mi to daje (poza tym że konwertuje na stringa)... Przecież konwertowanie to nie największy problem tego zadania - tylko jest problem jak wywołać procedurę nie znając jej parametrów (przecież nie napiszę żeby programista pisał procedurę na takiej zasadzie jak procedura "A" - bo musiałby zamienić b. wiele linijek kodu...)
Nadal pozostaje pytanie w jaki sposob wywolac taka procedure, i jak okreslic typ jakiego bedziemy uzywac!

0

A(['ai',1]); <-- chodzi o wywołanie

Zauważ, że wywołując procedurę nie ma ustalonych parametrów. Konwersja na string do tylko przykład, jak zareagować na różne typy parametrów.

[DOPISANE]

A jak potrzebujesz podpiąć normalne procedury o początkowo nie znanej liczbie parametrów, to wywołaj je ręcznie: parametry do rejestrów/na_stos, a potem wywołanie (możesz to zrobić np.: asm'em, albo Delphi metodami podobnymi)

0
Szczawik napisał(a)

A jak potrzebujesz podpiąć normalne procedury o początkowo nie znanej liczbie parametrów, to wywołaj je ręcznie: parametry do rejestrów/na_stos, a potem wywołanie (możesz to zrobić np.: asm'em, albo Delphi metodami podobnymi)

Tylko żebym ja wiedział gdzie wrzucać parametry... jak próbowałem na stos to nie wyszło :

type
 tpr=procedure;
...
procedure Proc1(s:string);
begin
showmessage(s);
end;

...

var
p:TPr;
s:string;
begin
p:=@proc1;
s:='aaa';
asm
push s;
end;
p;
end;

kończy się oczywiście na Access Violation. Niestety nie mam pojęcia skąd się dowiedzieć gdzie wrzucać - czy do rejestrów czy na stos czy jak ;(

0

BTW własnie spróbowałem zrobić w ten sposób:

type
 tpr = procedure;

procedure Proc1(s,s2:string);
begin
showmessage('s1: '+s+#10+'s2: '+s2);
end;

...

var
p:TPr;
a,a2:string;
begin
p:=@proc1;
a:='aaa';
a2:='bbb';
asm
mov EAX,a;
mov EDX,a2;
end;
p;

i o dziwo działało (operacje na ECX i EBX skończyły sie Access Violation)
Ale to nie rozwiązuje kwestii w przypadku jeśli użytkownik ma jeszcze dodać "s3" - nie mam pojęcia co zrobić z 3 zmienną [???]

0
Szczawik napisał(a)

Może pomoże http://info.borland.com/techpubs/delphi/delphi5/oplg/control.html

A i owszem, pomoże :) Choć doszedłem do podobnej wiedzy naciskając Ctrl+Alt+C jak zatrzymało się na breakpoint`cie przed "normalnym" wywołaniem procedury z pięcioma parametrami :)
Jeśli ktoś ma jeszcze jakiś pomysł to mile widziane - bo myślę że da się jakoś ominąć asm :]

0

tymczasem temat zainteresowal i mnie - tym bardziej ze widzialem podobny bajer w RemObjects Pascal Script i sie zastanawialem jak to dziala :]

A wiec na podstawie linka szczawika wykombinowalem co niniejszym przedstawiam:
http://rafb.net/paste/results/iEQrJQ50.html

Niestety, nie mam pojecia (a raczej mam tylko nie wiem jak to ominac) w momencie dwoch parametrow wywala Acces Violation... Tak wiec test2 dziala bez zarzutu - a przy test3 wywalal blad... Wg. debuggera przy ktoryms z end;ow nastepuje modyfikacja rejestru - ale jak mam to rozwiazac, skoro musze stosowac if-y w celu sprawdzenia czy wartosc ma byc w EAX, EDX, ECX czy pozostac na stosie? [sciana]

1 użytkowników online, w tym zalogowanych: 0, gości: 1