Delphi. Установка программ через FTP.
24.01.2020Предистория: Не так давно мне необходимо было распространить на кучу компьютеров свеже-написанную программу, — очередную хотелку местного руковоства, но поскольку у нас все ПК находятся в домене, то соответсвенно и действуют доменные политики. Так вот, распространить программу на пару тысяч компьютеров через доменную политику не удалось, поскольку софтина не включена в некий реестр программ имеющих цетрализованную техподдержку, и соответсвенно в таком способе распространения мне было отказано. Но поскольку мы имеем местное начальство, считающее написанную программу остро необходимой всем работникам, то вынужден был в обход доменных политик распространять ее через FTP-сервер. Естественно, выполнять соединение с парой тысяч ПК через UltraVNC, — задача проблемная. К тому же пользователи не имеют прав админа и установка софта стандартным способом подсыпает немало проблем. Поэтому подготовил загрузчик, который попросту выкачивает с FTP-сервера готовый софт, заливая его на целевой компьютер. Далее опишу как я это сделал, заодно обойдя пару «подводных камней».
И так, определившись, что распространять буду через сервер FTP, начал стряпать мини-проект.
1. Форма с одной кнопкой, дабы не вызывать о пользователя лишних вопросов.
Как видно, на форме кроме кнопки имеется ProgressBar — дабы показать пользователю что процесс идет, а не «висит программа».
2. Для соединения с FTP-сервером был использован компонент Indy, соответсвенно секция uses содержит
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP
И поскольку для выбранного способа установки программы не будет автоматически создан ярлык на рабочем столе пользователя, необходимо объявить константы, которые нам пригодятся позже.
const SFolderKey = '\Software\Microsoft\Windows\CurrentVersion\' + 'Explorer\Shell Folders'; // ветка реестра, отвечающая за ярлыки. AppName = 'c:\problvop\prv.exe'; //приложение на которое будет ссылаться ярлык.
3. Функция, позволяющая создать ярлык, как на рабочем столе, так и добавлять его в в меню «Избранное», в автозагрузку, или же в ветку «Программы» меню «Пуск».
Не буду подробно описывать каждую строку функции, но для понимания ее работы, советую Вам изучить ее код. Возможно Вы ее оптимизируете:
function CreateShortcut(const ShortcutDir, CmdLine, Param, WorkDir,DirName: string; LinkFile:String): Boolean; var MyObject : IUnknown; MySLink : IShellLink; MyPFile : IPersistFile; WideFile : WideString; Directory, TempStr: String; Reg:TRegistry; begin Result:=False;Directory:=''; If (ShortcutDir='Desktop') or (ShortcutDir='Favorites') or (ShortcutDir='Programs') or (ShortcutDir='SendTo') or (ShortcutDir='Start Menu') or (ShortcutDir='Startup') then begin Reg:=TRegistry.Create; Reg.OpenKey('Software\MicroSoft\Windows\CurrentVersion\Explorer\Shell Folders',False); Directory := Reg.ReadString(ShortcutDir); Reg.Free; If not(DirName='') then Directory:=Directory+'\'+DirName; end; If linkFile='' then Exit; TempStr:=linkFile; If Length(linkFile)>4 then Delete(TempStr,1,Length(TempStr)-3); If not(AnsiUpperCase(TempStr)='LNK') then linkFile:=linkFile+'.lnk'; MyObject := CreateComObject(CLSID_ShellLink); MySLink := MyObject as IShellLink; MyPFile := MyObject as IPersistFile; with MySLink do begin SetPath(PChar(CmdLine)); SetArguments(PChar(Param)); SetWorkingDirectory(PChar(WorkDir)); end; if Directory[Length(Directory)]='\' then WideFile := Directory+LinkFile else WideFile := Directory+'\'+LinkFile; if MyPFile.Save(PWChar(WideFile), False)= S_OK then Result:=True; end;
4. Ну и собственно сам процесс загрузки файлов и создания ярлыка. Поскольку у нас ограниченные права пользователя, то создание каталога программы без прав админа, запуском setup.exe невозможно, а вручную пользователь создать папки может, то имитируем пользовательскую операцию.
Будем создавать каталог «problvop» и заливать в него необходимые файлы, а после и создавать ярлык. Вот и дошли до обработчика нажатия единственной кнопки:
procedure TForm1.Button1Click(Sender: TObject); var si: TSTARTUPINFO; pif: PROCESS_INFORMATION; begin button1.Enabled:=false; si.cb := SizeOf(tstartupinfo); si.dwFlags := STARTF_USESHOWWINDOW; si.wShowWindow := SW_SHOWDEFAULT; si.lpReserved := nil; si.lpDesktop := nil; si.lpTitle := nil; if DirectoryExists('c:\problvop')=false then CreateDir('c:\problvop'); idFtp1.Host:='10.110.29.58'; (*передача адреса*) idFtp1.Username:='anonymous'; (*передача логина*) idFtp1.Password:=''; (*передача пароля*) idFtp1.Port:=21; idFtp1.Passive:=True; idFtp1.Connect; if idFtp1.Connected then begin Label1.Caption:='Установлено соединение с сервером'; pb.Position:=10; // Это позиция ProgressBar //закачка с фтп всех необходимых файлов idFtp1.ChangeDir('/upload/DISTR/problvop/'); pb.Position:= 20; idFtp1.Get('upd.ini','c:\problvop\upd.ini',True); pb.Position:= 30; idFtp1.Get('Acryl.asz','c:\problvop\Acryl.asz',True); pb.Position:= 40; idFtp1.Get('iphist.dat','c:\problvop\iphist.dat',True); pb.Position:= 50; idFtp1.Get('istr_prv.pdf','c:\problvop\istr_prv.pdf',True); pb.Position:= 60; idFtp1.Get('libmysql.dll','c:\problvop\libmysql.dll',True); pb.Position:= 70; idFtp1.Get('prv.exe','c:\problvop\prv.exe',True); pb.Position:= 80; idFtp1.Get('upd.exe','c:\problvop\upd.exe',True); pb.Position:= 99; //конец закачки с фтп // создание ярлыка на рабочий стол pb.Position:= 100; CreateShortcut( 'Desktop', 'c:\problvop\prv.exe', '', 'c:\problvop\', '', 'Проблемные вопросы'); //конец создания ярлыка end else begin Label1.Caption:='Невозможно установить соединение с сервером'; end; // И не забываем разорвать соединение с сервером, и завершить работу загрузчика. idFtp1.Disconnect; application.Terminate; end;
Вот собственно и всё. Как видите нет ничего сложного.