For those interested, here is my final solution (until I find a new
"final" solution, I guess.)

First, I had to use templated functions, because the CString in MFC is
slightly different from the CString in ATL.  Parameterizing the "Traits"
parameter of the template base class (CStringT) was the first solution I
found that worked with both.

Second, I added another function to convert wide strings to fit in a
CharMessageBuffer.  This handles the case where you start logging an
Ansi string, and then try to stream in a CStringW.
LOG4CXX_DEBUG(MyLogger, "This is a CString: " << CString(_T("Hello")))

Third, to keep with the spirit of simultaneous support of Ansi and
Unicode strings in log4cxx, I specified the char type.

One nice thing about this solution is that it can be put in an optional
header file.  It is not compiled with log4cxx, and it is up to the
including project to choose MFC or ATL CStrings.  It could therefore be
added to log4cxx, without breaking the multi-platform compatibility.


namespace log4cxx {
namespace helpers {

// -- Wide String Operators --

template<class Traits>
WideMessageBuffer& operator<<(MessageBuffer& buf, const
CStringT<wchar_t, Traits>& str)
{
        return buf << (const wchar_t*) str;
}

template<class Traits>
WideMessageBuffer& operator<<(WideMessageBuffer& buf, const
CStringT<wchar_t, Traits>& str)
{
        return buf << (const wchar_t*) str;
}

template<class Traits>
CharMessageBuffer& operator<<(CharMessageBuffer& buf, const
CStringT<wchar_t, Traits>& str)
{
        USES_CONVERSION;
        return buf << W2CA((const wchar_t*)str);
}

// -- ANSI String Operators --

template<class Traits>
CharMessageBuffer& operator<<(MessageBuffer& buf, const CStringT<char,
Traits>& str)
{
        return buf << (const char*) str;
}

template<class Traits>
CharMessageBuffer& operator<<(CharMessageBuffer& buf, const
CStringT<char, Traits>& str)
{
        return buf << (const char*) str;
}

} // namespace helpers
} // namespace log4cxx


-----Original Message-----
From: Dale King [mailto:[EMAIL PROTECTED] 
Sent: Thursday, April 24, 2008 4:30 AM
To: Log4CXX User
Subject: Re: Problem logging unicode MFC/ATL CString with LOG4CXX_*
macros

Which is something that should probably be added to log4cxx.hw.

On Wed, 2008-04-23 at 23:30 -0500, Curt Arnold wrote:
> On Apr 23, 2008, at 8:12 PM, Jara, Mike SEA wrote:
> 
> > I'm having trouble getting (Windows) MFC or ATL CStrings to log
> > properly, when using the LOG4CXX_* macros.  For example, this will
log
> > the pointer's hex value, rather than the string contents:
> >
> > CString sMyString(_T("Test CString"));
> > LOG4CXX_DEBUG(MyLogger, sMyString);
> >
> > CString does implement a cast operator to LPCTSTR (wchar_t* in my  
> > case).
> > If I explicitly call this, the string logs properly:
> >
> > CString sMyString(_T("Test CString"));
> > LOG4CXX_DEBUG(MyLogger, (LPCTSTR)sMyString);
> >
> > I would expect this cast operator to be implicitly called inside
> > MessageBuffer, to make the argument comply with the function  
> > signature.
> > I think this is the function that should be called:
> >
> > WideMessageBuffer& MessageBuffer::operator<<(const wchar_t* msg);
> >
> > But when I step through in the debugger, I see that there is a
global
> > cast operator called instead.  I assume it's a better fit, as far as

> > the
> > compiler's concerned:
> >
> > template<class V>
> > std::ostream& operator<<(MessageBuffer& os, const V& val) {
> >   return ((std::ostream&) os) << val;
> >
> > I tried commenting this cast operator out, and then I no longer have

> > to
> > cast my CString!  But I'm afraid this was probably put in for a  
> > reason,
> > and I hate to just hack something when I don't completely understand

> > it.
> > Does anyone know if I can safetly remove this?  Looking at the
change
> > list, I see it was added by "carnold" on 11/6/07, revision number
> > 592542.
> >
> > I'm using the last snapshot before the 0.10 release, by the way.
> >
> > Any help would be appreciated.
> >
> > Thanks!
> > Mike
> 
> 
> The template that you mentioned basically says that when attempting to

> insert, you do not recognize the right hand side as a recognized  
> string type (char*, wchar_t*, std::string, std::wstring), then use any

> available insertion operator for a std::ostream and force the rest of

> the expression to be char* based.
> 
> What you'd like to have is something like the following in scope:
> 
> #if defined(_UNICODE)
> WideMessageBuffer& operator<<(MessageBuffer& buf, const CString& str)
{
>      return buf << (const wchar_t*) str;
> }
> WideMessageBuffer& operator<<(WideMessageBuffer& buf, const CString&  
> str) {
>      return buf << (const wchar_t*) str;
> }
> #else
> CharMessageBuffer& operator<<(MessageBuffer& buf, const CString& str)
{
>      return buf << (const char*) str;
> }
> CharMessageBuffer& operator<<(CharMessageBuffer& buf, const CString&  
> str) {
>      return buf << (const char*) str;
> }
> #endif
> 
> which should take precedence over the fallback insertion operation.
> 
-- 
Dale King <[EMAIL PROTECTED]>

Reply via email to