Mpelec打包之后遇到一个问题:如果拖放视频到Mpelec Alpha.exe上,程序运行时会找不到相应的动态链接库。 这个问题棘手在于,1)我不知道他去哪找的DLL文件,毕竟DLL就在安装目录下呆着呢;2)直接双击运行是正常的,所以拖放行为影响了程序运行时的某个环境。

默认的DLL搜索顺序

打开一个程序,如果是隐式调用的动态链接库, 那么查找DLL的顺序官方文档里写得很清楚。

  1. Directory containing the loading EXE application (load-exe)
  2. System directory (e.g. C:\Windows\System32) (sys32)
  3. 16 bit system directory (sys16)
  4. Windows directory (e.g. C:\Windows) (win)
  5. Current directory (pwd)
  6. Directories listed in PATH environment variable (env-paths)

如果引入的是程序私有的链接库,那么最关键的应该是①和⑤这两步。 ①加载的是程序(.exe文件)目录下的链接库文件,一般私有库在这一步就应该找到了。而⑤就很有说法:这个Current Directory到底是个啥?

Current Directory

暂时把它叫做“当前目录”吧。

当前目录是实际调用程序时的目录。举个例子:你在 H:/foo/ 这个目录下使用Shift+右键打开终端,在终端键入 > E:/bar/player.exe ,那么,对于启动的player.exe来说,它此时的当前目录就是E:/bar/player.exe 。所以说,当前目录是会变的。

再举个例子。假设我拖放一个文件到可执行文件上(比如拖放source.cpp到Notepad++.exe上),则此时Notepad++.exe的当前目录 = source.cpp所在目录。

另外,Current Directory还能这么设置:创建一个快捷方式,快捷方式里的“Start in..”字段能起到指定当前目录的作用。

因此,开头的问题就很明显是这样:只有直接双击运行能成功打开——因为当前目录=exe所在目录,所以实际上是在第⑤步才找到了链接库文件。

DLL文件放错了吗?

所以一直以来我的.DLL文件都放错了位置吗?怎么找到他最应该呆着的位置?这时候就要祭出神器——Process Monitor。这个程序能捕获应用运行时的各种外部调用和结果。在Process Monitor里设置Filter:Process Name = Mpelec Alpha.exe, Operation = QueryOpen,这样就能捕获所有该程序尝试打开的文件和返回结果。

Process Monitor截图

从截图可以看到,我先引入了C++ Addon,也就是addon.node文件。之后这个插件隐式调用了动态链接库文件mpv-1.dll,此时第一次查询发生在和addon.node相同的目录下,而不是index.js所在的目录(Current Directory)下!

结论:NodeJS Native Addon调用的链接库,其查找位置是这个插件的同目录,而不是调用这个插件的js脚本目录。