3

Suppose I have a dll with 2 functions.name of dll="dll1" f1(int a, int b, int c);

f2(int a);

My program would take the function name ,the dll name and a "list" of parameters as input. how would i call the appropriate function with its appropriate parameters. i.e, if input is dll1 f1 list(5,8,9)

this would require me to call f1 with 3 parameters if input was dll1 f2 list(8) it would require me to call f2 with one parameter how would i call the function without knowing the number of parameters in advance.

further clarification: how do I write code that will call any function with all its arguments by building the argument list dynamically using some other source of information

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Sourabh Bose
  • 189
  • 2
  • 10
  • Do you know in advance that the function only takes integers? – David Schwartz Mar 26 '12 at 03:22
  • I don't understand the question - it seems you *do* know the number of parameters in advance, because they are passed into your program. On the other hand, if you don't know how many parameters a function expects in the .dll, then you probably shouldn't try to call the function. – Brian L Mar 26 '12 at 03:23
  • Expanding on @BrianL comments, are you suggesting that the functions in the *dll* may change in the future? – cctan Mar 26 '12 at 03:30
  • 2
    The C++ language does not have the ability to call functions whose signatures are determined at runtime. – Raymond Chen Mar 26 '12 at 03:41
  • 1
    What is the value of calling a function if you are unsure about the number of arguments? you're asking for uninitialized variables and/or stack corruption. – Oscar Korz Mar 26 '12 at 03:42
  • @RaymondChen: printf's signature is determined at runtime. – Carey Gregory Mar 26 '12 at 04:08
  • @CareyGregory You can write a function which is *called* with a runtime-determine number of arguments, but the question was about *calling* with a runtime-determined signature. printf is an example of the former not the latter.(Note that printf's signature is still compile-time: (char*, ...) – Raymond Chen Mar 26 '12 at 05:09
  • You can know every function's number of parameter in advance, if you assume the dll will not change, so why would it be unknown? – cctan Mar 26 '12 at 05:52
  • @RaymondChen: I think you're reading the question too academically. He can, indeed, accomplish what he wants to do using variadic function declarations and dynamic loading. In short, it's certainly possible to construct the stack correctly and use the correct calling convention for any function using strictly C++. It will be hackish, but it can be done. – Carey Gregory Mar 26 '12 at 19:16

4 Answers4

3

Since the generated code differs based on the number of parameters, you have two choices: you can write some code in assembly language to do the job (basically walk through the parameter list and push each on the stack before calling the function), or you can create something like an array of pointers to functions, one for each number of parameters you care about (e.g., 0 through 10). Most people find the latter a lot simpler to deal with (if only because it avoids using assembly language at all).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • yes i thought of that but it becomes a bit less flexible. i.e, no function may have more than 10 parameters . – Sourabh Bose Mar 26 '12 at 03:18
  • 1
    @SourabhBose: Yes, a little. If you really need to support an arbitrary number, assembly language is about your only choice. Realistically, it's pretty trivial to support up to, say, 20; needing more than that is so rare it's hardly worth most people's time. – Jerry Coffin Mar 26 '12 at 03:20
  • @user1131467: Perhaps if you could offer a truly workable alternative, that would be merited, but so far you haven't (and I doubt you will either). – Jerry Coffin Mar 26 '12 at 03:41
  • @user1131467: Have you actually tested it? I tried, and it completely failed, even when the number/type of parameters matched. – Jerry Coffin Mar 26 '12 at 15:52
  • @JerryCoffin: No I didn't debug it (if it's not working maybe you have misinterpreted the pass-by-value/pass-by-reference semantics of the Args... deduction), but I am withdrawing my answer anyway because the questioner implies that he doesn't know until runtime the number of paramters, and my solution requires compile-time binding to instantiate the signature and template function. – Andrew Tomazos Mar 26 '12 at 19:00
  • @user1131467 yes,but your answer did help me in another project thnx. – Sourabh Bose Mar 27 '12 at 13:02
2

