• Advertisement
Sign in to follow this  

Using GetProcAddress in C

This topic is 3928 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I am using VC++ 7.1 I need to call a function from a dll(MSQ.dll) using run time loading from the application app.exe I would be thankful if anyone can see the below piece of code and see if there are any mistakes in the way the function ModuleStateQuery() is called. The function ModuleStateQuery() is exported using a .def file.I have checked the dll exports using dumpbin and the function name is not decorated. I am not getting the correct return value that is expected. ==========MSQ.dll(C code compiled in VC++ 7.1)========= extern "C" int FAR PASCAL ModuleStateQuery(const char * moduleName){ } =============================================== =====app.exe(C code compiled in VC++ 7.1)============== HMODULE hDLL_ = NULL; FARPROC ModuleStateQuery; int active; hDLL_ = LoadLibrary("MSQ.dll"); if(hDLL_) { ModuleStateQuery = GetProcAddress(hDLL_,"ModuleStateQuery"); if (ModuleStateQuery != NULL) { active = (ModuleStateQuery)("MODULEA\0"); } } ================================================ Thanks in advance, Rohini Chandra

Share this post


Link to post
Share on other sites
Advertisement
Declare a typedef for the function pointer and use that instead of FARPROC.



typedef int (FAR PASCAL *ModuleStateQueryT)(const char * moduleName);

HMODULE hDLL_ = NULL;
ModuleStateQueryT ModuleStateQuery;
int active;

hDLL_ = LoadLibrary("MSQ.dll");
if(hDLL_)
{
ModuleStateQuery = (ModuleStateQueryT)GetProcAddress(hDLL_,"ModuleStateQuery");
if (ModuleStateQuery != NULL) {
active = (*ModuleStateQuery)("MODULEA\0");
}



Share this post


Link to post
Share on other sites
What return value are you getting? If it's nonzero, then it must be the address of the function by that name, by definition of GetProcAddress.

Edit: I see now that you meant the return function of ModuleStateQuery, not GetProcAddress. I second the typedef suggestion.

Admiral

Share this post


Link to post
Share on other sites
I would create a typedef (and not use FARPROC). You're probably using a C++ compiler, and FARPROC is a fake type that does not match the declaration of your functions - that would explain your problem.

// in app.exe
typedef int (FAR PASCAL *module_state_query_pfnt)(const char*);

module_state_query_pfnt ModuleStateQuery;
ModuleStateQuery = (module_state_query_pfnt)(GetProcAddress(hDLL_,"ModuleStateQuery"));
if (ModuleStateQuery)
{
// you don't need to zero-terminate your sring - this is done
// automagically by the compiler.
int active = ModuleStateQuery("MODULEA");
}


HTH,

[Damn. beaten]

Share this post


Link to post
Share on other sites
Hi,

Thank you every one.
It works now and I am getting the proper return code that was expected.
Initially I used a function pointer defined by me instead of FARPROC but did not
use the calling convention FAR PASCAL(Is FAR also part of calling convention)
while defining the function pointer(I haven't written the MSQ.dll that the app.exe used.)and so I turned to FARPROC.

Thanking you once again,
Rohini Chandra

Share this post


Link to post
Share on other sites
The FAR statement is a leftover from the days of DOS and 64kb memory segments. The preprocessor replaces it with an empty string.

Share this post


Link to post
Share on other sites
i've a situation where i want to call a dll(i create this dll) and this function return 2 string values.how to get those return value for me to use it im my exe??

here's some of my codes:
//declaration
typedef int (*MYPROC)(LPTSTR);
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

char libname[100];
char funcname[100];
char tmpbuf[1000];

// Get a handle to the DLL module.
hinstLib = LoadLibrary(libname);

// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, funcname);


// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (tmpbuf); //here's i send the input value//
//but where should i get the return value??//
}

// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}

// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message via alternative method\n");

Share this post


Link to post
Share on other sites
Quote:
Original post by biggurlz
i've a situation where i want to call a dll(i create this dll) and this function return 2 string values.how to get those return value for me to use it im my exe??


Erm...how does your function manage to return 2 string values when a function can return only one value.

Share this post


Link to post
Share on other sites
Pass two buffers to the function as "out" parameters.


int myfunk(char **buff1, char **buff2)
{
*buff1 = // fill me up
*buff2 = // fill me up
return 0; // return ok or whatever
}

char buffer1[256];
char buffer2[256];

int rok = myfunk(&buffer1, &buffer2);

printf("%s, %s", buffer1, buffer2);



This doesn't seem to me like a question of how to use loadlibrary/getprocaddress.

Share this post


Link to post
Share on other sites
Quote:
Original post by LessBread
FAR PASCAL

OTOH, this should be WINAPI. Correct me if I'm wrong.

Share this post


Link to post
Share on other sites
Quote:
Original post by Konfusius
Quote:
Original post by LessBread
FAR PASCAL

OTOH, this should be WINAPI. Correct me if I'm wrong.


Track down the macros. They'll both end up as _stdcall.




To be on the safe side, a function like

int myfunk(char **buff1, char **buff2)
{ ... }

should pass the length of the array

int myfunk(char **buff1, int buff1len, char **buff2, buff2len)
{ ... }

Share this post


Link to post
Share on other sites
Quote:
Original post by Specchum
Quote:
Original post by biggurlz
i've a situation where i want to call a dll(i create this dll) and this function return 2 string values.how to get those return value for me to use it im my exe??


Erm...how does your function manage to return 2 string values when a function can return only one value.


mayb i misunderstood with all the article i've read.sorry guys.since i'm new with this loadlibrary things.

i've change some codes in mydll to return only one string.but then,how am i gonna get the return value? how should i code it?tq so much.

Share this post


Link to post
Share on other sites
Quote:
Original post by LessBread
Pass two buffers to the function as "out" parameters.


I was aware of that but I was wondering if biggurlz literally meant returning 2 values (as in return str1, str2;).

This...

Quote:

i've change some codes in mydll to return only one string.


...seems to bear out my initial hunch.


As for how to get the returned string, biggurlz, you simply do:

char* s = ProcAdd(tmpbuf); //assuming ProcAdd actually returns & to char array.

It could also be that ProcAdd actually modifies the tmpbuff in some way, which means that it's using tmpbuf to actually "return" the string (see LessBreads post for example), in which case tmpbuf already holds the returned data and you don't need to the above.

You'll have to give us more details on ProcAdd itself to help you further.

Share this post


Link to post
Share on other sites
----------CODE.DLL-------------
extern "C" { BOOL Generate_Code(char* input, char* output); }
--------------------------------------

here's first attempt i do it :

-----------APPLICATION.EXE-------------

typedef BOOL(__stdcall *MYPROC)(LPTSTR);

MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

int main(char *IN,char *OUT)
{
// Get a handle to the DLL module.
HMODULE hdll = LoadLibrary ("CODE.DLL");

// If the handle is valid, try to get the function address.
if hdll!= NULL)
{
ProcAdd = (MYPROC) GetProcAddress (hdll,"Generate_Code");


// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (IN); //input data sent to dll
}

// Free the DLL module.
fFreeResult = FreeLibrary(hdll);
}

// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message via alternative method\n");

return 0;
}
-------------------------------------------------------------------------------

input is value that i supply and out is output i get from library
the question is...how to get value out?


so,here's my second attempt :

------------APPLICATION.EXE-------------

typedef BOOL(__stdcall *MYPROC)(char * in, char * out);

MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

int main(char *IN,char *OUT)
{
// Get a handle to the DLL module.
HMODULE hdll = LoadLibrary ("CODE.DLL");

// If the handle is valid, try to get the function address.
if hdll!= NULL)
{
ProcAdd = (MYPROC) GetProcAddress (hdll,"Generate_Code");


// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (IN,OUT); //in is input that i supply and out is output i get from library
}

// Free the DLL module.
fFreeResult = FreeLibrary(hdll);
}

// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message via alternative method\n");

return 0;
}
------------------------------------------------------------------------------
but the program got error.when i debug it stop at --> (ProcAdd) (IN,OUT); right after -->fRunTimeLinkSuccess = TRUE;

how to solve this problem?
please help me..

Share this post


Link to post
Share on other sites
If that is your actual code and not pseudo code, then

int main(char *IN,char *OUT)

should cause problems. The signature for main should be like

int main(int argc, char *argv[])

where argv is an array of strings and argc holds the number of items in argv.

argv[0] should hold the name of the program as typed on the command line
argv[1] should be the first string after the program name
argv[2] the next string... and so on

the delimiter for the command line is the empty space.

