Recent

Author Topic: [SOLVED] One more: Accessing C DLL from Lazarus  (Read 2912 times)

garysn

  • Newbie
  • Posts: 6
[SOLVED] One more: Accessing C DLL from Lazarus
« on: September 15, 2021, 07:47:03 pm »
Hi all,

I have to use a C DLL in my Lazarus Project and most of the stuff is working, but there is one callback routine that will always crashes when it is called.

Here are the essential parts of the original C Code:

Code: C  [Select][+][-]
  1. // Header Definitions …
  2.  
  3. typedef enum
  4. {
  5.   VLD_success                 =  0,
  6.   VLD_xxx                     =  …
  7.   VLD_winSocketNotAvailable   = 27,
  8. } VLD_Error;
  9.  
  10.  
  11. typedef enum
  12. {
  13.   VLD_callbackDone     = 0,
  14.   VLD_callbackFailed   = 1,
  15.   VLD_callbackDeferred = 2,
  16. } VLD_CallbackReturn;
  17.  
  18. typedef
  19. VLD_CallbackReturn(*VLD_SensorCallback) (void *context,
  20.                                          int sensorIndex,
  21.                                          uint32_t firstSample,
  22.                                          int32_t *data,
  23.                                          int dataLength,
  24.                                          bool dataContainsError);
  25.  
  26. struct VLD_Device_;
  27. typedef struct VLD_Device_ VLD_Device;
  28.  
  29.  
  30. // Programm Code
  31.  
  32. // 1. Implementation of callback routine
  33. VLD_CallbackReturn writeDataToFile(void *context,
  34.                                    int sensorIndex,
  35.                                    uint32_t sampleNumber,
  36.                                    int32_t* data,
  37.                                    int dataLength,
  38.                                    bool dataContainsError)
  39. {
  40.     if (context == nullptr)
  41.         return VLD_callbackFailed;
  42.  
  43.     // … some other code
  44. }
  45.  
  46.  
  47. // 2. Registration of callback routine … works fine
  48. VLD_Error VLD_enableCallback            (VLD_Device *device,
  49.                                          int sensorIndex,
  50.                                          VLD_SensorCallback callback,
  51.                                          void *context);
  52.  


And here is my ported Lazarus Version

Code: Pascal  [Select][+][-]
  1. // Header Definitions …
  2.  
  3. type
  4.   TVLDError = (
  5.     vldSuccess                 =  0,
  6.     vld_XXX                    =  …,
  7.     vldWinSocketNotAvailable   = 27
  8.   );
  9.  
  10.   TVLDCallbackReturn = (
  11.     vldCallbackDone     = 0,
  12.     vldCallbackFailed   = 1,
  13.     vldCallbackDeferred = 2
  14.   );
  15.  
  16.   {$POINTERMATH ON}
  17.   PSampleData = ^Int32;
  18.   {$POINTERMATH OFF}
  19.  
  20.   TVLDSensorCallback = function(Context:           pointer;
  21.                                 SensorIndex:       integer;
  22.                                 firstSample:       UInt32;
  23.                                 Data:              PSampleData;
  24.                                 DataLength:        integer;
  25.                                 DataContainsError: boolean
  26.                                ): TVLDCallbackReturn; stdcall;
  27.  
  28.   TVLDDevice = record end;
  29.   PVLDDevice = ^TVLDDevice;
  30.  
  31.  
  32. // Program Code
  33.  
  34. // 1. Implementation of callback routine
  35. function WriteDataToFile( Context:           pointer;
  36.                           SensorIndex:       integer;
  37.                           firstSample:       integer;
  38.                           Data:              PSampleData;
  39.                           DataLength:        integer;
  40.                           DataContainsError: boolean
  41.                         ): TVLDCallbackReturn; stdcall;
  42.  
  43. begin
  44.   if not Assigned(Context) then
  45.     Result := vldCallbackFailed;  
  46.  
  47.  // … some other code
  48. end;
  49.  
  50. // 2. Registration of callback routine … works fine
  51. VLDResult := VLD_enableCallback(VLDDevice,
  52.                                 SensorList[Idx],
  53.                                 @WriteDataToFile,
  54.                                 @Contexts[Idx]);
  55.  


I'm able to compile it and run it, but at the moment when the DLL is calling the callback routine I will get a RunError (202)

Is there anybody who can show me the error?

Thanks for your help
  garysn
« Last Edit: September 16, 2021, 11:28:54 am by garysn »

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: One more: Accessing C DLL from Lazarus
« Reply #1 on: September 15, 2021, 08:48:00 pm »
I found this unusual, line 41
 ): TVLDCallbackReturn; stdcall;

The brackets seem strangely placed.
« Last Edit: September 15, 2021, 10:06:33 pm by BobDog »

korba812

  • Sr. Member
  • ****
  • Posts: 390
Re: One more: Accessing C DLL from Lazarus
« Reply #2 on: September 15, 2021, 09:05:03 pm »
'stdcall' calling mechanism is only valid for Windows platform. If you are using a non-Windows platform try 'cdecl' instead of 'stdcall'.

garysn

  • Newbie
  • Posts: 6
Re: One more: Accessing C DLL from Lazarus
« Reply #3 on: September 15, 2021, 09:34:35 pm »
'stdcall' calling mechanism is only valid for Windows platform. If you are using a non-Windows platform try 'cdecl' instead of 'stdcall'.

Indeed I have to run the program on a Linux device. So I have changed all stdcall to cdecl but no difference. It's still crashing.
The DLL offers a lot more functions and all are working, doesn't matter if I declare them with stdcall or cdecl - the only exception is this callback routine.

Meanwhile I have had a look with the "file" command into my .so file.
Here is the output:

