CStringT を使用した文字列クラスのエクスポート

更新 : 2007 年 11 月

従来、MFC 開発者は、CString から派生させて独自の文字列クラスを作成してきました。Microsoft Visual C++.NET (MFC 8.0) では、CString クラスの代わりに、CStringT と呼ばれるテンプレート クラスを使用するようになりました。これには、いくつかの利点があります。

  • より大きな MFC スタティック ライブラリまたは DLL でリンクを使用せずに、ATL プロジェクトで MFC CString クラスを使用できるようになりました。

  • 新しい CStringT テンプレート クラスを使用すると、標準テンプレート ライブラリ (STL: Standard Template Library) のテンプレートと同様に、文字の特徴を指定するテンプレート パラメータを使用して、CString の動作をカスタマイズできます。

  • CStringT を使用して DLL から独自の文字列クラスをエクスポートすると、コンパイラは CString 基本クラスも自動的にエクスポートします。CString 自体はテンプレート クラスなので、CString が DLL からインポートされることをコンパイラが認識しない限り、コンパイラの使用時にインスタンス化される可能性があります。プロジェクトを Visual C++ 6.0 から Visual C++.NET に移行した場合、DLL からインポートされた CString とローカルでインスタンス化されたバージョンの競合が原因で、重複して定義された CString に関するリンカ シンボル エラーが発生することがあります。エラーを発生させずに適切に使用する方法については、以下で説明します。この問題の詳細については、MSDN ライブラリ CD-ROM または https://support.microsoft.com/default.aspx にあるサポート技術情報の文書「Linking Errors When you Import CString-derived Classes」 (Q309801) を参照してください。

次のシナリオでは、リンカで重複して定義されたクラスに関するシンボル エラーが発生します。CString 派生クラス (CMyString) を MFC 拡張 DLL からエクスポートしていると仮定します。

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

コンシューマ コードで、CString と CMyString が一緒に使用されています。"MyString.h" はプリコンパイル済みヘッダーに含まれていないため、CString の使用法によっては、CMyString が表示されません。

個別のソース ファイル (Source1.cpp および Source2.cpp) で CString クラスおよび CMyString クラスを使用すると仮定します。Source1.cpp では、CMyString および #include MyString.h を使用します。Source2.cpp では、CString を使用しますが、#include MyString.h を使用しません。この場合、リンカでは、CStringT が重複して定義されていることを示すエラーが発生します。これは、CString が、CMyString をエクスポートする DLL からインポートされると同時に、コンパイラによって CStringT テンプレートが使用されローカルでインスタンス化されることが原因です。

この問題を解決するには、次のように操作します。

MFC90.DLL. から CStringA および CStringW (さらに、必要な基本クラス) をエクスポートします。MFC を含むプロジェクトでは、以前の MFC 実装と同様に、MFC DLL からエクスポートされた CStringA および CStringW が常に使用されます。

次に、CStringT テンプレートを使用して、エクスポート可能な派生クラスを作成します。たとえば、CStringT_Exported を使用します。

#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
};

AfxStr.h では、以前の CStringCStringA、および CStringW の各 typedef を次のように置き換えます。

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

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

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

いくつかの注意点を次に示します。

  • CStringT 自体はエクスポートしないでください。このエクスポートが原因で ATL 専用プロジェクトがプロジェクトに特化した CStringT クラスをエクスポートするためです。

  • エクスポートできる派生クラスを CStringT から使用すると、CStringT 機能を再実装する必要性を最小限に抑えることができます。追加のコードは、構造体を CStringT 基本クラスに転送することに制限されています。

  • CStringCStringA、および CStringW は、MFC 共有 DLL でビルドする場合のみ、__declspec(dllexport/dllimport) に設定する必要があります。MFC スタティック ライブラリとリンクする場合、これらのクラスをエクスポート済みに設定しないでください。それ以外の場合は、CStringCStringA、および CStringW をユーザー DLL の内部で使用すると、CString が同様にエクスポート済みに設定されます。

関連トピック

CStringT クラス

参照

その他の技術情報

CStringT の使用

CString の使用