Recent

Author Topic: DLL function with variable paramters  (Read 1064 times)

Graham1

  • Jr. Member
  • **
  • Posts: 57
DLL function with variable paramters
« on: February 29, 2024, 03:45:02 am »
I'm trying to write a DLL based on an example I've got that's written in C. The example code has an exported function defined as:

Code: C  [Select][+][-]
  1. CPEXTDEVICE_API int SendDeviceMessage(UINT msgid,...)
  2. {
  3.         va_list marker;
  4.         va_start(marker, msgid );     /* Initialize variable arguments. */
  5.         switch(msgid)
  6.         {
  7.         case EXTDEVMSG_INITDEVICE:
  8.                 {
  9.                         UINT mode=va_arg(marker,UINT);
  10.                         HWND hWnd=va_arg(marker,HWND);
  11.                         UINT msgid=va_arg(marker,UINT);
  12.                         return dev.InitDevice(mode,hWnd,msgid);
  13.                 }
  14.         case EXTDEVMSG_STOPDEVICE:
  15.                 return dev.StopDevice();
  16.         case EXTDEVMSG_CONFIGURE:
  17.                 return dev.ConfigureDevice(va_arg(marker,HWND));
  18.         case EXTDEVMSG_SETMODE:
  19.                 return dev.SetMode(va_arg(marker,UINT));
  20.         case EXTDEVMSG_GETDESCRIPTION:
  21.                 {
  22.                         LPSTR outstr=va_arg(marker,LPSTR);
  23.                         UINT len=va_arg(marker,UINT);
  24.                         return dev.GetDescription(outstr,len);
  25.                 }
  26.         case EXTDEVMSG_DOMOVE:
  27.                 return dev.DoMove(va_arg(marker,LPCSTR));
  28.         case EXTDEVMSG_SETPOSITION:
  29.                 return dev.SetPosition(va_arg(marker,LPCSTR));
  30.         case EXTDEVMSG_NEWGAME:
  31.                 return dev.NewGame();
  32.  
  33.         }
  34.         va_end( marker );              /* Reset variable arguments.      */
  35.         return EXTDEVERR_NOTIMPL;       // unknown function
  36. }
  37.  

The problem is that the parameters of the function depend on the value of the first parameter, and there might not be any more or they might be of different types. Also, in the case of GETDESCRIPTION two of the parameters (outstr and len) are VAR parameters. How should I do this? I don't think I can define the same procedure name with different parameter lists but then just have one exports statement.

I only require 32-bit Windows (so I suppose it will be STDCALL) if that makes a difference.

Thanks.

EDIT: I should have mentioned in my post that I have no access to the source code of the calling EXE. So anything I do can only be done in the DLL!
« Last Edit: February 29, 2024, 04:38:36 am by Graham1 »
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

hshatti

  • New member
  • *
  • Posts: 7
  • Don't be evil isn't enough, Be virtuous!
Re: DLL function with variable paramters
« Reply #1 on: February 29, 2024, 03:56:39 am »
I think you should consider adding the following routine decorator in pascal
Code: Pascal  [Select][+][-]
  1.  procedure invokeMe(const arg1:pchar); cdecl; varargs;
this will allow the function to have open untyped parameters and behave exactly like in C, here is an example from FPC language reference :

Code: Pascal  [Select][+][-]
  1. // The following declarations are two ways of referring to the same function in the C library:
  2.  
  3. Function PrintF1(fmt : pchar); cdecl; varargs;  
  4.  
  5.                                external 'c' name 'printf';  
  6.  
  7. Function PrintF2(fmt : pchar; Args : Array of const); cdecl;  
  8.  
  9.                                external 'c' name 'printf';
  10.  

hope this helps,
cheers
Don't be evil isn't enough, Be virtuous!
------------
Research-O-Holic .. Highly Skilled Delphi/Lazarus/FPC developer Oh C/C++ too - Solutions with Micro-Controllers (PIC+AVR +STM .. etc )- I.A - anything related to bind thinking and humanity with technology .. all the interesting ideas

TRon

  • Hero Member
  • *****
  • Posts: 2491
Re: DLL function with variable paramters
« Reply #2 on: February 29, 2024, 04:13:10 am »
I'm trying to write a DLL based on an example I've got that's written in C. The example code has an exported function defined as:
While hshatti's suggestion is a good one it does actually create a problem.

There is no counterpart for the in c available macros' va_list and va_start, and even when you would implement them it is (c) compiler and platform specific.

So then the problem is how to obtain (access to) the other arguments and determine their size and position on the stack.

Graham1

  • Jr. Member
  • **
  • Posts: 57
Re: DLL function with variable paramters
« Reply #3 on: February 29, 2024, 04:47:53 am »
I think you should consider adding the following routine decorator in pascal
Code: Pascal  [Select][+][-]
  1.  procedure invokeMe(const arg1:pchar); cdecl; varargs;
this will allow the function to have open untyped parameters and behave exactly like in C, here is an example from FPC language reference :

