Error calling function with CString parameter by reference - mfc

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.

Related

Problem of Compilation when defining factory for boost logger

Following the question asked here Boost.Log, using custom attributes in filename or target value of configuration file, I tried to develop the proposed solution but I encounter a build issue on Windows due to wchar_t vs char while trying to set the name of the files.
Error C2664 'boost::log::v2s_mt_nt6::basic_formatter<char>::result_type boost::log::v2s_mt_nt6::basic_formatter<char>::operator ()(const boost::log::v2s_mt_nt6::record_view &,boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &) const': cannot convert argument 2 from 'boost::log::v2s_mt_nt6::sinks::file::file_name_composer_adapter<boost::log::v2s_mt_nt6::basic_formatter<char>>::stream_type' to 'boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>> &'
file: boost\log\sinks\text_multifile_backend.hpp 107
stream_type being ostream of wchar_t due to Windows
if (boost::optional< std::string > param = settings["FileName"]) {
auto fmt = logging::parse_formatter((*param));
auto composer = sinks::file::as_file_name_composer(fmt);
backend->set_file_name_composer(composer);
}
How can I make parse_formatter works with wchar_t?
I also tried to use wchar_t as type of the sink_factory + std::wstring but it doesn't build either
Error C2664 'boost::log::v2s_mt_nt6::basic_formatter<wchar_t>::result_type boost::log::v2s_mt_nt6::basic_formatter<wchar_t>::operator ()(const boost::log::v2s_mt_nt6::record_view &,boost::log::v2s_mt_nt6::basic_formatting_ostream<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &) const': cannot convert argument 2 from 'boost::log::v2s_mt_nt6::expressions::aux::stream_ref<boost::log::v2s_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>>>' to 'boost::log::v2s_mt_nt6::basic_formatting_ostream<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>> &'
file: boost\log\detail\light_function.hpp 362
supplying 'std::locale("en_US.UTF-8")' to the composer doesn't change anything as it's runtime
same remark for "expr::stream << expr::format(*param)" as formatter
I'm using boost_1_70_0
Do you know any solution?
Thanks!
parse_formatter returns basic_formatter<CharT>, where CharT is the character type deduced from the input argument. Thus, you will need to pass std::wstring in order to get wformatter which you can use with as_file_name_composer.
In order to get std::wstring parameter values from settings you will have to use wsettings, which you can obtain from parse_settings if you pass a std::wistream as input.

Symbol resolution prevented by differences in class StrTrait?

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?

MessageBox in c++ using string

I am getting an error on the following code and I can't figure it out.
string name1 = om->get_name();
if (om->search(name, code))
{
MessageBox::Show("name"+name1);
}
else
MessageBox::Show("such a car doesn't exist");
Gives me the following error
error C2665: 'System::Windows::Forms::MessageBox::Show' : none of the 21 overloads could convert all the argument types
It looks like you are passing in a std::string when you should be passing in a managed String^.
Either convert om->get_name() to return a managed String^ or use the Win32 MessageBox function directly (which takes LPCTSTR parameters).
Reference for System::Windows::Forms::MessageBox::Show is at https://msdn.microsoft.com/en-us/library/519bytz3(v=vs.110).aspx
Reference for Win32 API MessageBox function is at https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx

None of the 3 overloads could convert all the argument types (in MFC / C++ project)

I have copied some code from another project which I downloaded (and which compiled fine) and get the compiler error message when compiling the same code ( a file called player.cpp) in my own project:
Error 1 error C2665: 'MATExceptions::MATExceptions' : none of the 3 overloads could convert all the argument types c:\users\daniel\documents\visual studio 2012\projects\mytest1\mytest1\player.cpp 137 1 Test1
The error occurs on this line in player.cpp:
EXCEP(DirectSoundErr::GetErrDesc(hres), _T("Player::CreateDS DirectSoundCreate"));
Here is the definition of EXCEP and GetErrDesc:
#define EXCEP(/*const wchar_t * */ desc, /*const wchar_t * */ from) throw( MATExceptions(__LINE__, _T(__FILE__), 0, from, desc) );
CComBSTR DirectSoundErr::GetErrDesc(HRESULT hres)
{
switch(hres)
{
case DSERR_ALLOCATED :
return _T("The request failed because resources, such as a
priority level, were already in use by another caller.");
...
default : return _T("Unknown error");
}
}
I don't know what is different (as I have not changed the source file player.cpp). Could it be due to different compiler settings in my project compared to the original (how would I check this)?
I changed the EXCEP definition to the following:
#define EXCEP(desc, from) throw(MATExceptions(__LINE__, (wchar_t *)(__FILE__), 0, (wchar_t *)from, (wchar_t *)desc));
...and changed the call from:
EXCEP(DirectSoundErr::GetErrDesc(hres), _T("Player::CreateDS DirectSoundCreate"));
to:
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::CreateDS DirectSoundCreate");
Is that acceptable?
The original "new" can be killed by defining these in project (since Visual Studio 2015 I guess):
__PLACEMENT_NEW_INLINE
__PLACEMENT_VEC_NEW_INLINE
But once they are gone, they are gone. Now you need to make sure to include the project-specific header file which redefines them.

C++ type cast operator code that won't compile in visual studio 2012, but worked fine in visual studio 2005

I'm trying to update a old project that has been building with visual studio 2005 to uses visual studio 2012, and I'm getting an error that I cant solve.
The code that works fine under VS2005:
#include <iostream>
#include <string>
#include <sstream>
using std::cout;
using std::wcout;
using std::endl;
using std::wstring;
using std::string;
class Value
{
public:
Value(const wstring& value)
{
v = value;
}
Value(Value& other)
{
this->v = other.v;
}
template<typename T>
operator T() const
{
T reply;
std::wistringstream is;
is.str(v);
is >> reply;
return reply;
}
operator wstring() const
{
return v;
}
private:
wstring v;
};
int main()
{
Value v(L"Hello World");
wstring str = v;
wcout << str << endl;
Value int_val(L"1");
int i = int_val;
cout << i + 1 << endl;
return 0;
}
When I'm compiling this under VS2012 I get an error on the line "wstring str = v;", the error is:
error C2440: 'initializing' : cannot convert from 'Value' to 'std::basic_string<_Elem,_Traits,_Alloc>'
1> with
1> [
1> _Elem=wchar_t,
1> _Traits=std::char_traits<wchar_t>,
1> _Alloc=std::allocator<wchar_t>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
I can kinda fix it by changing the operator signature from 'operator wstring() const' to 'operator const wstring&() const'. But why does the original code not work, even though it works in VS2005.
I'm not getting an error on the line "int i = int_val;".
This also compiles and runs fine with GCC (g++) in cygwin (version 4.5.3).
Update
To really simulate my real problem there was some information left out in the sample code above. In between the Value class and the usage is a few other classes. One that look like this:
class Config
{
public:
virtual Value getValue(const string& key) const = 0;
Value operator()(const string& key)
{
return getValue(key);
}
};
And the usage
const wstring value2 = config("key");
That will give the error above when compiling but also IntelliSense will give other hints on whats wrong and it says: "More than one user-defined conversion from "Value" to "const std::wstring" applies:" and it points at both the regular constructor and the move constructor of basic_string. So it seem to have something to do with rvalues to do and I have been reading up on that, and understand the basics. But there is probably a lot I am missing.
I find that I can fix this problem by changing the usage to:
const wstring&& value = config("key");
Then it seem like the VS2012 compiler understand which constructor it should use then.
Questions:
* Are there a way to not use && in this example?
* What is really happening here?
I put up the sample code on GitHub:
https://github.com/Discordia/ImplicitTypeConversion
In simple (hopefully not simplified) terms, with C++11, you'll have to start thinking of references in terms of lvalue and rvalue. Basically, C++11 gives you the ability to handle operations on references differently depending on whether or not you are dealing with a "temporary" object. This gives you ability to do things like move data internal to your object rather than copy in different situations. The down side to this is the effect you are seeing, where old code is not specific enough about which you are dealing with. There's more to it than that, it's not really something that can be fully explained in a short SO answer, but previous answers gave some good places to start. I would rework your code to provide both rvalue and lvalue operators (which it sounds like you're already on your way to doing).