Reputation: 1061
I have code that looks like this:
extern "C" __declspec(dllexport) myInterface(int id, void** pFunction)
{
...
}
I need to make the void** pFunction argument point to a function so that the caller can use this function via the pFunction pointer. This function gets called through a DLL, I don't want to do it this way but for a lot of reasons I have no choice. I know that COM is made for this but I can not use it, the reasons come down to management.
At this point I have no idea how to do this, everything I have tried to do gives me cast problems. Do anyone have any idea how I can do this? I can post more if this is unclear.
Thanks.
Upvotes: 0
Views: 508
Reputation: 1061
I want to thank everyone for help. Here is how I get it to work at least in part. Basically the wrapper idea works.
struct myProj { virtual HRESULT __stdcall myMethod(unsigned short* & myname); };
HRESULT __stdcall myMethod(unsigned short* & myname) { myname = L"myname";
return(1); }
struct myProj xProject;
To call it:
extern "C" HRESULT __declspec(dllexport) fInterface(UINT id, LPVOID * pObj) { switch(id) { case FVI_ID: *pObj = &xProject; break; } }
This does call the correct function, but it still has it's problems. The third party DLL uses CStrings and I suspect they are giving my other problems as well as some trace functions they contain.
I believe my real solution is I can't fake out the com, that we need to realize the DLL's can not be used in our project.
Thanks everyone.
Upvotes: 0
Reputation: 89975
As Jonathan Leffler and David Thornley mentioned, you aren't guaranteed that a function pointer can be converted to void*
and back. A portable workaround would be to package the function pointer into a struct
and to pass a pointer to that.
(Be aware that void**
itself might have its own issues. You can avoid this too.)
For example:
typedef int (*SomeFuncType)(int);
struct FuncWrapper
{
SomeFuncType func;
void* output;
};
...
FuncWrapper funcWrapper;
funcWrapper.func = ...;
myInterface(id, &funcWrapper);
and then myInterface could be implemented as:
void myInterface(int id, FuncWrapper* funcWrapper)
{
funcWrapper->func(...);
funcWrapper->output = ...;
}
Upvotes: 1
Reputation: 48267
It's tricksy, but I've had good luck with code like so:
*reinterpret_cast<void**>( &(PVOID&)( DetourFunc ) ) = (PVOID) 0x00FFFF00;
The concept, as I understand it, is you're referencing a reference, reinterpreting the reference, then dereferencing it. Bit confusing, but I can verify it works. You can also put an address on the right side (&func) and it'll work. Calling DetourFunc, using the form:
(DetourFunc)(param, param)
will call the original address or function.
Edit: This works, but it seems like a pretty heavy abuse of the language. It does work, though, and has been recommended in a few other questions here.
Upvotes: 1
Reputation: 753765
If you are looking at the implementation of 'myInterface', then you might be wanting:
switch (id)
{
case FUNC_1:
*pFunction = (void *)first_function;
break;
...
}
If you are trying to call the function and pass in a pointer to function, then:
void *vp = (void *)the_function_to_pass;
myInterface(1, &vp);
If you have something else in mind, you need to specify what.
(Note that strictly, C does not guarantee that function pointers can be assigned to object pointers and vice versa. However, POSIX does make that guarantee for you. I believe similar comments apply to C++.)
Upvotes: 3
Reputation: 57036
This is not something that can be done in standard C or C++. There is no guarantee that a function pointer can fit into a void pointer (C++ member function pointers typically can't). In other words, if you can't change the function signature, you can't do what you want in standard C or C++, and there's no guarantee you can do it at all.
Therefore, any solution would be a platform-specific one. You don't specify a platform directly in question or tag, but my guess would be Visual C++ from other things.
Please specify your platform specifically, and anything useful about the function pointer you want to pass.
Upvotes: 1