Recent

Author Topic: [SOLVED]Troubles when converting C .h (Measurement Computing / Digilent device)  (Read 4862 times)

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
I am trying to update some DLL definitions from a .h file for C.
The source in the C is :
Code: Pascal  [Select][+][-]
  1.  
  2. int EXTCCONV cbGetDaqDeviceInventory(INT32 InterfaceType, DaqDeviceDescriptor* Inventory, INT* NumberOfDevices);
  3. ...
  4. typedef struct
  5. {
  6.    CHAR               ProductName[64];
  7.    UINT               ProductID;         // product ID
  8.    DaqDeviceInterface              Int32; // USB, BLUETOOTH, ...
  9.    CHAR               DevString[64];
  10.    CHAR               UniqueID[64];      // unique identifier for device. Serial number for USB deivces and MAC address for  bth and net devices
  11.    ULONGLONG            NUID;            // numeric representation of uniqueID
  12.    CHAR               Reserved[512];      // reserved for the future.
  13.                                    
  14. } DaqDeviceDescriptor;
  15.  

I did it the following way in Lazarus (attached in file MCCULDynBind.pas):


Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   ...
  4.   pdaqDeviceDescriptor = ^daqDeviceDescriptor;
  5.   ...
  6.   daqDeviceDescriptor = record
  7.      ProductName   : array [0..63] of char;
  8.      ProductID   :       UInt32;
  9.      InterfaceType:     Int32; //USB_IFC= 1; BLUETOOTH_IFC = 2; ETHERNET_IFC = 4; ANY_IFC = 7;
  10.      DevString:         array [0..63] of char;
  11.      UniqueId:          array [0..63] of char;
  12.      NUID:              UInt64;
  13.      Reserved:          array [0..511] of char;
  14.   end;
  15.   ...
  16.   TcbGetDaqDeviceInventory = function (InterfaceType : integer; var Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;
  17. ...
  18. var
  19. ...
  20.   cbGetDaqDeviceInventory : TcbGetDaqDeviceInventory;
  21. ...
  22. implementation
  23. ...
  24. function LoadMCCLib: Boolean; //True if successful
  25. begin
  26.    if DllHandle = NilHandle then DllHandle := SafeLoadLibrary(libname);
  27.    if DLLHandle <> NilHandle then
  28.    begin  
  29. ...
  30.       cbGetDaqDeviceInventory := TcbGetDaqDeviceInventory (GetProcedureAddress  (DLLHandle, 'cbGetDaqDeviceInventory'));
  31. ...
  32. end;
  33.  




I call the function the following way:


Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   ULStat : integer = 0;
  4.   i : integer = 0;
  5.   ProductName : string = '';
  6.   ProductID : UInt32;
  7.   Inventory : ^DaqDeviceDescriptor;
  8.   NumberOfDevices : Integer = -1;
  9. begin
  10.   cbErrHandling(PRINTALL, STOPALL);
  11.   //ULval := cbIgnoreInstaCal;
  12.   //SetLength (Inventory,100);
  13.  
  14.  
  15.     ULStat := cbGetDaqDeviceInventory(7,Inventory,NumberOfDevices);
  16.     ProductName := Inventory[0].ProductName;
  17.     ProductID := Inventory[0].ProductID;
  18.     ShowMessage(IntToStr (i) + '; ' + IntToStr(ULStat)  + '; ' + IntToStr  (NumberOfDevices ));
  19. end;    
  20.  


A sample app in C works (solution attached), but it does not work in Lazarus -sometimes it crashes, sometimes it returns a correct value in NumberOfDevices, but DaqDeviceDescriptor contains no data or shit.
ULStat becomes 154 (BADBUFFERSIZE (Buffer is too small for operation)).
The function shall return an array of DaqDeviceDescriptor, but the definition in the C header is not for an array, which really confuses me.


I have little hope that someone could help, because a device is used to debug, but anyway...
« Last Edit: January 15, 2025, 12:49:57 pm by CM630 »
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

Thaddy

  • Hero Member
  • *****
  • Posts: 16573
  • Kallstadt seems a good place to evict Trump to.
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #1 on: January 14, 2025, 11:33:08 am »
{$packrecords C} ?
I have almost the same and this should work
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$packrecords C}
  2.  type
  3.     DaqDeviceDescriptor = record
  4.         ProductName : array[0..63] of CHAR;
  5.         ProductID : UINT;
  6.         _Int32 : DaqDeviceInterface; // this differs from yours
  7.         DevString : array[0..63] of CHAR;
  8.         UniqueID : array[0..63] of CHAR;
  9.         NUID : ULONGLONG;
  10.         Reserved : array[0..511] of CHAR;
  11.       end;
  12. ....
