View Full Version : implementing a callback mechanism
JernejL
20-09-2006, 10:09 AM
i need help with adding callback mechanism to my program, i have this:
// global
var
CBackProc: Procedure(src: Longword); stdcall;
// a procedure
CBackProc:= Sources[src].DeleteCB; <-deletecb is pointer to a procedure, filled from another function
CBackProc(src); // call it
this causes my program to collapse and crash, any idea why? and perhaps what am i doing wrong?
jdarling
20-09-2006, 01:18 PM
From a quick glance, I don't see whats wrong. So I'll show you another way of doing it that is common:
unit test;
interface
type
TMyProc=procedure(SomeVar1, SomeVar2 : PChar); cdecl;
var
MyProc : TMyProc;
procedure LoadProcs;
implementation
procedure LoadProcs;
var
l : Cardinal;
begin
l := LoadLibrary('MyDLL.dll');
if l <> nil then
begin
@MyProc := GetProcAddress(l, 'FOO');
end;
end;
end.
Then later to call it:
MyProc('Test1', SomeOtherPChar);
While this is FPC source it should work for you. Also you might try taking a look at the Dr Bob's article (a bit dated, but still useful) at: http://www.drbob42.com/delphi/headconv.htm
JernejL
20-09-2006, 01:56 PM
no, what i am doing is right the opposite, and it has nothing to do with dlls, this will be used in a unit to notify main program that a sound source got deleted (within the application).. something for my audio library.
cairnswm
20-09-2006, 02:10 PM
Why not just make it a TNotifyEvent and use it as an event handler?
JernejL
20-09-2006, 02:50 PM
i don't use delphi's vcl... this is intended for raw coding..
cairnswm
20-09-2006, 02:53 PM
I dont use the VCL either but I still make use of TNotifyEvent :)
Maybe you need to make your own event handler then:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
Type
TMyNotify = Procedure(Value : Integer) of Object;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FNotify: TMyNotify;
procedure SetNotify(const Value: TMyNotify);
{ Private declarations }
public
{ Public declarations }
Property Notify : TMyNotify read FNotify write SetNotify;
Procedure MyNotifyHandler(Value : Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
If Assigned(Notify) then
Notify(100);
end;
procedure TForm1.MyNotifyHandler(Value: Integer);
begin
Button1.Caption := IntToStr(Value);
end;
procedure TForm1.SetNotify(const Value: TMyNotify);
begin
FNotify := Value;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Notify := MyNotifyHandler;
end;
end.
VilleK
20-09-2006, 02:55 PM
Why the need for stdcall? Have you tried without it?
Are you compiling in Delphi?
Try a simple example first, such as:
var
CBackProc: Procedure(src: Longword);
procedure test(src: Longword);
begin
WriteLn('Hello')
end;
begin
CBackProc:= Test;
CBackProc(src); // call it
end.
JernejL
20-09-2006, 03:23 PM
I'm doing just that, but i think the problem is storing the function reference in a pointer..
declarations:
Type
TDeleteNotifyproc = Procedure(src: Longword; userdata: pointer); stdcall;
Tsource = packed record
UserData: Pointer;
mode: TSourceMode;
ALsource: ALuint;
DeleteCB: TDeleteNotifyproc;
VirtualSource: Tvirtualsource;
end;
savage
20-09-2006, 03:40 PM
this works for me...
program Project1;
{$APPTYPE CONSOLE}
type
TDeleteNotifyproc = procedure( src : Longword; userdata : pointer ); stdcall;
TSource = packed record
DeleteCB : TDeleteNotifyproc;
end;
var
aSource : TSource;
aCallBack : TDeleteNotifyproc;
procedure test( src : Longword; userdata : pointer ); stdcall;
begin
WriteLn( 'Hello' )
end;
begin
aSource.DeleteCB := Test;
aCallBack := aSource.DeleteCB;
aCallBack( 0, nil ); // call it
end.
If you are doing everything within Pascal you really do not need the "stdcall" calling convention. If you plan to make it accessible to C and allow plugins then on windows use stdcall and on Linux I believe you need to use cdecl.
savage
20-09-2006, 03:49 PM
// a procedure
CBackProc:= Sources[src].DeleteCB; <-deletecb is pointer to a procedure, filled from another function
just looking back over this code are you sure that Sources[src].DeleteCB is pointing to a valid callback function?
to avoid the AV you could use some defensive programming and try
if Assigned ( aCallBack ) then
begin
aCallBack( 0, nil ); // call it
end
else
begin
WriteLn( 'No Callback function defined' )
end
Using "if aCallBack <> nil" will not work as the compiler treats that as an attempt to make a function/procedure call.
JernejL
20-09-2006, 05:30 PM
thanks for all the help, i got it working :)
i'll post the code, what i was doing here:
http://www.pascalgamedevelopment.com/forums/viewtopic.php?p=24603#24603
savage
20-09-2006, 07:51 PM
Can you tell us what the problem was so that some of us don't make the same mistake as well.
JernejL
20-09-2006, 10:26 PM
Can you tell us what the problem was so that some of us don't make the same mistake as well.
well if i am completely honest, i named a field in the record "DeleteCB" same as one of function parameters, and so the function was assigning the record's DeleteCB to the same variable instead grabbing it from parameter.. :oops:
i'd appreciate if people look at the other topic and test the audio management code a bit :)
savage
21-09-2006, 08:29 AM
Thanks for your honesty. We've all done stuff like that.
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.