The question pretty much boils down to "Can I safely cast a function pointer to one with parameters convertible to those types?", but that sounds extremely suspicious without a practical example.
I made a small utility function to call something from a DLL, given the DLL name, function name, the appropriate return type, and the parameter types and arguments. However, there might be extra bloat when using this utility than what is needed. I'm wondering if it's safe to not explicitly specify the parameter types. Taking the Windows API MessageBoxW
as an example:
callStdcallDllFunction<int, HWND, PCWSTR, PCWSTR, UINT>(
L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0
);
Here I explicitly specify the return type and four parameter types of MessageBoxW
. Of course, if the arguments, starting from the right, have types equivalent to the ones in the function, I don't have to specify those. But is it ok to deduce the types as long as the arguments are valid to pass to the function in the first place (which these all are)?
callStdcallDllFunction<int>(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);
Here, I believe the result of GetProcAddress
will be casted to int(__stdcall *)(std::nullptr_t, std::nullptr_t, std::nullptr_t, int);
. The arguments passed in still fit the actual function, though. Is this still well-defined behaviour and will it always do what I want? It's worked so far every time I've tested it.
While I'm at it, is it ok to leave the return type as void
if it's unused?
//return type is void instead of the actual int
callStdcallDllFunction(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);
As far as I can tell, this has worked every time I've tried as well. If these are actually guaranteed to work, I'd love to be able to use them like this, but I really don't know if they always will, and I'm not about to take a chance of what I write being undefined behaviour.
The exact code isn't relevant to the problem, but you can find the stdcall versions (like what MessageBox
is) that you can use to test here. The only difference between these and the cdecl versions is the addition of __stdcall
in the function signature.