So if the command line is supposed to look like "program input output" then you'll want to pass argv[1] as input and argv[2] as output - but that wouldn't make much sense either because the command line is input only.

char output[256];
ProcAdd(argv[1],&output); // this call won't work yet

To use a string as an out parameter, you'll need to make the parameter type a pointer to pointer. For example

typedef BOOL (__stdcall *MYPROC)(char * in, char ** out);

otherwise, it will only work with a pointer to char, like so:

char output;
ProcAdd(argv[1],&output);

And you might want to put a space between BOOL and the open parenthesis

typedef BOOL (WINAPI *MYPROC)(char * in, char * out);

And Konfusius did have a point, it might be better to use WINAPI rather than __stdcall because some compilers prefix stdcall with one underscore and others with two but regardless of how they do that, WINAPI will always work. That is, the preprocessor will replace it with the stdcall stipulation that is appropriate for that compiler.

Share this post


Link to post
Share on other sites
[quote]Original post by LessBread

To use a string as an out parameter, you'll need to make the parameter type a pointer to pointer. [quote]

i've done that,but i still got error.here's the error i got:
"the value of ESP was not properly saved accross a function call.this is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."

help me.tq

Share this post


Link to post
Share on other sites
That's where the stdcall/WINAPI stuff comes in. (See X86 calling conventions for a run down of the details).

So to restate, you're trying to load a function from code.dll into an exe using LoadLibrary/GetProcAddress.

The function in code.dll has this prototype

extern "C" { BOOL Generate_Code(char* input, char* output); }

The function pointer you want to load has this prototype

typedef BOOL(__stdcall *MYPROC)(char * in, char * out);

It might be helpful to note that a function pointer is a pointer variable like any other pointer. It holds the address where the code for the function is located. In the typical case, when it's called, code execution jumps to that address and continues from there until the function completes and execution jumps back to the return address - usually the next instruction after the call instruction. This return address is stored on the stack during the call and popped from the stack as the function is exited.

The prototype decorations are there for the compiler (and the programmer too). The compiler uses that information to check that a call to that function pointer is passed two arguments. That is what the prototype tells the compiler to expect. But since that address returned via GetProcAddress is typecast into the function pointer, it's possible that the prototype (or signature) of the pointer doesn't match that of the original function. It could be typecast to a function pointer that only accepts one parameter when the original function expects two or it could be typecast to a function pointer that expects three parameters when the original function expects two and so on.

(What I'm saying here is that there's room here to shoot yourself in the foot if you're not careful. [smile])

In addition to the expectation of parameter count, there is the expectation of calling convention. This gets to your error. With _stdcall functions, before returning parameters passed to them on the stack are removed. These functions clean the stack themselves. With cdecl functions, parameters passed to them on the stack are left in place and the code that called these functions is required to clean them from the stack. In your case, you have a function in a dll defined to uses the cdecl convention. It expects that whomever called it will clean up for it afterwards. The instructions that make up the function do not clean up the stack. When you import that function into your exe, you cast it to a function pointer that has been defined to be stdcall. So when you go to use that pointer, the compiler sees that it is stdcall and does not bother to include instructions to clean up the stack after the call completes. The compiler sees stdcall and assumes that the function will clean up after itself.

So, you've used a function pointer declared stdcall but that really points to a function that is cdecl. The compiler has provided code for the call to the function pointer that doesn't clean up the stack, but the actual function pointed to by the function pointer expects that the stack will be cleaned up. Code execution flows from the call through the stdcall pointer to the cdecl function and back again but in the mixup the parameters are left on the stack resulting in ESP getting messed up.

So much for my confusing explanation!

To fix the problem, make the calling convention of the function pointer match that of the imported function.

The simplest thing to do would be to remove the stdcall portion of the typedef for the function pointer

Change

typedef BOOL (__stdcall *MYPROC)(char * in, char * out);

To

typedef BOOL (*MYPROC)(char * in, char * out);


The long term solution would be to change the function exported by the dll to use stdcall instead

So, change

extern "C" { BOOL Generate_Code(char* input, char* output); }

To

extern "C" { BOOL WINAPI Generate_Code(char* input, char* output); }

And add the WINAPI to the function defintion as well

BOOL WINAPI Generate_Code(char* input, char* output)
{
// ... guts of function
return TRUE;
}

Hope that helps.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement