如何为我在 Windows 95、 Windows 98 和 Windows 32 位代码中调用 16 位代码

注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。

点击这里察看该文章的英文版: 155763
本文已归档。它按“原样”提供,并且不再更新。
概要
作为一名开发人员,您可能需要访问由 16 位动态链接库 (DLL) 从您的 Win32 应用程序提供功能。尤其是当您没有源代码的 DLL,以便可以对 Win32 移植,它也是如此。本文讨论的 32 位 dll 可以调用 16 位 dll 的机制。该机制称为一个 thunk 和方法实现在 Microsoft Windows 95,Windows 98,Windows Millennium 版称为平面 thunk。

将创建平面 thunk 过程中所涉及的三个主要步骤如下:
  1. 创建 thunk 脚本。
  2. 生成 32 位 DLL。
  3. 生成 16 位 DLL。
更多信息
平面 thunk 包括 32 位和 16 位 DLL 一起工作的。 Win32 应用程序调用 32-位 DLL 和 32 位 DLL 中 16 位 DLL 中调用导出的函数。在 16 位 DLL 中的函数返回时, 它将返回到该又返回到 Win32 应用程序的 32 位 DLL。32 位和 16 位 dll 工作通过调用所有处理的低级别的详细信息从 32 位到 16 位代码转换并返回所需的 Windows 95 32年位和 16 位内核。

设计新的平面 thunk 涉及创建 thunk 脚本 (.thk 文件)。 此脚本用 Thunk 编译器编译到两次 ; 一次的两个标志-DIS_32 和 DIS_16 的每个然后装配的程序集语言文件。这使您可以创建两个 32 位和 16 位的对象模块。这些对象模块分别链接所的 32 位和 16 位 dll 中。下图总结了在生成 dll 中所涉及的文件:
                         +------------+                         | 32to16.thk |                         +------------+                               |                         +------------+                         | 32to16.asm |                         +------------+                           /         \                   -DIS_32 /           \ -DIS_16                        /              \                   +-----------+  +-----------+                  | 32THK.obj |  | 16THK.obj |                  +-----------+  +-----------+                        /                 \         +-------+    +-------+             +-------+        | APP32 | -> | DLL32 | -- THUNK -- | DLL16 |        +-------+    +-------+             +-------+				

生成平面 thunk 所需的工具

  • Microsoft Visual c + + 版本 1.5 x (16 位) 编译器,16 位边的创建将 thunk。在 thunk 的在 16 位端是一个 16 位 DLL。
  • Microsoft Visual c + + 版本 2.x 或更高 (32 位) 编译器用于创建该 thunk 32-位侧边。在 thunk 32-位侧是一个 32 位 DLL。
  • 从 Microsoft Win32 SDK 编译 thunk 脚本 thunk 编译器 (Thunk.exe)。
  • Microsoft 宏汇编程序 (MASM) 版本 6.1 或更高的汇编 thunk 编译器的程序集语言输出。
  • 16 位 Rc.exe BINW16 目录的 Microsoft Win32 SDK 中的文件标记为 4.0 版本的 16 位 thunk DLL。

创建 Thunk 脚本

您需要创建一个脚本,Thunk 编译器可用于创建一个 thunk。thunk 脚本是方向的包含类型定义的要 thunk 通过调用该函数的函数原型以及将为每个函数参数的规范的文本文件。例如对于有些函数需要输入和输出参数,而其他人可能只需输入的参数。thunk 脚本使用特殊语法来描述是否输入参数、 输出,或输入和输出。

用于 32-> 16 的 thunk thunk 脚本以下面的语句:
enablemapdirect3216 = true ;
Thunk 编译器要求在 thunk 32-位侧边被声明为 __stdcall,并在 16 位端是 __far __pascal。(WINAPI 声明负责这两面上)。由 Thunk 编译器不支持 __cdecl 和 __fastcall 调用约定。 请注意但是,Thunk 编译器并不实际接受 __far、 __pascal,或 __stdcall 关键字,; 它们假设。

下面的示例演示用于没有参数的函数的 thunk 脚本:
   enablemapdirect3216 = true;   void MyThunk16()   {   }				
等效声明将是:
   C   language:  void WINAPI MyThunk16(void);   C++ language:  extern "C" void WINAPI MyThunk16();				
该下面的示例脚本描述一个函数,该函数采用两个参数并返回一个值。第二个参数是输出参数包含被传递回 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 = 输出"通知 Thunk 编译器 16 位函数将返回需要从一个选择器: 偏移量指针转换为一个 32 位的线性地址的地址。

下面的 thunk 脚本使用更复杂的参数类型,如结构。本示例还演示如何以指定输入和输出参数。
   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"告诉脚本编译器将此指针用于输入和输出。这会导致 Thunk 编译器 lpCircleInOut 从 32 位线性地址时将其转换为选择器: 偏移量的指针调用该函数时,并再移回 32-位线性地址时,该函数返回。转换在 thunk Thunk 编译器创建由处理。

