Johny777
19-01-2013, 15:11
R.i.m.s.k.y., на этапе ssDone WizardForm.RunList уже не существует и соответственно будут ошибки, придётся работать только с переменными
Vstanka, предлагаю такой способ:
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DirExistsWarning=no
DefaultDirName={pf}\My Program
[Components]
Name: server; Description: Install Server; Types: full custom;
[ code]
#ifdef UNICODE
#define A "W"
#else
#define A "A"
#endif
type
RUNLIST_BOOL_COLLECTION = record
Application: BOOL;
Server: BOOL;
end;
var
Run: RUNLIST_BOOL_COLLECTION;
const
QS_KEY = $0001;
QS_MOUSEMOVE = $0002;
QS_MOUSEBUTTON = $0004;
QS_POSTMESSAGE = $0008;
QS_TIMER = $0010;
QS_PAINT = $0020;
QS_SENDMESSAGE = $0040;
QS_HOTKEY = $0080;
QS_MOUSE = (QS_MOUSEMOVE or QS_MOUSEBUTTON);
QS_INPUT = (QS_MOUSE or QS_KEY);
QS_ALLEVENTS = (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT or QS_HOTKEY);
QS_ALLINPUT = (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT or QS_HOTKEY or QS_SENDMESSAGE);
STATUS_TIMEOUT = $00000102;
WAIT_TIMEOUT = STATUS_TIMEOUT;
function MsgWaitForMultipleObjects(nCount: DWORD; var pHandles: THandle; fWaitAll: BOOL; dwMilliseconds, dwWakeMask: DWORD): DWORD; external 'MsgWaitForMultipleObjects@user32.dll stdcall';
function CreateEvent(lpEventAttributes: Longint; bManualReset, bInitialState: BOOL; lpName: PChar): THandle; external 'CreateEvent{#A}@kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle@kernel32.dll stdcall';
function GetTickCount: DWORD; external 'GetTickCount@kernel32.dll stdcall';
function SetWindowText(hWnd: HWND; lpString: String): BOOL; external 'SetWindowText{#A}@user32.dll stdcall';
function StrFromTimeInterval(var pszOut: Char; cchMax: UINT; dwTimeMS: DWORD; digits: Byte): Integer; external 'StrFromTimeIntervalA@shlwapi.dll stdcall';
function TicksToTime(Ticks: DWORD): String;
var
i: Byte;
arr: array [0..31] of Char;
begin
for i := 0 to StrFromTimeInterval(arr[0], sizeof(arr), Ticks, 8)-1 do Result := Result + arr[i];
end;
procedure Delay(dwMilliseconds: DWORD; hElapstedTimeInfo: HWND);
var
dwTick: DWORD;
hEvent: THandle;
begin
hEvent := CreateEvent(0, False, False, '');
try
dwTick := GetTickCount + dwMilliseconds;
while (dwMilliseconds > 0) and (MsgWaitForMultipleObjects(1, hEvent, False, dwMilliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
begin
Application.ProcessMessages;
dwMilliseconds := dwTick - GetTickCount;
if hElapstedTimeInfo <> 0 then SetWindowText(hElapstedTimeInfo, 'запуск приложения через' + TicksToTime(dwMilliseconds));
end;
finally
CloseHandle(hEvent);
end;
end;
procedure RunListOnClickCheck(Sender: TObject);
begin
with WizardForm.RunList do if (Items.IndexOf('запуск приложения') <> -1) and (Items.IndexOf('запуск сервера БД') <> -1) then
begin
ItemEnabled[Items.IndexOf('запуск приложения')] := Checked[Items.IndexOf('запуск сервера БД')];
Refresh;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
ErrorCode: Integer;
WaitingForm: TForm;
StaticText: TNewStaticText;
begin
if CurStep = ssDone then
begin
if Run.Server then Exec(ExpandConstant('{app}\server.exe'), '', ExpandConstant('{app}'), SW_SHOW, ewNoWait, ErrorCode);
if Run.Application then
begin
WaitingForm := TForm.Create(nil);
with WaitingForm do
begin
ClientWidth := ScaleX(200);
ClientHeight := ScaleY(50);
Position := PoscreenCenter;
BorderStyle := bsDialog;
Caption := 'Waiting';
StaticText := TNewStaticText.Create(WaitingForm)
with StaticText do
begin
Parent := WaitingForm;
SetBounds(ScaleX(10), ScaleY(20), ScaleX(180), ScaleY(20));
end;
Show;
Delay(20000, StaticText.Handle);
end;
WaitingForm.Free;
Exec(ExpandConstant('{app}\hl.exe'), '', ExpandConstant('{app}'), SW_SHOW, ewNoWait, ErrorCode);
end;
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if (CurPageID = wpFinished) then with WizardForm.RunList do
begin
if (Items.IndexOf('запуск приложения') <> -1) and (Items.IndexOf('запуск сервера БД') <> -1) then
begin
Run.Server := Checked[Items.IndexOf('запуск сервера БД')];
Run.Application := ItemEnabled[Items.IndexOf('запуск приложения')] and Checked[Items.IndexOf('запуск приложения')];
Items.Delete(Items.IndexOf('запуск сервера БД'));
Items.Delete(Items.IndexOf('запуск приложения'));
Result := True;
end;
end else Result := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if (CurPageID = wpFinished) and IsComponentSelected('server') then with WizardForm.RunList do
begin
AddCheckBox('запуск сервера БД', '', 0, True, True, False, False, nil);
AddCheckBox('запуск приложения', '', 0, True, True, False, False, nil);
WizardForm.RunList.OnClickCheck := @RunListOnClickCheck;
Refresh;
Visible := True;
end;
end;
к тому же заметил аномалию: если вручную добавить айтемы в RunList и установить в них галки, то при разрушении WizardForm ошибки, что их нет, поэтому их нужно удалить до деинициализации
Vstanka, предлагаю такой способ:
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DirExistsWarning=no
DefaultDirName={pf}\My Program
[Components]
Name: server; Description: Install Server; Types: full custom;
[ code]
#ifdef UNICODE
#define A "W"
#else
#define A "A"
#endif
type
RUNLIST_BOOL_COLLECTION = record
Application: BOOL;
Server: BOOL;
end;
var
Run: RUNLIST_BOOL_COLLECTION;
const
QS_KEY = $0001;
QS_MOUSEMOVE = $0002;
QS_MOUSEBUTTON = $0004;
QS_POSTMESSAGE = $0008;
QS_TIMER = $0010;
QS_PAINT = $0020;
QS_SENDMESSAGE = $0040;
QS_HOTKEY = $0080;
QS_MOUSE = (QS_MOUSEMOVE or QS_MOUSEBUTTON);
QS_INPUT = (QS_MOUSE or QS_KEY);
QS_ALLEVENTS = (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT or QS_HOTKEY);
QS_ALLINPUT = (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT or QS_HOTKEY or QS_SENDMESSAGE);
STATUS_TIMEOUT = $00000102;
WAIT_TIMEOUT = STATUS_TIMEOUT;
function MsgWaitForMultipleObjects(nCount: DWORD; var pHandles: THandle; fWaitAll: BOOL; dwMilliseconds, dwWakeMask: DWORD): DWORD; external 'MsgWaitForMultipleObjects@user32.dll stdcall';
function CreateEvent(lpEventAttributes: Longint; bManualReset, bInitialState: BOOL; lpName: PChar): THandle; external 'CreateEvent{#A}@kernel32.dll stdcall';
function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle@kernel32.dll stdcall';
function GetTickCount: DWORD; external 'GetTickCount@kernel32.dll stdcall';
function SetWindowText(hWnd: HWND; lpString: String): BOOL; external 'SetWindowText{#A}@user32.dll stdcall';
function StrFromTimeInterval(var pszOut: Char; cchMax: UINT; dwTimeMS: DWORD; digits: Byte): Integer; external 'StrFromTimeIntervalA@shlwapi.dll stdcall';
function TicksToTime(Ticks: DWORD): String;
var
i: Byte;
arr: array [0..31] of Char;
begin
for i := 0 to StrFromTimeInterval(arr[0], sizeof(arr), Ticks, 8)-1 do Result := Result + arr[i];
end;
procedure Delay(dwMilliseconds: DWORD; hElapstedTimeInfo: HWND);
var
dwTick: DWORD;
hEvent: THandle;
begin
hEvent := CreateEvent(0, False, False, '');
try
dwTick := GetTickCount + dwMilliseconds;
while (dwMilliseconds > 0) and (MsgWaitForMultipleObjects(1, hEvent, False, dwMilliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
begin
Application.ProcessMessages;
dwMilliseconds := dwTick - GetTickCount;
if hElapstedTimeInfo <> 0 then SetWindowText(hElapstedTimeInfo, 'запуск приложения через' + TicksToTime(dwMilliseconds));
end;
finally
CloseHandle(hEvent);
end;
end;
procedure RunListOnClickCheck(Sender: TObject);
begin
with WizardForm.RunList do if (Items.IndexOf('запуск приложения') <> -1) and (Items.IndexOf('запуск сервера БД') <> -1) then
begin
ItemEnabled[Items.IndexOf('запуск приложения')] := Checked[Items.IndexOf('запуск сервера БД')];
Refresh;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
ErrorCode: Integer;
WaitingForm: TForm;
StaticText: TNewStaticText;
begin
if CurStep = ssDone then
begin
if Run.Server then Exec(ExpandConstant('{app}\server.exe'), '', ExpandConstant('{app}'), SW_SHOW, ewNoWait, ErrorCode);
if Run.Application then
begin
WaitingForm := TForm.Create(nil);
with WaitingForm do
begin
ClientWidth := ScaleX(200);
ClientHeight := ScaleY(50);
Position := PoscreenCenter;
BorderStyle := bsDialog;
Caption := 'Waiting';
StaticText := TNewStaticText.Create(WaitingForm)
with StaticText do
begin
Parent := WaitingForm;
SetBounds(ScaleX(10), ScaleY(20), ScaleX(180), ScaleY(20));
end;
Show;
Delay(20000, StaticText.Handle);
end;
WaitingForm.Free;
Exec(ExpandConstant('{app}\hl.exe'), '', ExpandConstant('{app}'), SW_SHOW, ewNoWait, ErrorCode);
end;
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if (CurPageID = wpFinished) then with WizardForm.RunList do
begin
if (Items.IndexOf('запуск приложения') <> -1) and (Items.IndexOf('запуск сервера БД') <> -1) then
begin
Run.Server := Checked[Items.IndexOf('запуск сервера БД')];
Run.Application := ItemEnabled[Items.IndexOf('запуск приложения')] and Checked[Items.IndexOf('запуск приложения')];
Items.Delete(Items.IndexOf('запуск сервера БД'));
Items.Delete(Items.IndexOf('запуск приложения'));
Result := True;
end;
end else Result := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if (CurPageID = wpFinished) and IsComponentSelected('server') then with WizardForm.RunList do
begin
AddCheckBox('запуск сервера БД', '', 0, True, True, False, False, nil);
AddCheckBox('запуск приложения', '', 0, True, True, False, False, nil);
WizardForm.RunList.OnClickCheck := @RunListOnClickCheck;
Refresh;
Visible := True;
end;
end;
к тому же заметил аномалию: если вручную добавить айтемы в RunList и установить в них галки, то при разрушении WizardForm ошибки, что их нет, поэтому их нужно удалить до деинициализации