file /usr/lib/libVLDAQ.so
/usr/lib/libVLDAQ.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=3867affe9098b34da78ce55e278905ae4dc35730, stripped


Don't know if this helps to solve the problem?

garysn

  • Newbie
  • Posts: 6
Re: One more: Accessing C DLL from Lazarus
« Reply #4 on: September 15, 2021, 09:43:25 pm »
Here is a screenshot of the callstack directly after the crash ... (see attached image)

If you compare the parameters it really looks good, 2 Pointers at the right locations, the values of the integers and the boolean variable are correct ...

Most of the stuff looks right ...
I can't see whats going wrong  :'(

Soner

  • Sr. Member
  • ****
  • Posts: 305
Re: One more: Accessing C DLL from Lazarus
« Reply #5 on: September 15, 2021, 11:00:46 pm »
Look at the C code. The return type for the WriteDataToFile function should be Pointer. Change it to " function WriteDataToFile( ... ): ^TVLDCallbackReturn; cdecl; " and try again.

tetrastes

  • Sr. Member
  • ****
  • Posts: 469
Re: One more: Accessing C DLL from Lazarus
« Reply #6 on: September 16, 2021, 12:08:52 am »
Look at the C code. The return type for the WriteDataToFile function should be Pointer. Change it to " function WriteDataToFile( ... ): ^TVLDCallbackReturn; cdecl; " and try again.
Where do you see pointer? WriteDataToFile returns variable of type VLD_CallbackReturn, which is simply enum.

@garysn: may be the problem in different length of enum members or/and enum packing in C and Pascal?

garysn

  • Newbie
  • Posts: 6
Re: One more: Accessing C DLL from Lazarus
« Reply #7 on: September 16, 2021, 12:27:41 am »
Look at the C code. The return type for the WriteDataToFile function should be Pointer. Change it to " function WriteDataToFile( ... ): ^TVLDCallbackReturn; cdecl; " and try again.
Where do you see pointer? WriteDataToFile returns variable of type VLD_CallbackReturn, which is simply enum.

@garysn: may be the problem in different length of enum members or/and enum packing in C and Pascal?

To compensate the different length I tried the compiler directives {$PACKENUM 1}, {$PACKENUM 2} and {$PACKENUM 4}, but in all cases the callback still crashes :-(

When trying to add a ^ in front of TVLDCallbackReturn then I will get a Syntax Error (see attached picture)

garysn

  • Newbie
  • Posts: 6
Re: One more: Accessing C DLL from Lazarus
« Reply #8 on: September 16, 2021, 01:26:46 am »
Create a type if you haven't already..

Type
  PVLDCallbackReturn = ^TVLDCallbackReturn;

Okay with this construct I will be able to compile (after some small additional adjustments on the code) without any warning but the result is the same.

See Screenshot 1:
The callback is called by the DLL and will reach my Breakpoint located at the "begin" of the function.

See Screenshot 2:
Before entering the function with F7 here is the call stack
As you can see the Parameters of WRITEDATATOFILE are looking strange.
I assume that they are not yet filled with the correct values?

See Screenshot 3:
After key in F7 the software crashes.
Looking now on the call stack shows us, that now the parameters are "looking correct" - nevertheless the crash isn't gone   

Zvoni

  • Hero Member
  • *****
  • Posts: 2300
Re: One more: Accessing C DLL from Lazarus
« Reply #9 on: September 16, 2021, 08:27:53 am »
Use the ctypes-Unit, and replace your native Pascal-Types with the corresponding ctype

EDIT: There is a difference in your 3rd Argument in WriteDataToFile: You have in your Pascal Integer, in C it's UInt32_t
So at a guess, Your integer overflows

EDIT2: Err, that is in your Pascal-Sample-Code. In your Screenshot it's correct
« Last Edit: September 16, 2021, 08:46:28 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: One more: Accessing C DLL from Lazarus
« Reply #10 on: September 16, 2021, 09:03:38 am »
Look at the C code. The return type for the WriteDataToFile function should be Pointer. Change it to " function WriteDataToFile( ... ): ^TVLDCallbackReturn; cdecl; " and try again.

No, it's not. The declaration is VLD_CallbackReturn(*VLD_SensorCallback) (...), the * refers to the VLD_SensorCallback type, not the return type.

I'm able to compile it and run it, but at the moment when the DLL is calling the callback routine I will get a RunError (202)

Is there anybody who can show me the error?

Runtime error 202 is a stack overflow. Can it be that the callback is called from a different thread? Did you include the cthreads unit then? Otherwise the RTL (and thus also the variable that's used for checking the thread) won't be initialized correctly when a foreign thread comes in.

garysn

  • Newbie
  • Posts: 6
Re: One more: Accessing C DLL from Lazarus
« Reply #11 on: September 16, 2021, 11:27:46 am »
Look at the C code. The return type for the WriteDataToFile function should be Pointer. Change it to " function WriteDataToFile( ... ): ^TVLDCallbackReturn; cdecl; " and try again.

No, it's not. The declaration is VLD_CallbackReturn(*VLD_SensorCallback) (...), the * refers to the VLD_SensorCallback type, not the return type.

I'm able to compile it and run it, but at the moment when the DLL is calling the callback routine I will get a RunError (202)

Is there anybody who can show me the error?

Runtime error 202 is a stack overflow. Can it be that the callback is called from a different thread? Did you include the cthreads unit then? Otherwise the RTL (and thus also the variable that's used for checking the thread) won't be initialized correctly when a foreign thread comes in.

CTHREADS was the magic word !!!
I have added the unit and now it works !!!

Thanks a lot to PascalDragon and of cause all you other guys that helped me to solve this problem.

This is a really great community
  garysn
« Last Edit: September 16, 2021, 11:30:51 am by garysn »

 

TinyPortal © 2005-2018