Показать полную графическую версию : Скрипты Inno Setup. Помощь и советы [часть 6]
Приветствую!
Подскажите, можно ли создать страницу в инсталляторе, чтобы она отображалась после распаковки приложения?
Я сделал как в help, но не знаю как ее отобразить после распаковки
DBPage := CreateInputQueryPage(wpReady,
'Информация для соединения с базой данных MySQL', '',
'Введите данные для соединения с сервером и нажмите далее.');
Конечная цель - это распаковать программу, на странице DBPage попросить пользователя ввести данные для подключения к MySQL, далее занести эти данные в ini файл и проверить соединение с базой MySQL по введенным данным. И второй вопрос, как можно осуществить проверку успешного соединения с базой?
laboart, кастомная страницы после страницы прогресса установки:
DBPage := CreateInputQueryPage(wpInstalling, 'Информация для соединения с базой данных MySQL', '', 'Введите данные для соединения с сервером и нажмите далее.');
R.i.m.s.k.y., спасибо, экая я невнимательная:)
Вопрос появился. На этапе инсталляции пользователь вводит какие-то значения, которые дальше используются (с помощью Scripted Constants). Можно ли до этих значений (конкретно тех, что ввел пользователь) доступиться при деинсталляции?
Johny777
03-09-2013, 14:59
Shkutu,
данные лучше хранить в реестре, понятное дело к ним есть доступ пока есть ключ.
как "На этапе инсталляции пользователь вводит какие-то значения"?
можешь показать код?
тогда может смогу написать соответствующий пример
Данные должны сохраняться сразу после ввода?
вот небольшой пример работы с реестром на чистом WinApi http://forum.oszone.net/post-2201802.html#post2201802
если тебе его не хватит, то скажи. Попробую сделать
Johny777, ввод значений так:
[Code]
procedure AskInstanceName();
begin
Instancepage:= CreateInputQueryPage(wpSelectComponents,
ExpandConstant('{cm:InstName}'), ExpandConstant('{cm:InstFolderName}'),
ExpandConstant('{cm:ChooseInstFolderName}'));
Instancepage.Add(ExpandConstant('{cm:InstName}'), false);
if ActiveLanguage = 'russian' then
Instancepage.Values[0]:= ExpandConstant('{#InstanceNameRus}')
else Instancepage.Values[0]:= ExpandConstant('{#InstanceName}');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var b: boolean;
path:string;
RunModeIdx:integer;
begin
if (CurPageID=Instancepage.ID) then
begin
if ((RegKeyExists(HKEY_LOCAL_MACHINE, 'Software\UCS\instances\' + Instancepage.Values[0]))
and (DirExists(ExpandConstant('{app}')+'\UCS\'+Instancepage.Values[0]+'\Rk7Reference')))
then
begin
MsgBox(ExpandConstant('{cm:InstNameErr}'), mbInformation, MB_OK);
result:=false;
end
else
begin
Instancename:= Instancepage.Values[0];
path:=ExpandConstant('{app}\UCS\')+Instancename+'\Rk7Reference\';
//b:=ForceDirectories(path);
RefBasePath :=path+'base';
BasePathPage.Values[0] := RefBasePath;
result:=true;
end;
end
...
end;
function GetInstancename(param:string):string;
begin
if Instancename='' then
if ActiveLanguage = 'russian' then
Instancename:= ExpandConstant('{#InstanceNameRus}')
else Instancename:= ExpandConstant('{#InstanceName}');
result:=Instancename;
end;
Данные не просто сохраняются после ввода, а используются при установке в именах папок, ини файлах и т д
С реестром не получится, т к значения в него пишутся тоже с учетом того, что ввел пользователь, т е
[Registry]
Root: "HKLM"; Subkey: "Software\UCS\instances\{code:GetInstanceName}"; ValueType: string; ValueName: "path"; ValueData: "{app}\UCS\{code:GetInstanceName}"
Вот и получается, что на момент деинсталляции не понятно (мне, по крайней мере), как доступиться до нужных данных, чтобы как раз удалить ненужные ключи реестра и ini файлы.
UPD. И еще нет ли какого-нибудь примера про то, как можно добавить форму к деинсталлятору (в InitializeUninstallProgressForm наверное)? А то у меня что-то толком не получается это сделать, а примеров на эту тему вообще не нашла (
El Sanchez
03-09-2013, 19:24
С реестром не получится, т к значения в него пишутся тоже с учетом того, что ввел пользователь »
Shkutu, вы в реестр пишете свои данные не для мусора ради, а чтобы эти данные потом использовать. При деинсталляции вызывайте функцию RegGetSubkeyName, чтобы получить массив всех instances, потом в цикле перебираете и делаете черные дела.
реестр пишете свои данные не для мусора ради »
Естественно, чтобы использовать - лицензии проверять например.
цикле перебираете »
Мне же не все инстансы (которых может быть целая куча) удалять надо, а какой-то конкретный. Собственно вопрос как раз в том, как этот самый конкретный определить.
Johny777
03-09-2013, 20:22
Shkutu,
а какой-то конкретный »
просто сохраняй имя инстансы в директории установки в текстовом файле, и когда надо считывай из него текст. В качестве защиты от дурака скрой его
вот накатал функции сохранения текста в файле и чтения оттуда. Они на чистом WinApi
#define A = (Defined UNICODE) ? "W" : "A"
const
OPEN_ALWAYS = 4;
GENERIC_READ = $80000000;
GENERIC_WRITE = $40000000;
FILE_SHARE_READ = $00000001;
FILE_SHARE_WRITE = $00000002;
OPEN_EXISTING = 3;
TRUNCATE_EXISTING = 5;
INVALID_HANDLE_VALUE = -1;
OFS_MAXPATHNAME = 128;
type
Pointer = Longint;
POverlapped = Pointer;
PSecurityAttributes = Pointer;
function CreateFile(lpFileName: String; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition,
dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; external 'CreateFile{#A}@Kernel32.dll stdcall';
function WriteFile(hFile: THandle; const Buffer: Pointer; nNumberOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD;
lpOverlapped: POverlapped): BOOL; external 'WriteFile@Kernel32.dll stdcall';
function ReadFile(hFile: THandle; Buffer: Pointer; nNumberOfBytesToRead: DWORD;
var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; external 'ReadFile@Kernel32.dll stdcall';
function GetFileSize(hFile: THandle; lpFileSizeHigh: Pointer): DWORD; external 'GetFileSize@Kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle@kernel32.dll stdcall';
function GetTextFromFile(const FileName: String; out Text: String): Boolean;
var
dwBytesRead: DWORD;
FileSize: DWORD;
hFile: THandle;
begin
hFile := CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
Result := hFile <> INVALID_HANDLE_VALUE;
if Result then
try
FileSize := GetFileSize(hFile, 0);
SetLength(Text, FileSize);
Result := ReadFile(hFile, CastStringToInteger(Text), FileSize, dwBytesRead, 0);
finally
CloseHandle(hFile);
end;
end;
function SaveTextToFile(const FileName, Text: String): Boolean;
var
dwByteWritten: DWORD;
hFile: THandle;
begin
hFile := CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_ALWAYS or TRUNCATE_EXISTING, 0, 0);
Result := hFile <> INVALID_HANDLE_VALUE;
if Result then
try
Result := WriteFile(hFile, CastStringToInteger(Text), Length(Text), dwByteWritten, 0);
finally
CloseHandle(hFile);
end;
end;
procedure InitializeWizard();
var
S: String;
begin
if SaveTextToFile('C:\file.txt', 'Shkutu') then
if GetTextFromFile('C:\file.txt', S) then
MsgBox(S, mbInformation, MB_OK);
end;
у меня нет доверия к встроенным
SaveString(s)ToFile
LoadString(s)FromFile
но если хочешь воспользуйся ими
или пиши своё собственное значение в реестр с именем инстансы только для самой себя, и читай её в деинсталяторе
как можно добавить форму к деинсталлятору »
объясни лучше на словах как оно должно выглядеть. Может не форму а страницу типа той которую ты создаёшь у себя в коде?
А то я честно говоря не знаю что мне писать :)
El Sanchez, раз уж ты здесь можешь пожалуйста проверить правильность моих функций SaveTextToFile и GetTextFromFile. Как бы я с флагами не напутал, хотя всё работает, но фиг знает
El Sanchez
03-09-2013, 20:54
а какой-то конкретный »
Shkutu, какой? У вас в распоряжении полный список instances, не знаете какой выбрать? Кстати, где лежит деинсталлятор?
правильность моих функций SaveTextToFile и GetTextFromFile. Как бы я с флагами не напутал, хотя всё работает, но фиг знает »
Johny777, сойдет.
El Sanchez, да, полный список инстансов вытащить из реестра можно при желании, но вот выбрать конкретный действительно не могу.
Кстати, где лежит деинсталлятор? »
Деинсталлятор кладу в ту же папку, куда устанавливается экземпляр программы. Думала, что с этим учетом получится вытащить хотя бы имя папки с помощью GetCurrentDir, но он почему-то вернул C:\Windows\System32.
просто сохраняй имя инстансы в директории установки в текстовом файле, »
Эта идея тоже в голову приходила. Но если есть директория, то имя инстанса я и так могу вытащить (из реестра например). Но инстансов может быть сколько угодно и ставится они могу куда угодно, причем имя папки установки получается с учетом имени пользователя (такой вот извращенный способ, но идея не моя), поэтому вытащить нужный файлик тоже не получается.
словах как оно должно выглядеть. Может не форму а страницу »
Просто подумала, что можно сделать типа универсальный инсталлятор, чтобы пользователь сам выбирал имя инстанса - раз уж у меня не получается его вытащить. Так что выглядеть это должно как форма с выпадающим списком инстансов, например. Насчет страницы - можно было бы. Но разве можно создавать такую для деинсталлятора? Там же указывается ид страницы, после которой кастомная страница должна идти, а у деинсталлятора никаких страниц нет.
Dinvin4ester
05-09-2013, 11:04
Ребята помогите пожалуйста . Вот скрипт - http://multi-up.com/900429 , но не видно прогресс бара (как устанавливается,строки) и еще бы хотелось музыку прописать . Буду рад помощи ..
El Sanchez
05-09-2013, 11:16
полный список инстансов вытащить из реестра можно при желании, но вот выбрать конкретный действительно не могу »
Shkutu, тогда вы пишете в реестр мусор.
Деинсталлятор кладу в ту же папку, куда устанавливается экземпляр программы. »
Shkutu, вы все правильно сделали, это от вас я и хотел услышать. В каждой копии программы по деинсталлятору, удаляющего только саму копию и не трогая остальные. Только каждый из деинсталляторов должен быть готовым к удалению не только своей копии, но и родительской директории UCS, если он остался последним среди удаленных копий. Тоже самое и с реестром. Удаление файлов организовать через [UninstallDelete], удаление реестровых записей через [Registry] с нужными флагами:
[UninstallDelete]
Type: filesandordirs; Name: {app}\UCS\instances\{code:GetInstanceName}
Type: dirifempty; Name: {app}\UCS\instances
Type: dirifempty; Name: {app}\UCS
[Registry]
Root: HKLM; Subkey: SOFTWARE\UCS; Flags: uninsdeletekeyifempty
Root: HKLM; Subkey: SOFTWARE\UCS\instances; Flags: uninsdeletekeyifempty
Root: HKLM; Subkey: SOFTWARE\UCS\instances\{code:GetInstanceName}; Flags: uninsdeletekeyifempty
Root: HKLM; Subkey: SOFTWARE\UCS\instances\{code:GetInstanceName}; ValueType: string; ValueName: path; ValueData: {app}\UCS\{code:GetInstanceName}; Flags: uninsdeletevalue
деинсталлятора никаких страниц нет. »
Формы инсталлятора и деинсталлятора похожи и обе имеют страничный компонент TNewNotebook, так что ничто не мешает для деинсталлятора добавить свои страницы, только строить их с нуля нужно, шаблоны-функции Create*Page - это не для деинсталлятора. Вот пример, создается пустая страница, кнопка Далее для перехода на следующую страницу (если выборочных страниц больше одной делать, то необходима еще кнопка Назад), стандартная страница с прогрессом должна быть последней:
//////////////////////////////////////////////////
procedure UninsNextButtonOnClick(Sender: TObject);
begin
with UninstallProgressForm.InnerNotebook do
begin
ActivePage := Pages[ActivePage.PageIndex + 1]; // go to next page
if ActivePage.PageIndex = PageCount-1 then // on last page...
begin
TButton(Sender).Hide; // ...hide Next button...
UninstallProgressForm.Close; // ...and close modal form
end;
end;
end;
////////////////////////////////////////////////////
procedure UninsCancelButtonOnClick(Sender: TObject);
begin
UninstallProgressForm.ModalResult := mrAbort;
end;
////////////////////////////////////////////
procedure InitializeUninstallProgressForm();
var
Page: TNewNotebookPage;
UninsNextButton: TButton;
begin
with UninstallProgressForm do
begin
// create Next button
UninsNextButton := TButton.Create(UninstallProgressForm);
with UninsNextButton do
begin
Parent := UninstallProgressForm;
Top := UninstallProgressForm.CancelButton.Top;
Width := UninstallProgressForm.CancelButton.Width;
Height := UninstallProgressForm.CancelButton.Height;
Left := UninstallProgressForm.CancelButton.Left - Width - ScaleX(10);
Caption := SetupMessage(msgButtonNext);
OnClick := @UninsNextButtonOnClick;
end;
// modify Cancel button
CancelButton.Enabled := True;
CancelButton.OnClick := @UninsCancelButtonOnClick;
// create custom page
Page := TNewNotebookPage.Create(UninstallProgressForm);
with Page do
begin
Parent := UninstallProgressForm.InnerNotebook;
Notebook := UninstallProgressForm.InnerNotebook;
PageIndex := 0; // first page
end;
// set active (first) page
InnerNotebook.ActivePage := InnerNotebook.Pages[0];
// default page to last page
InstallingPage.PageIndex := InnerNotebook.PageCount-1;
// show form
if ShowModal = mrAbort then Abort;
end;
end;
Dinvin4ester ты используеш внутреное сжатие inno setup а скрипт от isdone потому и не работает
пример http://rghost.ru/48577915
Dinvin4ester
05-09-2013, 17:38
vint56,
Огромное спасибо за помощь .
El Sanchez, спасибо, буду пробовать
Привет. И снова вопрос. Можно ли закрыть окно инсталляции из кода, но без вывода стандартного диалога "хотите ли вы прервать процесс установки.. да/нет" (как это происходит при использовании wizardform.close())? Или у wizardform.close() отключить вывод этого самого диалога?
Johny777
06-09-2013, 16:42
Shkutu, можно
в процедуре CancelButtonClick() в булев переменную Confirm пишешь False, чтоб не было диалога подтверждения, а в Cancel - True, чтоб прервать работу инсталла
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
Confirm := False;
Cancel := True;
end;
если тебе это нужно только во время установки то нужна проверка
if CurPageID = wpInstalling then
begin
Confirm := False;
Cancel := True;
end;
Johny777, то, что нужно, спасибо за помощь!:)
wertulll
06-09-2013, 19:21
Ребят извеняюсь конечно за вопрос но может ктонибудь поможет ?собрал себе скрипт из разных примеров на основе ISDone всё вроди работает нормально вот только кажется мне что он какойта запутаный получился(можете глянуть пожалуйста может его можно както попроше можно реализовать ? http://rghost.ru/48601229
insombia
08-09-2013, 17:22
wertulll нормальный там код,ты мой в некоторых скриптах не видел :happy:
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC