Recent

Author Topic: Converting betwen D's Structs and Free Pascal's records...  (Read 6058 times)

Nafees

  • Jr. Member
  • **
  • Posts: 55
I made a shared library, that has some functions, all of which take strings as arguments, and return in structs. I used the D Language to write that library, and now I want to use it in Free Pascal, with Lazarus, to make a GUI for it.

Will Lazarus automatically convert between pascal style strings and D Strings? I believe not, so how can I do that. Plus, how can I convert a D struct to a Pascal record?

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #1 on: May 05, 2016, 04:19:57 pm »
I don't know what D is, but I trust it supports a C calling conventions. If so, then calling a D library from Pascal would be similar calling a C library.

That is, in general, if you need to pass in a string, you would pass a pointer. Eg, in Pascal:

  PAnsiChar(AnsiString(mystring))

Returning strings and structures generally means passing in a pointer to a buffer that the library then populates. With a string, you would also pass in the size of the buffer so that the library doesn't overwrite the end of the buffer. Converting a C string after the library function returns looks like something like this:

  AnsiString(StrBuf)

These articles deal with calling a Pascal library from different languages, but many of the principles are the same:

https://dl.dropboxusercontent.com/u/28343282/MacXPlatform/PascalDynLibs.html

-Phil
« Last Edit: May 05, 2016, 04:31:11 pm by Phil »

Nafees

  • Jr. Member
  • **
  • Posts: 55
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #2 on: May 22, 2016, 03:30:47 pm »
I don't know what D is, but I trust it supports a C calling conventions. If so, then calling a D library from Pascal would be similar calling a C library.

That is, in general, if you need to pass in a string, you would pass a pointer. Eg, in Pascal:

  PAnsiChar(AnsiString(mystring))

Returning strings and structures generally means passing in a pointer to a buffer that the library then populates. With a string, you would also pass in the size of the buffer so that the library doesn't overwrite the end of the buffer. Converting a C string after the library function returns looks like something like this:

  AnsiString(StrBuf)

These articles deal with calling a Pascal library from different languages, but many of the principles are the same:

https://dl.dropboxusercontent.com/u/28343282/MacXPlatform/PascalDynLibs.html

-Phil
Sorry for the late reply (reeeallly late). You're right, D is just like C/C++. same calling conventions. I understand how to pass/receive strings, but how can I do that with structs. I will have to receive+send structs.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #3 on: May 22, 2016, 04:39:19 pm »
I understand how to pass/receive strings, but how can I do that with structs. I will have to receive+send structs.
No different. As long as both languages agree about the packing, padding, field ordering and such specific details, it can be passed from one to another.

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer

Nafees

  • Jr. Member
  • **
  • Posts: 55
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #5 on: May 29, 2016, 06:49:13 pm »
I tried Phil's solution, but the problem is somewhere else. I found out that the functions in the library don't receive their parameters in the right form. I created a new empty library, created a new function, that takes no parameters, and return 58 in a byte, it worked. But when I changed it to receive a byte, and return it, as-it-was-sent, it sends back 0. Then using the debugger, I found out that either Lazarus isn't sending the parameters correctly, or the library isn't receiving them correctly.

I don't doubt my code as much as I do lazarus, because the same library works on C++, C, and D hosts.

Any ideas what's causing this? I posted a question on Stackoverflow.com too, but no help from there yet.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #6 on: May 29, 2016, 07:37:47 pm »
Using the wrong calling convention perhaps ?

More details can be found here. Unfortunately i have not the slightest idea about how D generated libraries expects things to be pushed to their functions.
« Last Edit: May 29, 2016, 07:41:27 pm by molly »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #7 on: May 29, 2016, 08:35:48 pm »
I tried Phil's solution, but the problem is somewhere else. I found out that the functions in the library don't receive their parameters in the right form. I created a new empty library, created a new function, that takes no parameters, and return 58 in a byte, it worked. But when I changed it to receive a byte, and return it, as-it-was-sent, it sends back 0. Then using the debugger, I found out that either Lazarus isn't sending the parameters correctly, or the library isn't receiving them correctly.

I don't doubt my code as much as I do lazarus, because the same library works on C++, C, and D hosts.

Any ideas what's causing this? I posted a question on Stackoverflow.com too, but no help from there yet.
Compilable or at least inspectable code please, I can't guess what you code. It's very likely the calling convention is wrong. D's ABI is clearly documented and it follows C whenever C provides one.

My early test has no problem at all on the first try:
Code: D  [Select][+][-]
  1. // testdll.d
  2. module testdll;
  3.  
  4. extern(C) {
  5.  
  6. export int lol(int param) {
  7.   return param;
  8. }
  9.  
  10. struct S { int a; int b; int c; int d;}
  11.  
  12. export void lol2(ref S s) {
  13.   import std.stdio;
  14.   printf("%d %d %d %d\n", s.a, s.b, s.c, s.d);
  15.   s.a = 2;
  16.   s.b = 4;
  17.   s.c = 8;
  18.   s.d = 16;
  19. }
  20.  
  21. }
  22.  
Code: Pascal  [Select][+][-]
  1. // lol.pas
  2. uses ctypes;
  3.  
  4. {$packrecords c}
  5.  
  6. type
  7.   TWhatever = record
  8.     a,b,c,d : cint;
  9.   end;
  10.  
  11. function lol(param: cint): cint; cdecl; external 'testdll';
  12. procedure lol2(var param: TWhatever); cdecl; external 'testdll';
  13.  
  14. var
  15.   w: TWhatever;
  16. begin
  17.   writeln(lol(234));
  18.   with w do begin
  19.     a := 256;
  20.     b := 128;
  21.     c := 64;
  22.     d := 32;
  23.   end;
  24.   lol2(w);
  25.   writeln(w.a,' ',w.b,' ',w.c,' ',w.d);
  26. end.
  27.  
Code: Bash  [Select][+][-]
  1. $ LD_LIBRARY_PATH=. ./lol
  2. 234
  3. 256 128 64 32
  4. 2 4 8 16
  5.  
« Last Edit: May 29, 2016, 08:58:27 pm by Leledumbo »

Nafees

  • Jr. Member
  • **
  • Posts: 55
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #8 on: May 30, 2016, 07:04:24 am »
@Leledumbo My mistake here, I was using integer type instead of the cint. Thanks everyone, you solved a problem on which I had wasted a whole of 8 hours!

Nafees

  • Jr. Member
  • **
  • Posts: 55
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #9 on: May 30, 2016, 09:41:36 am »
Just one more question, How can I send/receive arrays (dynamic)?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8746
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #10 on: May 30, 2016, 11:14:30 am »
Just one more question, How can I send/receive arrays (dynamic)?
The same way and restriction as string types.

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #11 on: May 30, 2016, 09:31:51 pm »
Just one more question, How can I send/receive arrays (dynamic)?

Follow Leledumbo's lead here. With a string, the null byte at the end will indicate the length, but with an array passed as a pointer to a structure or buffer, you'll probably need to pass the length of the array too.

Note his use of {$packrecords c} in the calling code. Since he's working on Linux, he's assuming that the D library is conforming to GCC alignment of the packed record, I would guess. If you're working on Windows, check to see what the assumption is for your D compiler. With Visual C++, I believe the assumption is normally "natural" alignment. You can handle both like this if so:

 {$IFDEF MSWINDOWS}
  {$packrecords default} //assume compiled with Visual C++, natural alignment
 {$ELSE}
  {$packrecords c} //assume compiled with GCC
 {$ENDIF}

-Phil

Nafees

  • Jr. Member
  • **
  • Posts: 55
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #12 on: May 31, 2016, 08:00:59 am »
Thanks again everyone. And @Phil, I'm on Linux too, abandoned Windows development months ago.

Zoran

  • Hero Member
  • *****
  • Posts: 1829
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Converting betwen D's Structs and Free Pascal's records...
« Reply #13 on: May 31, 2016, 08:37:56 am »
Thanks again everyone. And @Phil, I'm on Linux too, abandoned Windows development months ago.

That is actually the reason to be more careful, as once you might want to compile your application and library on Windows. I suggest you to take care of it from the start. So, use ifdef as Phil suggested.

 

TinyPortal © 2005-2018