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:
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.)
typedef void (*noargfunc)();
void argfunc(int i)
noargfunc p = (noargfunc)argfunc;
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.
Except that the types don't match. So you have to cast.
void(* ptrFunc)(void) = NULL;
ptrFunc = 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.
ptrFunc = (void (*)(void))GetProcAddress(dllLib,"mensaje");
Okay, this is where my excurse about calling conventions comes in.
typedef void (*func_type)(void);
func_type func = NULL;
func = (func_type)GetProcAddress(dllLib, "mensaje");
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.