C ランタイムの使い方


概要


このドキュメントには、次のセクションが含まれています。
セクション 1: C ランタイム (CRT) ライブラリの3つのフォームは、「セクション 2: DLL のビルド時に CRT ライブラリを使う NTWIN32」セクション3を参照してください。MAK のビルドプロセスを簡素化するセクション 4: 複数の CRT ライブラリを使用しているときに発生する問題セクション 5: ライブラリの種類の混在

詳細情報


セクション 1: C ランタイム (CRT) ライブラリの3つのフォームを使用できます。

Win32 SDK で提供される C ランタイムライブラリには、次の3つの形式があります。
  • LIBC.LIB は、シングルスレッドプログラム用の静的にリンクされたライブラリです。
  • LIBCMT.LIB は、マルチスレッドプログラムをサポートする静的にリンクされたライブラリです。
  • CRTDLL.LIB は、CRTDLL のインポートライブラリです。DLL は、マルチスレッドプログラムもサポートしています。 CRTDLL.DLL 自体は Windows NT の一部です。
Microsoft Visual C++ 32 ビット版には次の3つの形式も含まれていますが、DLL の CRT は MSVCRT.DLL という名前です。変数. DLL は再頒布可能です。 この名前は、VC + + (ie MSVCRT10 のバージョンによって異なります。DLL または MSVCRT20。DLL)。 ただし、この MSVCRT10 に注意してください。DLL は Win32s ではサポートされません。 CRTDLLLIB は、Win32s でサポートされています。 MSVCRT20.DLL には、Windows NT 用と Win32s 用の2つのバージョンが用意されています。

セクション 2: DLL のビルド時に CRT ライブラリを使う

C ランタイムライブラリのいずれかを使う DLL をビルドするときに、CRT が適切に初期化されるようにするには、次のいずれかの方法を実行します。
  1. 初期化関数には、DllMain () という名前を指定する必要があり、リンカーオプション-entry でエントリポイントを指定する必要があり _DllMainCRTStartup@12 ます。
  2. DLL のエントリポイントでは、プロセスのアタッチとプロセスのデタッチの際に CRT_INIT () を明示的に呼び出す必要があります。
これにより、C ランタイムライブラリは、プロセスまたはスレッドが DLL にアタッチされているときに、c ランタイムデータを適切に割り当てて初期化することができます。これにより、プロセスが DLL からデタッチされ、DLL 内のグローバル C++ オブジェクトが適切に構築および destructed されます。Win32 SDK のサンプルでは、すべて最初のメソッドが使われています。 例として使用してください。 また、DllEntryPoint () の Win32 プログラマーズリファレンスと DllMain () の Visual C++ ドキュメントも参照してください。 CRT_INIT CRT_INIT DllMainCRTStartup () によって、アプリケーションの DllMain () が存在する場合は、そのアプリの DllMain () が呼び出されることに注意してください。2番目のメソッドを使用して、DllMainCRTStartup () と DllMain () を使用する代わりに CRT の初期化コードを手動で呼び出す場合は、次の2つの方法があります。
  1. 初期化コードを実行する entry 関数がない場合は、DLL のエントリポイントとして CRT_INIT () を指定するだけです。 NTWIN32 が含まれていることを前提としています。MAK は、DLL エントリを "@ 12" として定義します。次のオプションを DLL のリンク行に追加します。
    -entry: _CRT_INIT $ (DLLENTRY)
    /
  2. * do * に独自の DLL エントリポイントがある場合は、エントリポイントで次の操作を行います。
    1. このプロトタイプは CRT_INIT () に使用します。
      BOOL WINAPI _CRT_INIT (HINSTANCE hinstDLL、DWORD fdwReason、LPVOID lpReserved)
      CRT_INIT () の戻り値については、ドキュメント Dll のエントリポイントをご覧ください。同じ値が返されます。
    2. これらのフラグの詳細については、DLL_PROCESS_ATTACH と DLL_THREAD_ATTACH (Win32 API リファレンスの「DllEntryPoint」を参照してください)。 C ランタイム関数が呼び出されたとき、または浮動小数点演算が実行される前に、CRT_INIT () を呼び出します。
    3. 独自のプロセス/スレッド初期化/終了コードに呼び出します。
    4. DLL_PROCESS_DETACH と DLL_THREAD_DETACH で、すべての C ランタイム関数が呼び出され、浮動小数点演算がすべて完了した後、CRT_INIT () を呼び出します。
    必ず、エントリポイントのすべてのパラメーターを CRT_INIT () に渡してください。CRT_INIT () はこれらのパラメーターを想定しているため、省略された場合、確実に動作しない可能性があります (特に、プロセスの初期化または終了が必要かどうかを判断するには、fdwReason が必要です)。 次に示すのは、DLL エントリポイントでこれらの CRT_INIT () への呼び出しを行うタイミングと方法を示すスケルトンのサンプルエントリポイント関数です。
        BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,        LPVOID lpReserved)    {    if (fdwReason == DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH)        if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))            return(FALSE);    if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH)        if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))            return(FALSE);    return(TRUE);    }
    DllMain () と-entry: _DllMainCRTStartup@12 を使っている場合、これは * 必要ではないことに注意してください。

セクション 3: NTWIN32 を使用する。MAK でビルドプロセスを簡略化する

NTWIN32 には、マクロが定義されています。MAK を使いやすくし、競合を避けるために適切に構築されていることを確認するために使用できる MAK。 このため、Microsoft は NTWIN32 を使用することを強くお勧めします。MAK とその中のマクロコンパイルの場合は、次のように使用します。
   $(cvarsdll)          for apps/DLLs using CRT in a DLL 
リンクについては、次のいずれかを使用します。
   $(conlibsdll)        for console apps/DLLs using CRT in a DLL   $(guilibsdll)        for GUI apps using CRT in a DLL 

セクション 4: 複数の CRT ライブラリを使用しているときに発生する問題

C ランタイムで呼び出される DLL へのリンクが c の実行時に呼び出されるアプリケーションでは、静的にリンクされた C ランタイムライブラリ (LIBC) のいずれかにリンクされている場合に注意してください。LIB または LIBCMT。LIB)、.EXE と DLL には、すべての C ランタイム関数とグローバル変数のコピーが個別に含まれています。 つまり、C のランタイムデータをとの間で共有することはできません。EXE と DLL。 その結果、次のような問題が発生する可能性があります。
  • からのバッファリングされたストリームハンドルの受け渡し。他のモジュールへの EXE/DLL
  • C ランタイム呼び出しでのメモリの割り当てEXE/DLL をもう1つのモジュールで再割り当てまたは解放する
  • のグローバル errno 変数の値の確認または設定。EXE/DLL は、他のモジュールと同じにする必要があります。 これに関連する問題は、C ランタイムエラーが発生した反対側のモジュールで、エラー発生時には errno を使っているためです。
このような問題を回避するには、との両方をリンクします。EXE と DLL を CRTDLL します。LIB または MSVCRT.DLLLIB を使用すると、の両方が許可されます。EXE と DLL を使って、DLL 内の CRT に含まれる関数とデータの共通セットを使用することができます。また、ストリームハンドルなどの C ランタイムデータは、の両方で共有することができます。EXE と DLL。

セクション 5: ライブラリの種類の混在

DLL を CRTDLL にリンクさせることができます。LIB/MSVCRT.DLLに関係なく、EXE は、CRT データ構造体の混在を回避し、CRT ファイルハンドルまたは CRT ファイル * ポインターを他のモジュールに渡すことができない場合にリンクされます。ライブラリの種類を混在させると、次のようになります。
  • CRT ファイルハンドルは、それを作成した CRT モジュールでのみ操作できます。
  • CRT ファイル * ポインターは、それを作成した CRT モジュールでしか操作できません。
  • CRT 関数 malloc () によって割り当てられたメモリは、それを割り当てた CRT モジュールでのみ解放または再割り当てすることができます。
これを示すために、次の例を考えてみます。
   - .EXE is linked with MSVCRT.LIB   - DLL A is linked with LIBCMT.LIB   - DLL B is linked with CRTDLL.LIB 
の場合は、EXE は _create () または _open () を使用して CRT ファイルハンドルを作成します。このファイルハンドルは、の _lseek ()、_read ()、_write ()、_close () などにのみ渡すことができます。EXE ファイル。 この CRT ファイルハンドルは、いずれの DLL にも渡しません。 いずれかの DLL から取得した CRT ファイルハンドルを他の DLL またはに渡しません。形式. DLL A が malloc () を使ってメモリのブロックを割り当てる場合、DLL A では、このブロックを操作するために free ()、_expand ()、または realloc () を呼び出すことができます。 DLL A から malloc () を呼び出すことはできません。また、からそのブロックを解放してください。EXE または DLL B から 注: 3 つのモジュールがすべて CRTDLL にリンクされている場合。LIB または3つすべてが MSVCRT.DLL にリンクされています。LIb では、これらの制限は適用されません。
Dll を LIBC にリンクする場合。LIB では、このような DLL がマルチスレッドプログラムによって呼び出される可能性がある場合は、dll で同時に実行されている複数のスレッドをサポートしていないため、重大な問題が発生する可能性があります。 DLL がマルチスレッドプログラムによって呼び出される可能性がある場合は、マルチスレッドプログラムをサポートするライブラリの1つとリンクするようにしてください (LIBCMT。LIB、CRTDLLLIB または MSVCRT.DLLLIB) を選びます。