« Last Edit: January 14, 2025, 11:40:33 am by Thaddy »
But I am sure they don't want the Trumps back...

cdbc

  • Hero Member
  • *****
  • Posts: 1871
    • http://www.cdbc.dk
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #2 on: January 14, 2025, 11:39:13 am »
Hi
Maybe:
Code: Pascal  [Select][+][-]
  1. TcbGetDaqDeviceInventory = function (InterfaceType : Longint; Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;
  2.  
The 'Inventory' is already a pointer = (P)daqDeviceDescriptor, so there's no need for 'var'... The integer needs var oth...
Regards Benny
« Last Edit: January 14, 2025, 11:41:28 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Zvoni

  • Hero Member
  • *****
  • Posts: 2847
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #3 on: January 14, 2025, 11:41:54 am »
don't forget the recommendation, you should use ctypes for any c-header conversion
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

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #4 on: January 14, 2025, 12:55:35 pm »
...
Code: Pascal  [Select][+][-]
  1. TcbGetDaqDeviceInventory = function (InterfaceType : Longint; Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;
The 'Inventory' is already a pointer = (P)daqDeviceDescriptor, so there's no need for 'var'... The integer needs var both......

Without var (TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;) I get an system exception immediately.

In the C code there is DaqDeviceDescriptor inventory[MAXNUMDEVS]; , MAXNUMDEVS is 100. So inventory is an static array with 100 elements of DaqDeviceDescriptor.
In the Lazarus code I do not set the size of the array. I do not know how to set it, actually I use a pointer.
But if I set TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: array [0.99daqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;)
I also tried  TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: daqDeviceDescriptor_100; var NumberOfDevices : Integer) : Longint; StdCall;, but I still get nothing in inventory (daqDeviceDescriptor_100 = array [0..99] of daqDeviceDescriptor;)


don't forget the recommendation, you should use ctypes for any c-header conversion

Sorry, I did not understand you. I tied to keep exactly the same variable types as in the C file, if that is what you mean.
« Last Edit: January 14, 2025, 01:25:04 pm by CM630 »
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

Zvoni

  • Hero Member
  • *****
  • Posts: 2847
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #5 on: January 14, 2025, 01:07:37 pm »

Code: Pascal  [Select][+][-]
  1. TcbGetDaqDeviceInventory = function (InterfaceType : Longint; Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;
The 'Inventory' is already a pointer = (P)daqDeviceDescriptor, so there's no need for 'var'... The integer needs var both....
Without var (TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: PdaqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;) I get an system exception immediately.

In the C code there is DaqDeviceDescriptor inventory[MAXNUMDEVS]; , MAXNUMDEVS is 100. So inventory is an static array with 100 elements of DaqDeviceDescriptor.
In the Lazarus code I do not set the size of the array. I do not know how to set it, actually I use a pointer.
But if I set TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: array [0.99daqDeviceDescriptor; var NumberOfDevices : Integer) : Longint; StdCall;)
I also tried  TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: daqDeviceDescriptor_100; var NumberOfDevices : Integer) : Longint; StdCall;, but I still get nothing in inventory (daqDeviceDescriptor_100 = array [0..99] of daqDeviceDescriptor;)
don't forget the recommendation, you should use ctypes for any c-header conversion
Sorry, I did not understand you. I tied to keep exactly the same variable types as in the C file, if that is what you mean.

https://wiki.freepascal.org/Creating_bindings_for_C_libraries#Manual_conversion_of_C_headers_to_Pascal
Quote
Note that one should use the ctypes unit together with the types that it declares to convert C headers instead of trying to use the basic Pascal types directly. This ensures that the bindings are correct in all platforms, as the C types might have different sizes on different architectures and operating systems.
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

TRon

  • Hero Member
  • *****
  • Posts: 3995
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #6 on: January 14, 2025, 01:26:24 pm »
Quote
Note that one should use the ctypes unit together with the types that it declares to convert C headers instead of trying to use the basic Pascal types directly. This ensures that the bindings are correct in all platforms, as the C types might have different sizes on different architectures and operating systems.
[/quote]
I wish more people (would have) actually follow(ed) that recommendation. Unfortunately the interwebs seems riddled with windows only headers (32-bit only seems to be a favourite and yes, even in this day and age). I don't bother anymore with the smartypants and do it myself instead as that saves at least 80% of painstakingly fixing existing borked headers. Similar thing with linking instead of loading  %)
I do not have to remember anything anymore thanks to total-recall.

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #7 on: January 14, 2025, 01:26:43 pm »
I think it runs now.
I changed

Code: Pascal  [Select][+][-]
  1. var...  NumberOfDevices : Integer = -1;      

to NumberOfDevices : Integer = 100

And this is in the converted header:


Code: Pascal  [Select][+][-]
  1. type
  2. ...
  3.  
  4.   daqDeviceDescriptor = record
  5.      ProductName   : array [0..63] of char;
  6.      ProductID   :       UInt32; //0 to 4 294 967 295
  7.      InterfaceType:     Int32; //USB_IFC= 1; BLUETOOTH_IFC = 2; ETHERNET_IFC = 4; ANY_IFC = 7;
  8.      DevString:         array [0..63] of char;
  9.      UniqueId:          array [0..63] of char;
  10.      NUID:              UInt64;
  11.      Reserved:          array [0..511] of char;
  12.   end;
  13. ...
  14.   daqDeviceDescriptor_100 = array [0..99] of daqDeviceDescriptor; ...
  15.   TcbGetDaqDeviceInventory = function (InterfaceType : integer; Invertory: daqDeviceDescriptor_100; var NumberOfDevices : Integer) : Longint; StdCall;
  16.  

And this is how I use it:


Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   ULStat : integer = 0; //Errors from the library are receved in this var. f 0, there is no error
  4.   Inventory : array [0..99] of daqDeviceDescriptor;
  5.   NumberOfDevices : Integer = 100;
  6.   DevIndex : integer = 0;
  7. begin
  8.   cbErrHandling(PRINTALL, STOPALL);
  9.   //ULStat := cbIgnoreInstaCal;
  10.   ULStat := cbGetDaqDeviceInventory(7,Inventory,NumberOfDevices);
  11.   if (ULStat = 0) and (NumberOfDevices > 0) then
  12.   for DevIndex := 0 to (NumberOfDevices -1) do
  13.   begin
  14.     ShowMessage('Device №' + IntToStr (DevIndex)
  15.     + '; Product name: ' + Inventory[DevIndex].ProductName
  16.     + '; ProductID: ' + IntToStr(Inventory[DevIndex].ProductID));
  17.   end; //for
  18. end;  
« Last Edit: January 14, 2025, 02:14:27 pm by CM630 »
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #8 on: January 14, 2025, 01:38:10 pm »

{$packrecords C} ?
I have almost the same and this should work
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$packrecords C}
  2.  type
  3.     DaqDeviceDescriptor = record
  4.         ProductName : array[0..63] of CHAR;
  5.         ProductID : UINT;
  6.         _Int32 : DaqDeviceInterface; // this differs from yours
  7.         DevString : array[0..63] of CHAR;
  8.         UniqueID : array[0..63] of CHAR;
  9.         NUID : ULONGLONG;
  10.         Reserved : array[0..511] of CHAR;
  11.       end;
  12. ....


Oddly, I saw your post just now.
_Int32 : DaqDeviceInterface; // this differs from yours

It shall be
  DaqDeviceInterface = (USB_IFC = 1,BLUETOOTH_IFC = 2,ETHERNET_IFC = 4,ANY_IFC = 7);
But it also shall be 32 bit, so considering the issues present I did not try it with an enum. As far as I understood, I shall {$MINENUMSIZE 4} in my code.

Would you share your headers?
Mine does not contain some newly introduced functions.
I do not know how to convert int EXTCCONV cbIgnoreInstaCal(); to Lazarus.   TcbIgnoreInstaCal = function: Integer; StdCall; throws an error when trying to use it (Incompatible types: got "<procedure variable type of function:LongInt;StdCall>" expected "LongInt").
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

