65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows 的通用 Thunk

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.76/5 (6投票s)

2008年9月27日

CPOL

1分钟阅读

viewsIcon

17521

通用 Thunk 的最小应用。

引言

通用 Thunk 是微软的一项技术,允许 16 位 Windows 应用程序对 32 位 DLL 的导出函数进行进程内调用。本文介绍该技术的一个简单应用。

使用代码

#include <Windows.h>

// KERNEL.DLL

DWORD (FAR PASCAL *LoadLibraryEx32W)(
  LPCSTR lpszLibFile,
  DWORD hFile,
  DWORD dwFlags
);
DWORD (FAR PASCAL *FreeLibrary32W)(
  DWORD hInst
);
DWORD (FAR PASCAL *GetProcAddress32W)(
  DWORD hModule,
  LPCSTR lpszProc
);
DWORD (FAR PASCAL *CallProc32W0)(
  DWORD lpProcAddress,
  DWORD fAddressConvert,
  DWORD nParams
);

static HINSTANCE ghKernelDll;

void PASCAL LoadKernelDll(void)
{
  ghKernelDll = LoadLibrary("Kernel.DLL");

  LoadLibraryEx32W = (DWORD (FAR PASCAL *)(LPCSTR, DWORD, DWORD))
    GetProcAddress(ghKernelDll, "LoadLibraryEx32W");
  FreeLibrary32W = (DWORD (FAR PASCAL *)(DWORD))
    GetProcAddress(ghKernelDll, "FreeLibrary32W");
  GetProcAddress32W = (DWORD (FAR PASCAL *)(DWORD, LPCSTR))
    GetProcAddress(ghKernelDll, "GetProcAddress32W");
  CallProc32W0 = (DWORD (FAR PASCAL *)(DWORD, DWORD, DWORD))
    GetProcAddress(ghKernelDll, "CallProc32W");
}
void PASCAL FreeKernelDll(void)
{
  FreeLibrary(ghKernelDll);
}

// KERNEL32.DLL

static DWORD ghKernel32Dll;
static DWORD ghGetTickCount32;

void PASCAL LoadKernel32Dll(void)
{
  LoadKernelDll();

  ghKernel32Dll = LoadLibraryEx32W("Kernel32.DLL", 0, 0);

  ghGetTickCount32 = GetProcAddress32W(ghKernel32Dll, "GetTickCount");
}
void PASCAL FreeKernel32Dll(void)
{
  FreeLibrary32W(ghKernel32Dll);

  FreeKernelDll();
}

DWORD PASCAL GetTickCount32(void)
{
  DWORD ret;

  LoadKernel32Dll();

  ret = CallProc32W0(ghGetTickCount32, 0, 0);

  FreeKernel32Dll();

  return ret;
}

// WinMain

int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, 
                   LPSTR lpCmdLine, int nCmdShow)
{
  DWORD tick16, tick32;

  tick16 = GetTickCount();
  tick32 = GetTickCount32();

  MessageBox(NULL, tick16 <= tick32 ? "Success" : 
             "Failure", "GetTickCount32", MB_ICONASTERISK);

  return 0;
}

这是用 C 语言编写的完整代码,适用于 Win16 平台。我们将重点关注 GetTickCount32 函数。

GetTickCount32 函数由入口点函数 WinMain 调用一次。GetTickCount32 函数调用 LoadKernel32Dll 函数、CallProc32W0 函数和 FreeKernel32Dll 函数。

调用 CallProc32W0 是对所需 32 位 DLL 函数的进程内跨边界调用。为了使用 CallProc32W0 函数,我们需要获取它的过程地址。它是 KERNEL.DLL 库的 CallProc32W 函数的过程地址。

调用 LoadKernel32Dll 获取一个 32 位值,该值表示 KERNEL32.DLL 库的 GetTickCount 过程。此外,它通过调用 LoadKernelDll 函数获取 KERNEL.DLL 库的 CallProc32W 函数的过程地址。

调用 FreeKernel32Dll 递减已加载的 KERNEL32.DLL 库的引用计数。此外,它通过调用 FreeKernelDll 函数递减已加载的 KERNEL.DLL 库的引用计数。

摘要

本文演示了从 Win16 平台调用 KERNEL32.DLL 库的 GetTickCount 函数。

© . All rights reserved.