2009-01-22 4 views
6

У меня есть процесс самообучения, реализованный там, где мое основное приложение exe запускает программу updater exe, передавая дескриптор себе в командной строке. Затем приложение exe вызывает вывод ExitProcess для выхода, и программа обновления вызывает WaitForSingleObject в обработанном дескрипторе, чтобы дождаться завершения EXE-приложения.Когда окна сигнализируют дескриптор процесса?

The WaitForSingleObject ждет. Пока приложение не вызовет ExitProcess, программа обновления останавливается.

Однако иногда, когда программа обновления пытается перезаписать DLL приложения с новыми версиями, я получаю ошибку с блокировкой файлов, которую текущая версия моего обновления рассматривает как неустранимую ошибку и завершается. Похоже, что включение произвольного сна (100) достаточно, чтобы обойти эту «проблему», но я действительно ненавижу такой код. действительно ненавижу.

Мне кажется очень странным, что дескриптор процесса может сигнализироваться, в то время как основное приложение все еще достаточно для блокировки файлов DLL.

ответ

1

Как еще один ответ указывает, дескриптор процесса получает сигнал, когда процесс прекратил выполнение, а операционная система может занять немного больше времени, чтобы освободить библиотеки 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 существует много странности. Вам не нужно иметь дело с каждым случаем, пока вы можете найти приемлемое решение. Очевидно, сон (100) может сломаться, но 30-секундные петли опроса мне кажутся приемлемыми.

2

Процесс сигнализирует о выходе кода приложения. Может потребоваться немного времени для полной загрузки ОС. Точка сигнализации должна сказать: «Я сделал то, что мне нужно сделать», тем более эффективным, чтобы выпустить другой код, который может иметь действительно полезный материал, вместо того чтобы заставить этот код ждать, пока ОС выполняет некоторую домашнюю работу.

+0

Кажется, что - практически - дескриптор процесса становится сигнализируемым, как только существует допустимый код выхода для возврата из GetExitCode(). Но, с точки зрения распространенных случаев, приложения, которые больше всего ждут обработки дескрипторов процесса, являются установщиками/программами обновления, которые должны знать, когда они могут удалять вещи. –

0

Возможно, DLL блокируется каким-либо другим процессом в то время. Один из способов проверить это - создать отчет о том, что держится за DLL, когда это произойдет.

0

Видел сыпь с помощью некоторых антивирусных программ около шести месяцев назад. Попробуйте без AV и, по крайней мере, убедитесь, что AV обновлен.

0

Если какой-либо из этих библиотек вы используете используют потоки, они не могут прекратить (или присоединиться) достаточно быстро, если вы явно не выгружать сами за которые, конечно, произойти, если бы вы явно загрузили их с помощью LoadLibrary

Посмотрите здесь: http://msdn.microsoft.com/en-us/library/ms682596(VS.85).aspx

Конкретно эта линия:

... Библиотека DLL выгружается, когда процесс завершается или вызывает FreeLib rary, а отсчет становится равным нулю. Если процесс завершается в результате функции TerminateProcess или TerminateThread , система не вызывает функцию точки входа DLL.

0

Возможное решение для вас ... пока вы не можете заменить dll, который используется, вы можете переименовать его. поэтому, если у вас есть dll, который вам нужно заменить, но его по какой-то причине использовать, переименуйте его в .delete или что-то в этом роде. сделайте обновление, затем попросите свою основную программу найти любые файлы .delete и удалите их при запуске.

-don