用 RunDLL32.exe 命令实现 xdg-open
xdg-open
是 Linux 下的一个命令,可以调用对应的程序来打开目标文件,等同于在文件管理器中双击打开该文件。Ubuntu 用户可以通过执行 sudo apt install xdg-utils -y
来安装 xdg-open
命令,这个命令的用法也很简单:
xdg-open { file | URL }
遗憾的是, Windows 系统并没用提供类似的命令,不过我们可以通过 Windows 自带的 rundll32.exe 命令来实现一个类似功能的脚本。
RunDLL32.exe 用来加载指定的 DLL 文件并调用指定的导出函数。用法如下:
rundll32 <dll name>,<entry point> <optional arguments>
其中:
dll name
是 DLL 文件名;entry point
是导出的函数名称;optional arguments
是传递给函数的参数。
能接受 rundll32.exe 调用的 API 函数签名应满足如下形式:
c++// __stdcall
void CALLBACK EntryPointW(
HWND hWnd,
HINSTANCE hInst,
LPWSTR lpszCmdLine,
int nCmdShow
);
函数签名不一致的 API 也有被调用成功的可能,但是这些 API 并不能正确地接收参数。以 ShellAboutA 为例,其函数原型为:
c++INT ShellAboutA(
[in, optional] HWND hWnd,
[in] LPCSTR szApp,
[in, optional] LPCSTR szOtherStuff,
[in, optional] HICON hIcon
);
当执行 rundll32 shell32.dll,ShellAboutA Other Stuff
命令后,发现关于对话框的标题是 关于“MZ?”
,版权信息下会显示 Other Stuff
字样。这是由于 rundll32.exe 将 hInst
当作 szApp
字符串指针传递给了 ShellAboutA
函数,而 hInst
的值就是可执行文件 rundll32.exe 在内存中的加载位置,我们看到的 MZ?
字符串正是 rundll32.exe 的 PE 文件头;而参数 lpszCmdLine
正好对应参数 szOtherStuff
显示在了对话框中。
用户在 Windows 资源管理器中双击一个文件后,最终会通过 Windows API ShellExecuteW
来打开文件。这个 API 由 shell32.dll 文件导出,不过由于参数的格式限制, rundll32.exe 并不能直接调用该 API 。所幸 shell32.dll 导出了一系列以 _RunDLL(A/W)
为结尾的 Undocumented API 专门用于被 rundll32.exe 调用:
OpenAs_RunDLL
OpenAs_RunDLLA
OpenAs_RunDLLW
PrintersGetCommand_RunDLL
PrintersGetCommand_RunDLLA
PrintersGetCommand_RunDLLW
SHHelpShortcuts_RunDLL
SHHelpShortcuts_RunDLLA
SHHelpShortcuts_RunDLLW
AppCompat_RunDLLW
Control_RunDLL
Control_RunDLLA
Control_RunDLLAsUserW
Control_RunDLLW
LaunchMSHelp_RunDLLW
Options_RunDLL
Options_RunDLLA
Options_RunDLLW
RunAsNewUser_RunDLLW
ShellExec_RunDLL
ShellExec_RunDLLA
ShellExec_RunDLLW
其中 ShellExec_RunDLL
正是对应 ShellExecuteW
的版本。用法如下:
rundll32.exe shell32.dll,ShellExec_RunDLL { file }
然而 ShellExec_RunDLL
并不像 xdg-open
那样支持打开 URL 。经过一番搜索,发现 url.dll 导出的 Undocumented API OpenURL
可以满足要求,且支持被 rundll32.exe 调用:
rundll32.exe url.dll,OpenURL { file | URL }
创建一个名为 xdg-open.ps1
的脚本文件,内容如下:
powershellparam($file)
rundll32 url.dll,OpenURL $file
将脚本文件保存在系统 PATH 路径下,就可以在命令行中使用 Windows 版的 xdg-open
命令了。
附录:常用的 RunDLL32 命令
描述 | 命令 |
---|---|
关于 Windows | rundll32 shell32.dll,ShellAbout |
映射网络驱动器 | rundll32 shell32.dll,SHHelpShortcuts_RunDLL Connect |
添加打印机 | rundll32 shell32.dll,SHHelpShortcuts_RunDLL AddPrinter |
打印机文件夹 | rundll32 shell32.dll,SHHelpShortcuts_RunDLL PrintersFolder |
字体文件夹 | rundll32 shell32.dll,SHHelpShortcuts_RunDLL FontsFolder |
打开方式 | rundll32 shell32.dll,OpenAs_RunDLL { file } |
文件资源管理器选项 - 常规 | rundll32 shell32.dll,Options_RunDLL 0 |
任务栏设置 | rundll32 shell32.dll,Options_RunDLL 1 |
文件资源管理器选项 - 搜索 | rundll32 shell32.dll,Options_RunDLL 2 |
开始设置 | rundll32 shell32.dll,Options_RunDLL 3 |
文件资源管理器选项 - 查看 | rundll32 shell32.dll,Options_RunDLL 7 |
打开控制面板 | rundll32 Shell32.dll,Control_RunDLL { CPL file },{@appletindex},{tabindex} 更多内容 |
交换鼠标主按钮 | rundll32 user32.dll,SwapMouseButton |
锁定计算机 | rundll32 user32.dll,LockWorkStation |
存储的用户名和密码 | rundll32 keymgr.dll,KRShowKeyMgr |
Windows To Go 启动选项 | rundll32 pwlauncher.dll,ShowPortableWorkspaceLauncherConfigurationUX |
添加标准 TCP/IP 打印机端口向导 | rundll32 tcpmonui.dll,LocalAddPortUI |
休眠 | rundll32 powrprof.dll,SetSuspendState |
环境变量 | rundll32 sysdm.cpl,EditEnvironmentVariables |
添加网络位置向导 | rundll32 shwebsvc.dll,AddNetPlaceRunDll |
设备管理器 | rundll32 devmgr.dll DeviceManager_Execute |
打印机用户界面 | rundll32 printui.dll,PrintUIEntry [options] [@commandfile] 使用 rundll32 printui.dll,PrintUIEntry /? 查看所有参数 |
打开文件或 URL | rundll32 url.dll,OpenURL { file | URL } |
打开文件协议 | rundll32 url.dll,FileProtocolHandler { file scheme URL } 参数为 file:// 协议的文件 URL |
打开 Internet 快捷方式 | rundll32 shdocvw.dll,OpenURL { internet shorcut file } 打开 *.url 文件 |
打开 Internet 快捷方式 | rundll32.exe ieframe.dll,OpenURL { internet shorcut file } |
打开文件 | rundll32 zipfldr.dll,RouteTheCall { file } |
下载并打开网络图片 | rundll32 shimgvw.dll,ImageView_Fullscreen { image url } |