关闭由 LoadLibrary 打开的 DLL 文件句柄

Close DLL file handle opened by LoadLibrary

如何关闭由 LoadLibrary 调用 .dll 打开的文件句柄,同时保持库加载?例如,FreeLibrary 将不起作用。

在我的例子中,有一个程序我想保持打开状态,它打开了 DLL,但我不想在每次重新编译和替换 DLL 时都关闭该程序。我不在乎程序是否在内存中有旧版本的库。该 DLL 还被另一个程序使用,这就是我希望能够替换它的原因。

这是不可能的,因为“加载的”DLL 是内存映射文件。这意味着“关闭句柄”会将其从内存中删除,因为它没有 copied 到内存,只是 mapped.

这就是为什么只要所有程序都使用完全相同的文件,DLL 的内存效率就如此高 - 它(几乎)不需要任何额外的内存来加载它数百次! (如果您想知道:它被映射为 copy-on-write,因此在内存中修改它不会修改磁盘上的文件,而是将受影响的 4k 页复制到实际内存并在那里修改。)

但是,您可以在文件仍在使用时重命名它(或移动它,只要它在同一卷上,这在技术上也是一种重命名操作)。然后你可以用原来的名字新建一个文件,等老文件到处卸载后删除。

您还可以使用 MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT) 将旧文件标记为在下次重新启动时自动删除,但这需要更高的权限。 non-elevated updaters/uninstallers 避免这种情况的一个流行选择是将批处理或 vbs 文件放在本地 appdata 文件夹中,该文件夹会删除文件,然后删除自身(确实工作是因为脚本 复制到内存)并将其注册到 per-user RunOnce 注册表项中。

(请注意,使用 FILE_FLAG_DELETE_ON_CLOSE 打开文件将不起作用。)