PDA

View Full Version : Pointers, objects, functions and execution - is this even possible?



code_glitch
16-02-2011, 05:06 PM
Theoretically a pointer is a memory adsress to something in your program; and a function/procedure is stored in memory too. (I think you see where this is going by now). So is there any way to do the following:L



object
Task = object
MainProc: Pointer;
end;

var
TT: Task;

procedure foo();
begin
writeln('HI');
end;

begin
TT.MainProc := @foo;
foo();
end.


However I cannot even get this to compile. Theoretically it should work but I have my reservations. I heard you can do this in C or whatever - so I was wondering if it could be done in pascal - since it would make my life sooo much easier. Think about it:
1 engine manages tasks
each task has init, main and end procedures and etc
you would not have to worry about modes and etc - just register your 'task' and let it all run. or something like that.
any pointers folks? (excuse pun) ;D

Murmandamus
16-02-2011, 05:59 PM
Generally, the way you do function pointers in Object Pascal is to declare a Function or Procedure type, like so:



Type
TMyProc = Procedure(X : Integer);

Var
MyProc : TMyProc;

Procedure Foo(X : Integer);
Begin
Writeln('Hi!');
Writeln(X);
End;

Begin
MyProc := @Foo;
MyProc(10);
End.

code_glitch
16-02-2011, 07:34 PM
Is there no way to use any procedure without defining it? Or putting that into an object? The way you present works, but does sort of defeat the point of the idea...

LP
16-02-2011, 07:54 PM
Do you mean something like this:



var
ExecPtr: Pointer;
begin
ExecPtr:= @foo;

asm
mov eax, ExecPtr
call eax
end;
end;

User137
16-02-2011, 07:57 PM
Just 1 thing to add to Murmandamus code...

MyProc := @Foo; // This compiles on Freepascal

MyProc := Foo; // This compiles on Delphi

Mirage
16-02-2011, 08:06 PM
How you will call a procedure without defining it? How compiler will manage arguments of an undefined procedure?
Nonetheless, you can define a generic procedure (or method and put it into an instance of a class) with variable number of parameters of any type:


type
TMyProc = Procedure(args: array of const) of object;

Procedure TSomeClass.Foo(args: array of const);
Begin
if lengths(args) > 1 then begin
Writeln(args[0]);
Writeln(args[1]);
end;
End;

var
SomeClass: TSomeClass;
MyProc: TMyProc;

Begin
MyProc := @SomeClass.Foo;
MyProc(['Hello!', 10]);
End.


A well-known Format() function works this way. You can see it in VCL sources.
You can also read more on topic "variant open array parameters".

imcold
16-02-2011, 08:17 PM
Proc/fn type must be defined, because procedure parameters must be known to call the given procedure correctly. Proc/fn pointers can be used in objects, of course.

Edit: too slow.

code_glitch
16-02-2011, 08:49 PM
Thanks for all the replies - will start testing ASAP.

cheers
code_glitch

arthurprs
17-02-2011, 12:39 AM
I didn't test, but if you typecast the pointer to a procedure/function type, you can call it.

wodzu
17-02-2011, 07:31 AM
Is there no way to use any procedure without defining it? Or putting that into an object? The way you present works, but does sort of defeat the point of the idea...

Maybe you had on your mind without "declaring" instead of "defining"?

With anonymous methods in Delphi you can do things like:



initialization
with TMyClass.Create do
begin
DoStuff(
procedure(value: string)
begin
Writeln(value);
end);

Free;
end;
end.

Colin
17-02-2011, 10:22 AM
the code LifePower posted will work... to pass params in the asm block you just need to use push

Murmandamus
17-02-2011, 05:43 PM
I'm mainly curious about the application at this point. Is it possible that you're going the long way around to doing something that would be syntactically easier (and more portable) done a different way?

For example, just make the "task" a class, and just override the method which does the work for whatever specific task you want to do by inheritance.



Type
TMyTask = class
Procedure DoStuff; Virtual; Abstract;
End;
TMyTextTask = class(TMyTask)
Procedure DoStuff; Override;
End;
TMySoundTask = class(TMyTask)
Procedure DoStuff; Override;
End;

Var
MyTask : TMyTask;
Command : String;

Procedure TMyTextTask.DoStuff;

Begin
Writeln('Hi there!');
End;

Procedure TMySoundTask.DoStuff;

Begin
PlaySound('SystemQuestion', 0, SND_ALIAS or SND_ASYNC);
End;

Begin
MyTask := Nil;
Command := LowerCase(ParamStr(1));
If Command = 'text' Then
MyTask := TMyTextClass.Create;
Else
If Command = 'sound' Then
MyTask := TMySoundClass.Create;
If (Assigned(MyTask)) Then
MyTask.DoStuff;
End.


Does something like that make more sense?