方法: 移行先 /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_terminateSIGTERM原因となる可能性があります。 詳細については、定数とを参照してくださいsignalset_terminate

新しい Visual C++ 機能の使用

アプリケーションのコンパイル、リンク、および実行が完了したら、.NET でコンパイルされた任意のモジュールで .NET 機能の使用を /clr開始できます。 詳細については、「 Component Extensions for Runtime Platforms」を参照してください。

Visual C++ での .NET プログラミングの詳細については、次を参照してください。

関連項目

混在 (ネイティブおよびマネージド) アセンブリ