INSTALL'им программы по списку
17 октября 2005 года
Предисловие
Просмотрев комментарии к своей прошлой статье о создании оболочки для диска, я обратил внимание на слова Abigor'а, процитирую: "Вот если бы ты описал, для широкого круга, возможность создания списка программ на установку и запуском их в соответствии с очередностью в списке, это было бы уже другое дело." Так как подробностей о том, какая же она все-таки должна быть здесь немного, то пришлось написать что-то похожее, но идея я думаю была полностью реализована.
Постановка задачи. Подготовка
Писать будем на Delphi. Исходя из идеи, мы должны создать список программ, которые будут видны в нашей программе, и предоставить возможность выбора(какие программы устанавливать), после чего начать устанавливать их по очереди, не отвлекаясь на поиск setup'ного файла в папках. Список программ будет создан заранее и ручками. Хранить названия программ, путь доступа к ним, относительно нашего exe'шника, и краткое описание, будем в ini файле. Структура ini файла:
[Название программы] Path=путь к программе Text=краткое описание
Например:
[winamp.exe] Path=soft\winamp.exe Text=плейер
К тому же наша программа будет сохранять введенные пользователем данные, в случае перезагрузки компьютера (что часто бывает после установки драйверов), и запускать после неё для продолжения операций. Для хранения настроек будем использовать спецкаталог для временных файлов. На этом, пожалуй, подготовительный этап закончен.
Реализация
Нам естественно понадобится форма, назовем её installform. Также бросить на неё компоненты: ChtckListBox, 4 Button'a , Memo ( по желанию добавьте, что-нибудь что будет пояснять что для чего). Присвоим имена в том же порядке, в котором положили на форму компоненты: filelist, startbutton, closebutton, allbutton, nonebutton, textlist. После старта программы сразу должны отображаться доступные программы, для этого пишем следующее:
procedure TInstallForm.FormCreate(Sender: TObject); var s:string; f:textfile; i:integer; res:word; begin // определяем местоположение папки Temp temppath := StrAlloc(255); res:= gettemppath(255,temppath); // ассоциируем переменную inifile типа TIniFile с нашим ini файлом INIFile:=TIniFile.Create(extractfilepath(application.ExeName)+'installlist.ini'); // создаем tstr:TStringList для хранения названия программ tstr:=TStringList.Create; // считываем названия прог в tstr inifile.ReadSections(tstr); // отображаем в filelist'е filelist.Items.AddStrings(tstr); // проверяем были ли до этого сохранены какие-нибудь данные (в случае //перезагрузки компа или его отключения до окончания операции установки) if fileexists(temppath+'\installlist.txt')=true then begin assignfile(f,temppath+'\installlist.txt'); reset(f); readln(f,s); while not eof(f) do begin readln(f,s); for i:=0 to filelist.count-1 do if filelist.Items.Strings[i]=s then filelist.Checked[i]:=true; end; closefile(f); end; end;
Как видно, данные о предшествующей загрузке будем хранить в txt файле. Если файл существует, то применяем соответствующие настройки. Теперь рассмотрим случай, когда понадобится сбросить выбор всех программ или же наоборот поставить в очередь сразу все проги. Вот для этого мы будем использовать allbutton и nonebutton: при нажатии на первую будут устанавливаться флажки, а на вторую сниматься. Пишем этот код:
procedure TInstallForm.AllButtonClick(Sender: TObject); var i:integer; begin for i:=0 to filelist.Count-1 do filelist.Checked[i]:=true; end; procedure TInstallForm.NoneButtonClick(Sender: TObject); var i:integer; begin for i:=0 to filelist.Count-1 do filelist.Checked[i]:=false; end;
Несложно, правда. Теперь займемся отображением описания каждой программы. Для этого код вот этот:
procedure TInstallForm.FileListClick(Sender: TObject); var def:string; begin textlist.Clear; textlist.LineS.add( inifile.ReadString(filelist.Items.strings[filelist.itemindex],'Text',def)); end;
Кстати, переменная inifile распространяется на всю нашу прогу. Здесь мы просто выводим в textlist, то что считали из ini файла (это происходит при клике по надписи выбранной строки). Ну, теперь опишем кнопку closebutton:
procedure TInstallForm.CloseButtonClick(Sender: TObject); var reg:tregistry; begin reg:=tregistry.Create; reg.RootKey:=HKEY_LOCAL_MACHINE; if reg.openkey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run',false)=true then begin reg.DeleteValue('AutoInstall') ; end; reg.CloseKey; reg.Destroy; deletefile(temppath+'\installlist.txt'); application.Terminate; end;
А что так много спросите вы? Казалось бы application.terminate и все, но не так все просто, а вот почему: дело в том, что если выход из программы корректен, то нам нужно удалить из реестра следы нами оставленные (оставим мы их только при незавершенных операция установки), или просто удостовериться, что их там нет(и рам и пользователю спокойно). Также удаляем файл с настройками. Почему application.terminate, а не installform.close, потому что мне полгода твердили в институте, что так правильнее (хотя кто как хочет). переходим к самому сложному в коде - описанию кнопки startbutton. Хотя если хоть немного читать и иметь под рукой MSDN и это несложно (сам проверял). Итак, пишем вот это:
procedure TInstallForm.StartButtonClick(Sender: TObject); var k,i:integer; def:string; f:textfile; reg:tregistry; pres:string; begin // сохраняем себя в реестре (на всякий случай) reg:=tregistry.Create; reg.RootKey:=HKEY_LOCAL_MACHINE; if reg.openkey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run',false)=true then begin pres:=reg.ReadString('AutoInstall'); if (pres='')or(pres<>application.exename) then if reg.CreateKey('AutoInstall')=true then reg.WriteString('AutoInstall',application.exename); end; reg.CloseKey; reg.Destroy; // минимизируемся showwindow(installform.Handle,2); // обрабатываем все отмеченные флаги по очереди for k:=0 to tstr.count-1 do begin // предварительно сохраняем настройки в installlist.txt assignfile(f,temppath+'\installlist.txt'); rewrite(f); for i:=0 to filelist.count-1 do if filelist.Checked[i]=true then writeln(f,filelist.items.strings[i]); closefile(f); if filelist.Checked[k]=true then begin filelist.Checked[k]:=false; StartAndWaitEnd(extractfilepath(application.ExeName)+ inifile.ReadString(tstr.Strings[k],'Path',def)); end; end; // после окончания операции устраняем себя из реестра reg:=tregistry.Create; reg.RootKey:=HKEY_LOCAL_MACHINE; if reg.openkey('SOFTWARE\Microsoft\Windows\CurrentVersion\Run',false)=true then begin reg.DeleteValue('AutoInstall') ; end; reg.CloseKey; reg.Destroy; // возвращаем окно к исходному виду и положению showwindow(installform.Handle,1); // убиваем файл с настройками deletefile(temppath+'\installlist.txt'); end;
Вот и все. А нет не все я еще не рассказал о функции StartAndWaitEnd. Она нужна для того, чтобы запустить приложение, передать ему управление и, дождавшись его закрытия, передать управление нашей проге для продолжения работы. Вот и код этой функции:
function TInstallForm.StartAndWaitEnd(cmdline:string):boolean; var si:TSTARTUPINFO; pi:TPROCESSINFORMATION; begin ZeroMemory(@si,sizeof(si)); si.cb:=SizeOf(si); si.dwFlags := startf_UseShowWindow; si.wShowWindow:=1; if not CreateProcess( nil,PChar(cmdline),nil,nil,False,0,nil,nil,si,pi ) then begin StartAndWaitEnd:=false; end else StartAndWaitEnd:=true; application.ProcessMessages; WaitForSingleObject( pi.hProcess, INFINITE ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); end;
Здесь CreatePorcess запускает выбранное приложение, а WaitForSingleObject ожидает, пока процесс завершится. Кто хочет знать больше - читайте MSDN, есть еще много всякой литературы по этому поводу. Вот теперь все!
Заключение
Это вроде все, но если кто знает способ по-лучше с удовольствием ознакомлясь. Не забудьте подключить модули Registry и IniFiles. Кстати, сама наша прога будет недоступна пока работает запущенное с помощью неё приложение (много пытался не получилось "оживить"), а так все работает корректно, а нажимать "да", "далее", "готово" придется все равно самому. Пишите комментарии, почитаю. Если у кого-то есть предложения (например, как и Abigor'а оставьте сообщение kosfiz'у или в комментарии опишите). Если у кого есть вопросы, то пишите мне на ящик, обязательно отвечу. Прошу прощение за возможные опечатки.
P.S. Abigor, ну как получилось?
Оставить комментарий
Комментарии
Примеры использования этих функций именно в сочетании с CreateProcess можно найти в том же Яндексе, набрав имя этой функции.
Описание доступнов MSDN.
Как всё круто, клёво, и ... сложно.
А зачем?
Я решил эту задачу примерно так:
MyInstal.bat
@echo off
echo УСТАНОВКА Power DVD 'это выводится на экран
del C:\WINDOWS\ГЛАВНО~1\ПРОГРА~1\АВТОЗА~1\7DVD.pif
REM удаление ярлыка со ссылкой на этот .bat из автозагрузки
copy C:\MYINSTAL\Programs\8Aditor.pif C:\WINDOWS\ГЛАВНО~1\ПРОГРА~1\АВТОЗА~1
REM ярлык в автозагрузку на следующий .bat , на случай если понадобится перезагрузка
D:\DVD\POWERD~5.062\setup.exe
pause После завершения установки Power DVD,
REM ожидание окончания установки проги
И ВСЁ!!!
в .pif стоит галка закрыть окно по завершению...
если прога установки однозначно выходит на рестарт, строка "pause После завершения установки..." не нужна. Если рестарт не нужен - аналогичный текст для следующей проги
если какую-то из программ не надо ставить - в ней самой есть кнопка "Отмена".
Тем более, что "нажимать "да", "далее", "готово" придется все равно самому"
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx
Вот в этом вся проблема. Зачем она нужна тогда?
crack_or_keygen =