Exportar classes de cadeia de caracteres usando CStringT

No passado, os desenvolvedores do MFC fizeram derivação de CString para especializar suas próprias classes de cadeia de caracteres. No .NET (MFC 8.0) do Microsoft Visual C++, a classe CString foi substituída por uma classe de modelo chamada CStringT. Isso forneceu vários benefícios:

  • Permitiu que a classe CString do MFC fosse usada em projetos da ATL sem vinculação na biblioteca estática no MFC maior ou na DLL.

  • Com a nova classe de modelo CStringT, você pode personalizar o comportamento CString usando parâmetros de modelo que especificam características de caractere, semelhantes aos modelos na Biblioteca Padrão C++.

  • Quando você exporta sua própria classe de cadeia de caracteres de uma DLL usando CStringT, o compilador também exporta automaticamente a classe base CString. Como CString é uma classe de modelo, ela pode ser instanciada pelo compilador quando usada, a menos que o compilador esteja ciente de que CString é importado de uma DLL. Se você migrou projetos do Visual C++ 6.0 para o Visual C++ .NET, talvez tenha visto erros de símbolo do vinculador para um CString com multiplicação definida devido à colisão do CString importado de uma DLL e da versão localmente instanciada. A maneira adequada de fazer isso é descrita abaixo.

O cenário a seguir fará com que o vinculador produza erros de símbolo para multiplicar classes definidas. Suponha que você esteja exportando uma classe derivada de CString (CMyString) de uma DLL de extensão MFC:

// MyString.h
class AFX_EXT_CLASS CMyString : public CString
{
   // Your implementation code
};

O código do consumidor usa uma mistura de CString e CMyString. "MyString.h" não está incluído no cabeçalho pré-compilado e alguns usos de CString não têm CMyString visível.

Suponha que você use as classes CString e CMyString em arquivos de origem separados, Source1.cpp e Source2.cpp. Em Source1.cpp, você usa CMyString e #include MyString.h. Em Source2.cpp, você usa CString, mas não usa #include MyString.h. Nesse caso, o vinculador reclamará de CStringT ter sido definido por multiplicação. Isso é causado por CString ser importado da DLL que exporta CMyString e instanciado localmente pelo compilador por meio do modelo CStringT.

Para resolver esse problema, execute uma das seguintes ações:

Exporte CStringA e CStringW (e as classes base necessárias) de MFC90.DLL. Os projetos que incluem o MFC sempre usarão a DLL do MFC exportada CStringA e CStringW, como nas implementações anteriores do MFC.

Em seguida, crie uma classe derivada exportável usando o CStringT modelo, como CStringT_Exported está abaixo, por exemplo:

#ifdef _AFXDLL
   #define AFX_EXT_CSTRING AFX_EXT_CLASS
#else
   #define AFX_EXT_CSTRING
#endif

template< typename BaseType, class StringTraits >
class AFX_EXT_CSTRING CStringT_Exported 
   : public CStringT< BaseType, StringTraits >
{
   // Reimplement all CStringT<> constructors and
   // forward to the base class implementation
};

No AfxStr.h, substitua os typedefs CString, CStringA e CStringW anteriores da seguinte maneira:

typedef CStringT_Exported< wchar_t, 
      StrTraitMFC< wchar_t > > CStringW;

typedef CStringT_Exported< char,
      StrTraitMFC< char > > CStringA;

typedef CStringT_Exported< TCHAR,
      StrTraitMFC< TCHAR > > CString;

Existem várias advertências:

  • Você não deve exportar apenas CStringT porque isso fará com que projetos somente ATL exportem uma classe CStringT especializada.

  • O uso de uma classe derivada exportável de CStringT minimiza a necessidade de implementar novamente a funcionalidade CStringT. O código adicional é limitado ao encaminhamento de construtores para a classe base CStringT.

  • CString, CStringA e CStringW só devem ser marcados como __declspec(dllexport/dllimport) quando você estiver criando com uma DLL compartilhada do MFC. Se estiver vinculando com uma biblioteca estática do MFC, você não deverá marcar essas classes como exportadas. Caso contrário, o uso interno de CString, CStringA e CStringW nas DLLs do usuário também marcará CString como exportado.

Classe CStringT

Confira também

Usando CStringT
Usando CString