Decorated name for function generated improperly - c++

I'm trying to compile some third party C++ code into my 32-bit C++ application with Visual Studio 2017 (upgrading from Visual Studio 6.0). I have .h files and a .lib file from the third party. The linker is finding the library, but it is not finding the decorated names contained within. It appears to be because the compiler is replacing "__int8" with "char".
The linker error is:
LNK2019 unresolved external symbol "signed char __cdecl Check_The_Thing(void)" (?Check_The_Thing##YACXZ) referenced in function (redacted)
The function is defined in the .h:
_declspec(dllexport) API_RETURN_TYPE Check_The_Thing ( void );
API_RETURN_TYPE is defined in the .h:
_declspec(dllimport) typedef signed __int8 int_8;
_declspec(dllimport) typedef int_8 API_RETURN_TYPE;
Using dumpbin /exports, I can see that my lib and associated dll exports Check_The_Thing:
?Check_The_Thing##YA_DXZ (__int8 __cdecl Check_The_Thing(void))
Using undname, I can see that the decorated name in the lib evaulates properly:
Undecoration of :- "?Check_The_Thing##YA_DXZ"
is :- "__int8 __cdecl Check_The_Thing(void)"
But the compiler-generated decorated name does NOT evaluate properly (based on the code):
Undecoration of :- "?Check_The_Thing##YACXZ"
is :- "signed char __cdecl Check_The_Thing(void)"
According to https://en.wikiversity.org/wiki/Visual_C%2B%2B_name_mangling, the "C" in YACXZ evaluates to "signed char" and the "_D" evaluates to "__int8". What I can't figure out is why the compiler is interpreting API_RETURN_TYPE as "char" instead of "__int8". It's clear that the lib/dll exports should have "_C" instead of "_D" given that API_RETURN_TYPE is a "signed __int8" not just "__int8".
I've fiddled with a bunch of the compiler settings with no luck. As suggested here (Cannot find decorated function name in dll) , I made sure I was using MBCS instead of Unicode (it was unset before), but that also made no difference.
Specifically defining API_RETURN_TYPE as __int8 makes no difference except to change the "C" to a "D" (progress!) and likewise undname shows the return type as "char" instead of "signed char". Changing the function definition's return type to __int8 has the same effect as changing API_RETURN_TYPE.
So, my question: How can I force the compiler to properly define my exports with "__int8" (or "_D") instead of char ("D")?
Side note: the linker error is the same for the cases where __int16, __int32, and __int64 are used.
EDIT: Actually, the library defines __int64 types but I'm not using any. There aren't any __int64 linker errors.

At least since Visual Studio 2003 (!), "The __int8 data type is synonymous with type char".
Obviously, the compiler can't have different name mangling for two ways to name the same type.
Also insightful is this page which shows that __int8 is (signed) char but __int64 is not long long; the latter are merely equivalent.

Related

Calling external function, unable to specify types C++/MVS

I am following this tutorial for accessing functions stored in a 3rd party .dll. (For full disclosure, I am not trying to hack a video game, I just need to use the same tools).
I'm using Visual Studio 2017 (v141) and my current code looks like this:
if (HMODULE const hLib = LoadLibraryA(PATH_TO_LIB)) {
typedef IServer(__cdecl * _Create)(char* version);
_Create Create_addr = (_Create)GetProcAddress(hLib, "Create");
}
I am trying to call the function IServer Create(char* version) stored in the .dll, the type IServer is also defined in the .dll. After running dumpbin I can confirm that the function is exported correctly.
I have also imported the header file containing the IServer definition.
The issue is that, according to visual studio:
In lieu of __cdecl * it "expected a type specifier"
At (char* GameServerInterfaceVersion), it claims "a function returning function is not allowed"
On the last line, _CreateGameServer is apparently an "unidentified identifier"
I believe I have followed the tutorial to the letter and can't see what I'm doing wrong.
How can I get VS to recognize these types?
You have to define IServer first and then the errors will disappear

How to wrap a C __cdecl API so that FORTRAN can call it (using __stdcall)?

I'm working with a third party C library that is using the default (__cdecl) calling convention and I need to be able to call the third party library from FORTRAN. FORTRAN's default calling convention is __stdcall and so I've written a basic wrapper in C++
int __stdcall wrapper_sub(char* ver, int* days)
{
return original_sub(ver,days);
};
with function prototype
int __stdcall wrapper_sub(char*, int*);
I'm able to compile without errors but when I check the symbol table of the wrapper library I get
?wrapper_sub##YAHOADPAH#Z(int __cdecl original_sub(char *, int *))
It would seem that the linker is not finding original_sub and the process is failing silently. I've included all necessary references and directories into the project so that the wrapper solution should correctly resolve the third party API.
The FORTRAN call is made as follows
PROGRAM MAIN
IMPLICIT REAL*8 (A-H, O-Z)
CHARACTER*(4) VER
VER = '1.0'
ISTAT = wrapper_sub(VER,IDAYS)
STOP
END
after including an external reference to the wrapper library, I get the following error
error LNK2001: unresolved external symbol _WRAPPER_SUB#12
Is there something I'm missing? or is there a another (less error prone?) way to wrap the C API so that I can call it from FORTRAN?
The linker can't link your FORTRAN code to the library because the function name is mangled ( C++ thinks the function is named ?wrapper_sub##YAHOADPAH#Z, FORTRAN is expecting it to be named wrapper_sub)
Write your wrapper in C, not C++, or add an extern "C" to fix the problem.
extern "C" int __stdcall wrapper_sub(char* ver, int* days)
See this SO question for more details: In C++ source, what is the effect of extern "C"?

How to disable C++ 7.1 Name mangling? :(

I have a library code which is written in VS 2003 , C++ 7.1
I managed to compile it in VS 2010. Now i need to compile it in VS2003 as well.
Problem is that i can not prevent VS2003 name mangling !
I used __declspec(dllexport) __stdcall before function name and i also put codes in extern "C" block.
I still get mangled function names when i compile it in VS 20003. I dont need a .def file when i use __declspec(dllexport) right?
hee is the code :
extern "C"
{
void __declspec(dllexport) __stdcall FreeMyObject(MyObjectHandle pObj)
{
delete pObj;
}
}
Also "Callin Convention" is __cdecl (/Gd)
Why i get mangled function names? is there any options i need to set in compiler option?
The keyword _stdcall, along with _cdecl, _thiscall, and others, are all calling conventions specifying how the compiler handles pushing and popping the arguments and the return value. Functions names made with _stdcall (at least in visual studio) are "decorated" when they are exported. If you want to find the exported name of the function, you can use the visual studio command line function DUMPBIN /EXPORTS "DLL file location". Your function name will probably look something like this: _FreeMyObject#(some number). You could also use a .def file and define the name yourself, but I personally think that is a pain.

Linking to a C++ Static Library from a Qt Application

I am trying to link a non-Qt static library, to a Qt-based application (its a Visual Studio project).
The issue is that the static library has some APIs which take a pointer to a TCHAR string as one of the inputs.
When I try building the project, I get a linking error, complaining about the TCHAR.
Header
class Test
{
public:
static bool TestFunc( TCHAR *empty );
};
Source
bool Test::TestFunc( TCHAR *empty )
{
return true;
}
Error:
error LNK2019: unresolved external symbol "public: static bool __cdecl Test::TestFunc(unsigned short *)" (?TestFunc#Test##SA_NPAG#Z) referenced in function "public: __thiscall TestApp::TestApp(class QWidget *,class QFlags<enum Qt::WindowType>)" (??0TestApp##QAE#PAVQWidget##V?$QFlags#W4WindowType#Qt#####Z)
The interesting thing is that if I have the function implementation in the header file, it works fine. Or if I change the TCHAR to a regular char and keep the declaration/definition separate, it also works (using wchar_t directly fails with the same linking error).
Does anyone know what could be causing that issue, and how to resolve it?
Thanks in advance,
What was the static library compiled using? Visual studio? What version?
I'll try to explain the problem you are having.
First of all, the reason it works when you put the function body in the header, is because this essentially causes the function body to be recompiled by your app. The linker doesn't actually need to resolve any symbols from the static library any more. Ergo, the linker problem goes away.
The problem is that when the static library was compiled, a function that it exports Test::TestFunc was mangled by the compiler (it essentially renames it according to some internal schema). Function name mangling is what a compiler does, to simplify symbol resolution for the linker. The way a function name is mangled, is not specified according to the c++ standard. Therefore, different compilers, with different settings turned on, will mangle the function names differently.
When you try to build your app that links this library, Visual Studio now mangles the function where it is called (probably in main()). If the name mangling of the static library, where the function is defined, doesn't match the name mangling from where the function is called, then you get the error you received. That is, the linker will be looking for function X in the static library, and all it can find is function Y.
Now, as other posters have pointed out, the name mangling also depends on the parameters the function takes as input. If the parameter types are different in the two places (definition and usage), the compiler will mangle the functions names differently. Ergo, once again, the linker will not be able to resolve a match.
Bottom line is that, in both places where the symbol exists (library and app), the symbol MUST be mangled identically. The best way to do this, is to compile using the exact same compiler, with exact same settings.
The other possibility of course, is that the symbol doesn't actually exist in the static library you are linking against!
Make sure that the compiler settings are the same for both projects. In particular look at the "Character Set" property, make sure they're both Unicode. This changes the definition of the TCHAR macro.
By default, VS compiles with "Treat wchar_t as Built-in Type" enabled (/Zc:wchar_t). Qt compiles with that option disabled (/Zc:wchar_t-). If you disable the "Treat wchar_t as Built-in Type" in VS (under Configuration Properties > C/C++ > Language), before building the static library, does that fix it?
TCHAR is either a char or a wchar (ie utf16) depending on how the app is built.
edit: if you want to mix Qt's strign type with TCHAR
Simply convert your QString to local8bit or utf16() and then cast the result to TCHAR*
And to convert back from TCHAR to QString
QString toQString(const char *str) { return QString::fromLocal8Bit(str); }
QString toQString(const wchar_t *str) { return QString::fromWCharArray(str); }

Mixed calling conventions make compilation errors

I have a library (C++) which has some API functions. One of them is declared as __cdecl, but gets a function poiner from __stdcall. Something like:
typedef int (__stdcall *Func)(unsigned char* buffer);
//...
int ApiFunc(Func funcPtr); //This is __cdecl since it is an 'extern "C"' library and the calling convention is not specified
Then - I have a C++ executable project which uses this library, but doesn't call the above API or uses the Func type.
After changing the calling convention of Func to __stdcall, I get the following compilation error:
error C2995:
'std::pointer_to_unary_function<_Arg,_Result,_Result(__cdecl *)(_Arg)> std::ptr_fun(_Result (__cdecl *)(_Arg))' : function
template has already been
defined c:\program files\microsoft
visual studio 8\vc\include\functional
Any idea what could it be?
Thanks in advance!!
Err.. they're incompatible. You have to specify the same calling convention on both sides of the call. Otherwise attempting to call will blow up the machine stack.
They ARE compatible, in Windows at least (and in Linux there isn't __stdcall at all...)
The problem was that by mistake, the library re-defined __stdcall for compatibility with Linux, as:
#ifndef __MYLIB_WIN32
//Just an empty define for Linux compilation
#define __stdcall
#endif
The exe project includes this definition, and __MYLIB_WIN32 was not defined in it, but in the library only.
Changing the above definition to:
#ifndef WIN32
//Just an empty define for Linux compilation
#define __stdcall
#endif
and everything works fine.
Thank you all.