get pointer of member function delphi - delphi

Is there some trick how to get pointer of a member function in Lazarus / delphi?
I have this code which won't compile.... Error is
in Delphi:
variable required
in Lazarus:
Error: Incompatible types: got "<procedure variable type of function(Byte):LongInt of object;StdCall>" expected "Pointer"
The code:
TClassA = class
public
function ImportantFunc(AParameter: byte): integer; stdcall;
end;
TClassB = class
public
ObjectA: TClassA;
ImportantPtr: pointer;
procedure WorkerFunc;
end;
function TClassA.ImportantFunc(AParameter: byte): integer; stdcall;
begin
// some important stuff
end;
procedure TClassB.WorkerFunc;
begin
ImportantPtr := #ObjectA.ImportantFunc; // <-- ERROR HERE
end;
Thanks!

A member function cannot be represented by a single pointer. It needs two pointers, one for the instance and one for the code. But that's implementation detail and you just need to use a method type:
type
TImportantFunc = function(AParameter: byte): integer of object; stdcall;
You can then assign ImportantFunc to a variable of this type.
Since you are using stdcall I suspect you are trying to use this as a Windows callback. That's not possible for a member function. You need a function with global scope, or a static function.

type
TImportantFunc = function(AParameter: byte): integer of object;stdcall;
ImportantPtr: TImportantFunc;
procedure TClassB.WorkerFunc;
begin
ImportantPtr := ObjectA.ImportantFunc; // <-- OK HERE
end;

ObjectA.ImportantFunc is not a memory location, so address operator # can't be applied to it - hence compiler error. It is 2 pointers, #TClassA.ImportantFunc (method code) and ObjectA (Self argument). An answer to your question depends on what you really need - code pointer, Self, both or none.
If you need just to scope a function name use static class method
TClassA = class
public
class function ImportantFunc(Instance: TClassA; AParameter: byte): integer;
stdcall; static;
end;

Related

Function passed as parameter causes an E2035 error

In one file, I have a piece of code that goes like this:
// foo.pas
unit Foo;
type
FooExecutorMethod = function (param: Pointer) : Integer of Object;
FooExecutor = class
private
FMethod: TiTefExecutorMethod;
FMethodParam: Pointer;
FMethodResult: Integer;
public
function RunMethod(method: TiTefExecutorMethod; param: Pointer) : Integer;
end;
implementation
function FooExecutor.RunMethod(method: FooExecutorMethod; param: Pointer) : Integer;
begin
FMethod:= method; // Never gets assigned :(
FMethodParam:= param;
// Some threading logic here.
end;
In another file in the same project, I got something like this:
// bar.pas
uses Foo;
type
bar = class
protected
executor: FooExecutor;
function doSomething(params: Pointer): Integer;
Constructor Create(params: Pointer);
implementation
Function bar.doSomething(params: Pointer) : Integer;
begin
// Do something with the pointer
Result := 1;
end;
Constructor bar.Create(params: Pointer)
var
r: Integer;
begin
executor := FooExecutor.Create
r := executor.RunMethod(doSomething, params);
end;
Problem is, bar.DoSomething never gets executed. While debugging FooExecutor.RunMethod, the evaluator does not show a value for its "method" parameter - it shows the following instead:
E2035 Not enough actual parameters
And thus I am unable to use a reference to bar.DoSomething.
What am I doing wrong?
The method is never executed because you never call it. All you ever do is pass around a reference to the method. But you never call it.
You would call it like this:
function FooExecutor.RunMethod(method: FooExecutorMethod; param: Pointer): Integer;
begin
Result := method(param);
end;
Obviously your code is trying to do something else, but this is how to call the method.

EnumWindows in a nested class delphi