Code: Pascal  [Select][+][-]
  1. // The following declarations are two ways of referring to the same function in the C library:
  2.  
  3. Function PrintF1(fmt : pchar); cdecl; varargs;  
  4.  
  5.                                external 'c' name 'printf';  
  6.  
  7. Function PrintF2(fmt : pchar; Args : Array of const); cdecl;  
  8.  
  9.                                external 'c' name 'printf';
  10.  

hope this helps,
cheers

Thank you, but as far as I can tell the VARARGS modifier needs to be in the calling program rather than the DLL. I think. I couldn't get my library to compile using it as it wanted an EXTERNAL too.
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

440bx

  • Hero Member
  • *****
  • Posts: 4013
Re: DLL function with variable paramters
« Reply #4 on: February 29, 2024, 04:50:06 am »
the problem is, FPC does NOT allow vararg functions/procedures.  Vararg can only be used to declare an _external_ function (usually written in C or C++).

However, FPC provides an elegant, simple and type-safe solution to the problem.

The function you've shown takes a variable number of parameters... no problem!  in the DLL define _multiple_ functions for the different types and number of parameters. You'd have something along these lines:
Code: Pascal  [Select][+][-]
  1. SendDeviceMessage_1P(UINT msgid, Parameter: ParameterType); begin <code> end;
  2. SendDeviceMessage_2P(UINT msgid, P1 : P1type; P2: P2type); begin end;
and so on for every possibility (which in your case is determined by the enumeration in the switch.

In the unit that declares the dll functions (to make them available to the external program) you use FPC's function overloading.  You simply declare every function with the same name, i.e, SendDeviceMessage and specifying external <yourdllname>; name "SendDeviceMessage_xP" where x is the name that matches the number of parameters in the declaration.

that way, you can have a single function name along with a variable number of parameters of different types and, all that with the Pascal bonus that the compiler can do type checking, which neither C nor C++ can type check because "..." may be anything.  Long live Pascal :)

« Last Edit: February 29, 2024, 04:52:29 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Graham1

  • Jr. Member
  • **
  • Posts: 57
Re: DLL function with variable paramters
« Reply #5 on: February 29, 2024, 05:09:50 am »
the problem is, FPC does NOT allow vararg functions/procedures.  Vararg can only be used to declare an _external_ function (usually written in C or C++).

However, FPC provides an elegant, simple and type-safe solution to the problem.

The function you've shown takes a variable number of parameters... no problem!  in the DLL define _multiple_ functions for the different types and number of parameters. You'd have something along these lines:
Code: Pascal  [Select][+][-]
  1. SendDeviceMessage_1P(UINT msgid, Parameter: ParameterType); begin <code> end;
  2. SendDeviceMessage_2P(UINT msgid, P1 : P1type; P2: P2type); begin end;
and so on for every possibility (which in your case is determined by the enumeration in the switch.

In the unit that declares the dll functions (to make them available to the external program) you use FPC's function overloading.  You simply declare every function with the same name, i.e, SendDeviceMessage and specifying external <yourdllname>; name "SendDeviceMessage_xP" where x is the name that matches the number of parameters in the declaration.

that way, you can have a single function name along with a variable number of parameters of different types and, all that with the Pascal bonus that the compiler can do type checking, which neither C nor C++ can type check because "..." may be anything.  Long live Pascal :)

I'm beginning to think the people that wrote the calling EXE only expected people writing DLLs to talk to it in C. The problem here is that the DLL still seems to be exporting two functions, and the overload is handled by the calling EXE. What I need is the DLL to export one function and have it handle the parameters itself. Something like:

Code: Pascal  [Select][+][-]
  1. exports SendDeviceMessage1 name 'SendDeviceMessage',
  2.         SendDeviceMessage2 name 'SendDeviceMessage';
  3.  

where the two functions have different parameter lists. As TRon says, there doesn't seem to be any way to do this in Pascal.  :(
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

TRon

  • Hero Member
  • *****
  • Posts: 2491
Re: DLL function with variable paramters
« Reply #6 on: February 29, 2024, 05:17:45 am »
You can't at least not solve it the way c does, unless resorting to assembler (that is, to my knowledge).

But you can actually use other approaches such as the use of a taglist or an array of const.

The question becomes, is that how the dll /can/ be used by 3th parties ?
« Last Edit: February 29, 2024, 05:23:23 am by TRon »

440bx

  • Hero Member
  • *****
  • Posts: 4013
Re: DLL function with variable paramters
« Reply #7 on: February 29, 2024, 05:29:06 am »
The problem here is that the DLL still seems to be exporting two functions, and the overload is handled by the calling EXE. What I need is the DLL to export one function and have it handle the parameters itself.
Yes, the dll will actually be exporting more than  one function BUT that fact will be hidden from the caller by the overloads in the unit that declares the dll functions.  The dll user will see only one function that "magically" takes a variable number of parameters of different types.

