Click here to Skip to main content
15,902,447 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
In VC++ I'm struggling with calls to decorated functions in an external DLL which I did not create. The undecorated functions I'm trying to use are:
C#
bool Orc::cCodecHuffman::fixedTable_decode_decompress(void *,unsigned int,void const *,unsigned int)
unsigned int Orc::cCodecHuffman::fixedTable_decode_getuncompressedlength(void const *,unsigned int)
void Orc::cCodecHuffman::fixedTable_decode_init(void const *,unsigned int)


An example of my function prototypes is:
MIDL
int (__stdcall *_GetUncompressedLength) (int, int);
HMODULE hMyDLL = LoadLibrary("my.dll");

*(void**)&_GetUncompressedLength = GetProcAddress(hMyDLL, " -- decorated name -- ");

FUNC(unsigned int, GetUncompressedLength, (void* source, unsigned int sourceSz));


.. where the macro 'FUNC' is defined as:
C#
#define FUNC(ret, name, args) \
        extern "C" typedef ret (__stdcall *raw_##name) args; \
        raw_##name* name = (raw_##name*)&_##name;


An example of calling these functions:
unsigned int NUMuBytes = (*GetUncompressedLength)( (void*)sourceBytes, csize );


With this, I'm happy that I'm no longer getting
(a) access violations, and
(b) the debug error "The value of ESP was not properly saved across a function call".
But in fact the code above is way over my head.

1.) Should I create class prototypes for 'Orc' and 'cCodecHuffman' ?

2.) If I use a template to 'force_cast' the function pointers (according to the example http://www.codeguru.com/cpp/w-p/dll/importexportissues/article.php/c123), I seem to lose the '__stdcall' convention, because I get a Debug error "The value of ESP was not properly saved across a function call". How can I avoid this?

3.) I'm not sure whether I'm interpreting the output of 'GetUncompressedLength' correctly, because the number is much too high.
Am I receiving a pointer?

Please note that I'm trying to call C++ member functions:
(".. There are two problems. The first problem is that C++ member function names are decorated names (Specifying extern "C" does not help). The second problem is that C++ language specifications do not allow pointer to member functions to be converted into other types..")
Posted
Updated 22-Sep-10 10:16am
v6
Comments
Pesmontis 6-Sep-10 12:22pm    
I wasn't too careful when typing my question, I should have typed "-- decorated name --" where it previously read "-- undecorated name --".

Before I posted this question I did test code like you (both) propose, but that way I never got a proper pointer to the function (always error 'access violation'). I read somewhere else that I should use the decorated function names, and this is working: the functions are present and accept input without raising further errors.

Note that my three questions are quite specific, so what I'm really interested in is (more) specific answers.
Alain Rist 9-Sep-10 2:46am    
Use dumpbin on your library file to get the "exported name" and use it as in my answer.
Pesmontis 22-Sep-10 15:43pm    
I still get the Debug error: "The value of ESP was not properly saved across a function call"
Pesmontis 2-Oct-10 6:16am    
I've got it to work with the following changes:

#define FUNCDECL(ret, name, args) \
typedef ret (__cdecl *raw_##name) args; \
raw_##name* name = (raw_##name*)&_##name;

and:

FUNCDECL(unsigned int, GetUncompressedLength, (void*, unsigned int));

So this means I had to stop using standard calls, and I think that it is necessary to specify the exact function arguments (ie. without my own parameter names). Therefor I can now answer my own first question:

It is not necessary to create class prototypes in order to address the exports listed above (even / only for member functions from singleton classes).

The answer to the second question is: you can probably use a force cast as suggested by the codeguru article if you use a __cdecl convention. However, this is not necessary therefor I have not tested it.

The answer to the third question is: if you address the function(s) properly, using proper arguments, then the return value is indeed the function result. This will be a pointer if it is specified as a pointer. In the example I described above, the output was produced with improper function arguments. I should not have added argument names.

Hi,

Use typedef to have a readable code, and use the function signatures of your headers:
// typedef your function pointer
typedef unsigned int (__stdcall *pFnGetUncompressedLength) (void const *,unsigned int);
// declare a variable of that type
pFnGetUncompressedLength GetUncompressedLength = NULL;
HMODULE hMyDLL = LoadLibrary(_T("my.dll"));
// get the value from the dll
if (hMyDLL)
	GetUncompressedLength = (pFnGetUncompressedLength)::GetProcAddress(hMyDLL, "exported name");

Then just call the function through your variable:
if (GetUncompressedLength != NULL)
	int i = GetUncompressedLength(NULL, 0);

cheers,
AR
 
Share this answer
 
Comments
Richard MacCutchan 5-Sep-10 12:59pm    
Yes, I forgot the cast (mea culpa)!
Alain Rist 5-Sep-10 13:36pm    
I look forward to see it in your answer, without typedef it will be beautiful :)
Richard MacCutchan 5-Sep-10 14:32pm    
I leave that as an exercise for the student. And yes, it will be beautiful, in a hideous sort of way.
Pesmontis 26-Sep-10 16:48pm    
Reason for my vote of 5
Automatic vote of 5 for accepting answer.
You seem to be making things more complicated than necessary. To use the function you need a function pointer which you will initialize by calling GetProcAddress() and you can then use that pointer just like a normal function call. Your code should thus look like (I'm not actually certain that you need the __stdcall qualifier):
int (__stdcall *_GetUncompressedLength) (void*, unsigned int);

HMODULE hMyDLL = LoadLibrary("my.dll");
_GetUncompressedLength = GetProcAddress(hMyDLL, " -- undecorated name -- ");
int result = _GetUncompressedLength(source, sourceSz);

where source and sourceSz are variables of the correct type.
 
Share this answer
 
Comments
Alain Rist 5-Sep-10 12:40pm    
You need to cast the GetProcAddress() returned value :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900