Windows Rundll 和 Rundll32 介面

來源:互聯網
上載者:User
概要
Microsoft Windows 95、Windows 98 和 Windows Millennium Edition (Me) 包含兩個命令列公用程式,分別名為 Rundll.exe 和 Rundll32.exe,使用它們可以調用從 16 位或 32 位 DLL 匯出的函數。但是,使用 Rundll 和 Rundll32 程式並不能調用從任何 DLL 匯出的任何函數。例如,您不能使用這兩個公用程式調用從系統 DLL 匯出的 Win32 API(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 的命令列如下所示:    RUNDLL.EXE <dllname>,<entrypoint> <optional arguments>
                
樣本如下:    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:

  void FAR PASCAL __loadds
  EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
                
32 位 DLL:   void CALLBACK
  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++ 編譯器時,請參考產品文檔和以下文章,以瞭解有關名稱修飾的更多資訊:  

引用

Exporting PASCAL-Like Symbols in 32-Bit DLLs

SUMMARY

There is no _pascal keyword in the 32-bit editions of Visual C++. Instead the Windef.h header file has PASCAL defined as __stdcall. This creates the correct style calling convention for the function (the called function cleans up the stack) but decorates the function name differently. So, when __declspec(dllexport) is used (in a .dll file, for example), the decorated name is exported instead of the desired PASCAL style name, which is undecorated and all uppercase.

MORE INFORMATION

PASCAL name decoration is simply the undecorated symbol name in uppercase letters. __stdcall name decoration prefixes the symbol name with an underscore (_) and appends the symbol with an at sign (@) character followed by the number of bytes in the argument list (the required stack space). So, the function when declared as:    int  __stdcall func (int a, double b)

                

is decorated as:    _func@12

                

The C calling convention (__cdecl) decorates the name as _func. Whereas the desired PASCAL style name is FUNC.

To get the decorated name set the Generate Mapfile option in the Linker General category setting.

Use of __declspec(dllexport) does the following: &#8226; If the function is exported with C calling convention (_cdecl), it strips the leading underscore (_) when the name is exported.  

&#8226; If the function being exported does not use the C calling convention (for example, __stdcall ), it exports the decorated name.  

So to simulate PASCAL name decoration and calling conventions, you must have the "Called Function stack clean-up" provided by using __stdcall and the undecorated uppercase name.

Because there is no way to override who does the stack clean up, you must use __stdcall. To undecorate names with __stdcall, you must specify them by using aliases in the EXPORTS section of the .def file. This is shown below for the following function declaration:    int  __stdcall MyFunc (int a, double b);

   void __stdcall InitCode (void);

                

In the .def file:    EXPORTS

      MYFUNC=_MyFunc@12

      INITCODE=_InitCode@0

                

For .dll files to be called by programs written in the 32-bit versions of Visual Basic (versions 4.0 and above), the alias technique shown in this article is needed in the .def file. If alias is done in the Visual Basic program, use of aliasing in the .def file is not necessary. It can be done on the Visual Basic program by adding an Alias clause to the Declare statement as shown here: Declare Function MyFunc Lib "dlllibname" Alias "_MyFunc@12"  (...)

   As Integer

                

The complete syntax for the Visual Basic Declare statement follows:    [Public | Private ] Declare Function name Lib

   "libname" [Alias "aliasname" ] [([arglist])][As type]

                

References

For more information, query the MSDN compact disc using these keywords:

VB alias DLL

Rundll 進入點的參數如下所示: hwnd -  視窗控制代碼,它應該用作您的 DLL 建立的任何視窗的
所有者視窗
hinst - 您的 DLL 的執行個體控制代碼
lpszCmdLine - 您的 DLL 應該分析的 ASCIIZ 命令列
nCmdShow - 描述您的 DLL 的視窗應如何顯示
                
在下面的樣本中:      RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:/WINDOWS/INF/SHELL.INF
                
Rundll 將調用 Setupx.dll 中的 InstallHinfSection() 進入點函數,並向其傳遞以下參數: hwnd =(父視窗控制代碼)
hinst = HINSTANCE of SETUPX.DLL
lpszCmdLine = "132 C:/WINDOWS/INF/SHELL.INF"
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 以擷取其地址。如果找到該進入點,則假定原型為:    void CALLBACK
   EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine,
               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 函數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.