Делаю механизм самообновления для проги, может ли exe скачивать обнову и на лету себя ею перезаписывать? Качаю в TMemoryStream. Делал с сохранением обновления на диск, замещением и т.д., но это не очень стабильно работало.
IUnknown
7.05.2011 19:23
Цитата
может ли exe скачивать обнову и на лету себя ею перезаписывать?
Размечтался... Что именно "не очень стабильно" работало у тебя, расскажешь?
Кстати, лучше бы обновляемые части программы хранить в DLL. Скачал новую DLL-ку, выгрузил старую, заменил старый файл новым, загрузил новую библиотеку. С EXE-шником так не получится. В любом случае его надо будет выгружать. То есть, после того, как скачал обновление - перезапускать программу.
Unconnected
7.05.2011 21:43
С DLL заморачиваться не хочу, не тот левел) Ну, я качал обновление в C:\windows\temp (даже не C:\, а букву диска получал), запускал его и закрывал работающий старый процесс. В обнове была пауза в несколько секунд, чтобы старый успел закрыться, и перемещение с заменой, это делал средствами cmd. Вот думаю, там потоки были работающие, а я перед уходом их не гасил, а тупо halt-ил.. может, они там как-то в памяти оставались через раз и не давали заместить exe.. процентов 30 проваленных обновлений было стабильно.
IUnknown
7.05.2011 22:33
Цитата
Вот думаю, там потоки были работающие, а я перед уходом их не гасил
Ты б делал правильно, проблем бы было меньше
Цитата
С DLL заморачиваться не хочу, не тот левел)
В таком случае, кроме BAT-файла вариантов просто нет. Раньше были, но теперь (начиная с WinXP) они не проходят. Корректно завершай потоки - будет работать.
IUnknown
8.05.2011 1:02
А нет. Только что попробовал еще один способ - работает. Итак: есть основная программа, и программа-обновлялка. Нет, я не предлагаю при запуске проверять, есть ли обновления, и если есть - то вытягивать. Все проще: проверяет твоя программа, которая загружена и работает.
А вот когда она обнаружила, что обновление есть, и его надо качать - она запускает обновлялку. Та сама, в автономном режиме, скачивает обновление, и как только скачала - дает сигнал основной программе, "неплохо бы завершиться" (реализация этого взаимодействия может быть любой. Я сделал так, что при запуске обновлялки ей параметром передается Handle главного окна приложения, на который потом и отсылается WM_CLOSE. Тут все зависит от твоей фантазии). Основная программа завершается (корректно, без спешки, чтоб не убивать потоки, а завершить как положено), возможно - перед закрытием основного потока дает сигнал обновлялке, возможно - просто обновлялка ждет какое-то время, убирает старый EXE-шник, подменяет его новым и запускает его. После чего ее функция закончена - она может самоликвидироваться. Я надеюсь, как сделать, чтоб EXE-файл после завершения работы самоудалился - знаешь? У Рихтера есть рецепт.
Да, да, я знаю, какой вопрос ты сейчас задашь...(Показать/Скрыть)
"Это как так, если обновлялка будет самоудаляться, как же она запустится для следующего обновления. А если не будет удаляться - на кой фиг мне лишний файл еще нужен?" Так?
"Усе под контролем, шеф!" (С) ... Я как раз обновлялку запихал в ресурсы и в нужный момент вытаскиваю ее оттуда и запускаю. Очень удобно. Правда, размер программы увеличится на несколько десятков килобайт.
Unconnected
8.05.2011 3:44
А я то думал, что память, выделенная под потоки, автоматом освобождается и распределяется после завершения процесса.. что интересно, в 100% тестов на моей вирте всё было нормально) На данный момент у меня практически второй способ - исходный файл качает обнову, после запускает её и завершается. И скачанный заменяет старый. Непонятно, где здесь слабое место - как нужно правильно гасить свет, уходя? Или move /y не всегда срабатывает..
-TarasBer-
8.05.2011 15:14
> В обнове была пауза в несколько секунд, чтобы старый успел закрыться
Когда будешь писать многопоточные и прочие такие вещи, НИКОГДА не делай "паузу, чтобы успело сделать что-то там", всегда делай "подождать, пока не придёт сигнал, что что-то успело сделать что-то там"
Unconnected
8.05.2011 18:02
Хочешь сказать, что в моем случае после halt-а программа как бы не закрывается и не дает себя заместить?
IUnknown
8.05.2011 19:14
Ты сам это сказал. Вот тут:
Цитата
я качал обновление в C:\windows\temp (даже не C:\, а букву диска получал), запускал его и закрывал работающий старый процесс. В обнове была пауза в несколько секунд, чтобы старый успел закрыться, <cut>процентов 30 проваленных обновлений было стабильно.
Закрывалась бы программа - не было б 30% провалов.
P.S. ВременнЫе интервалы для ожидания закрытия программы - "Не наш метод" (С). Только сообщения/другие средства межпроцессного взаимодействия.
Unconnected
8.05.2011 20:58
Короче алгоритм я понял такой.. скачали новый, старый запускает его с параметром-своим хэндлом (или pid-ом, идентефикатором, в общем), и начинает аккуратно закрываться, а новый мониторит по ид-у, работает старый или нет, и когда его не станет - устанавливается, так? И что нужно ещё сделать при закрытии проги, кроме освобождения потоков (thread.free)? Глобально описанных и динамически создаваемых объектов нет.
IUnknown
8.05.2011 21:38
Цитата
скачали новый, старый запускает его с параметром-своим хэндлом
Кого это "его"? Я тебе что выше писал? Как только обновление доступно - запускается Updater, который и производит скачку. Скачал - послал сообщение твоей основной программе. Она его приняла, аккуратно, без спешки закрыла все потоки (не Halt-ами, а /Terminate + FreeOnTerminate/ или /Terminate + WaitFor/, заодно отслеживая, что нет спящих потоков), и потом, перед самым своим завершением, послала Updater-у сообщение: "Все, все потоки удалены, все файлы закрыты, я никого не держу и делаю харакири". Твой Updater, приняв это сообщение, понимает, что основная программа уже вот-вот отбросит коньки, и, выждав контрольный промежуток времени (уже все закрыто, тормозов при выходе не будет, ага, тут можно и подождать), удаляет старый EXE-шник, заменяет его новым, и запускает его на выполнение. После чего завершается сам (его EXE-файл при этом удаляется автоматически, спасибо Дж. Рихтеру). Итог: обновленная программа работает, имя EXE-шника не изменилось, установщик исчез. Все как и было.
В твоем случае опять будет проблема. Скачал ты файл, запустил НОВОЕ приложение, старое закрылось. И что? Новое работает под новым именем. Чего ты добился? Нет уж, "разделяй и властвуй". Каждый делает то, что ему положено делать. Обновлялка качает обновления и занимается, собственно, его установкой, приложение ей в этом не мешает. А только помогает.
Unconnected
8.05.2011 21:51
В смысле "Новое работает под новым именем"? После запуска оно копируется на место старого exe, с заменой. При новом обновлении повторяется всё, как встарь.. По-моему, что я описал, это то же самое, только без доп. программы.
IUnknown
8.05.2011 22:47
Цитата
После запуска оно копируется на место старого exe, с заменой.
Ты из работающей программы его запускаешь, и оно тебе на место работающей программы же и устанавливается? Ну-ну. Удачи.
Без доп. программы не выйдет.
Unconnected
8.05.2011 22:52
Цитата
Ты из работающей программы его запускаешь, и оно тебе на место работающей программы же и устанавливается?
Ну да, говорю же, запущенное обновление мониторит, жив ли старый exe, и когда узнает, что уже закрылся, ждет несколько секунд и ставится с замещением, почему бы и нет..
IUnknown
8.05.2011 23:39
Это "почему бы и нет" у тебя уже было. Ну, реализуй это, попробуй. Соберешь статистику отказов - приходи.
С отдельным приложением - все просто, как хозяйственное мыло: поскольку никакого "с замещением" делать не надо, то спокойно дожидаемся завершения головной программы, удаляем ее файл, так же спокойно сбрасываем содержимое TMemoryStream на диск под тем же именем, и перезапускаем приложение. Никаких мониторингов, пустых разбазариваний ресурсов, никаких "ух ты, опять 30% сбоев. Почему это, интересно? Может, действительно, надо было послушать, когда говорили про _несколько_ приложений?".
Да ладно, делай как знаешь, мне что, надо очень переубеждать тебя? Только зачем спрашивать, если все равно изначально решил делать по-своему?
Unconnected
9.05.2011 6:01
Ок, совет понял) Закрывание
loaderthread:=Tread2.create(false); loaderthread.FreeOnTerminate:=true;//в конце OnExecute потока вызывается terminate loaderthread.waitfor; exitprocess(0);
И ещё один поток создается BeginThread-ом, его гашу TerminateThread(trhNotify,0);.
IUnknown
12.05.2011 13:26
У тебя, я надеюсь, не совершенно секретная разработка? Можешь исходники своей программы показать? (да знаю я, знаю, что ты на KOL пишешь, у меня Лазарус есть, там KOL работает). Может, нашли бы совместными усилиями, где поток держится, и как это исправить... Можно на почту, адрес у тебя есть...
Unconnected
12.05.2011 16:32
Спасибо, но в принципе уже разобрался, сделал так (где-то нашел, что freeonTerminate:=true может мешать WaitFor-у. До этого у меня на нём вылетала ошибка №6, неверный дескриптор, как-то так).
try loaderl:=dcrypt(b64decode(getintxt(loaderlink+b64encode(crypt(mac,pas)))),pas); loaderthread:=Tread2.create(false); loaderthread.FreeOnTerminate:=false; loaderthread.WaitFor; if length(updatel)>5 then exitprocess(0); except end;
В самом потоке в секции finally выполняется loaderthread.terminate;
И такой код в начале обновления:
repeat deletefile(writepath+nname); sleeping(2000); until not(fileexists(writepath+nname)); //тут уже перемещение нового
Обновилось 100% (ну может без 1-2), это из 120 обновлений. На днях больший объем попробую.. Кстати, в KOL для работы с потоками достаточно так же унаследовать от TThread, как и делаю, хотя там и спецкомпонент есть.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.