From 6b583d40a8cd1dd38de2ad84e650023b857f80f7 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 30 Oct 2008 23:04:29 +0000 Subject: [PATCH] fix linking problems due to MSVC implicitly considering template classes specializations used as base classes DLL-exported even though it doesn't actually export them when building the DLL (with or without explicit declspec(dllexport)); also replace wxCharTypeBuffer::NullData with a static function to allow not DLL-exporting this class git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@56602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/buffer.h | 35 ++++++++++++++----------------- include/wx/string.h | 47 +++++++++++++++++++++++++++++++++++------- src/common/string.cpp | 45 ---------------------------------------- src/common/ustring.cpp | 13 ------------ 4 files changed, 55 insertions(+), 85 deletions(-) diff --git a/include/wx/buffer.h b/include/wx/buffer.h index 3244323737..2f8bc64866 100644 --- a/include/wx/buffer.h +++ b/include/wx/buffer.h @@ -27,7 +27,7 @@ class WXDLLIMPEXP_FWD_BASE wxCStrData; // ---------------------------------------------------------------------------- template -class WXDLLIMPEXP_BASE wxCharTypeBuffer +class wxCharTypeBuffer { public: typedef T CharType; @@ -37,7 +37,7 @@ public: if ( str ) m_data = new Data(wxStrdup(str)); else - m_data = &NullData; + m_data = GetNullData(); } wxCharTypeBuffer(size_t len) @@ -64,7 +64,7 @@ public: // that ref-counting is used, it's not really needed. CharType *release() const { - if ( m_data == &NullData ) + if ( m_data == GetNullData() ) return NULL; wxASSERT_MSG( m_data->m_owned, _T("can't release non-owned buffer") ); @@ -121,7 +121,7 @@ public: if ( !str ) return false; - if ( m_data == &NullData ) + if ( m_data == GetNullData() ) { m_data = new Data(str); } @@ -167,30 +167,27 @@ private: }; // placeholder for NULL string, to simplify this code - // NB: this is defined in string.cpp, not (non-existent) buffer.cpp -#ifdef __MINGW32__ - // MinGW requires explicit WXDLLIMPEXP_DATA_BASE to avoid compilation - // errors - static WXDLLIMPEXP_DATA_BASE(Data) NullData; -#else - // but Visual C++ doesn't like it - static Data NullData; -#endif + static Data *GetNullData() + { + static Data s_nullData(NULL); + + return &s_nullData; + } void IncRef() { - if ( m_data == &NullData ) // exception, not ref-counted + if ( m_data == GetNullData() ) // exception, not ref-counted return; m_data->m_ref++; } void DecRef() { - if ( m_data == &NullData ) // exception, not ref-counted + if ( m_data == GetNullData() ) // exception, not ref-counted return; if ( --m_data->m_ref == 0 ) delete m_data; - m_data = &NullData; + m_data = GetNullData(); } private: @@ -199,7 +196,7 @@ private: WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer ) -class WXDLLIMPEXP_BASE wxCharBuffer : public wxCharTypeBuffer +class wxCharBuffer : public wxCharTypeBuffer { public: typedef wxCharTypeBuffer wxCharTypeBufferBase; @@ -216,7 +213,7 @@ public: #if wxUSE_WCHAR_T WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer ) -class WXDLLIMPEXP_BASE wxWCharBuffer : public wxCharTypeBuffer +class wxWCharBuffer : public wxCharTypeBuffer { public: typedef wxCharTypeBuffer wxCharTypeBufferBase; @@ -342,7 +339,7 @@ private: }; -class WXDLLIMPEXP_BASE wxMemoryBuffer +class wxMemoryBuffer { public: // ctor and dtor diff --git a/include/wx/string.h b/include/wx/string.h index 43dfbcb175..10729ed6eb 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -3605,7 +3605,7 @@ private: #endif // !wxUSE_STL_BASED_WXSTRING template -class WXDLLIMPEXP_BASE wxStringTypeBufferBase +class wxStringTypeBufferBase { public: typedef T CharType; @@ -3645,8 +3645,7 @@ protected: }; template -class WXDLLIMPEXP_BASE wxStringTypeBufferLengthBase - : public wxStringTypeBufferBase +class wxStringTypeBufferLengthBase : public wxStringTypeBufferBase { public: wxStringTypeBufferLengthBase(wxString& str, size_t lenWanted = 1024) @@ -3750,25 +3749,57 @@ typedef wxStringInternalBufferLength wxUTF8StringBufferLength; WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxStringTypeBufferBase ) -class WXDLLIMPEXP_BASE wxUTF8StringBuffer : public wxStringTypeBufferBase +// Note about inlined dtors in the classes below: this is done not for +// performance reasons but just to avoid linking errors in the MSVC DLL build +// under Windows: if a class has non-inline methods it must be declared as +// being DLL-exported but, due to an extremely interesting feature of MSVC 7 +// and later, any template class which is used as a base of a DLL-exported +// class is implicitly made DLL-exported too, as explained at the bottom of +// http://msdn.microsoft.com/en-us/library/twa2aw10.aspx (just to confirm: yes, +// _inheriting_ from a class can change whether it is being exported from DLL) +// +// But this results in link errors because the base template class is not DLL- +// exported, whether it is declared with WXDLLIMPEXP_BASE or not, because it +// does have only inline functions. So the simplest fix is to just make all the +// functions of these classes inline too. + +class wxUTF8StringBuffer : public wxStringTypeBufferBase { public: wxUTF8StringBuffer(wxString& str, size_t lenWanted = 1024) : wxStringTypeBufferBase(str, lenWanted) {} - ~wxUTF8StringBuffer(); + ~wxUTF8StringBuffer() + { + wxMBConvStrictUTF8 conv; + size_t wlen = conv.ToWChar(NULL, 0, m_buf); + wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); + + wxStringInternalBuffer wbuf(m_str, wlen); + conv.ToWChar(wbuf, wlen, m_buf); + } DECLARE_NO_COPY_CLASS(wxUTF8StringBuffer) }; WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxStringTypeBufferLengthBase ) -class WXDLLIMPEXP_BASE wxUTF8StringBufferLength - : public wxStringTypeBufferLengthBase +class wxUTF8StringBufferLength : public wxStringTypeBufferLengthBase { public: wxUTF8StringBufferLength(wxString& str, size_t lenWanted = 1024) : wxStringTypeBufferLengthBase(str, lenWanted) {} - ~wxUTF8StringBufferLength(); + ~wxUTF8StringBufferLength() + { + wxCHECK_RET(m_lenSet, "length not set"); + + wxMBConvStrictUTF8 conv; + size_t wlen = conv.ToWChar(NULL, 0, m_buf, m_len); + wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); + + wxStringInternalBufferLength wbuf(m_str, wlen); + conv.ToWChar(wbuf, wlen, m_buf, m_len); + wbuf.SetLength(wlen); + } DECLARE_NO_COPY_CLASS(wxUTF8StringBufferLength) }; diff --git a/src/common/string.cpp b/src/common/string.cpp index 04a606a3c5..fcdca45d58 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -2096,48 +2096,3 @@ int wxString::Freq(wxUniChar ch) const } return count; } - -// ---------------------------------------------------------------------------- -// wxUTF8StringBuffer -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE_WCHAR -wxUTF8StringBuffer::~wxUTF8StringBuffer() -{ - wxMBConvStrictUTF8 conv; - size_t wlen = conv.ToWChar(NULL, 0, m_buf); - wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); - - wxStringInternalBuffer wbuf(m_str, wlen); - conv.ToWChar(wbuf, wlen, m_buf); -} - -wxUTF8StringBufferLength::~wxUTF8StringBufferLength() -{ - wxCHECK_RET(m_lenSet, "length not set"); - - wxMBConvStrictUTF8 conv; - size_t wlen = conv.ToWChar(NULL, 0, m_buf, m_len); - wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); - - wxStringInternalBufferLength wbuf(m_str, wlen); - conv.ToWChar(wbuf, wlen, m_buf, m_len); - wbuf.SetLength(wlen); -} -#endif // wxUSE_UNICODE_WCHAR - -// ---------------------------------------------------------------------------- -// wxCharBufferType -// ---------------------------------------------------------------------------- - -#ifndef __VMS_BROKEN_TEMPLATES -template<> -#endif -wxCharTypeBuffer::Data -wxCharTypeBuffer::NullData(NULL); - -#ifndef __VMS_BROKEN_TEMPLATES -template<> -#endif -wxCharTypeBuffer::Data -wxCharTypeBuffer::NullData(NULL); diff --git a/src/common/ustring.cpp b/src/common/ustring.cpp index c0cae8f58d..a9b9241eb4 100644 --- a/src/common/ustring.cpp +++ b/src/common/ustring.cpp @@ -542,16 +542,3 @@ wxU16CharBuffer wxUString::utf16_str() const return result; } - - -#if SIZEOF_WCHAR_T != 2 -template<> -wxCharTypeBuffer::Data -wxCharTypeBuffer::NullData(NULL); -#endif - -#if SIZEOF_WCHAR_T != 4 -template<> -wxCharTypeBuffer::Data -wxCharTypeBuffer::NullData(NULL); -#endif