Board logo

标题: [转贴] Windows Rundll 和 Rundll32 接口 [打印本页]

作者: CrLf    时间: 2014-8-5 01:30     标题: Windows Rundll 和 Rundll32 接口

转自:http://support.microsoft.com/kb/164787/zh-cn

概要
Microsoft Windows 95、Windows 98 和 Windows Millennium Edition (Me) 包含两个名为 Rundll.exe 和 Rundll32.exe 的命令行实用程序,通过这两个程序可调用从 16 位或 32 位 DLL 导出的函数。但是,使用 Rundll 和 Rundll32 程序并不能调用从任何 DLL 导出的任何函数。例如,不能使用这两个实用程序调用从系统 DLL 中导出的 Win32 API(应用程序编程接口)调用。这两个程序只允许您调用从 DLL 导出的、明确编写为供这两个程序调用的函数。本文详细介绍了 Rundll 和 Rundll32 程序在上面列出的 Windows 操作系统中的用法。

MIcrosoft Windows NT 4.0、Windows 2000 和 Windows XP 在发行时只附带 Rundll32。这些平台都不提供对 Rundll(Win16 实用程序)的支持。

Rundll 和 Rundll32 实用程序最初设计为仅供 Microsoft 内部使用。但是它们提供的功能非常通用,因此现在可供在一般情况下使用。请注意,Windows NT 4.0 发行时只随附 Rundll32 实用程序,并且只支持 Rundll32。


Rundll 与 Rundll32 之比较

Rundll 加载并运行 16 位 DLL,而 Rundll32 加载并运行 32 位 DLL。如果您向 Rundll 或 Rundll32 传递了错误的 DLL 类型,它可能无法运行,并且不显示任何错误信息。

Rundll 命令行

Rundll 的命令行如下所示:
  1.    RUNDLL.EXE <dllname>,<entrypoint> <optional arguments>
复制代码
示例如下:
  1.    RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
复制代码
在上面的命令行中,有三个问题需要特别注意:

1.Rundll 或 Rundll32 在标准位置搜索给定的 DLL 文件名(请参见有关 LoadLibrary() 函数的文档了解详细信息)。建议您提供 DLL 的完整路径以确保找到所需的 DLL。为获得最佳结果,请使用短文件名而不是长文件名,以确保不会出现非法字符。请特别注意,这意味着“C:\Program Files”文件夹中的 DLL 应转换为短名称。
2.<dllname> 不能包含任何空格、逗号或引号。这是 Rundll 命令行分析器的局限。
3.在上面的命令行中,<dllname> 和 <entrypont> 函数名称之间的逗号 (,) 极为重要。如果缺少这个逗号分隔符,Rundll 或 Rundll32 将失败,而且不显示任何错误。另外,在 <dllname>、逗号和 <entrypoint> 函数之间不能有任何空格。

Rundll 的工作方式

Rundll 执行以下步骤:
1.它分析命令行。
2.它通过 LoadLibrary() 加载指定的 DLL。
3.它通过 GetProcAddress() 获取 <entrypoint> 函数的地址。
4.它调用 <entrypoint> 函数,并传递作为 <optional arguments> 的命令行尾。
5.当 <entrypoint> 函数返回时,Rundll.exe 将卸载 DLL 并退出。

如何编写 DLL

在您的 DLL 中,使用以下原型编写 <entrypoint> 函数:
16 位 DLL:
  1.   void FAR PASCAL __loadds
  2.   EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
复制代码
32 位 DLL:
  1.   void CALLBACK
  2.   EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
复制代码
同样,对于 EntryPoint 函数也有三个问题需要注意:
1.很明显,“EntryPoint”名称应该替换为您的入口点函数的实际名称。请注意,Rundll32 的入口点与 32 位 DLL 中的 DllEntryPoint 函数完全无关,后者处理进程和线程的连接/分离通知。
2.Rundll32 的入口点函数必须使用 _stdcall 调用约定定义(CALLBACK 默认情况下使用 _stdcall 属性)。如果缺少 _stdcall 属性,则函数默认使用 _cdecl 调用约定,然后 Rundll32 将在调用该函数后异常终止。
3.由于您必须如上所述使用 _stdcall 调用约定声明该函数,因此如果 DLL 是用 C 语言编写的,Visual C++ 编译器会将该函数实际导出为 _EntryPoint@16;如果 DLL 是用 C++ 语言编写的,则 Visual C++ 编译器将进一步使用名称修饰。所以,请务必在 Rundll 或 Rundll32 的命令行中使用正确导出的名称。如果您想避免使用修饰名称,请使用 .def 文件,并按名称导出入口点函数。在使用 Visual C++ 编译器时,请参考产品文档和以下文章,以了解有关名称修饰的更多信息:
140485 导出 32 位 DLL 中类似 PASCAL 的符号

Rundll 入口点的参数如下所示:
  1. hwnd - 窗口句柄,它应该用作 DLL 创建的任何窗口的
  2. 所有者窗口
  3. hinst - DLL 的实例句柄
  4. lpszCmdLine - DLL 应分析的 ASCIIZ 命令行
  5. nCmdShow - 描述 DLL 的窗口应如何显示
复制代码
在下面的示例中:
  1.      RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
复制代码
Rundll 将调用 Setupx.dll 中的 InstallHinfSection() EntryPoint 函数,并向其传递以下参数:
  1. hwnd =(父窗口句柄)
  2. hinst = SETUPX.DLL 的 HINSTANCE
  3. lpszCmdLine = "132 C:\WINDOWS\INF\SHELL.INF"
  4. nCmdShow =(传递给 CreateProcess 的任何 nCmdShow)
复制代码
请注意,<entrypoint> 函数(在上例中为 InstallHinfSection())必须分析它自己的命令行(上面的 lpszCmdLine 参数),并在必要时使用个别参数。Rundll.exe 最多只分析到传递给它的命令行的可选参数。其余的分析工作则由 <entrypoint> 函数来完成。

有关 Windows 95 和 Windows NT 之间的区别的特别提示

在 Windows NT、Windows 2000 和 Windows XP 中,Rundll32.exe 的行为稍有不同,目的是为了适应 UNICODE 命令行。

Windows NT 首先尝试对 <EntryPoint>W 调用 GetProcAddress 以获取其地址。如果找到该入口点,则假定原型为:
  1.    void CALLBACK
  2.    EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine,
  3.                int nCmdShow);
复制代码
这与 ANSI EntryPoint 相同,只是 lpszCmdLine 参数现在是一个 UNICODE 字符串。

如果没有找到 <EntryPoint>W 入口点,Windows NT 就会对 <entrypoint>A 和 <entrypoint> 调用 GetProcAddress 以获取其地址。如果发现其中任何一个地址,则将其视为 ANSI 入口点,并像在 Windows 95/98/Me 中那样进行处理。因此,如果希望 DLL 在带 ANSI 支持的 Windows 95 中以及带 UNICODE 支持的 Windows NT/2000/XP 中运行,您应该导出以下两个函数:EntryPointW 和 EntryPoint。在 Windows NT/2000/Me 中,通过 UNICODE 命令行调用 EntryPointW 函数;在 Windows 95/98/Me 中,则通过 ANSI 命令行调用 EntryPoint 函数。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2