The overhead associated with having multiple functions is very low - mostly just additional stack frames, one per function - and for that small additional overhead you gain type checking (a major bonus IMO)

All that said, as TRon pointed out, if you need the dll to be available to other languages, such as C and C++, then with the method I suggested, you're out of luck for any language that does not support function overloading (such as C.)  Such languages would have to use each individual name.

Anyway, the bottom line is: Pascal does not have the equivalent to C's "...".  It can be simulated quite well using function overloading but, it isn't the same thing because the interfaces (low level parameter passing) are different.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Graham1

  • Jr. Member
  • **
  • Posts: 57
Re: DLL function with variable paramters
« Reply #8 on: February 29, 2024, 05:34:27 am »
You can't at least not solve it the way c does, unless resorting to assembler (that is, to my knowledge).

But you can actually use other approaches such as the use of a taglist or an array of const.

The question becomes, is that how the dll /can/ be used by 3th parties ?

There is only one "third party"! A company has written a program and provided an example DLL written in C showing how to get other devices working with their program. I am trying to write a DLL to do that. Unfortunately the way they have done it uses this C construct that doesn't translate into Pascal. So, i can't change the calling EXE and I can't implement the DLL function exactly how they do it in C but if there was any other way that would work that would be good.

The function seems to have a maximum of 4 parameters. Can I just define them all as UINT and treat them as integers, handles, or pointers once I know what the msgid is, or isn't that going to work? If it's called with only one paramter by the EXE I suppose the other three would appear as NIL to my DLL?
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

TRon

  • Hero Member
  • *****
  • Posts: 2491
Re: DLL function with variable paramters
« Reply #9 on: February 29, 2024, 05:41:09 am »
There is only one "third party"! A company has written a program and provided an example DLL written in C showing how to get other devices working with their program. I am trying to write a DLL to do that.
I was afraid you were going to say that...

Quote
Unfortunately the way they have done it uses this C construct that doesn't translate into Pascal. So, i can't change the calling EXE and I can't implement the DLL function exactly how they do it in C but if there was any other way that would work that would be good.
It is not only unfortunate, it is the way how many API's work because... well.. OS (or 3th party software) written in c

Quote
The function seems to have a maximum of 4 parameters. Can I just define them all as UINT and treat them as integers, handles, or pointers once I know what the msgid is, or isn't that going to work? If it's called with only one paramter by the EXE I suppose the other three would appear as NIL to my DLL?
No unfortunately you cannot. It has to do with the number of parameters that are passed to the stack. You will have to retrieve exactly the same amount from that stack otherwise it will result in stack corruption.

Since you can't change the exe.... that is a problem. As said (and afaik), it is not possible to realize without resorting to some assembler code (and a fair bit of understanding on how parameters are pushed on and popped from the stack.

440bx

  • Hero Member
  • *****
  • Posts: 4013
Re: DLL function with variable paramters
« Reply #10 on: February 29, 2024, 05:44:54 am »
There is only one "third party"! A company has written a program and provided an example DLL written in C showing how to get other devices working with their program.
Is the company going to use C to call your function written in Pascal ?
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Graham1

  • Jr. Member
  • **
  • Posts: 57
Re: DLL function with variable paramters
« Reply #11 on: February 29, 2024, 05:51:56 am »
it is not possible to realize without resorting to some assembler code (and a fair bit of understanding on how parameters are pushed on and popped from the stack.

Ah, OK. I'll give up on this plan for the moment. Thank you all for your help though!
Windows 10/11 Home 64-bit (and Linux because I have to)
Lazarus 2.0.12 / FPC 3.2.0 (because libQt5pas 1.2.6)
Linux Mint 20 (because GLIBC_2.31)

440bx

  • Hero Member
  • *****
  • Posts: 4013
Re: DLL function with variable paramters
« Reply #12 on: February 29, 2024, 05:54:12 am »
Ah, OK. I'll give up on this plan for the moment. Thank you all for your help though!
If you had answered my question and depending on what the answer is, there could be a solution to the problem you face.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

TRon

  • Hero Member
  • *****
  • Posts: 2491
Re: DLL function with variable paramters
« Reply #13 on: February 29, 2024, 06:17:14 am »
If you had answered my question and depending on what the answer is, there could be a solution to the problem you face.
Beside what 440bx wrote there (because he has a point and I only assumed you have no influence regarding the caller) I seem to have found a solution that does not require assembler (but does require knowledge on how the stack works) though it is specifically written for Delphi, aimed at 32-bit and Windows specific.

The solution is from Barry Kelly and could perhaps help you inspire. It can be found here.

Also note that all my answers are AFAIK. and on that same note I am not aware of any (other) provision by FPC that is able to aid in approaching your problem.

TRon

  • Hero Member
  • *****
  • Posts: 2491
Re: DLL function with variable paramters
« Reply #14 on: February 29, 2024, 07:16:19 am »
Mystery repeats... or is it History repeats... ?  :)

 

TinyPortal © 2005-2018