Symbol resolution prevented by differences in class StrTrait? - c++

In a new application, MyProg.exe, I would like to re-use a function defined in another dll/lib, MyDll.lib/.dll. The call has this signature:
CString CallToDllCodeFuncFromExe( const CString & someStr );
In MyProg.exe I #include the dll’s header file and input the MyDll.lib so the linker can resolve it, but I get an unresolved symbol.
MSDN tells me that one reason why this occurs may be that “A function is used but the type or number of the parameters do not match the function definition”. That seems to be the case here. Below is a comparison of the unmangled signatures for the function taken from the exe error messages and from a dumpbin of MyDll.lib. Notice that there is a difference in StrTraitMFC and StrTraitMFC_DLL which keeps it from resolving:
Build error message (unresolved symbols) of MyProg.exe:
__cdecl CallToDllCodeFuncFromExe(class ATL::CStringT< wchar_t,class StrTraitMFC< wchar_t,class ATL::ChTraitsCRT< wchar_t> > > const &)
Dumpbin /exports of MyDll.lib for CallToDllCodeFuncFromExe:
__cdecl CallToDllCodeFuncFromExe(class ATL::CStringT< wchar_t,class StrTraitMFC_DLL< wchar_t,class ATL::ChTraitsCRT< wchar_t> > > const &))
But in practice I notice that there is a workaround. All I need to do is template the function and the call works fine. Here is IntToStr with one token template parameter by value:
template< int N > CString IntToStr( int N )
{
CString intToStr;
intToStr.Format( L"%d", N );
return intToStr;
}
And the call is:
CString str = IntToStr< 33 >( 33 );
And the exported function looks like this:
class ATL::CStringT< wchar_t,class StrTraitMFC_DLL< wchar_t,class ATL::ChTraitsCRT< wchar_t> > > __cdecl IntToString(int)
My questions are, why does this workaround work and why doesn’t the non-templated call not work? Is it just a Visual Studio inconsistency/bug or is there something more C++ abstract going on here?

Related

Error calling function with CString parameter by reference

Coming from C# I was recently moved to work on a Visual C++ 2010 project. Thing is I have been stuck with a problem with the use of CString for the most part of the day and no one around the office has found the solution.
Situation is: 2 projects with the same settings (unicode on, Use MFC in Shared DLL and NOT Using ATL among others).
In Project1 I have a function like this:
BOOL ETextBoxWrapper::GetValue (ETextBox ^textBox ,CString &value)
From Project2, I call the above function like this:
ETextBoxWrapper::GetValue (m_txtText, m_cText) ;//m_TxtText is a ETextBox and m_cText is a CString
Compiling Project1 works just fine. When compiling Project2, I get an error:
Interface::ControlsWrappers::ETextBoxWrapper::GetValue' : none of the 5
overloads could convert all the argument types >c:\MFLDR\interface.dialogbase.dll: could be 'int
Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^,long &)
Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^,long &)'
c:\MFLDR\einterface.dialogbase.dll: or 'int >Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^,int &)'
c:\MFLDR\interface.dialogbase.dll: or 'int Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^,double &)'
c:\MFLDR\interface.dialogbase.dll: or 'int Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^, ATL::CStringT < wchar_t , StrTraitMFC_DLL < wchar_t , ATL::ChTraitsCRT > > &)'
c:\MFLDR\interface.dialogbase.dll: or 'int Interface::ControlsWrappers::ETextBoxWrapper::GetValue(Interface::Controls::ETextBox ^,wchar_t *)'
while trying to match the argument list >'(Microsoft::VisualC::MFC::CWinFormsControl, CString)'
with [ TManagedControl=Interface::Controls::ETextBox ]
The bolded overload is the one it should be detecting as the CString, but it is asking for ATL::CStringT < wchar_t , StrTraitMFC_DLL < wchar_t , ATL::ChTraitsCRT > > instead of a CString.
As you can see at the end, the calling function correctly identifies the CString as a CString.
When going to the definition of CString, it redirects me to "afxstr.h" in both projects, finding:
typedef ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > > CStringW;
typedef ATL::CStringT< char, StrTraitMFC_DLL< char > > CStringA;
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
I modified the functions to look like:
In Project1:
BOOL ETextBoxWrapper::GetValue (ETextBox ^textBox ,ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > >&value)
In Project2, I call the above function like this:
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > auxiliar (m_cText) ;
ETextBoxWrapper::GetValue (m_txtText, auxiliar) ;
And the compile error changed a bit. First part remains the same, but at the end:
while trying to match the argument list '(Microsoft::VisualC::MFC::CWinFormsControl, ATL::CStringT)'
with [ TManagedControl=Lantek::Expert::Interface::Controls::ETextBox ]
and
[ BaseType=wchar_t, StringTraits=StrTraitMFC_DLL ]
If I twist it a little bit more and leave Project 1 like:
BOOL ETextBoxWrapper::GetValue (ETextBox ^textBox ,ATL::CStringT<BaseType,StringTraits> &value)
Then automatically and without compiling I get an error saying that BaseType and StringTraits are both undefined.
I don't know what's wrong. It would seem like one project is using one definition for CString and the other project a different definition, but both seems to be gettint the definition from the "afxstr.h". I've read a lot on the Internet but no one seems to be having a problem like this, or at least I haven't found a related issue.
I'm in the dark here, so any help would be appreciated. Thanks in advance.
It is looks like there is abbiguity between MFC's CString and ATL's CString.
To verify this is the problem, try to use ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > instead of CString.
Thanks for the feedback received so far. After more investigation we have narrowed down the problem:
Somehow Project1 is using the ATL definition (atlstr.h) of CString and Project2 is using the MFC definition.(afxstr.h)
Having said that, I am still unable to make this work.I don't understand how they are taking different definitions as project settings are - apparently - the same (unicode, atl support, crt, etc).
There is some info on the internet with problems relating to CString definitions of MFC vs ATL, but most of them are pretty old, before mfc-atl library was joined and the problem is usually a LNK2019. In my V2015 i get error code C2665.
Finally I couldn't solve this so I had to work out a workaround. I encapsulated a CString inside a class that I made public to the other project. My getValue method now requieres CStringPublic, but calling this getValue method with a simple CString works, so I don't have to change anything in Project 2.
My wrapper class:
class CStringPublic {
public:
CStringPublic ( CString &string ) { m_string = &string ; }
CStringPublic& operator=(const CString &string) { *m_string = string ; return *this ; }
operator CString () { return *m_string ; }
private:
CString *m_string ;
} ;
GetValue Method:
BOOL ETextBoxWrapper::GetValue (ETextBox ^textBox ,CStringPublic value)
You can call GetValue like:
CString test;
GetValue(textBox, test);
And you would get the value in test variable.

