方法: 移行先 /clr
この記事では、ネイティブ コードをコンパイルするときに発生する問題について説明します /clr
。 (詳細については、「/clr (共通言語ランタイムのコンパイル)」を参照してください)。 /clr
では、他のネイティブ C++ コードに加えて、ネイティブ C++ コードを呼び出し、.NET アセンブリから呼び出すことができます。 コンパイル/clr
の利点の詳細については、「混合 (ネイティブおよびマネージド) アセンブリとネイティブおよび .NET 相互運用性」を参照してください。
ライブラリ プロジェクトのコンパイルに関する既知の問題 /clr
Visual Studio には、次を使用してライブラリ プロジェクト /clr
をコンパイルするときの既知の問題がいくつか含まれています。
コードでは、実行時に 〘 を使用して型を
CRuntimeClass::FromName
照会できます。 ただし、型が MSIL DLL 内にある場合 (コンパイル後/clr
)、静的コンストラクターがマネージド DLL で実行される前に呼び出しFromName
が失敗する可能性があります。 (マネージド DLL でコードが実行された後にFromName
呼び出しが行われると、この問題は表示されません)。この問題を回避するには、マネージド静的コンストラクターの構築を強制します。マネージド DLL で関数を定義し、エクスポートして、ネイティブ MFC アプリケーションから呼び出します。 次に例を示します。// MFC extension DLL Header file: __declspec( dllexport ) void EnsureManagedInitialization () { // managed code that won't be optimized away System::GC::KeepAlive(System::Int32::MaxValue); }
Visual C++ でのコンパイル
プロジェクト内の任意のモジュールで使用 /clr
する前に、まずネイティブ プロジェクトをコンパイルして Visual Studio にリンクします。
次の手順に従って、コンパイルへの最も簡単なパスを /clr
指定します。 これらの各手順の後に、プロジェクトをコンパイルして実行することが重要です。
以前のバージョンの Visual Studio からのアップグレード
Visual Studio を以前のバージョンからアップグレードする場合は、Visual Studio の強化された Standard C++ 準拠に関連するコンパイラ エラーが表示されることがあります。
以前のバージョンの Visual Studio でビルドされたプロジェクトも、最初にコンパイルする /clr
必要があります。 Visual Studio では、Standard C++ の準拠といくつかの重大な変更が増加しました。 最も注意が必要となる可能性が高い変更は、CRT のセキュリティ機能です。 CRT を使用するコードでは、非推奨の警告が生成される可能性があります。 これらの警告は抑制できますが、セキュリティが強化された新しい バージョンの CRT 関数 に移行することをお勧めします。これは、セキュリティが強化され、コードのセキュリティの問題が明らかになることがあります。
C++ マネージド拡張からのアップグレード
Visual Studio 2005 以降のバージョンでは、Managed Extensions for C++ で記述されたコードはコンパイルされません /clr
。
C コードを C++ に変換する
Visual Studio は C ファイルをコンパイルしますが、コンパイルのために C++ /clr
に変換する必要があります。 実際のファイル名を変更する必要はありません。を使用/Tp
できます (「 , /Tp
, /TC
( /TP
ソース ファイルの種類を指定する)」を参照/Tc
してください)。 C++ ソース コード ファイルは必須 /clr
ですが、オブジェクト指向パラダイムを使用するようにコードをリファクタリングする必要はありません。
C コードでは、C++ ファイルとしてコンパイルするときに変更が必要な場合があります。 C++ の型保証の規則は厳密なので、型の変換はキャストで明示的に行う必要があります。 たとえば、malloc は void ポインターを返しますが、キャストによる C では任意の型のポインターに割り当てることができます。
int* a = malloc(sizeof(int)); // C code
int* b = (int*)malloc(sizeof(int)); // C++ equivalent
また C++ では関数ポインターの型も厳密に保証されているので、次のような C コードは変更が必要です。 C++ では、関数ポインター型を定義するオブジェクトを作成 typedef
し、その型を使用して関数ポインターをキャストすることをお勧めします。
NewFunc1 = GetProcAddress( hLib, "Func1" ); // C code
typedef int(*MYPROC)(int); // C++ equivalent
NewFunc2 = (MYPROC)GetProcAddress( hLib, "Func2" );
また C++ では、関数を参照したり呼び出すには、その前にプロトタイプを作成するか完全に定義する必要があります。
C++ でキーワード (keyword)される C コードで使用される識別子 (例: virtual
, new
, delete
, bool
, true
, false
, など) の名前を変更する必要があります。 この変更は、通常、単純な検索と置換の操作で行うことができます。
COMObj1->lpVtbl->Method(COMObj, args); // C code
COMObj2->Method(args); // C++ equivalent
プロジェクト設定を再構成する
Visual Studio でプロジェクトをコンパイルして実行したら、既定の構成を変更するのではなく、新しいプロジェクト構成 /clr
を作成する必要があります。 /clr
は、一部のコンパイラ オプションと互換性がありません。 個別の構成を作成すると、プロジェクトをネイティブまたはマネージドとしてビルドできます。 [プロパティ ページ] ダイアログ ボックスで選択すると /clr
、プロジェクト設定と /clr
互換性がありません。 (無効なオプションは、後で選択されていない場合 /clr
は自動的に復元されません)。
新しいプロジェクト構成を作成する
[新しいプロジェクト構成] ダイアログ ボックス ([ビルド]>[構成マネージャー]>[アクティブ ソリューション構成]>[新規作成]) の [設定のコピー元] オプションを使用すると、既存のプロジェクト設定に基づいてプロジェクト構成を作成できます。 デバッグ構成用に 1 回、リリース構成用に 1 回、構成のコピーを作成します。 それ以降の変更は、-specific 構成にのみ適用 /clr
でき、元のプロジェクト構成はそのまま残ります。
カスタム ビルド規則を使用するプロジェクトには、特別な注意が必要な場合があります。
この手順は、メイクファイルを使用するプロジェクトにとって別の意味があります。 この場合、別のビルド ターゲットを構成することも、コンパイルに固有のバージョンを /clr
元のバージョンのコピーから作成することもできます。
プロジェクトの設定を変更する
/clr
は、/clr (共通言語ランタイム コンパイル) の手順に従って、開発環境で選択できます。 既に説明したように、この手順によって競合するプロジェクト設定は自動的に無効になります。
Note
Visual Studio 2003 からマネージド ライブラリまたは Web サービス プロジェクトをアップグレードすると、/Zl
コンパイラ オプションがコマンド ライン プロパティ ページに追加されます。 これにより、LNK2001 エラーが発生します。 エラーを解決するには、[コマンド ライン] プロパティ ページから削除/Zl
します。 詳細については、「/Zl
(既定のライブラリ名を省略する)」および「コンパイラとビルドのプロパティを設定する」を参照してください。
メイクファイルを使用してビルドされたプロジェクトの場合、互換性のないコンパイラ オプションは、追加後 /clr
に手動で無効にする必要があります。 互換性/clr
のないコンパイラ オプションについては、制限を参照してください/clr
。
プリコンパイル済みヘッダー
プリコンパイル済みヘッダーは、/clr
ただし、CPP ファイルの一部のみをコンパイルする /clr
(残りをネイティブとしてコンパイルする) 場合は、いくつかの変更が必要です。 生成されたプリコンパイル済みヘッダーは、メタデータを生成/clr
して必要とするため/clr
、生成/clr
されないプリコンパイル済みヘッダーと互換性がありません。 コンパイルされた /clr
モジュールは、メタデータを含まないプリコンパイル済みヘッダーを使用できません。また、非/clr
モジュールでは、メタデータを含むプリコンパイル済みヘッダー ファイルを使用できません。
一部のモジュールがコンパイルされる /clr
プロジェクトをコンパイルする最も簡単な方法は、プリコンパイル済みヘッダーを完全に無効にすることです。 (プロジェクトの [プロパティ ページ] ダイアログで、 C/C++ ノードを選択し、[プリコンパイル済みヘッダー] を選択 します。次に、[プリコンパイル済みヘッダーの 作成/使用] プロパティを [プリコンパイル済みヘッダー を使用しない] に変更します)。
ただし、特に大規模なプロジェクトでは、プリコンパイル済みヘッダーのコンパイル速度が大幅に向上するため、この機能を無効にすることは望ましくありません。 この場合は、個別のプリコンパイル済みヘッダーを /clr
使用するようにファイルと非/clr
ファイルを構成することをお勧めします。 1 つの手順で構成できます。ソリューション エクスプローラーを使用して、コンパイルに使用/clr
するモジュールを複数選択します。 グループを右クリックし、[プロパティ] を選択します。 次に、それぞれ異なるヘッダー ファイル名と PCH ファイルを使用するように、ファイルによる PCH の作成/使用プロパティとプリコンパイル済みヘッダー ファイルプロパティの両方を変更します。
エラーの修復
コード /clr
をコンパイルすると、コンパイラ、リンカー、またはランタイム エラーが発生する可能性があります。 このセクションでは、最も一般的な問題について説明します。
メタデータのマージ
データ型のバージョンが異なる場合、2 つの型に対して生成されるメタデータが一致しないため、リンカーのエラーが発生することがあります (型のメンバーを条件付きで定義したが、その型を使用するすべての CPP ファイルで条件が同じでない場合、エラーが発生します)。この場合、リンカーは失敗し、シンボル名と、型が定義された 2 番目の OBJ ファイルの名前のみが報告されます。 OBJ ファイルがリンカーに送信される順序をローテーションして、他のバージョンのデータ型の場所を検出すると便利な場合があります。
ローダー ロックのデッドロック
"ローダー ロックのデッドロック" が発生する可能性がありますが、これは確定的であり、実行時に検出および報告されます。 詳細な背景、ガイダンス、ソリューションについては、「混在アセンブリの初期化」を参照してください。
データのエクスポート
DLL データのエクスポートはエラーが発生しやすく、コードでは /clr
推奨されません。 これは、DLL の一部のマネージド部分が実行されるまで、DLL のデータ セクションの初期化が保証されないためです。 ディレクティブを使用してメタデータを #using
参照します。
型の可視性
ネイティブ型は private
既定で使用されます。 private
ネイティブ型は DLL の外部には表示されません。 このエラーを解決するには、これらの型に public
を追加します。
浮動小数点と配置の問題
__controlfp
は共通言語ランタイムではサポートされていません。 (詳細については、,,.__control87_2
) を_controlfp
参照してください_control87
。CLR も考慮align
しません。
COM の初期化
共通言語ランタイムは、モジュールが初期化されるときに COM を自動的に初期化します (COM が自動的に初期化されると、MTA として行われます)。 その結果、明示的に COM を初期化すると、COM が既に初期化されていることを示すリターン コードが生成されます。 COM が CLR によって既にいずれかのスレッド モデルに初期化されている場合、別のスレッド モデルを使用して明示的に COM を初期化しようとすると、アプリケーションが失敗するおそれがあります。
共通言語ランタイムは、既定で COM を MTA として起動します。COM モデルを変更するには、(CLR スレッド属性を設定する) を使用/CLRTHREADATTRIBUTE
します。
パフォーマンスの問題
MSIL に対して生成されたネイティブ C++ メソッドが (仮想関数呼び出しまたは関数ポインターを使用して) 間接的に呼び出されると、パフォーマンスが低下することがあります。 詳細については、「ダブル サンキング」を参照してください。
ネイティブから MSIL に移行すると、ワーキング セットのサイズが大きくなることがわかります。 この増加は、共通言語ランタイムには、プログラムが正しく実行されるようにするための多くの機能が用意されているために発生します。 /clr
アプリケーションが正常に実行されていない場合は、既定でオフのコンパイラ警告 (レベル 1 および 3) C4793 を有効にできます。
シャットダウン時にプログラムがクラッシュする
場合によっては、マネージド コードの実行が完了する前に CLR がシャットダウンされる場合があります。 シャットダウンのstd::set_terminate
SIGTERM
原因となる可能性があります。 詳細については、定数とを参照してくださいsignal
。set_terminate
新しい Visual C++ 機能の使用
アプリケーションのコンパイル、リンク、および実行が完了したら、.NET でコンパイルされた任意のモジュールで .NET 機能の使用を /clr
開始できます。 詳細については、「 Component Extensions for Runtime Platforms」を参照してください。
Visual C++ での .NET プログラミングの詳細については、次を参照してください。