To solve the problem in general you need to know:

  1. The calling conventions (those stdcall, cdecl, fastcall, thiscall (btw, the latter two can be combined in MSVC++), etc things) that govern how the functions receive their parameters (e.g. in special registers, on the stack, both), how they return values (same) and what they are allowed to trash (e.g. some registers).
  2. Exact function prototypes.

You can find all this only in the symbol/debug information produced by the compiler and (likely to a lesser extent) the header file containing the prototypes for the functions in the DLL. There's one problem with the header file. If it doesn't specify the calling convention and the functions have been compiled with non-default calling conventions (via a compiler option), you have ambiguity to deal with. In either case you'll need to parse something.

If you don't have this information, the only option left is reverse engineering of the DLL and/or its user(s).

In order to correctly invoke an arbitrary function only knowing its prototype and calling convention at run time you need to construct code analogous to that produced by the compiler when calling this function when it's known at compile time. If you're solving the general problem, you'll need some assembly code here, not necessarily hand-written, run-time generated machine code is a good option.

Last but not least, you need some code to generate parameter values. This is most trivial with numeric types (ints, floats and the like) and arrays of them and most difficult with structures, unions and classes. Creating the latter on the fly may be at least as difficult as properly invoking functions. Don't forget that they may refer to other objects using pointers and references.

The general problem is solvable, but not cheaply. It's far easier to solve a few simple specific cases and maybe avoid the entire problem altogether by rewriting the functions to have less-variable parameters and only one calling convention OR by writing wrapper functions to do that.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
0

If your clients know at compile-time, then can wrap it this way:

template<class Args...>
void CallFunctionPointer(void* pf, Args&&... args)
{
    typedef void(*FunctionType)(Args...);
    FunctionType* pf2 = (FunctionType*) pf;
    (*pf2)(forward<Args>(args)...);
}

Note, if you pass the wrong number of paramters or the wrong type(s) of parameters behaviour is undefined.

Background:

In C/C++ you can cast a function pointer to any signature you want, however if you get it wrong behavior is undefined.

In your case there are two signatures you have mentioned:

void (*)(int)

and

void (*)(int, int, int)

When you load the function from the DLL it is your responsibility to make sure you cast it to the correct signature, with the correct number and types of parameters before you call it.

If you have control over the design of these functions, I would modify them to take a variable number of arguments. It the base type is always int, than just change the signature of all the functions to:

void (*)(int* begin, size_t n);
// begin points to an array of int of n elements

so that you can safely bind any of the functions to any number of arguments.

Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • @SourabhBose: Ok I've updated my answer given you can't control function signatures. See above. – Andrew Tomazos Mar 26 '12 at 03:33
  • -1: It's undefined behavior to cast a function pointer to `void*`. – Oscar Korz Mar 26 '12 at 03:44
  • @OscarKorz: Can you provide a standard reference for that statement? Also I am not casting a function pointer to void*, I am casting it from void*. This happens every time a dynamic library is loaded. – Andrew Tomazos Mar 26 '12 at 15:48
  • I don't have a copy of the C99 standard so I cannot cite the appropriate section, but this has been discussed previously on SO: http://stackoverflow.com/questions/4924690/c-why-is-casting-from-void-pointer-to-function-pointer-undefined http://stackoverflow.com/questions/5579835/c-function-pointer-casting-to-void-pointer – Oscar Korz Mar 28 '12 at 02:57
  • Apparently this behavior is allowed by POSIX. I will retract the -1 if the post is edited again (my vote is locked). – Oscar Korz Mar 28 '12 at 03:00
0

You might want to check out the Named Parameter Idiom.

It uses method chaining to basically accomplish what you want.

It solves the problem where you know what a default set of arguments look like, but you only need to customize a few of them and not necessarily in the order they are declared.

Carl
  • 43,122
  • 10
  • 80
  • 104
  • 1
    This only applies when/if you can write the DLLs specifically to support this usage (at which point nearly the entire problem disappears -- he can just write the functions to take the list he's starting with, and use it directly). – Jerry Coffin Mar 26 '12 at 04:28