Jump to content
Frate

Pointer to Record.Function

Recommended Posts

Hi everyone,
first post for me so I shortly introduce myself.
I'm Aerospace Eng. student in Italy, passionate about electronics, PCs and aviation. Learned Lazarus at high school, now moving to Delphi some personal projects.

 

I'll drop here the code I'm having issues with:

uses bass, [...]

type TRadio = record
  counter : word;
  [...]
  function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; // BLOCK TONE GENERATION
end;

type TRadioPointer = ^TRadio;

function TRadio.MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; //3
var
  buf: ^WORD;
  i, k, len: Integer;
  ampl: real;
  j: word;
begin
  // Does stuff using properties from TRadio
  inc(cunter); 
  [...]
  Result := Alength;
end;

procedure initRadio(PRadio : TRadioPointer); //2
[...]
begin
  [...]
  resultValue := BASS_StreamCreate(cSAMPLE_RATE, 2, 0, @PRadio^.MakeSine, nil);  // Error here : E2036 Variable Required
  [...]
end;

procedure mainProgram; //1
var MyRadio : TRadio;
begin
   initRadio(@MyRadio);
end;

What I'm trying to achieve :

I'm using an audio library called Bass. I have to create a waveform (TRadio.MakeSine) using parameters from a TRadio record.

There is no possibility to change the parameters on the MakeSine function because BASS_StreamCreate wants specific function paramters (so for instance I can't pass the TRadio.parameters directly to the MakeSine function).

I decided to put MakeSine inside the TRadio record to allow access to the parameters i need (also for the program logic makes sense to do that).

BASS_StreamCreate requires a pointer to MakeSine function as input (see reference below).

 

The problem I have:

When i try to pass the function pointer to StreamCreate i get error E2036 Variable Required.

 

I don't understand what i'm doing wrong.

Kindly asking for help

 

Frate

 

Bass reference:

HSTREAM BASS_StreamCreate(
    DWORD freq,
    DWORD chans,
    DWORD flags,
    STREAMPROC *proc,
    void *user
);

DWORD CALLBACK StreamProc(
    HSTREAM handle,
    void *buffer,
    DWORD length,
    void *user
);


 

Share this post


Link to post
1 hour ago, Frate said:

When i try to pass the function pointer to StreamCreate i get error E2036 Variable Required.

This usually hapend when a function has a var argument and you try to pass a property.

Copy the property to a temporary variable, pass the variable as argument to the function, set the property with the [potentially new] temporary variable.

 

  • Like 1

Share this post


Link to post

There are a few issues with your code and a few things that could be improved.

 

1) A member function has a hidden "self" parameter so in reality the signature of the MakeSine function you have declared looks like this:

function MakeSine(const [ref] Self: TRadio; handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall;

If you want MakeSine declared as a member function then you need to declare it as a static class method:

type
  TRadio = record
    ...
    class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static;
  end;

but then you lose the reference to self and can't access the member variables inside the method.
I'm guessing that the user parameter is for passing context to the callback and if so you can achieve the same with an extra function:

type
  TRadio = record
    ...
  private
    function DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD;
  public
    class function MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD; stdcall; static;
  end;
  
class function TRadio.MakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD; user: Pointer): DWORD;
begin
  Result := TRadioPointer(user).DoMakeSine(handle, buffer, Alength);
end;

function TRadio.DoMakeSine(handle: HSTREAM; buffer: Pointer; Alength: DWORD): DWORD;
begin
  ...
end;

begin
  // Pass TRadio pointer as the "user" parameter
  resultValue := BASS_StreamCreate(cSAMPLE_RATE, 2, 0, @TRadio.MakeSine, PRadio);
end

 

2) The convention would be to name your TRadio pointer type "PRadio"

type
  TRadio = record
    ...
  end;

  PRadio = ^TRadio;

3) You don't need to deference typed complex pointer types with ^

PRadio^.MakeSine // standard Pascal
PRadio.MakeSine // allowed in Delphi

 


 

 

  • Like 1

Share this post


Link to post

Thank you both for replying.
@Anders MelanderThanks for your suggestions, I implemented your solution and at least i get no compiler error.
I have to complete some other parts of the software before checking if everything works fine.

 

Quote

2) The convention would be to name your TRadio pointer type "PRadio"

By convention what would be an appropriate name for pointer variable of type PRadio?

var
  ?MyRadioPointer? : PRadio;
Quote

3) You don't need to deference typed complex pointer types with ^ 

Heritage from school 😉

 

Thanks again

 

Frate

Share this post


Link to post
10 minutes ago, Frate said:

By convention what would be an appropriate name for pointer variable of type PRadio?

I don't think there's a widely used convention for that. I would just name it "Radio".

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×