ATL と MFC の変更点 : ATL 7.0 と MFC 7.0
更新 : 2007 年 11 月
メモ ここで説明している機能のいくつかは、現在のバージョンの Visual C++ には存在しない可能性があります。
Visual C++ 6.0 以降、ATL と MFC のライブラリが大幅に強化されました。これらの変更の一部は既存のコードに影響を与える可能性があります。
DLL の非互換性
Visual C++ .NET 2002 に含まれる ATL と MFC の DLL ファイルは、名前がそれぞれ ATL70.dll と MFC70.dll に変更されました。
Visual C++ .NET の ATL と MFC のクラスは、以前のリリースの同じクラスとバイナリ互換性がありません。このため、mfc42.dll を使用してビルドしたソース コードは、Visual Studio .NET でビルドし直す必要があります。また、アプリケーションで使用する DLL ファイルや LIB ファイルも、Visual Studio .NET でビルドし直す必要があります。
たとえば、Visual C++ 6.0 を使用してビルドした、CString というパラメータを受け取るエクスポート関数を含むライブラリは、Visual C++ .NET プロジェクトとのリンク中に未解決の外部参照エラーになります。
ATL モジュール クラス
ATL 3.0 には、CComModule クラスがありました。ATL 7.0 では、CComModule クラスの機能が複数の新しいクラスで処理されます。詳細については、「ATL モジュール クラス」を参照してください。
文字列の変換
Visual C++ 6.0 の ATL 3.0 までの ATL のバージョンでは、atlconv.h 内のマクロを使用する文字列の変換は、常にシステムの ANSI コード ページ (CP_ACP) を使用して行われていました。Visual C++ .NET の ATL 7.0 からは、文字列の変換は、現在のスレッドの既定の ANSI コード ページを使用して行われます。ただし、_CONVERSION_DONT_USE_THREAD_LOCALE が定義されている場合は、以前と同じようにシステムの ANSI コード ページが使用されます。
CW2AEX などの文字列変換クラスでは、変換に使用するコード ページをコンストラクタに渡すことができます。コード ページを指定しなかった場合は、マクロと同じコード ページが使用されます。
詳細については、「ATL と MFC の文字列変換マクロ」を参照してください。
抽象基本クラスである CException
CException は、MFC (Microsoft Foundation Class) ライブラリ内のすべての例外に関する基本クラスです。現在の CException は抽象基本クラスであるため、CException オブジェクトを直接作成することはできません。派生クラスのオブジェクトを作成する必要があります。オブジェクトを直接作成すると、エラーが発生します。詳細については、「CException」を参照してください。
BSTR から CString への変換
Visual C++ 6.0 では、次のコードを使用できました。
BSTR bstr = SysAllocString(L"Hello");
CString str = bstr;
SysFreeString(bstr);
Visual C++ .NET の新しいプロジェクトで上記のコードを使用すると、ANSI のビルドで次のエラーが発生します。
error C2440: 'initializing' : cannot convert from 'BSTR' to
'ATL::CStringT<BaseType,StringTraits>'
CString に UNICODE バージョンと ANSI バージョン (CStringW と CStringA) ができました。暗黙的な変換による不要なオーバーヘッドを示すため、逆のタイプ (たとえば UNICODE の引数を取る CStringA または ANSI の引数を取る CStringW) を取るコンストラクタは、stdafx.h 内の次のエントリを使用して明示的としてタグが設定されます。
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
このエラーを回避するには、以下のいずれかの操作を実行します。
CStringW を使用して変換を避けます。
BSTR bstr = SysAllocString(L"Hello"); CStringW str = bstr; SysFreeString(bstr);
コンストラクタを明示的に呼び出します。
BSTR bstr = SysAllocString(L"Hello"); CString str = CString(bstr); SysFreeString(bstr);
stdafx.h から #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS の行を削除します。
CTime の変更点
CTime クラス は、基になる __time64_t データ型を使用します。MFC 6.0 では、CTime は 32 ビット型であった time_t データ型を使用していました。この変更の理由は、2038 年 1 月 19 日の 3:14:07 より先の時刻をサポートするためです。
CComEnumImpl::Skip の変更点
ATL 7.0 より前のバージョンの CComEnumImpl::Skip メソッドでは、値 0 を入力した場合に正しいエラー コードが返されませんでした。また、入力する値が大きい場合の処理に一貫性がありませんでした。ATL 7.0 では、これらの動作が修正されました。
CWnd::DestroyWindow のアサーション
CWnd::DestroyWindow でツール ヒントを表示すると、アサーション エラーが発生していました。このため、MFC 7.0 では、以下のメンバ変数が AFX_THREAD_STATE から AFX_MODULE_THREAD_STATE に移動されました。
CToolTipCtrl* m_pToolTip
CWnd* m_pLastHit
int m_nLastHit
TOOLINFO m_lastInfo
int m_nLastStatus
CControlBar* m_pLastStatus
LNK2001 未解決の外部シンボル エラー
スタティック ライブラリまたは DLL にある、wchar_t 型を取る関数を呼び出すとき (BSTR と LPWSTR は解決されて wchar_t* になる)、LNK2001 未解決の外部シンボル エラーが発生する場合があります。
このエラーの原因は、/Zc:wchar_t コンパイラ オプションです。このオプションは、新しい MFC プロジェクトでは既定でオンに設定されます。このオプションがオンの場合は、コンパイラで wchar_t がネイティブな型として処理されます。Visual C++ .NET より前では、wchar_t は unsigned short として処理されていました。
したがって、メイン プロジェクトとライブラリで /Zc:wchar_t の同じ設定を使用しない場合は、関数シグネチャが一致しなくなります。この問題を避けるには、/Zc:wchar_t コンパイラ オプションを指定してライブラリをビルドし直すか、メイン プロジェクトでこのオプションをオフにします。プロジェクトでオプションをオフにするには、[プロパティ ページ] ダイアログ ボックスで、言語プロパティ ページの [wchar_t をビルトイン型として扱う] 設定を使用します。
BOOL 型ではなく bool 型であるブール式
次に、クラスの例を示します。
class CMyClass : public CObject
{
BOOL bFlag;
void Serialize (CArchive& ar))
{
if (ar.IsStoring())
ar << (bFlag != FALSE); // breaking change
else
ar >> bFlag;
}
};
Visual C++ .NET より前では、式 bFlag != FALSE は BOOL として評価され、4 バイトが書き込まれました。Visual C++ .NET では、この式は bool として評価され、1 バイトが書き込まれます。このため、別のバージョンのコンパイラでコンパイルされたプログラムは、相互に互換性のないデータ ファイルを生成することがあります。
この問題を回避するには、次に示すように式を BOOL にキャストします。
ar << (BOOL)(bFlag != FALSE);
CColorPropPage と CFontPropPage の削除
以前のバージョンの MFC では、ActiveX コントロールは、カラー プロパティとフォント プロパティのプロパティ ページを表示するために、GUID の CLSID_CColorPropPage と CLSID_CFontPropPage を指定しました。CColorPropPage クラスと CFontPropPage クラスを指すこれらの GUID は、現在は実装されていません。代わりに、GUID の CLSID_StockColorPage と CLSID_StockFontPage を使用します。これらは msstkprp.dll によって実装されるため、この DLL をアプリケーションで再配布する必要があります。
ON_MESSAGE の変更点
ON_MESSAGE マクロの関数パラメータは、afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM) 型と一致する必要があります。
OLE DB テンプレートの変更点
OLE DB テンプレートの変更点の詳細については、サポート技術情報の文書「INFO: Porting Issues with Visual Studio .NET OLE DB Provider Template Classes (Q321743)」を参照してください。サポート技術情報の文書は、MSDN ライブラリ CD-ROM または https://support.microsoft.com/support で参照できます。
OLE DB コンシューマ クラスとテンプレート
一般的な注意として、アクセサ クラスは追加メンバを実装する必要があります。この処理は、独自のアクセサ クラスを手動で実装する場合にだけ必要です。アクセサ クラスが CAccessor から派生する場合、この処理は不要です。
以前の動作 |
新しい動作 |
---|---|
CRowset はクラスです。 |
CRowset はクラス テンプレートであり、パラメータとして TAccessor アクセサ クラスを受け取ります。 |
CBulkRowset はクラスです。 |
CBulkRowset はクラス テンプレートです。 |
CArrayRowset の基本クラスは、テンプレート パラメータでした (既定値は CRowset)。 |
CArrayRowset は、常に CBulkRowset から派生します。 |
CDynamicAccessor::GetColumnInfo では 3 つのパラメータを使用していました。 |
CDynamicAccessor::GetColumnInfo には、追加のパラメータ ppStringsBuffer を受け取る新しい形式があります。このパラメータを使用すると、メモリ リークがなくなります。古いメソッドの使用は避けてください。 |
CAccessorRowset テンプレートの 2 番目のパラメータである Rowset は、行セット クラスです。 |
CAccessorRowset テンプレートの 2 番目のパラメータである TRowset は、行セット クラス テンプレートです。 |
CTable テンプレートの 2 番目のパラメータである Rowset は、行セット クラスです。 |
CTable テンプレートの 2 番目のパラメータである TRowset は、行セット クラス テンプレートです。 |
CCommand テンプレートの 2 番目のパラメータである Rowset は、行セット クラスです。 |
CCommand テンプレートの 2 番目のパラメータである TRowset は、行セット クラス テンプレートです。 |
DEFINE_COMMAND マクロ。 |
DEFINE_COMMAND マクロは使用しないでください。代わりに、DEFINE_COMMAND_EX を使用してください。 |
OLE DB プロバイダ クラスとテンプレート
多くのインターフェイスおよびメソッドの内部実装は、Visual C++ 6.0 から変更されました。これにより、アプリケーションがこれらのメソッドをオーバーライドするかどうかに応じて、互換性の問題が発生することがあります。
以前の動作 |
新しい動作 |
---|---|
行セット/アクセサの実装は、CSimpleMap/CSimpleArray クラスを使用しました。ユーザーが指定するコレクション クラスには、CSimpleMap/CSimpleArray との互換性が必要でした。 |
行セット/アクセサの実装は、CAtlMap/CAtlArray クラスを使用します。ユーザーが指定するコレクション クラスには、CAtlMap/CAtlArray との互換性が必要です。また、CAtl* クラスと CSimple* クラスの間には、ランタイム エラーの原因となる大きな違い (パラメータ、戻り値など) があるため、これらのコレクション クラスのメソッドを呼び出すコードを確認する必要があります。 |
ICommandImpl は、ICommand から派生しました。 |
ICommandImpl は、テンプレートの CommandBase 引数 (既定値は ICommand) から派生するテンプレートです。 |
ICommandTextImpl は、ICommandImpl<ICommandImpl<T> から派生しました。 |
ICommandTextImpl は、ICommandImpl<ICommandImpl<T, ICommandText> から派生します。この場合、ICommandImpl は、既定の ICommand ではなく ICommandText から派生します。 |