Перейти к содержимому

Delphi как программе обновить саму себя

  • автор:

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, используя один из его многочисленных багов — переполнение буфера

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *