C ++ 64-bit transfer functions with "different" calls as parameters give an ambiguous error

My goal is to easily extract a prototype of an arbitrary function with both __cdecl and __stdcall calls. It works great in 32-bit mode. The only thing that changes is the calling convention in my template function parameters.

According to Wikipedia : "When compiling for x64 architecture in a Windows context (whether they use Microsoft or not Microsoft), there is only one calling convention - described here, so stdcall, thiscall, cdecl, fastcall, etc. Now everything is the same. "

This breaks my code in 64-bit. Although the calling conventions are the same, passing functions as a parameter still requires the use of the correct nomenclature. I.E. if the function is defined as __stdcall, you must pass it to the shell that accepts __stdcall. Although __cdecl is identical, you should still pass functions defined as __cdecl to a shell that accepts __cdecl.

An example that works on a 32-bit version:

template<typename T, typename... Args> struct WrapperSTD { typedef T(__stdcall *Functor)(Args...); }; template<typename T, typename... Args> struct WrapperC { typedef T(*Functor)(Args...); }; template<typename T, typename... Args> WrapperSTD<T, Args...> wrap(T(__stdcall *func)(Args...)) { return WrapperSTD<T, Args...>{}; } template<typename T, typename... Args> WrapperC<T, Args...> wrap(T(*func)(Args...)) { return WrapperC<T, Args...>{}; } 

My goal was to be able to run, for example:

 using MsgBoxProto = decltype(wrap(MessageBoxA))::Functor; 

This is normal for 32 bit. However, since __stdcall and __cdecl seem to be identical in x64, it will not work in 64-bit mode and will throw an error saying that the calls are ambiguous. It also tells me that the template is already defined. It seems intuitively that I could pass functions with __cdecl to this __stdcall function, since the compiler considers them identical. However, this does not work:

 template<typename T, typename... Args> struct WrapperFC { typedef T(__stdcall *Functor)(Args...); }; template<typename T, typename... Args> WrapperFC<T, Args...> wrap(T(__stdcall *func)(Args...)) { return WrapperFC<T, Args...>{}; // same as below } template<typename T, typename... Args> WrapperFC<T, Args...> wrap(T(__cdecl *func)(Args...)) { return WrapperFC<T, Args...>{}; // same as above } 

Error C2995 'WrapperFC wrap (T (__cdecl *) (Args ...))': function template already defined

If I use only one of them, I cannot wrap both of these functions at the same time:

 void __cdecl foo(int i){} void __stdcall bar(int i){} 

If the compiler considers them the same, why does it require that I have different templates for making different calling conventions? And when I do this, why does it break completely and say that it is ambiguous and already defined?

TL DR: If the calling conventions in 64-bit architectures are identical, why can't I pass one calling convention to a function that expects another? And how can I fix this?

+6
source share

All Articles