Thread: why typedef? and not a pointer to function?

  1. #1
    Registered User
    Join Date
    Mar 2004
    Posts
    113

    why typedef? and not a pointer to function?

    hi,
    i'm tryinfg to load a function from a dll, this dll haves a function
    Code:
    void mensaje();
    in my client program when i try to load the function why i cant use or define a pointer to that function when retrieving from GetProcAddress()?

    ok a little bit more clear:
    Code:
    //pointer to the function to retrieve
    void(* ptrFunc)(void) = NULL;
    ...
    ptrFunc = GetProcAddress(dllLib,"mensaje");
    //here compiler generates an error
    but if i use typedef everything is fine

    Code:
    ...
    typedef void(WINAPI*ptrFunc)();
    ...
    ptrFunc funcion1;
    funcion1 = (ptrFunc)GetProcAddress(dllLib,"mensaje");
    so why cant use a pointer to the function to handle with the GetProcAdress() return value?
    GetProcAdress() returns a pointer to the specified function no?

    one more question:
    what
    Code:
    typedef void(WINAPI*ptrFunc)();
    means?
    im aliassing a pointer to a WINAPI function that returns no value and gets no value? is that what it means?

    thanks for any help why i need to define a typedef

    please excuse my poor english
    Last edited by terracota; 12-17-2004 at 10:01 AM.

  2. #2
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Are you compiling as C or C++?
    There is one big reason why the typedef version and its not because of the typedef its because you are casting the return value from GetProcAddress().

    The first one also didn't work because your parmeters in your pointer doesn't match the types in the function you are pointing to.

    Code:
    void somefunc(int, int);
    
    void foo ()
    {
      void (*ptrFunc)(int,int) = somefunc;
      ptrFunc(3,5);
    }
    If you search the boards you'll find a link to a very nice FAQ on function pointers in C and C++

    Edit: I looked up GetProcAddress so try this function pointer:
    Code:
    FARPROC (*funcPtr)(HMODULE, LPCSTR) = GetProcAddress;

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You are mistaken. It's not fine. More importantly, even if both snippets worked, they'd still do different things.

    But let's recap.

    Do you know about calling conventions? They describe how parameters are passed to a function. Visual C++ knows them as __cdecl and __stdcall (there's also __fastcall, but let's ignore that one for now).
    The default calling convention for C on x86 is cdecl. In this system, a function call means that first the parameters are pushed on the stack. Then a CALL instruction is executed, which pushes the return address to the stack and then transfers execution. After the called function has finished, it executes a simple RET, which pops the return address of the stack and transfers execution there. The calling function the proceeds by popping the parameters off the stack.
    The other calling convention is stdcall, also known as pascal. It is the calling convention the Pascal language uses, and it also is the one that the WinAPI uses for most of its functions. This method does not allow variable argument counts. The calling function pushes the arguments on the stack and executes a CALL. The called function does its stuff and then executes a RET with a numeric argument. This version of RET pops the return address off the stack, and then pops an additional number of bytes off the stack, the amount indicated by the argument. Then execution is transferred to the calling function, which must not attempt to pop arguments off the stack.

    Microsoft encourages people to use stdcall for DLLs, because this convention is apparently more interoperable with other languages. It is, for example, required that the functions in DLLs be stdcall in order to be imported in VB or C#, and probably in Delphi, too. Related with this (and I don't know which is the cause of which, or what technical considerations went into it) is that, as I said, most of the WinAPI functions are stdcall.

    WINAPI, APIENTRY, CALLBACK and a few other macros that you encounter in Windows programming are synonyms for __stdcall. (In 16-bit Windows they were more.)

    Ok, once you have that down, let's move on to function pointers and type safety. It's very simple: you can't convert one function pointer to another, save with an explicit cast. You shouldn't, either. What do you think happens when you do this:
    Code:
    typedef void (*noargfunc)();
    void argfunc(int i)
    {
      printf("%i", i);
    }
    int main()
    {
      noargfunc p = (noargfunc)argfunc;
      p();
      return 0;
    }
    That's right, undefined behaviour is what happens. (In practice, should main have a return address, that value will most likely be printed - but it's still a case of nasal demons.)

    Ok, Windows isn't nice, though. The fact of the matter is that GetProcAddress has a return type of FARPROC, and FARPROC is defined like so:
    typedef INT_PTR (FAR WINAPI *FARPROC)();
    After removing all the macros and typedefs, this comes out:
    typedef int (__stdcall *FARPROC)();

    So, GetProcAddress assumes that whatever function it fetches has an int return type and no arguments. (As said, __stdcall doesn't support variables arguments, so an empty list means none.) This will usually not be the case, so you need to explicitely cast.

    Ok. Nothing prevents you from having a pointer to a function.
    Code:
    void(* ptrFunc)(void) = NULL;
    ptrFunc = GetProcAddress(dllLib,"mensaje");
    Except that the types don't match. So you have to cast.
    Code:
    ptrFunc = (void (*)(void))GetProcAddress(dllLib,"mensaje");
    So the question you have to ask yourself is, do you want this weird syntax? (I haven't tested it - it might not even be valid.) Using typedef makes it a lot clearer.
    Code:
    typedef void (*func_type)(void);
    func_type func = NULL;
    func = (func_type)GetProcAddress(dllLib, "mensaje");
    Okay, this is where my excurse about calling conventions comes in.
    void (__cdecl*)(void) and void (__stdcall*)(void) are different types, and should be. Calling a cdecl function through a stdcall pointer will cause the arguments not to be popped off the stack, and thus stack corruption. Calling a stdcall function through a cdecl pointer causes the arguments to be popped off twice, and thus stack corruption again. You want neither.
    This means that you need to be aware what calling convention mensaje uses and have the function pointer use the same.

    __cdecl is the default, meaning that it will be used if you specify neither. Unless you use a compiler switch to make __stdcall the default.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Registered User
    Join Date
    Mar 2004
    Posts
    113
    ok and thats why typedef void(WINAPI*ptrFunc)(); haves the macro WINAPI?.

    so, the second example is the standard to call functions from dll's no?

    and thank you very very much for yer great help

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Yes, that's the reason why there's the WINAPI in the typedef, and yes, that's the standard way to call functions from DLLs. But just because it is standard doesn't mean it's exactly that way. This particular function in this particular DLL might be __cdecl. Either because the DLL author didn't know/care about calling conventions or sometimes because it's a requirement. wsprintf, for example, is __cdecl, because it expects a variable number of arguments.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    Registered User
    Join Date
    Mar 2004
    Posts
    113
    Quote Originally Posted by CornedBee
    But just because it is standard doesn't mean it's exactly that way. This particular function in this particular DLL might be __cdecl. Either because the DLL author didn't know/care about calling conventions or sometimes because it's a requirement. wsprintf, for example, is __cdecl, because it expects a variable number of arguments.
    sorry bro you lost me there
    can you give me an example when and how to use each please?

    i will really apreciate it a lot
    thanks for your great help again

    btw
    im not using __stdcall there in the example?because the (WINAPI) macro? and not __cdecl?.

  7. #7
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    can you give me an example when and how to use each please?
    Using __stdcall and __cdecl are not hard since the compiler handles the internals for you. All you have to do is place the keyword in the function declaration. For instance:

    Code:
    int __stdcall foo();
    int bar();
    In the above example, both functions are the same except for the calling conventions. foo() uses stdcall, and bar uses cdecl. Since cdecl is the default calling convention, it is not necessary to specify it.

    Deciding when to use it can be a bit more tricky. Basically I use __stdcall when I am creating a DLL function, creating a pointer to a function which uses stdcall (most win32 API functions are stdcall), or declaring a callback function for a thread or hook.

    im not using __stdcall there in the example?because the (WINAPI) macro?
    Actually you are using __stdcall. In some windows header, they have:
    Code:
    #define WINAPI __stdcall
    So WINAPI and __stdcall are the exact same thing.

  8. #8
    Registered User
    Join Date
    Mar 2004
    Posts
    113
    so in a few words,
    i dont need to worry too much using that keyword when developing a dll because the compiler is in charge of that ?

    and if i want to use it i need to define the __stdcall before the function declaration in the dll header file,
    and use the macro WINAPI with the typedef pointer declaration when trying to access the dll functions from the client program, is that ok?

    thanks for help

  9. #9
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    i dont need to worry too much using that keyword when developing a dll because the compiler is in charge of that ?
    Correct, just put __stdcall in the function declaration, and the compiler will handle the rest.

    i need to define the __stdcall before the function declaration in the dll header file
    Well you need to put __stdcall in the .h and .c file. Anywhere the function is declared.

    So in your .h you might have:
    Code:
    int __stdcall foo( int );
    and in the .c file:
    Code:
    int __stdcall foo( int i ) { return 42; }

  10. #10
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    Most compilers allow you the ability to reassign the default calling convention. There are also typically options to compile all dll exported functions in the standard calling convention.

  11. #11
    Registered User
    Join Date
    Mar 2004
    Posts
    113
    thanks a lot for your great help guys
    a beer for you all!!!

Popular pages Recent additions subscribe to a feed