[HOWTO] Windows 95、Windows 98、および Windows Me で 32 ビット コードから 16 ビット コードを呼び出す方法

文書翻訳 文書翻訳
文書番号: 155763 - 対象製品
すべて展開する | すべて折りたたむ

目次

概要

Win32 アプリケーションの開発時に、Win32 アプリケーションから 16 ビット DLL (ダイナミック リンク ライブラリ) で提供されている機能へのアクセスが必要な場合があります。このことは特に、DLL のソース コードが失われているときにコードを Win32 に移植する場合に該当します。この資料では、32 ビット DLL からの 16 ビット DLL の呼び出しに使用できるメカニズムについて説明します。このメカニズムはサンクと呼ばれ、Microsoft Windows 95、Windows 98、および Windows Millennium Edition (Me) に実装されているメソッドはフラット サンクと呼ばれています。

フラット サンクは、以下の 3 つの主要な手順を使用して作成します。
  1. サンク スクリプトを作成します。
  2. 32 ビット DLL をビルドします。
  3. 16 ビット DLL をビルドします。

詳細

フラット サンクは、連動する 32 ビット DLL と 16 ビット DLL で構成されています。Win32 アプリケーションが 32 ビット DLL を呼び出すと、32 ビット DLL が 16 ビット DLL でエクスポートされた関数を呼び出します。16 ビット DLL の関数から戻ると、その結果が 32 ビット DLL に返され、その後、Win32 アプリケーションに返されます。32 ビット DLL と 16 ビット DLL は、Windows 95 の 32 ビット カーネルおよび 16 ビット カーネルを呼び出して、32 ビット コードと 16 ビット コード間の変換に必要な下位レベルの詳細に対処します。

新しいフラット サンクをデザインするには、サンク スクリプト (.thk ファイル) を作成する必要があります。このスクリプトは、サンク コンパイラを使用してアセンブリ言語ファイルにコンパイルされます。その後、このファイルは、2 つのフラグ -DIS_32 と -DIS_16 を使用して 1 回ずつ、計 2 回アセンブルされます。これにより、32 ビット オブジェクト モジュールと 16 ビット オブジェクト モジュールの両方を作成できます。これらのオブジェクト モジュールは、それぞれ 32 ビット DLL と 16 ビット DLL にリンクされます。以下の図は、DLL のビルドに関連するファイルの概要です。
                         +------------+
                         | 32to16.thk |
                         +------------+
                               |
                         +------------+
                         | 32to16.asm |
                         +------------+
                           /         \ 
                  -DIS_32 /           \ -DIS_16
                        /              \ 
                  +-----------+  +-----------+
                  | 32THK.obj |  | 16THK.obj |
                  +-----------+  +-----------+
                        /                 \ 
        +-------+    +-------+             +-------+
        | APP32 | -> | DLL32 | -- THUNK -- | DLL16 |
        +-------+    +-------+             +-------+
				

フラット サンクのビルドに必要なツール

  • サンクの 16 ビット部分を作成するには Microsoft Visual C++ 1.5x (16 ビット) のコンパイラが必要です。サンクの 16 ビット部分は 16 ビット DLL です。
  • サンクの 32 ビット部分を作成するには Microsoft Visual C++ 2.x 以降 (32 ビット) のコンパイラが必要です。サンクの 32 ビット部分は 32 ビット DLL です。
  • サンク スクリプトをコンパイルするには、Microsoft Win32 SDK で提供されているサンク コンパイラ (Thunk.exe) が必要です。
  • サンク コンパイラのアセンブリ言語出力をアセンブルするには、Microsoft Macro Assembler (MASM) 6.1 以降が必要です。
  • サンクの 16 ビット DLL を Version 4.0 とマークするには、Microsoft Win32 SDK の BINW16 ディレクトリにある 16 ビット版 Rc.exe が必要です。

サンク スクリプトを作成する

サンクを作成するには、サンク コンパイラで使用できるスクリプトを作成する必要があります。サンク スクリプトは、型の定義、サンクを経由して呼び出す関数のプロトタイプ、および関数ごとのパラメータの指示に関する仕様を含むテキスト ファイルです。たとえば、入力パラメータと出力パラメータの両方を指定する必要のある関数もあれば、入力パラメータのみを指定する必要のある関数もあります。サンク スクリプトでは、パラメータが入力パラメータ、出力パラメータ、入出力パラメータのいずれであるかを定義するための特別な構文を使用します。

32 ビットから 16 ビットに変換するサンク スクリプトは、次のステートメントで始まります。
enablemapdirect3216 = true;
サンク コンパイラでは、サンクの 32 ビット部分が __stdcall、16 ビット部分が __far __pascal として宣言されることが想定されています (これは、どちらの部分でも WINAPI の宣言により行われます)。__cdecl と __fastcall の呼び出し規約は、サンク コンパイラではサポートされていません。ただし、サンク コンパイラでは、__far、__pascal または __stdcall キーワードは想定されているだけで、実際には受け付けられません。

次に、パラメータがない関数のサンク スクリプトの例を示します。
   enablemapdirect3216 = true;
   void MyThunk16()
   {
   }
				
これと等価な宣言は次のとおりです。
   C   言語 :  void WINAPI MyThunk16(void);
   C++ 言語 :  extern "C" void WINAPI MyThunk16();
				
次のスクリプトは、2 つのパラメータを受け取って、1 つの値を返す関数の例です。2 つ目のパラメータは、32 ビット DLL に返されるポインタを保存する出力パラメータです。
   enablemapdirect3216 = true;
   typedef int   BOOL;
   typedef char *LPSTR;
   BOOL MyThunk16(LPSTR lpstrInput, LPSTR lpstrOutput)
   {
      lpstrInput  = input;    // optional; input is default
      lpstrOutput = output;
   }
				
ステートメント "lpstrOutput = output" では、16 ビットの関数から返されたアドレスを selector:offset ポインタから 32 ビットのリニア アドレスに変換する必要があることをサンク コンパイラに指示しています。

次のサンク スクリプトでは、構造体など、より複雑な型のパラメータを使用しています。また、この例では、入力パラメータおよび出力パラメータを指定する方法も示しています。
   enablemapdirect1632 = true;
   typedef unsigned int UINT;
   typedef char *LPSTR;
   typedef struct _POINT {
      UINT x;
      UINT y;
   }POINT, *LPPOINT;
   typedef struct _CIRCLE {
      POINT center;
      UINT  radius;
   }CIRCLE, *LPCIRCLE;
   void MyThunk32( LPCIRCLE lpCircleInOut)
   {
      lpCircleInOut = inout;
   }
				
ステートメント "lpCircleInOut = inout" では、このポインタが入力および出力に使用されることがスクリプト コンパイラに指示されています。このステートメントにより、サンク コンパイラは、関数の呼び出し時に lpCircleInOut を 32 ビットのリニア アドレスから selector:offset ポインタに変換し、関数から戻るときには再度 32 ビットのリニア アドレスに変換します。この変換は、サンク コンパイラにより作成されたサンクで処理されます。

サンク コンパイラを使用する

サンク コンパイラを使用するには、次のコマンドを使用します。
thunk.exe /options <入力ファイル> -o <出力ファイル>
次のコマンド ラインは、32 ビット DLL から 16 ビット DLL に変換するサンク スクリプトをコンパイルする方法を示しています。このコマンドでは、32to16.thk という名前のサンク スクリプトを受け取り、32to16.asm という名前のアセンブリ言語ファイルを生成します。
thunk -t thk 32to16.thk -o 32to16.asm
"-t thk" オプションでは、アセンブリ言語ファイルのサンク関数にプレフィックス "thk_" を使用するようサンク コンパイラに指示しています。このプレフィックスは、複数のサンク スクリプトを 1 組の DLL にリンクする場合に使用し、32 ビットから 16 ビットに変換するサンクおよび 16 ビットから 32 ビットに変換するサンクの両方を含む 1 組の DLL を作成する場合に役立ちます。各サンク ファイルのプレフィックスは一意になる必要があります。

32 ビット DLL をビルドする

  1. 32 ビット DLL の DllMain 関数では、以下のコードに示すように、DllMain が呼び出された理由に関係なく (dwReason)、サンク コンパイラにより作成された thk_ThunkConnect32 という名前の関数を呼び出す必要があります ("thk" は、サンク コンパイラの -t スイッチにより指定されたプレフィックスです)。
          // prototype for function in .obj file from the thunk script
          BOOL WINAPI thk_ThunkConnect32(LPSTR     lpDll16,
                                         LPSTR     lpDll32,
                                         HINSTANCE hDllInst,
                                         DWORD     dwReason);
          BOOL WINAPI DllMain(HINSTANCE hDLLInst,
                              DWORD     dwReason,
                              LPVOID    lpvReserved)
          {
             if (!thk_ThunkConnect32("DLL16.DLL", "DLL32.DLL",
                                     hDLLInst, dwReason))
             {
                return FALSE;
             }
             switch (dwReason)
             {
                case DLL_PROCESS_ATTACH:
                   break;
                case DLL_PROCESS_DETACH:
                   break;
                case DLL_THREAD_ATTACH:
                   break;
                case DLL_THREAD_DETACH:
                   break;
             }
             return TRUE;
          }
    						
  2. 32 ビット DLL のモジュール定義ファイル (.def) の EXPORTS セクションに次の行を追加します。
          
       thk_ThunkData32
    						
  3. Win32 アプリケーションが呼び出す関数をエクスポートします。32 ビット DLL のモジュール定義ファイル (.def) を使用することも、__declspec(dllexport) キーワードを使用することもできます。関数が宣言され、__stdcall (または WINAPI) として定義されていることを確認します。32 ビット DLL が C++ で記述されている場合、extern "C" として関数を宣言していることも確認します。
  4. サンク スクリプトがコンパイルされていない場合は、次のコマンドを使用してスクリプトをコンパイルします。
          thunk -t thk 32to16.thk -o 32to16.asm
    						
  5. サンク コンパイラによって 32 ビットのオブジェクト モジュールとして生成されたアセンブリ言語ファイルをアセンブルします。次にコマンドの例を示します。
          ml /DIS_32 /c /W3 /nologo /coff /Fo thk32.obj 32to16.asm
    						
  6. このオブジェクト モジュールを 32 ビット DLL の一部としてリンクします。
  7. Thunk32.lib ライブラリを 32 ビット DLL の一部としてリンクします。これは、サンク コンパイラで作成されたコードが使用する 32 ビットのサンク API への参照を含む、Win32 SDK で提供されている 32 ビットのインポート ライブラリです。

