Delphi как программе обновить саму себя
Как правильно выполнить перезапуск программы?
Цель такая: нужно обновить программу.
Алгоритм такой: программа скачивает обновление, проверяет на валидность, обозначает как-то что доступно обновление (например пишет ключ в реестр) и перезапускает себя (как firefox, например). При запуске программа проверяет ключ в реестре, и, если доступно обновление — заменяет файлы новыми и дальше работает в штатном режиме.
Остается два узких места: как обновить сам exe-шник?
и как организовать перезагрузку?
но если первую проблему можно как-то обойти: сам exe-шник представляет из себя лоадер, который умеет обновлять основную программу и загружать ее и сам не обновляется. А во-вторых, его можно переименовать во время работы и записать новую версию (не знаю только всегда и везде ли это будет работать?),
то со второй что-то никак не справиться.
Подскажите пожалуйста, как решить данную проблему или укажите как правильно делают обновления программ. Не обязательно подробно объяснять, главное дать пинок в нужном направлении
Заранее благодарен.
Re: Перезапуск программы, обновление программы
| От: | misha_irpen |
| Дата: | 28.04.08 11:29 |
| Оценка: |
Системы семейства NT позволяют переименовать исполняемый файл даже если он сейчас загружен. Можно плясать от этого (простейший способ потребует записи ключика в RunOnce и перезагрузки машины).
А вообще я бы написал маленький екзешничек без использования VCL, сжал его UPX-ом и вложил в ресурс оновного исполняемого файла программы (добавит всего килобайт 10 к размеру). После загрузки обновления, отпочковываем от себя этот файлик, запускаем его с нужными параметрами, а сами завершаемся. Файлик же, дожидается нашего завершения, выполняет обновление всего что нужно, снова запускает программу с «секретным» параметром и тихо завершается. Программа при запуске с этим параметром первым делом дожидается завершения загрузчика, удаляет его и дальше работает как обычно.
Можно ничего не прятать, а просто держать этот загрузчик все время в каталоге программы, но тогда его самого обновить будет сложнее (это должна будет сделать сама программа перед его запуском).
Re: Перезапуск программы, обновление программы
| От: | BDEsoft |
| Дата: | 28.04.08 11:29 |
| Оценка: |
Здравствуйте, bsigr, Вы писали:
Я бы сделал следующим образом.
Первый exe (лоадер) запускает основную программу, и не закрывается, ожидает сообщения. Сама программа, уловив, что нужно обновление, выдает сообщение об этом, посялает сообщение лоадеру (типа мол нужно обновить) и сама закрывается. Лоадер, же скачивает обновления и заного запускает программу. Просто и ясно.
Re: Перезапуск программы, обновление программы
| От: | Rius |
| Дата: | 28.04.08 14:38 |
| Оценка: |
Здравствуйте, bsigr, Вы писали:
B>Как правильно выполнить перезапуск программы?
B>Цель такая: нужно обновить программу.
B>Алгоритм такой: программа скачивает обновление, проверяет на валидность, обозначает как-то что доступно обновление (например пишет ключ в реестр) и перезапускает себя (как firefox, например). При запуске программа проверяет ключ в реестре, и, если доступно обновление — заменяет файлы новыми и дальше работает в штатном режиме.
B>Остается два узких места: как обновить сам exe-шник?
B>и как организовать перезагрузку?
B>но если первую проблему можно как-то обойти: сам exe-шник представляет из себя лоадер, который умеет обновлять основную программу и загружать ее и сам не обновляется. А во-вторых, его можно переименовать во время работы и записать новую версию (не знаю только всегда и везде ли это будет работать?),
B>то со второй что-то никак не справиться.
B>Подскажите пожалуйста, как решить данную проблему или укажите как правильно делают обновления программ. Не обязательно подробно объяснять, главное дать пинок в нужном направлении
B>Заранее благодарен.
У меня работало так:
прога (exe), запускаясь, смотрит из какого каталога она запущена или в каком домене. если не из временного и не в домене, то копирует свой exe во временный каталог и запускает его, сама закрывается (это безоконная прога).
запустившись из временного каталога, прога создаёт домен приложения, включает его кеширование и загружает в него свой исходный exe из исходного каталога. кеширование позволяет программе самой перезаписывать свои файлы после того как они загружены.
загрузившись в домене, прога создаёт класс, создающий уже основное окно приложения из dll. таким образом exe’шнику не требуются остальные dll до этого момента, он имеет минимум кода и малый объём.
этот класс также ждёт здесь выхода из программы, после выхода проверяет, не установлен ли флаг перезапуска программы, и если установлен — вызывает функцию Application.Restart().
найдя обновление на сервере, приложение загружает файлы во временный каталог и предлагает юзеру их применить, либо тихо перезаписывает исходный набор файлов, т.к. они кешированы и доступ к ним не заблокирован.
p.s. что-то здесь явно можно упростить.
Delphi как программе обновить саму себя
Я делал через idHTTP. Получаешь файл обновлений с сервера:
var ustream:TMemoryStream; begin ustream:=TMemoryStream.Create; idHttp.Get('http://mysite.ru/update.xml',ustream); xml.LoadFromStream(ustream); // дальше анализируешь и скачиваешь файлы, путь которых записан в узлах XML ustream.Free; end;
Скачивание файлов также через idHttp.Get;
Последний раз редактировалось kettanaito; 12.12.2011 в 23:44 .
| kettanaito |
| Посмотреть профиль |
| Найти ещё сообщения от kettanaito |
Пользователь
Регистрация: 16.01.2011
Сообщений: 65
Нашел в одной из тем такой код:
procedure TForm1.Button1Click(Sender: TObject); var v:string; begin v:=HTTP.Get('http://адрес вашего сайта/update/version.txt'); if v=version.Caption then showmessage('Вы используете последнюю версию программы!') else begin ftp.Connect(true); if ftp.connected then begin ftp.ChangeDir('update'); ftp.Get('Project.exe',extractfilepath(application.ExeName)+'\project.exe',true); end; ftp.Disconnect; showmessage('ok'); end; end; end.
Все работает до места скачивания обновленной проги, вылазит что не может изменить директорию, вроде все сделал правильно. Что делать??
Delphi как программе обновить саму себя
← →
Алексей Петров ( 2009-09-23 21:28 ) [0]
Доброго времени суток уважаемые!
Требуется по нажатию кнопки обновить программу, т.е. скопировать из определенного каталога exe-файл на то место, откуда была запущена программа, а потом что бы эта программа опять сама запустилась.
← →
Сергей М. © ( 2009-09-23 21:35 ) [1]
Мы не против.
← →
Алексей Петров ( 2009-09-23 21:50 ) [2]
Подскажите как это можно сделать? нужно закрыть, обновить, и опять запустить программу. Закрыть , обновить — не проблема. а остальное как? может при закрытии запустить другую программу, которая заменит эту программу и опять ее запустит?
← →
Германн © ( 2009-09-23 22:00 ) [3]
> может при закрытии запустить другую программу, которая заменит
> эту программу и опять ее запустит?
Может.
← →
TIF © ( 2009-09-23 22:20 ) [4]
Программа завершает работу и запускает обновлятор, который копирует во временную папку.
Обновлятор делает своё дело и запускает обновлённую программу, а сам закрывается.
Программа запускаться и удаляет из временной папки обновлятор.
← →
TIF © ( 2009-09-23 22:22 ) [5]
> Программа завершает работу и запускает обновлятор, который
> копирует во временную папку.
Непонятно написал. Переписываю:
Программа копирует обновлятор во временную папку, запускает его, а сама после этого закрывается.
← →
Алексей Петров ( 2009-09-23 23:46 ) [6]
Спасибо! Я так примерно и думал! а как отследить например такую ситуацию: программа еще не закрылась, а обновлятор уже пытается ее заменить, и у него не получается это сделать.
← →
Алексей Петров ( 2009-09-24 00:02 ) [7]
так как нет доступа к файлу.
← →
TIF © ( 2009-09-24 01:01 ) [8]
> а обновлятор уже пытается ее заменить, и у него не получается
> это сделать.
Ну, например как-то так
В том месте кода, где осуществляется замена программы перехватывать сообщения об ошибках от функции, которая это дело будет выполнять. Если есть ошибка — присваиваем логической переменной B значение true, иначе false
Потом заключаем эту часть кода в
repeat
< Наш код, выполняющий замены программы >
Sleep(1000); // Задержка в 1000 мс (1 с), ждём
until B;
Правда если процесс завершения работы программы застопорился намертво, этот цикл получится бесконечным 😉 Поэтому надо немного доработать идею, решение находится за минуту
Ещё вариант: «убить» процесс своей программы, завершить её принудительно. Способы — в Google/Bing/Яндекс
Можно не убивать, а послать ей «обновлятором» намёк — сообщение (Message), но тогда надо в самой программе предусмотреть возможность это сообщение принимать и на него реагировать (Application.Terminate себя, не забыв сохранить данные, если это необходимо). Про сообщения — messages — много материалов, примеров, если этот вариант интересен — удачных поисков
← →
Алексей Петров ( 2009-09-24 13:26 ) [9]
Всем спасибо!
← →
Thrashead ( 2009-09-24 16:08 ) [10]
Алексей Петров:
просто интересно — для чего всё это понадобилось?
← →
TIF © ( 2009-09-24 22:10 ) [11]
> для чего всё это понадобилось?
?
> обновление программы
← →
Юрий Зотов © ( 2009-09-25 11:42 ) [12]
> Алексей Петров (23.09.09 23:46) [6]
> как отследить например такую ситуацию: программа еще не закрылась,
> а обновлятор уже пытается ее заменить
При запуске обновлятора программа передает ему в параметрах ID своего процесса. По нему обновлятор определяет хэндл процесса и вызывает WaitForSingleObject, а потом делает свое дело.
В обратную сторону — так же (при запуске программы обновлятор передает ей ID своего процесса, программа дожидается его завершения и удаляет обновлятор). Другой вариант: обновлятор дает системе запрос на удаление самого себя при перезагрузке (MoveFile с MOVEFILE_DELAY_UNTIL_REBOOT).
← →
Юрий Зотов © ( 2009-09-25 12:53 ) [13]
Поправка — MoveFileEx, конечно
← →
Пират ( 2009-09-25 14:42 ) [14]
А у мен в свое время было написано такое:
procedure TForm1.StartUpdate(NewFileName: string);
const
BatFileName = «temp.bat»;
BatFile = «@echo off» + #13#10 +
«:Loop» + #13#10 +
«del %1» + #13#10 +
«if exist %1 goto Loop» + #13#10 +
«rename %2 %1» + #13#10 +
«start %1»;
var
sl: TStringList;
begin
sl:= TStringList.Create;
try
sl.Text := BatFile;
sl.Add(«del » + BatFileName);
sl.SaveToFile(BatFileName);
WinExec(PChar(BatFileName + » » + ExtractFileName(ParamStr(0)) + » » + PChar(NewFileName)), SW_HIDE);
finally
sl.Free;
end;
Close;
end;
Как сделать автоматическое обновление программы на новую версию?
У меня программа автоматически проверяется на версию. Возможно ли такое, чтоб в случае новой версии она автоматически скачивала бы новую и заменялась на неё? Если да, то как? Подскажите, пожалуйста.
Отслеживать
371 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков
задан 9 июл 2012 в 10:07
9,194 4 4 золотых знака 24 24 серебряных знака 47 47 бронзовых знаков
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Это, конечно же, возможно. Раз это вопрос новичка в Delphi, то постараюсь ответить доходчиво, как такое реализовать.
- Для начала вам нужно завести хостинг или аккаунт на каком-л. облачном хранилище. Это необходимо для того, чтобы программа имела в сети «свой уголок», откуда могла бы проверять новую версию и самообновляться в случае появления новой. Лично я вам советую заводить именно хостинг, нежели пользоваться услугами «облаков», так как у этих облачных хранилищ очень ограничена пропускная способность канала, а если пользователей у вашей «программы» будет очень много, то аккаунт забанят из-за большого трафика. Пользуйтесь хостингом.
- Далее вам надо создать на этом хостинге файлик, в котором будет лежать текущая(последняя) версия вашего «продукта». Например, 1.72.. И еще, конечно же, на хостинг надо поместить «свежую» версию вашего «продукта», чтобы можно было её скачать.
- Далее в самой программе вы должны каждый раз при запуске проверять версию из того файла на хостинге, который содержит версию. В самой программе, естественно, должна быть константа, содержащая номер версии программы. Это можно сделать с помощью TIdHttp с панели IndyClients. Если версия больше, то качаем новую(расположена на нашем хостинге.
- Качать новую версию лучше всего из «вспомогательной» програмки, прилагаемой к основному файлу вашего «приложения». В случае обнаружения новой версии запускаем updator и он уже все сам сделает.
- Что будет делать апдейтор? Он, в случае обнаружения новой версии, будет закрывать основное «приложение», скачивать новое(Как? Это вам должно быть известно.) и копировать его вместо старого. Скачанный файл потом надо будет удалить.
Отслеживать
371 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков
ответ дан 9 июл 2012 в 10:21
13.6k 13 13 золотых знаков 62 62 серебряных знака 122 122 бронзовых знака
@Yura Ivanov, ну большинство этих «вещиц» можно сделать «динамически изменяемыми». Так, например, можно на хостинге создать файл параметров, где будет вся инфа по подключению к БД, прочим серверам, если надо и т.д. — А вообще, раз уж так может понадобиться обновлять апдейтор, то можно просто «схитрить» и сделать «взаимное обновление». То есть, например, при надобности основное приложение обновит тот апдейтор, а тот, в свою очередь, будет обновлять само приложение. Вариант здесь не один, на самом деле =)
9 июл 2012 в 11:42
чем больше компонент, тем сложнее становится система. в итоге превращается в слипшиеся макароны. идите сразу простым путем. некоторые ваще не парятся по поводу автообновлений, хотите новую версию — качайте, ставьте руками.
9 июл 2012 в 11:50
Судя по вопросам, ТС пишет не вирус, а что-то типа «калькулятор», но со всеми возможными и невозможными примочками — и автообновление и прятание в трей, скоро появятся вопросы про круглую форму/кнопку, таскание формы за любую область окна и т.д. В итоге программа будет скорее всего бесполезной, но в ней будет все остальное.
9 июл 2012 в 12:11
@Хэшкод, Опять кто-то мои комментарии потер. О чем речь теперь можно только догадываться.
11 июл 2012 в 10:50
@Yura Ivanov, этим занимается Asen, потому как критика сильно уязвляет нашего специалиста по безопасности. Например, нельзя смеяться над след. волшебной фразой: > Mozilla FireFox, например, умеет обходить UAC, используя один из его многочисленных багов — переполнение буфера