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

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); }

Related

What / where is __scrt_common_main_seh?

A third party library in my program is trying to call __scrt_common_main_seh by way of the Microsoft library msvcrt.lib, but is defined by some unknown library and therefore gives a linker error. I don't know what this function is supposed to do or where it is defined.
I looked online for this function, but did not find any clues except for general descriptions of what linker errors are.
I believe it might be doing some setup for win32 GUI applications. The library which defines it might be configured as project dependency by Visual Studio but my project is using Bazel.
Summary
For non-console applications having error error LNK2019: unresolved external symbol main referenced in function "int __cdecl __scrt_common_main_seh(void)" try adding linker flag /ENTRY:wWinMainCRTStartup or /ENTRY:WinMainCRTStartup
For console applications having that error, make sure to implement a main() function.
Details
This answer shows that __scrt_common_main_seh is normally called during mainCRTStartup which is the default entry point for windows console applications. __scrt_common_main_seh is then (indirectly) responsible for calling main().
My program did not have a main() function, which might have prevented the compiler from generating __scrt_common_main_seh (Just speculating. I am totally clueless about who defines __scrt_common_main_seh)
I did find, however, that the library I was linking against defined a wWinMain() function. So I tried adding the linker flag /ENTRY:wWinMainCRTStartup and the linker error went away.

Decorated name for function generated improperly

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.

Errors trying to call GetAsyncKeyState() in C++/CLI project

I'm working on a fairly convoluted project in which I'm accessing classes written in plain-old-C++ from a project using C++/CLI. It's a Windows Forms GUI project that uses a lot of the same functions as its (non-CLI) C++ sister project.
In one of my classes that I'm trying to adjustment to work in both environments, I'm polling keypresses with this function:
inline bool IsKeyDown(unsigned char ch) const {
return (GetAsyncKeyState(ch) & (1u << 15)) != 0;
}
I'm getting both Unresolved Token and Unresolved External Symbol errors on
"extern "C" short __stdcall GetAsyncKeyState(int)" (?GetAsyncKeyState##$$J14YGFH#Z) referenced in function "public: bool __clrcall Engine::InputManager::IsKeyDown(unsigned char)const " (?IsKeyDown#InputManager#Engine##$$FQBM_NE#Z)
Obviously, the issue is related to GetAsyncKeyState() but I'm not sure what needs to be different for a CLI-friendly implementation. Can anyone direct me how to fix this? The function works properly in my non-CLI environment (and has for months). I'm very new to this CLI stuff so any help would be wonderful and no help could be too-specific.
If it helps, I'm using Visual Studio 2010 and compiling with the /clr parameter (not :pure or :safe).
The MSDN library provides the details of which header files and libraries need to be included for any particular function.
In this case, you need windows.h (which you must already have) and user32.lib (which is probably missing). So add
#pragma comment(lib, "user32.lib")
at the top of your code and all should be well. Alternatively, you could add user32.lib to the list of libraries in the project properties pages, remembering to do this for each configuration, e.g., debug as well as release.
Just got the same issue. The solution is to link against a .lib which has a respective symbol, which in this case is user32.lib.
I fixed a problem in Visual Studio by making a project use inherited values. Check this checkbox in your project properties and it should fix it:

OpenCV 2.3 with Qt 4.3.7

I have successfully build and ran both Qt 4.3.7 and OpenCV 2.3 with Qt enabled. When I start a window using:
cvNamedWindow( "video", 0 );
I successfully load a full Qt interface! wonderful :)
However!! when I use the command
void callbackButton(int state, void* userdata){
int x;
x=3;
}
cvCreateButton(nameb2,callbackButton,nameb2,CV_CHECKBOX,0);
I get the error message
error LNK2001: unresolved external symbol _cvCreateButton
I don't understand as the Qt interface already has lots of buttons on it? could someone please explain what I am missing from the include that could cause this?
Thanks!
You use the wrong parameters for to call to cvCreateButton. According to the documentation here the signature of the function is
cvCreateButton(const char* button_name CV_DEFAULT(NULL), CvButtonCallback on_change CV_DEFAULT(NULL), void* userdata CV_DEFAULT(NULL), int button_type CV_DEFAULT(CV_PUSH_BUTTON), int initial_button_state CV_DEFAULT(0)
and sample calls are:
cvCreateButton(NULL,callbackButton);
cvCreateButton("button2",callbackButton,NULL,CV_CHECKBOX,0);
cvCreateButton("button3",callbackButton,&value);
cvCreateButton("button5",callbackButton1,NULL,CV_RADIOBOX);
cvCreateButton("button6",callbackButton2,NULL,CV_PUSH_BUTTON,1);
and the declaration of the callback function has to be:
CV_EXTERN_C_FUNCPTR( *CvButtonCallback)(int state, void* userdata));
You get a linking error and not a compiler error because cvCreateButton has extern "C" linkage - which means that parameters cannot be checked at compile time.
I solved this issue by calling the function cv::createButton instead of cvCreateButton (which is if I am correct the way to call methods in OpenCV2).
The third argument must be a void*. Change to:
cvCreateButton(nameb2,callbackButton,NULL,CV_CHECKBOX,0);
and it will work.
Edit
The statement above was given an error.
The third needed argument is a "void *" - this is compatible with anything and thus neither C nor C++ should have a problem with what you were providing. You can not raise a linker error with that.
The only reason a linker error can be raised by coding is when you don't use prototypes (forgot to use the header file) in C++ and then C++ creates a mangled name on its own that wont be part of any library. In such a case the compiler will first tell you with a warning at compile time that you are missing the prototype (for C and C++) - and then the linker will probably raise an error (for c++ only).
If you don't see a prototype warning from the compiler then that is not your problem.
This is a linking error.
Try to add the opencv .lib file (or files) to the project libraries path.
This may help : VS2010 OpenCV.
Edit
Refined problem: Even if adding any OpenCV libary to your project the linking will fail.
Reason: The symbol is often simply not there in the libraries.
Solution: You have to change a few settings and compile them on your own.
See also: openCV 2.2 createButton LNK 2019 error in Visual Studio 2010

