可从 Microsoft 下载中心下载以下文件:
Mti.exe
(http://download.microsoft.com/download/platformsdk/mti/3.1/w31/en-us/mti.exe)
有关如何下载 Microsoft
支持文件的其他信息请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
119591
(http://support.microsoft.com/kb/119591/EN-US/ ) 如何从联机服务获得
Microsoft 支持文件
Microsoft 扫描此文件的病毒。Microsoft
使用该文件已过帐的日期上获得的最新病毒检测软件。该文件存储在安全性得到增强的服务器,这有助于防止未经授权的情况下对其进行更改文件上。 本文讨论了模块、
实例,和任务。它包括以下主题:
- 模块、 实例,和任务控点的定义
- 处理这些图柄的 Microsoft(R) Windows(TM) 函数
- 导出和 $ MakeProcInstance 函数
- 任务切换并产生
概述
Windows 图形环境定义了两种类型的可执行文件: 应用程序和动态链接库 (dll)。在这两种类型代码是通常可共享的。多个实例的应用程序或 DLL
的多个用户可以共享由第一个实例加载的代码。大多数基于 Windows 的应用程序和 dll 还包含相同的方式可共享的资源。当 Windows 可将应用程序或
DLL 加载到内存,在第一次时, 它将分配称为一个模块句柄或 hModule,共享的代码和资源的唯一标识符。
当 Windows
加载应用程序时,它创建应用程序以区别于其他正在运行的副本,同一应用程序的一个唯一的执行的上下文。此执行上下文被赋予称为一个实例句柄或一个 hInstance
标识符。应用程序的执行上下文的部分是应用程序的静态数据、
堆栈,和本地堆的驻留位置其自动数据段。两份正在运行的应用程序共享代码,但每一个都有其自己的数据段。dll 不同于应用程序中的一个 DLL
共享相同的执行上下文的所有实例,并且因此共享通用的数据段。
由一组的 CPU 寄存器和堆栈定义应用程序的执行上下文的一部分。执行上下文
(任务上下文) 的这一部分都有一个称为一个任务句柄或一个 hTask 的特殊标识符。每个加载的应用程序都有其自己的任务句柄,但任务句柄是永远不会与 dll
相关联。因此,自动数据段的 DLL 的永远不会包含一个堆栈。
由于始终与只有一个模块相关联的执行上下文 Windows
轻松可以从一个实例句柄获取模块句柄。因为模块可以有多个正在运行的实例,但是,获取给定只有模块句柄的实例句柄是不可能的。
处理 HMODULE 和 HINSTANCE
在 Microsoft Windows 软件开发工具包 (SDK) 文档中使用下面的不一致现象: 模块和实例的句柄。例如对于 LoadLibrary
记录返回一个 hInstance,但 FreeLibrary 采用一个 hModule。如何可以释放库如果 Windows 提供了将一个 hInstance
转换为一个 hModule 没有明显方法?
接受只有模块句柄作为记录的编程接口 (api) 定义的错误地基于 Windows
的应用程序的一个数字: 最可能需要一个实例句柄或模块句柄。 例如对于 FreeLibrary,可以接受模块句柄或实例的句柄。下列 api 记录不正确 ;
下列简短说明该函数的功能是正确的:
DeviceMode, Obtain and set printer configuration data. Pass
ExtDeviceMode the hModule or the hInstance of a printer driver.
(Printer drivers are simply DLLs.)
FreeLibrary Identical to FreeModule but is provided for
symmetry with LoadLibrary. FreeLibrary accepts
either an hModule or an hInstance. Usually only
DLLs that are loaded by LoadLibrary are freed with
FreeLibrary because implicitly loaded DLLs are
freed by Windows when the application using the
DLL is terminated.
FreeModule Normally called with an hInstance but also takes
an hModule. For applications, all instance-
specific data associated with the hInstance passed
is freed. FreeModule also decrements the usage
count of the associated module, and if the usage
count becomes 0, the module is freed. For DLLs,
the window exit procedure (WEP) is called, and
instance-specific data is freed before the module
is freed. The FreeModule function should have been
named FreeInstance.
GetModuleFileName Returns the full path of the executable file (EXE
or DLL) for a module. This API takes either an
hModule or an hInstance.
GetModuleHandle Returns the hModule of a module given the module
name or an instance handle. The module name is not
always the same as the filename of the file from
which the module was loaded. The module name is
specified in the module definition file (DEF) when
the module is created (NAME and LIBRARY
statements). Most, but not all, applications and
DLLs specify a module name that is equivalent to
its root filename (the filename without the
extension). Modules that have different module
names and filenames may experience problems when
the module is debugged because some debuggers
assume they are equivalent. You can use an
instance handle in place of the module name by
passing the hInstance in the low word and a NULL
in the high word of the lpModuleName parameter.
GetModuleUsage Returns the usage count of a module. This function
accepts either an hModule or an hInstance. The
usage count is incremented each time a new
instance of the module is loaded, and it is
decremented each time an instance is freed.
GetProcAddress Obtains the address of a specified function in a
module. Either an hModule or an hInstance can be
passed to the function.
LoadLibrary Loads a DLL. If the DLL is not already loaded,
LoadLibrary creates a module and an execution
context for it. If the DLL is already loaded,
LoadLibrary simply increments the module's usage
count (no new execution context is created because
all instances of a DLL share the same execution
context). In both cases, the function returns the
hInstance for the DLL.
LoadModule Loads an application. If the application is
already loaded, LoadModule increments the module's
usage count and creates a new execution context
and task context. This function returns the
hInstance of the application just started.
WinExec Operates exactly the same as LoadModule but is
easier to use.
在此时您可能会问,"是否一个实例句柄可用于代替模块句柄,为什么有模块处理所有?为什么不只是实例句柄并使用它来完成?"好的问题。答案是它确实没有关系。您只是可以编写使用实例句柄,而不是模块句柄为上述功能的应用程序。这是好消息,因为实例句柄,则更容易获得比模块句柄。例如对于调用与
GWW_HINSTANCE GetWindowWord 获得应用程序或创建一个窗口的 DLL
实例句的柄。此实例句柄随后可用来确定创建窗口的应用程序的模块文件名。没有等效的方法存在要执行此操作使用模块句柄。
实际,模块句柄具有真正的使用。在内部,Windows
将用来标记特定的资源如窗口类和挂钩,与模块而不是与某个模块的特定实例相关联的模块句柄。模块的最后一个实例将被释放之前,不会释放这些资源。
虽然
Windows 3.0 版中未记录,从一个实例句柄获取模块句柄是可能的。调用 GetModuleHandle 函数与 lpModuleName
参数的较低的字设置为一个 hInstance 和相同的参数集,为 NULL 的高单词返回的指定 hInstance 模块句柄。3.1 版 WINDOWS.H
文件包含一个的宏 GetInstanceModule,这会为您的。
实例句柄 API 函数
下面的 Windows 函数处理的实例句柄:
Resource functions: AccessResource, AllocResource, CreateIcon,
FindResource, LoadAccelerators, LoadBitmap,
LoadCursor, LoadIcon, LoadMenu, LoadResource,
LoadString, SetResourceHandler,
SizeofResource
Window functions: CreateDialog, CreateDialogParam,
CreateDialogIndirect,
CreateDialogIndirectParam, CreateWindow,
CreateWindowEx, DialogBox, DialogBoxParam,
DialogBoxIndirect, DialogBoxIndirectParam
Class functions: GetClassInfo, RegisterClass, UnregisterClass
Miscellaneous functions: GetInstanceData, MakeProcInstance, WinMain
导出的函数
执行通常输入模块的代码通过已导出的入口点。如果应用程序中有多个实例必须能够设置正确的数据段进入已导出的入口点。这适用于所有的功能,如在应用程序中的函数的另一个模块中调用的目标的该
Windows 调用
(对话框过程和回调函数等)。但是,单独导出不足以设置正确的数据段。对于每个应用程序实例这些函数需要可以设置正确的数据段,然后跳转到"真正的"函数的唯一的入口点。在
MakeProcInstance 函数用于实现此目的。它的指针导出的函数和所需的实例句柄并创建一个调用 thunk。只是一段代码将 AX
寄存器,然后跳转到的特定实例的数据段值移动到真正的函数调用 thunk。导出的函数期望适当的数据段值来传递在 AX 寄存器和移动到 DS 值在函数 prolog
中注册。该应用程序使用由 MakeProcInstance 返回指针的位置,如 DialogBox 和 EnumWindows 的调用中实际函数的调用
thunk 将指针。
窗口过程并不需要调用 thunk。应用程序在创建一个窗口时它会提供在 CreateWindow 调用一个
hInstance 值。 该值被保存在内部,然后 Windows 将使用它来设置适当的 AX
值派遣给窗口过程的消息之前。对话框过程手动,不是真正的窗口过程,并需要调用 thunk。
驻留在 DLL 中的导出的函数也不需要调用
thunk。因为 DLL 的所有用户都共享同一个实例,则不需要为它们创建调用 thunk。
任务
任务可以被认为是"逻辑 CPU"具有自己的 cs: ip、 堆栈和寄存器。任务可以从任意数量的模块中执行代码。当执行输入 (通常是通过一个已导出的入口点)
的模块,当前任务句柄变,但该函数的 prolog 代码设置了正确执行上下文的也就是正确的数据段。
当应用程序调用放弃对的系统称为并生成一个过程的控制的 Windows 函数时,会发生任务切换。 因为 Windows 是一个
nonpreemptive 多任务处理系统,应用程序必须定期放弃控制的系统,使其他应用程序可以运行。下面的函数可能会导致产生调用任务:
- DialogBox,DialogBoxParam,DialogBoxIndirect DialogBoxIndirectParam
- DeviceMode,ExtDeviceMode (它们可以显示一个对话框。
- GetDC (仅如果所有的设备上下文 [dc] 是在使用。
- GetMessage,PeekMessage,WaitMessage
- MessageBox
- 收益率
随此列表上功能,将消息发送到另一个应用程序 (如 SendMessage)
的任何函数可能会导致临时任务开关,而目标应用程序处理的消息。几个 Windows
函数处理的任务。应用程序很少需要获得,或使用其任务的句柄。通常,任务句柄仅用于标识。只接受或返回任务控点的函数是 GetCurrentTask、
EnumTaskWindows 和 PostAppMessage。 正在枚举当前运行的所有任务是不可能,使用标准的 Windows
函数。需要此信息的应用程序可以使用为此目的提供了一个函数在 Toolhelp 库。
因为 dll 不在 Windows
(也就是所有实例共享相同的 DS) 实例化,创建可以为多个并发客户端提供服务的服务器类型 DLL 不是简单明了。问题了解哪些客户端请求服务的任何位置。 一些
dll 调用 GetCurrentTask 函数以检索当前任务的
hTask,然后添加一种数据结构或与此任务句柄的一些其他数据项目的标签。然后,每次进行请求的服务时,DLL
检查其列表中的已知的客户端任务与当前任务的句柄。此解决方案都有一个缺陷。任务句柄是内部数据结构,描述该任务的实际全局句柄。
可重复使用全局句柄。如果一个任务终止,并且另一个启动新任务可以有相同任务手柄为该任务只是终止。这不是问题到 DLL 的服务器,只要 DLL
知道原始任务的终止。即使客户端应用程序写入终止之前断开服务器动态链接库的应用程序异常终止可能仍会导致刚才描述的问题。在这种情况下服务器动态链接库并不知道终止任务。而不是解决此问题的黑客攻击,dll
在这种情况下可以方便地使用来检测到特定的任务终止时的 Toolhelp 通知服务。
由 Microsoft 公司的版权 1992。
保留的所有权利。