Unresolved external symbol error on variadic template c++ due to usage of unsigned int

I've declared a simple function with variadic template.
template<typename ...Args>
void Log(const LogLevel level, const char * format, Args ...args);
Upon calling it in the following manner -
Log(LogLevel::debug,
R"(starting x, %d pending call for "%s" with param "%s")",
id, first.c_str(),
second.c_str())
where the variable types are : id (unsigned int), first (std::string) , second (std::string)
I'm getting the following error:
Error LNK2001 unresolved external symbol "public: void __cdecl Log<unsigned int,char const *,char const *>(enum LogLevel,char const *,unsigned int,char const *,char const *)"
When I remove the unsigned int argument from the function call - the error disappears.
AFAIK the variadic template does support different types... so what am I missing?
It's a linker error, so (I suppose) you have declared the template function in a header file and defined it in a c++ (not header) file.
If you use the template function that receive the unsigned int in a different c++ file, the compiler doesn't know which versions of the function to implement.
Simple solution: declare and define the template functions/classes/structs in the headers.
If I'm wrong... please prepare a minimal example to replicate the error.

VS2015: LNK2019 error when linking with Muiload.lib

I'm experimenting the next error when including muiload.h and linking with muiload.lib and calling LoadMUILibrary in Visual Studio 2015:
Muiload.lib(muiload.obj) : error LNK2019: unresolved external symbol
__vsnwprintf referenced in function "long __stdcall StringVPrintfWorkerW(unsigned short *,unsigned int,unsigned int
*,unsigned short const *,char *)" (?StringVPrintfWorkerW##YGJPAGIPAIPBGPAD#Z)
Maybe something wrong in muiload.lib?
Solved adding the additional library legacy_stdio_definitions.lib to the linker input as explained in https://social.msdn.microsoft.com/Forums/en-US/5150eeec-4427-440f-ab19-aecb26113d31/updated-to-vs-2015-and-now-get-unresolved-external-errors?forum=vcgeneral
An alternative to linking against legacy_stdio_definitions.lib is to redefine these function signatures to match their deprecated style:
int (WINAPIV * __vsnprintf)(char *, size_t, const char*, va_list) = _vsnprintf;
int (WINAPIV * __vsnwprintf)(wchar_t *, size_t, const wchar_t*, va_list) = _vsnwprintf;
One benefit of this is that it avoids other possible linker definition issues caused by including the legacy library.
Note that this should be defined in a compiler unit (.cpp) rather than in a header file.

error LNK2005 when c++ lambdas used with /Yu flag in vs2012

I have the following function in one of my utility header files.
template<typename T>
static void rtrim(std::basic_string<T, std::char_traits<T>, std::allocator<T>> &t)
{
t.erase(find_if(t.rbegin(), t.rend(),
[](T& c)->bool{ return !isspace(c); }).base(), t.end());
}
I am building the code with Visual Studio 2012 with pre-compiled headers on (/Yu). The build fails with the following error.
1>stdafx.obj : error LNK2005: "public: void __cdecl
::operator()(class
std::basic_string,class
std::allocator > const &)const "
(??R##QEBAXAEBV?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std###Z)
already defined in
If I remove /Yu flag, it builds fine. Does it mean lambdas cannot be used with precompiled headers? Is there a work around?

Linker error when parameters are passed by reference to C++ dll

In my application, I have a dll which exposes a function that takes two vectors:
static int myFunc( vector<double> vec1, vector<double> &vec2 );
When I changed this declaration to
static int myFunc( vector<double> &vec1, vector<double> &vec2 );
I get a linker error saying this:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: static int __cdecl myFunctions::myFunc(class std::vector<double,class std::allocator<double> > &,class std::vector<double,class std::allocator<double> > &)" (__imp_?myFunc#myFunctions##SAHAAV?$vector#NV?$allocator#N#std###std##0#Z) referenced in function "public: void __thiscall MainWindow::modelMeanCurve(void)" (?modelMeanCurve#MainWindow##QAEXXZ)
Why is this behavior and how do I resolve this error so that I can pass the reference to the first argument also?
Thanks,Rakesh.
Well, it is not enough to change the declaration alone. You also have to change the definition of that function and recompile the DLL.
If you simply changed the declaration and left the definition unchanged, you essentially created a new declaration for a function that does not really exist. The DLL still contains the original function with original set of parameters, which is now completely unrelated to you new declaration. This is what the linker is telling you through the above error.
Thank you #Michael Burr, I was referring to a stale copy of the .lib file. I replaced this with the new version and everything built fine.