single.php

C++で64ビットアプリケーションをビルド時のエラーメッセージを回避する

古いVisual Studioで作成したMFCプロジェクトを変換して64ビットアプリケーションをビルドした場合のエラーを回避する話。

x64ビルド環境

Microsoftの統合開発環境(IDE)「Visual Studio」は32ビットで動作しています。ビルド時にコンパイラーを選択することで、様々なアーキテクチャー向けのプログラムを紡ぎだすように設計されています。

そのため、x64アプリを作成するためには、「Visual Studio」セットアップ時に、64ビットのビルドツールを追加でセットアップしておく必要があります。(すべてインストールを選んでおけば間違いない)

互換性

プロジェクトは新しいIDEに移行する際に変換が行われます。変換と言っても、プロジェクト内のファイル配置や、ファイルの互換性など、プロジェクトを開いた際の変換をしてくれているだけで、実際にビルド操作を行うと、多くのエラーが出力される。

プロジェクトに「スタティックライブラリ」などがリンクされている場合には、64ビット用の「スタティックライブラリ」にリンクするように設定しておかないと、ビルド時にエラーになってしまう。

互換性や移行のウィザードは表面的なもので、実際にコード内やビルド時の考慮などは含まれていないことが多い。

x64プラットフォーム構成の作成

次の手順で、64ビット向けのプラットフォーム構成を追加します。

  1. [プロジェクト|プロパティ]メニューを選択してプロジェクトのプロパティを表示する。
  2. [構成マネージャ]ボタンを選択する。
  3. 表示された[構成マネージャ]画面の[アクティブ ソリューション プラットフォーム]リストから[新規作成]を選択する。
  4. 表示された[新しいソリューション プラットフォーム]画面で[新しいプラットフォームを入力または選択してください]リストから[x64]を選択する。
  5. [OK]ボタンを選択する。
  6. プラットフォームに[x64]が追加されアクティブになります。
  7. Win32用の設定がとりあえずコピーされているので、構成を64ビット用に修正します。
  8. ビルドを行う。(ビルドエラーが延々と出力されます)

ビルドメッセージと回避方法

1>C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(431) : error C2146: 構文エラー : ‘;’ が、識別子 ‘rgclsidAllowed’ の前に必要です。
1>C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(431) : error C4430: 型指定子がありません – int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
1>C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(431) : error C4430: 型指定子がありません – int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
1>C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(6041) : error C2039: ‘rgclsidAllowed’ : ‘ATL::ATL_PROPMAP_ENTRY’ のメンバではありません。
1> C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(422) : ‘ATL::ATL_PROPMAP_ENTRY’ の宣言を確認してください。
1>C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include\atlcom.h(6041) : error C2660: ‘ATL::CComVariant::ReadFromStream’ : 関数に 4 個の引数を指定できません。

上記のようなメッセージであれば、マイクロソフト セキュリティ情報 MS09-035(Visual Studio の Active Template Library の脆弱性により、リモートでコードが実行される [KB969706])が適用されていない可能性があるので、修正パッチを適用する。 WindowsUpdateでは更新されない。

1>ライブラリ x64\Debug/*****.lib とオブジェクト x64\Debug/*****.exp を作成中
1>*****.exp : error LNK2001: 外部シンボル “_DllCanUnloadNow@0” は未解決です。
1>*****.exp : error LNK2001: 外部シンボル “_DllGetClassObject@12” は未解決です。
1>*****.exp : error LNK2001: 外部シンボル “_DllRegisterServer@0” は未解決です。
1>*****.exp : error LNK2001: 外部シンボル “_DllUnregisterServer@0” は未解決です。
1>x64\Debug/*****.dll : fatal error LNK1120: 外部参照 4 が未解決です。

プロジェクト内の下記の部分を探して

#pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0,PRIVATE")
#pragma comment(linker, "/EXPORT:DllGetClassObject=_DllGetClassObject@12,PRIVATE")
#pragma comment(linker, "/EXPORT:DllRegisterServer=_DllRegisterServer@0,PRIVATE")
#pragma comment(linker, "/EXPORT:DllUnregisterServer=_DllUnregisterServer@0,PRIVATE")

次のように書き換える

#ifdef _WIN64
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=DllCanUnloadNow,PRIVATE")
#pragma comment(linker, "/EXPORT:DllGetClassObject=DllGetClassObject,PRIVATE")
#pragma comment(linker, "/EXPORT:DllRegisterServer=DllRegisterServer,PRIVATE")
#pragma comment(linker, "/EXPORT:DllUnregisterServer=DllUnregisterServer,PRIVATE")
#else
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0,PRIVATE")
#pragma comment(linker, "/EXPORT:DllGetClassObject=_DllGetClassObject@12,PRIVATE")
#pragma comment(linker, "/EXPORT:DllRegisterServer=_DllRegisterServer@0,PRIVATE")
#pragma comment(linker, "/EXPORT:DllUnregisterServer=_DllUnregisterServer@0,PRIVATE")
#endif

1>.\*****.cpp(46) : error C2440: ‘static_cast’ : ‘void (__cdecl C*****::* )(UINT)’ から ‘void (__cdecl CWnd::* )(UINT_PTR)’ に変換できません。
1>base から derived へのキャストには、dynamic_cast または static_cast が必要です。

ON_WM_TIMER() で定義している関するの引数が変更されているため ヘッダーファイルのOnTimer (UINT idEvent)を探してOnTimer (UINT_PTR idEvent) にソースファイルのafx_msg void OnTimer(UINT nIDEvent)を afx_msg void OnTimer(UINT_PTR nIDEvent)に修正する。この他にもON_WM_NCHITTEST()の戻り値が、UINTからLRESULTに変更されたりしている。

.manifestファイルを適用している場合には、processorArchitecture=”x86″としていると、ビルドは成功しても実行時に、comdlgを呼び出すときに、どっちが呼び出されるは分からないので、processorArchitecture=”*”とする。

この修正作業で、x64プラットフォーム用のアプリを生成時に出力されるエラーメッセージが無くなるはずです。

スポンサーリンク

最後までご覧いただきありがとうございます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です