Open file in TagLib with Unicode chars in filename

I am quite new to the C++ 'area' so I hope this will not be just another silly 'C++ strings' question.
Here is my problem. I want to integrate TagLib (1.5, 1.6 as soon as I manage to build it for Windows) into an existing Windows MFC VS2005 project. I need it to read audio files metadata (not write).
The problem is that the program stores the input file names using CString(), and it has the Unicode option turned on (so the default chars are "wchar_t"). The reason for this (I think, the project was started by someone else) is that some of the 'input' file names could contain Unicode charaters (for example, Japanse or Arabic characters).
For example, the file path is something like "d:\docs\audio_test\stragecharڝhere.mp3", but I get it with:
CString fpath = tmpFile->GetFilePath();
Now.. if I try to do:
TagLib::FileRef f(fpath.GetBuffer(0));
fpath.ReleaseBuffer();
I get something like:
unresolved external symbol
"__declspec(dllimport) public:
__thiscall TagLib::FileName::FileName(wchar_t
const *)"
If I try something like:
TagLib::FileRef f(reinterpret_cast<char*>(fpath.GetBuffer(0)));
fpath.ReleaseBuffer();
I get rid of the compilation errors, but "f" is an invalid pointer/object.. and when I try reading a tag, I receive an assert failed.
So, can anyone give me some pointers on how should I pass that CString, in it's Unicode form, to the TagLib ?
Update: TagLib address: http://developer.kde.org/~wheeler/taglib.html
Thank you,
Alex
It's possible that the problem is caused by the issue described here. Basically MSVC has an option to treat the wchar_t type differently, which causes the compiled library is not binary compatible with an application compiled without that option. Unfortunately the CMakeLists.txt build file enables the /Zc:wchar_t- option by default. I'd try to edit the file, remove the option and re-compile TagLib. Ideally version 1.6, as it contains a lot of bug fixes.
I missed something essential when I first read your post, so here is another, new and improved answer:
The error comes from the linker, not the compiler. It thus seems that TagLib::FileName does have a ctor taking wchar_t const*, but the problem is that you don't link with the library implementing it, or link with a version of the library that does not include it.
IIUC, this library comes from the Linux world (where file names are expressed as char arrays), and was later ported to Windows (where file names are expressed as wchar_t arrays). The FileName ctor taking a wchar_t array is thus probably conditionally compiled on Windows (i.e., inside #ifdef _WIN32 or something similar), and the library you are linking with (if you are linking the library) was not compiled with the same preprocessor defines.