Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C callback function crash on object pascal

Tags:

c++

delphi

I'm creating a C dll like below.

#ifdef TEST_EXPORTS
#define TEST_API __declspec(dllexport)
#else
#define TEST_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif
    /* fun accept an argument status_callback which is a function pointer*/
    TEST_API void fun(void(*status_callback)(int));
#ifdef __cplusplus
}
#endif

and fun is implemented as:

void fun(void(*status_callback)(int)) {
   status_callback(0);
}

When using this dll on object pascal with delphi xe like below I got a crash with an access violation at the address of the callback function

type
 TStatusCallBack = procedure( Value: Integer ); stdcall;
 T_fun = procedure(cb : TStatusCallback );

procedure BCallBack( Value: Integer ); stdcall;
begin
   BStatus := value;
end;

begin
 _fun(BCallBack);
end;

Instantiation code:

DLLHandle := LoadLibrary( ‘mylib.dll’ );
if (DLLHandle > HDLL_ERROR) then
begin
  _fun := T_fun(GetProcAddress( DLLHandle, 'fun');
end;

What is the issue? Since I'm a noobie to C any comments??

like image 895
krishnakumarcn Avatar asked Sep 19 '18 06:09

krishnakumarcn


1 Answers

We are missing important details. We can't see the implementation of fun on the C++ side, and we can't see how you declared _fun on the Delphi side.

However there is one error that we can see. The calling convention for the callback does not match. The C++ code defines the callback as __cdecl. You need to use cdecl to match on the Delphi side, and not stdcall.

Likewise I expect that your Delphi code gets the calling convention wrong for _fun. Again it should be cdecl but the error message suggests your declaration is actually register.

In summary, make the following changes to your Delphi code:

  • Declare the callback function type as cdecl.
  • Declare the function that implements the callback as cdecl.
  • Declare the import of fun as cdecl.

Looking at your edit, your error checking for the return value of LoadLibrary is wrong. Error is indicated by the return value being zero. Compare for equality with zero to test for failure.

You also fail to check for errors when calling GetProcAddress. You need to handle the case where nil is returned. Again, that could lead to a runtime error with your code as written.

And the code in your edit shows that all my guesses were correct. The solution is as detailed in the bullet points above.

like image 186
David Heffernan Avatar answered Oct 17 '22 09:10

David Heffernan