Thaddy

  • Hero Member
  • *****
  • Posts: 16573
  • Kallstadt seems a good place to evict Trump to.
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #9 on: January 14, 2025, 06:12:36 pm »
The underscore just solves the int32 part, which is a legal fpc declaration and type.
After that, it behaves as expected. Just remember if you reference it in your code that the underscore is required.
But I am sure they don't want the Trumps back...

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #10 on: January 14, 2025, 09:58:53 pm »
Well, I added {$MINENUMSIZE 4}, things seem fine so far (cbGetDaqDeviceInventory does not find virtual devices even in C). Using an enum in this particular case seems wrong to me, but I will follow the MCC conception.

I still do not know how to convert int EXTCCONV cbIgnoreInstaCal(); to Lazarus.  I did TcbIgnoreInstaCal = function: Integer; StdCall; but the compiler throws an error when trying to use it (Incompatible types: got "<procedure variable type of function:LongInt;StdCall>" expected "LongInt").

I tried h2pas, but it failed to convert this part of the .h.
« Last Edit: January 14, 2025, 10:03:47 pm by CM630 »
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

Zvoni

  • Hero Member
  • *****
  • Posts: 2847
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #11 on: January 15, 2025, 08:02:11 am »
You're declaring a type.
You need a function
Code: Pascal  [Select][+][-]
  1. Function cbIgnoreInstaCal:Integer;stdcall;external MyLib; //blabalbla
or in case of dynamic loading a Var (definitely not a Type)
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

CM630

  • Hero Member
  • *****
  • Posts: 1261
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #12 on: January 15, 2025, 12:01:16 pm »
Code: Pascal  [Select][+][-]
  1. function cbIgnoreInstaCal: Integer; StdCall;
is for static binding.

For dynamic I use:


Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TcbIgnoreInstaCal  = function: Integer; StdCall;
  4.   cbIgnoreInstaCal:TcbIgnoreInstaCal ;
  5. ...
  6. function LoadDLL(...)
  7.       cbIgnoreInstaCal:=        TcbIgnoreInstaCal (GetProcedureAddress  (DLLHandle, 'cbIgnoreInstaCal'));
  8. ...


  TcbIgnoreInstaCal  = function: Integer; StdCall; does not look fine and causes problems. I have no idea if the static binding is fine, I do not intend to use it.
Лазар 4,0RC2 32 bit (sometimes 64 bit); FPC3,2,2

Zvoni

  • Hero Member
  • *****
  • Posts: 2847
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #13 on: January 15, 2025, 12:24:41 pm »
Code: Pascal  [Select][+][-]
  1. {$IFDEF Static}Function{$ELSE}Var{$ENDIF} cbIgnoreInstaCal{$IFDEF Dynamic}:Function{$ENDIF}():Integer;stdcall;{$IFDEF Static}External myLib;{$ENDIF}
  2. .
  3. .
  4. .
  5. Pointer(cbIgnoreInstaCal):=GetProcedureAddress(LibHandle,'cbIgnoreInstaCal');
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

alpine

  • Hero Member
  • *****
  • Posts: 1352
Re: Troubles when converting C .h (Measurement Computing / Digilent device)
« Reply #14 on: January 15, 2025, 12:38:50 pm »
I still do not know how to convert int EXTCCONV cbIgnoreInstaCal(); to Lazarus.  I did TcbIgnoreInstaCal = function: Integer; StdCall; but the compiler throws an error when trying to use it (Incompatible types: got "<procedure variable type of function:LongInt;StdCall>" expected "LongInt").

The trouble is perhaps in cbIgnoreInstaCal declaration. The following compiles without error:
Code: Pascal  [Select][+][-]
  1. type
  2.   TcbIgnoreInstaCal  = function: Integer; StdCall;
  3. var
  4.   cbIgnoreInstaCal: TcbIgnoreInstaCal;
  5.   DLLHandle: TlibHandle;
  6. begin
  7.   cbIgnoreInstaCal := TcbIgnoreInstaCal(GetProcAddress(DLLHandle, 'cbIgnoreInstaCal'));
  8. end.

Edit: Now I see: To invoke it just put () at the end:
Code: Pascal  [Select][+][-]
  1.  I := cbIgnoreInstaCal();
« Last Edit: January 15, 2025, 12:46:26 pm by alpine »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018