我们正在使用包装 DLL 以允许自动更新我们的应用程序(我们的产品是 DLL)。
当应用程序关闭时,我们应该在哪里释放内部 DLL?
(我们尝试在 DLLMain 回调中执行此操作,但它似乎不起作用,并且规范说它不应该存在。)
谢谢
我们正在使用包装 DLL 以允许自动更新我们的应用程序(我们的产品是 DLL)。
当应用程序关闭时,我们应该在哪里释放内部 DLL?
(我们尝试在 DLLMain 回调中执行此操作,但它似乎不起作用,并且规范说它不应该存在。)
谢谢
这是非常模糊的,根本不清楚你的包装器做了什么。通常,将 DLL 加载到进程中会锁定文件。这个锁是 Windows 将 DLL 映射到进程的虚拟内存地址空间的副作用而创建的,底层系统对象是一个内存映射文件。这将在更新文件时尝试覆盖文件失败。
在“应用程序关闭时”的情况下,您不必做任何特殊的事情,这也会使您的 DLL 被卸载并释放文件上的锁定。
更典型的问题是您完全无法控制加载 DLL 的进程。在该过程终止之前,您的更新无法完成。而且很明显,DLL 永远不应该从事强制终止宿主进程的业务,它无法判断这会造成什么样的损害。一种可能的包装方法是对每个导出函数都有一个入口点,该函数将调用委托给真正的 DLL。使用 GetProcAddress() 找到了谁的入口点,您现在可以使用 FreeLibrary() 来卸载真正的 DLL,以便您可以更新它。当 DLL 不是微不足道的时候,这是非常痛苦且容易出错的,您需要为每个导出的函数声明一个函数指针,并使用字符串而不是函数名。维护是相当残酷的。
一种可能的替代方法是详细说明 DLL 上的锁定是在 DLL 的文件数据上,而不是在目录条目上。它允许您在加载文件时重命名文件。您的更新现在可以写入具有相同名称的更新版本。下次程序启动时,它将使用您的更新。然而,这并不完全可靠,显然程序将无法在您应用更新时启动。考虑使用硬链接来避免这种故障模式。
我假设您在检查(并可能应用)内部 DLL 的可用更新之后,使用 LoadLibrary() 从包装 DLL 动态加载内部 DLL。
如果您有宿主进程的合作使用您的包装 DLL,您可以导出一个 Uninitialize() 方法,该方法应该由宿主在退出之前调用。在此例程中,您可以调用 FreeLibrary() 并进行任何其他清理。
如果你没有宿主进程的配合,那么你一般都无法正确清理。正如您所发现的,不允许从 DllMain 中调用 FreeLibrary(),这是 DLL 通常获得的唯一通知,即进程正在关闭。
在进程关闭期间泄漏 DLL 模块句柄实际上并不是什么大问题。系统正在跟踪所有资源并将自动清理它们。