Если кому будет нужна реализация обновления ПО через Интернет — привожу код простого класса для обновления. Как всегда рекомендации и ругань — приветсвуются
.
В принципе ничего не мешает оформить этот класс как компонент или сделать классу обвязку.
unit BDSInetUpdater;
interface
Uses Classes,UrlMon,Windows,IniFiles;
type
// событие, сигнализирующее о том, что есть обновленная версия
TOnStartUpdate=procedure (Sender:TObject; var StartUpdate:boolean) of object;
// событие при проверке обновленнной версии
TOnAddUpdateInfoCheck=procedure (Sender:TObject; Inf:TIniFile; var CheckResult,ContinueCheck:boolean;
var DownloadURL:string) of object;
// событие при проверке версии
TOnUpdateVersionInfo=procedure (Sender:TObject; Version:string) of object;
TInetUpdater=class
private
FUpdateInfoFile: string;
FUpdateResultFile: string;
FOnUpdateComplete: TNotifyEvent;
FProductVersion:string;
FProductName: string;
FOnUpdateExists: TNotifyEvent;
FOnStartUpdate: TOnStartUpdate;
FOnAddUpInfoCheck: TOnAddUpdateInfoCheck;
FOnUpdateVersionInfo: TOnUpdateVersionInfo;
FInetResult:HRESULT;
public
Constructor Create; virtual;
Destructor Destroy; override;
// проверить обнвления и обновится при возможности
function UpdateFile:boolean; virtual;
// только проверить обновления
function CheckUpdate(var DownloadURL:string):boolean; virtual;
// получение кода при операциях с Инетом для разбора полетов
property InetResult:HRESULT read FInetResult;
// ссылка на файл с информацией об обновлениях
property UpdateInfoFileURL:string read FUpdateInfoFile write FUpdateInfoFile;
// временный файл для записи загруженного обновленного файла
property UpdateResultFile:string read FUpdateResultFile write FUpdateResultFile;
// наименование продукта
property ProductName:string read FProductName write FProductName;
// версия
property ProductVersion:string read FProductVersion write FProductVersion;
// событие, которое позволяет проверить дополнительныую информацию, используется для пользовательской проверки
property OnAddUpdateInfoCheck:TOnAddUpdateInfoCheck read FOnAddUpInfoCheck write FOnAddUpInfoCheck;
// событие при старте обновлений
property OnUpdateStart:TOnStartUpdate read FOnStartUpdate write FOnStartUpdate;
// событие при завершении обновления
property OnUpdateComplete:TNotifyEvent read FOnUpdateComplete write FOnUpdateComplete;
// событие о существовании обновления (т.е. информация об обновлениях загружена и новая версия найдена)
property OnUpdateExists:TNotifyEvent read FOnUpdateExists write FOnUpdateExists;
// событие при проверке версии
property OnUpdateVersionInfo:TOnUpdateVersionInfo read FOnUpdateVersionInfo write FOnUpdateVersionInfo;
end;
implementation
Uses SysUtils;
// получить временное имя файла (тут возможна оптимизация, вместо времени можно например использовать GetTickCount())
Function GetTmpFileName:String;
begin
Result:=FormatDateTime('ddmmyyyyhhmmss',Now)+'.tmp';
end;
{ TInetUpdater }
function TInetUpdater.CheckUpdate(var DownloadURL:string): boolean;
var S1,TmpFileName:string;
Res:HRESULT;
Inf:TIniFile;
CheckResult,ContinueCheck:boolean;
begin
Result:=False;
// проверим, есть ли адрес для файла с информацией об обновлениях
if Trim(FUpdateInfoFile)='' then exit;
// будем файл с информацией сохранять во временный файл
TmpFileName:=ExtractFilePath(ParamStr(0))+ChangeFileExt(GetTmpFileName,'.ini');
// пытаемся получить информацию об обновлениях
FInetResult:=UrlDownloadToFile(nil,PChar(FUpdateInfoFile),PChar(TmpFileName),0,nil);
if FInetResult=S_OK then
begin
// ОК, файл с информацией получили, пробуем проверить новую версию
if Assigned(FOnUpdateExists) then FOnUpdateExists(Self);
// предполагается, что файл с информацией об обновлениях представляет собой обычный INI файл
Inf:=TIniFile.Create(TmpFileName);
try
CheckResult:=False; ContinueCheck:=True;
// здесь мы должны проверить информацию о версии, вызывая обработчик для OnAddUpInfoCheck().
// если ContinueCheck TRUE мы должны проверить версию сами в этом классе
//(в ином случае получим результат в переменной CheckResult и не будем проверять версию самостоятельно)
// Если файл с информацией НЕ INI файл - можем использовать свойство Inf.FileName
// для получения имени временного файла и попробовать получить данные другим методом
// в обработчике OnAddUpInfoCheck()
if Assigned(FOnAddUpInfoCheck) then
FOnAddUpInfoCheck(Self,Inf,CheckResult,ContinueCheck,DownloadURL);
// Проверяем версию самостоятельно
if ContinueCheck and Inf.SectionExists(FProductName) then
begin
// Читаем версию
S1:=Trim(Inf.ReadString(FProductName,'Version',FProductVersion));
// событие о получении информации о версии
if Assigned(FOnUpdateVersionInfo) then
FOnUpdateVersionInfo(Self,S1);
// Если версия не такая, как у нас => есть обновления
Result:=(S1<>Trim(FProductVersion));
// соответсвенно, получим URL для обновленного файла
if Result then DownloadURL:=Inf.ReadString(FProductName,'File',DownloadURL);
end
else Result:=CheckResult;
finally Inf.Free; end;
end;
// временный файл нам уже не нужен - удаляем его
if FileExists(TmpFileName) then SysUtils.DeleteFile(TmpFileName);
end;
// первоначальная инициализация
constructor TInetUpdater.Create;
begin
FUpdateInfoFile:='http://www.websitename.com/updates/verinfo.ini'; // URL к файлу с данными об обвлениях
FUpdateResultFile:=''; // результирующий файл
FProductName:=''; // имя продукта
FProductVersion:='1.0.0.0'; // версия
FOnUpdateComplete:=nil;
FOnStartUpdate:=nil;
FOnUpdateExists:=nil;
FOnAddUpInfoCheck:=nil;
FOnUpdateVersionInfo:=nil;
FInetResult:=S_OK;
end;
destructor TInetUpdater.Destroy;
begin
inherited;
end;
// собственно обновление
function TInetUpdater.UpdateFile;
var Flag:boolean;
DownloadURL:string;
Res:HRESULT;
begin
Result:=False;
// если мы не знаем, в какой файл сохранять обновления - они нам не нужны, уходим
if Trim(FUpdateResultFile)='' then exit;
DownloadURL:='';
// пробуем проверить обновления и получить URL для скачивания
if CheckUpdate(DownloadURL) then
begin
if Trim(DownloadURL)='' then exit; // обновления есть, но вот URL для скачивания не получили - уходим
Flag:=True;
if Assigned(FOnStartUpdate) then FOnStartUpdate(Self,Flag); // сигнализируем, что начали процесс обновления
// в переменной Flag - согласие на закачку ответ пользователя
if Flag then // если закачка разрешена - качаем
begin
FInetResult:=UrlDownloadToFile(nil,PChar(DownloadURL),PChar(FUpdateResultFile),0,nil);
Result:=FInetResult=S_OK;
// если закачка обновления прошла нормально - сигнализируем, что все прошло удачно
if Result and Assigned(FOnUpdateComplete) then FOnUpdateComplete(Self);
end;
end;
end;
end.
Пример использования:
1) размещаем на своем сайте обычный Ini файл updates.ini со следующей информацией:
[MyProgram]
Version=1.2
File=http://www.myhomesite.com/updates/MyProgram_12_setup.exe
2) пишем примерно такой код
Procedure MainForm.DoSelfInetUpdate;
var IU:TInetUpdater;
begin
IU:=TInetUpdater.Create;
try
IU.UpdateInfoFileULR := 'http://www.myhomesite.com/updates/updates.ini'; // где лежит информация об обновлениях
IU.UpdateResultFile := ChangeFileExt(ParamStr(0),'.new'); // куда ложить обновленную версию
IU.ProductName := 'MyProgram'; // имя продукта
IU.ProductVersion := '1.0.0 beta 123'; // текущая версия
if IU.UpdateFile then // пробуем обновится
begin
RenameFile(ParamStr(0),ChangeFileExt(ParamStr(0),'.old');
RenameFile(IU.UpdateResultFile,ParamStr(0));
ShowMessage('Обновление прошло удачно!');
// перезапускаемся или что-то еще
// .....................................................
end;
finally IU.Free; end;
end;