使用 Thunk 编译器

Thunk 编译器使用的是,如下所示:
thunk.exe/选项 <inputfile>-o <outputfile>
下面的命令行显示了如何编译-> 16 thunk 脚本是 32。 这行采用命名 32to16.thk thunk 脚本,并生成名为 32to16.asm 一个程序集语言文件。
thunk-t thk 32to16.thk-o 32to16.asm
在"-t thk"选项将告诉 Thunk 编译器将前缀 thunk 函数在程序集语言文件与"thk_。此前缀到一对 dll,链接多个 thunk 脚本时使用,用于创建一个对包含两个 32-> 16 和 32 thunk-> 16 的 dll。每个 thunk 脚本应具有唯一的前缀。

生成 32 位 DLL

  1. 在 32 位 DLL DllMain 功能,您必须进行名 thk_ThunkConnect32 为每个原因 dwReason DllMain 称为,(如下所示的 Thunk 编译器创建一个函数的调用 ("thk"是从 Thunk 编译器-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) 文件的导出部分中包括以下几行。例如:
             thk_ThunkData32						
  3. 导出的 Win32 应用程序调用函数。您可以使用 32 位 DLL 的模块定义 (.def) 文件或 __declspec(dllexport) 关键字。确保函数声明和定义为 __stdcall (或 WINAPI)。如果 32 位 DLL 用 c + + 编写的一定要将函数声明为 extern"C"以及。
  4. (如果尚未编译),如下所示编译 thunk 脚本:
          thunk -t thk 32to16.thk -o 32to16.asm						
  5. 组合所生成的 Thunk 编译器为 32 位对象模块的程序集语言文件。例如:
          ml /DIS_32 /c /W3 /nologo /coff /Fo thk32.obj 32to16.asm						
  6. 链接该对象模块,作为 32 位 DLL 的一部分。
  7. 链接 Thunk32.lib 库作为 32 位 DLL 的一部分。这是 32-位导入库 Win32 SDK,其中包含对由 Thunk 编译器创建的代码使用在 32 位 thunking api 的引用中提供。

生成 16 位 DLL

  1. 16 位 DLL 必须导出函数名为"DllEntryPoint。此函数必须使名为 thk__ThunkConnect16 Thunk 编译器创建一个函数的调用 ("thk"是从 Thunk 编译器-t 开关前缀) 每次调用时 DllEntryPoint:
          // 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. 模块定义 (.def) 文件的导入部分中包括以下行,为 16 位 DLL。例如:
          C16ThkSL01      = KERNEL.631      ThunkConnect16  = KERNEL.651						
  3. 模块定义 (.def) 文件的导出部分中包括以下行,为 16 位 DLL。THK_THUNKDATA16 装配 Thunk 编译器的输出中的对象文件中定义。这两个这些符号必须有 RESIDENTNAME 关键字,但可以有任何的序号。
          THK_THUNKDATA16 @1  RESIDENTNAME      DllEntryPoint   @2  RESIDENTNAME						
  4. 将 thunk 函数添加到导出语句的 16 位 DLL 的模块定义 (.def) 文件。确保声明和定义为 __far __pascal __export (或 WINAPI __export)。如果 DLL 用 c + + 编写的请务必将它们声明为 extern"C"以及。在 thunk 32-位侧调用这些函数。
  5. (如果尚未编译),如下所示编译 thunk 脚本:
          thunk -t thk 32to16.thk -o 32to16.asm						
  6. 组合所生成的 Thunk 编译器为 16 位对象模块的程序集语言文件。例如:
          ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 32to16.asm						
  7. 链接该对象模块,作为 16 位 DLL 的一部分。
  8. 标记为 4.0 版本的 16 位 DLL。若要执行此操作使用资源编译器 (Rc.exe)。下面的行显示了语法:
    rc-40 < DLL 文件 >
    此-40 选项是在与 Win32 SDK 提供的资源编译器中可用。

    : 确保使用 Rc.exe 文件 BINW16 目录中的,以使 DLL 版本 4.0 使用标记。Rc.exe 文件随 16-位版本的 Microsoft Visual c + + 不标记为 4.0 版本的 DLL。
参考
有关如何调试平面 thunk,请参阅下列文章 Microsoft 知识库中相应的信息:
133722如何调试平面 thunk
win95 平面 thunk win16 调试

警告:本文已自动翻译

属性

文章 ID:155763 - 上次审阅时间:12/04/2015 15:20:56 - 修订版本: 2.3

Microsoft Win32 Application Programming Interface

  • kbnosurvey kbarchive kbmt kbapi kbhowto kbkernbase kbnetwork kbprogramming kbthunks kbtshoot KB155763 KbMtzh
反馈