16 ビット DLL をビルドする

  1. 16 ビット DLL では、"DllEntryPoint" という名前の関数をエクスポートする必要があります。この関数では、DllEntryPoint が呼び出されるたびに、サンク コンパイラにより作成された thk__ThunkConnect16 という名前の関数を呼び出す必要があります ("thk" は、サンク コンパイラの -t スイッチにより指定されたプレフィックスです)。
          // prototype for function in .obj file from the thunk script
          BOOL WINAPI __export thk_ThunkConnect16(LPSTR lpDll16,
                                                  LPSTR lpDll32,
                                                  WORD  hInst,
                                                  DWORD dwReason);
          BOOL WINAPI __export DllEntryPoint(DWORD dwReason,
                                             WORD  hInst,
                                             WORD  wDS,
                                             WORD  wHeapSize,
                                             DWORD dwReserved1,
                                             WORD  wReserved 2)
          {
             if (!thk_ThunkConnect16("DLL16.DLL",
                                     "DLL32.DLL",
                                     hInst,
                                     dwReason))
             {
                return FALSE;
             }
             return TRUE;
          }
    						
  2. 16 ビット DLL のモジュール定義ファイル (.def) の IMPORTS セクションに、以下の行を追加します。
          C16ThkSL01      = KERNEL.631
          ThunkConnect16  = KERNEL.651
    						
  3. 16 ビット DLL のモジュール定義ファイル (.def) の EXPORTS セクションに以下の行を追加します。THK_THUNKDATA16 は、サンク コンパイラの出力からアセンブルされたオブジェクト ファイルで定義されています。これらのシンボルでは、どちらも RESIDENTNAME キーワードを使用する必要がありますが、任意の序数を指定できます。
          THK_THUNKDATA16 @1  RESIDENTNAME
          DllEntryPoint   @2  RESIDENTNAME
    						
  4. 16 ビット DLL のモジュール定義ファイル (.def) の EXPORTS ステートメントにサンク関数を追加します。これらの関数が宣言されており、__far __pascal __export (または WINAPI __export) として定義されていることを確認します。DLL が C++ で記述されている場合は、これらの関数が extern "C" として宣言されていることも確認します。これらの関数は、サンクの 32 ビット部分で呼び出されます。
  5. サンク スクリプトがコンパイルされていない場合は、次のコマンドを使用してスクリプトをコンパイルします。
          thunk -t thk 32to16.thk -o 32to16.asm
    						
  6. サンク コンパイラによって 16 ビットのオブジェクト モジュールとして生成されたアセンブリ言語ファイルをアセンブルします。次にコマンドの例を示します。
          ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 32to16.asm
    						
  7. このオブジェクト モジュールを 16 ビット DLL の一部としてリンクします。
  8. 16 ビット DLL を Version 4.0 としてマークします。この操作を行うには、リソース コンパイラ (Rc.exe) を使用します。構文は次のとおりです。
    rc -40 <DLL ファイル>
    この -40 オプションは、Win32 SDK で提供されているリソース コンパイラでも使用できます。

    : DLL が Version 4.0 としてマークされるように、BINW16 ディレクトリの Rc.exe を使用していることを確認します。Microsoft Visual C++ 16 ビット版に含まれる Rc.exe では、DLL を Version 4.0 としてマークすることはできません。

関連情報

フラット サンクのデバッグ方法の詳細については、「サポート技術情報」 (Microsoft Knowledge Base) の次の資料を参照してください。
133722 HOWTO: Debug Flat Thunks

関連情報

この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID 155763 (最終更新日 2003-05-10) を基に作成したものです。

なお、この資料は英語版の翻訳であり、日本語環境での確認は行っておりません。

プロパティ

文書番号: 155763 - 最終更新日: 2005年7月11日 - リビジョン: 2.3
この資料は以下の製品について記述したものです。
  • Microsoft Win32 Application Programming Interface?を以下の環境でお使いの場合
    • Microsoft Windows 95
    • Microsoft Windows 98 Standard Edition
    • Microsoft Windows Millennium Edition
    • Microsoft Platform SDK January 2000 Edition
キーワード:?
kbhowto kbtshoot kbapi kbnetwork kbprogramming kbkernbase kbthunks KB155763
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。"

フィードバック

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com