8

我实现了一个自我升级过程,其中我的主应用程序 exe 启动一个更新程序 exe,在命令行上将句柄传递给自身。应用程序 exe 然后调用 ExitProcess 退出,更新程序在传入的句柄上调用 WaitForSingleObject 以等待应用程序 exe 终止。

WaitForSingleObject 确实等待。直到应用程序调用 ExitProcess,更新程序才会停止。

但是,有时,当更新程序尝试用新版本覆盖应用程序 dll 时,我会收到一个文件锁定错误,我的更新程序的当前版本将其视为不可恢复的错误并终止。似乎包含任意 sleep(100) 足以绕过这个“问题”,但我真的很讨厌这样的代码。真的很讨厌。

对我来说似乎很奇怪,当主应用程序仍然存活到足以锁定 dll 文件时,可以向进程句柄发出信号。

4

6 回答 6

3

当应用程序代码退出时,进程会发出信号。操作系统可能需要更多时间才能完全卸载该进程。发出信号的重点是说“我已经完成了我需要做的事情”,它更有效地释放其他可能有真正有用的东西要做的代码,而不是让那些代码等待操作系统做一些家务。

于 2009-01-22T08:27:48.017 回答
2

正如另一个答案指出的那样,当进程停止执行时,进程句柄会收到信号,并且操作系统可能需要更长的时间来释放 DLL。

你说得对,依赖 Sleep(100) 是个坏主意。您应该将覆盖您的 DLL 包装在这样的循环中:

BOOL UpdateDll(LPCTSTR dll_name, WHATEVER whatever) {
  int tries = 150;
  while (tries--) {
    if (TryUpdateDll(dll_name, whatever))
      return TRUE;
    Sleep(200);
  }
  return FALSE;
}

这会一直尝试卸载您的 DLL 30 秒,然后放弃。即使系统负载很重,30 秒也足够了,但仍然可以保护您的更新程序不会永远挂起。(如果 UpdateDll 返回 FALSE,请务必向您的用户提供有意义的错误消息,说明违规 DLL 的名称。)

如果您在搞乱 COM,在退出之前调用 CoFreeUnusedLibraries 也可能会有所帮助。( http://msdn.microsoft.com/en-us/library/ms679712.aspx ) 坦率地说,我不知道即使在您的进程退出后 COM 是否会保留 DLL,但最好是安全的。

底线是 Win32 API 有很多奇怪之处。只要您能找到可接受的解决方案,您就不必处理每个案例。显然 Sleep(100) 可能会中断,但我似乎可以接受 30 秒的轮询循环。

于 2009-03-10T01:24:03.777 回答
0

可能是 DLL 当时被其他进程锁定。对此进行测试的一种方法是在发生这种情况时生成一份报告,说明 DLL 上的任何内容。

于 2009-01-28T07:35:23.243 回答
0

大约六个月前,使用一些防病毒软件看到了这些问题。尝试不使用 AV,至少确保 AV 是最新的。

于 2009-03-06T02:47:05.983 回答
0

如果您正在使用的任何 DLL 正在使用线程,如果您没有显式卸载它们,它们可能不会足够快地终止(或连接)——如果您使用 LoadLibrary 显式加载它们当然会发生这种情况

看看这里: http: //msdn.microsoft.com/en-us/library/ms682596 (VS.85).aspx

特别是这一行:

...当进程终止或调用 FreeLibrary 函数并且引用计数变为零时,DLL 被卸载。如果进程因 TerminateProcess 或 TerminateThread 函数而终止,则系统不会调用 DLL 入口点函数。

于 2009-03-09T07:45:10.827 回答
0

一个可能为您解决的问题...虽然您无法替换正在使用的 dll,但您可以重命名它。因此,如果您有需要替换的 dll,但由于某种原因正在使用中,请将其重命名为 .delete 或类似的名称。进行更新,然后让您的主程序搜索任何 .delete 文件并在启动时将其删除。

-大学教师

于 2009-03-09T20:04:38.240 回答