I've got some problems with EnumWindows function that uses callback function from a nested class:
TProcessWatch = class(TObject)
private
...
type
TProcessInfo = class(TObject)
private
type
PEnumCallbackParam = ^TEnumCallbackParam;
TEnumCallbackParam = class
A : Integer;
...
end;
private
FOwner : TProcessWatch;
function FEnumWindowsCallback(hWindow : HWND; lParam : LPARAM) : BOOL; export;
procedure SomeProc;
...
end;
private
FProcesses : TProcessInfo;
...
public
...
Within the SomeProc there is a call to EnumWindows
EnumCallbackParam := TEnumCallbackParam.Create;
try
EnumCallbackParam.A := 0;
EnumWindows(#TProcessWatch.TProcessInfo.FEnumWindowsCallback, LongInt(#EnumCallbackParam));
...
finally
EnumCallbackParam.Free;
end;
And here is a FEnumWindowsCallback function listing:
function TProcessWatch.TProcessInfo.FEnumWindowsCallback(hWindow: HWND;
lParam : LPARAM): BOOL; export;
var
CallbackParam : PEnumCallbackParam;
begin
CallbackParam := Pointer(lParam); // A is inaccessible
Result := True;
...
end;
In runtime, when EnumWindows is called, FEnumWindowsCallback is always receiving hWindow = 0 and lParam is pointing to inaccessible value.
All this working fine if callback function is declared private in the form, but when I've tried to make this function private in nested class it went wrong.
Why? And how to make this working? The goal is to make FEnumWindowsCallback and all other involved functions private in TProcessWatch.
The callback is declared wrongly. It should be:
class function EnumWindowsCallback(hWindow: HWND;
lParam: LPARAM): BOOL; static; stdcall;
You were using the wrong calling convention, and an instance method.
Other comments:
EnumCallbackParam is already a pointer. You can pass it as the param.
Cast to LPARAM rather then LongInt so that you code will work if you ever compile to 64 bit.
The export keyword has no meaning in 32 or 64 bit Delphi. It is ignored and you should not use it since it adds clutter and may confuse.

Class function/procedure and instance function/procedure with the same name

Consider this class:
unit u_myclass;
interface
type
TMyClass = class
public
class function Foo : Integer;
function Foo : Integer;
end;
implementation
{ TMyClass }
class function TMyClass.Foo: Integer;
begin
Result := 10;
end;
function TMyClass.Foo: Integer;
begin
Result := 1;
end;
end.
I want to use a class function and an instance function with the same name.
Sadly Delphi doesn't like this and the compiler barfs these errors:
[DCC Error] u_myclass.pas(9): E2252 Method 'Foo' with identical parameters already exists
[DCC Error] u_myclass.pas(20): E2037 Declaration of 'Foo' differs from previous declaration
[DCC Error] u_myclass.pas(9): E2065 Unsatisfied forward or external declaration: 'TMyClass.Foo'
My Question: is this possible or is this simply a language limitation (And I need to rename one of the 2 methods)?
It's not possible to give use the same name for an instance method and a class method. That this is not allowed is that the compiler cannot distinguish between them in some scenarios.
For instance, if you write:
procedure TMyClass.Bar;
begin
Foo;
end;
then the compiler cannot determine whether or not you wish to call the class method or the instance method.
The only solution I found is to use overload and different parameters:
unit u_myclass;
interface
type
TMyClass = class
public
class function Foo(A : Integer) : Integer; overload;
function Foo : Integer; overload;
end;
implementation
{ TMyClass }
class function TMyClass.Foo(A: Integer): Integer;
begin
Result := A;
end;
function TMyClass.Foo: Integer;
begin
Result := 1;
end;
end.

Delphi 2006: I'm trying to call a function of a class, but I'm not familiar with the VAR type parameter

Here is the function I'm trying to call:
function TPipeClient.Write(var Buffer; Count: Integer): Boolean;
I have another class that is a queue of tMessages to write:
tMessage = class
public
function getData(): PByte; virtual; abstract;
function getLen(): integer; virtual; abstract;
end;
So when I try to call: TPipeClient.Write like this:
FClient.Write(queue[pos].getData(), queue[pos].getLen());
(Fclient is a tClientPipe, queue is array of tMessage)
I get an error saying no matching overlaoded version that matches, so I do a:
FClient.Write(#(queue[pos].getData()), queue[pos].getLen());
And I get another compile error: Variable required.
Any ideas on how I can cast this so it will pass and get sent out?
That is an untyped var parameter which is covered in some detail by the documentation. In short you need to pass a variable.
In your case you'll need to define one:
var
P: PByte;
And you can then call your function like this:
P := queue[pos].getData();
FClient.Write(P^, queue[pos].getLen());

Is there a way to overload a function based on different Result type in Delphi?

Function overloading by return type?
has a very detailed answer on the rational on function overloading by return type, and from what I can see Delphi does not allow this, but are there any workarounds to overload a function based on different return type in Delphi?
The implicit and explicit conversion operators for records permit overloading by return type: namely, the type being converted to:
type
TFoo = record
class operator Implicit(const AFoo: TFoo): Integer;
class operator Implicit(const AFoo: TFoo): string;
end;
Depending on the context, using a value of type TFoo will call the appropriate implicit conversion. If trying to use a value of type TFoo as an argument to an overloaded routine that can take either Integer or string in that position, an overload error will occur:
test.pas(33) Error: E2251 Ambiguous overloaded call to 'Q'
+ Test.pas(19) Related method: procedure Q(Integer);
+ Test.pas(24) Related method: procedure Q(const string);
You can take the "result" as a parameter.
procedure Blah( InVar : word; out OutVar : Byte ); overload;
procedure Blah( InVar : word; out OutVar : String ); overload;
I took the above idea and implemented it in a tokenreader used for importing data.
Each token is a string, which is then converted to the appropriate type.
The code needed for converting to integer and string is at the bottom of the post.
To read and convert a token only the following code is needed:
Myvalue := DataImporter.ImportToken;
Depending on the type of Myvalue, the correct implicit conversion is triggered.
The code:
TTokenValue = record
public
FValue:string;
constructor Create(const AValue:string);
class operator Implicit(const AFoo:TTokenValue): integer;
class operator Implicit(const AFoo:TTokenValue): string;
end;
Implementation
function TDataImporter.ImportToken: TTokenValue;
begin
result := TTokenValue.Create(GetCurrentToken());
end;
constructor TTokenValue.Create(const AValue: string);
begin
FValue := AValue;
end;
class operator TTokenValue.Implicit(const AFoo: TTokenValue): integer;
begin
result := strtointdef(AFoo.FValue, 0);
end;
class operator TTokenValue.Implicit(const AFoo: TTokenValue): string;
begin
result:=AFoo.FValue;
end;

Resources