我忘记了如何根据条件在Inno Setup中正确更新进度条,并且我编写了一个代码来更新我在向导中创建的进度条。
问题是,我为ProgressBar的最后一个位置获得了95,96,97,98或100,101,并且在我运行安装程序时,它的更新时间并不相同。我曾经划分的价值(这里是6)不会在所有系统上工作,因为它们的性能与每个系统非常不同。
我想知道一种正确更新进度条的方法,而不会出现这样的问题。
[Files]
Source: "C:\Program Files (x86)\Inno Setup 5\Examples\MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\InnoCallback.dll"; DestDir: "{app}"; Flags: ignoreversion
[Code]
Type
TTimerProc = procedure(HandleW, msg, idEvent, TimeSys: LongWord);
function SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc: LongWord): LongWord; external 'SetTimer@User32.dll stdcall';
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord; external 'wrapcallback@{tmp}\InnoCallback.dll stdcall delayload';
function KillTimer(hWnd, nIDEvent: LongWord): LongWord; external 'KillTimer@User32.dll stdcall';
var
TTimer: LongWord;
ConditionTracker: String;
P: Integer;
TestingPB: TNewProgressBar;
procedure Install;
var
ErrorCode: Integer;
begin
if ShellExec('Open', 'Timeout.exe', '/T 10', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode) = True then
ConditionTracker := 'DONE';
end;
procedure UpdateProgressBar(HandleW, msg, idEvent, TimeSys: LongWord);
begin
if ConditionTracker = 'DONE' then begin
KillTimer( 0, TTimer);
TestingPB.State := npbsPaused;
end else begin
P := P + 1;
Log('ProgressBar Position: ' + IntToStr(P div 6));
TestingPB.Position := P div 6;
if (P div 6) = 100 then P := 600;
end;
end;
procedure InitializeWizard;
begin
TestingPB := TNewProgressBar.Create(WizardForm);
with TestingPB do begin
Parent := WizardForm;
Width := WizardForm.ProgressGauge.Width;
Top := 200;
Left := (WizardForm.ClientWidth - Width) div 2;
Max := 100;
Position := 0;
Hide;
ExtractTemporaryFile('InnoCallback.dll');
P := 0;
end;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectTasks then begin
TestingPB.Show;
TTimer := SetTimer( 0, 0, 0, WrapTimerProc(@UpdateProgressBar, 4));
Install;
end else
TestingPB.Hide;
end;
提前致谢。
答案 0 :(得分:1)
两个主要问题是:
您没有设置计时器间隔(SetTimer
function的第三个参数)。该函数默认为USER_TIMER_MINIMUM
,即10 ms。一些机器可能太频繁,机器可能无法经常执行计时器。
因此,您可以在不同的机器上获得不同的结果。你代码中的神奇数字都是任意的。
在所有计算机上,每隔100秒执行一次计时器会严重浪费系统资源。
使用一些合理且可达到的频率(至少100毫秒,甚至更多)。
无论如何,您无法依赖定时器呼叫的频率。系统不保证您调用计时器。特别是,如果系统忙于大量安装过程,计时器将不可靠。
您应该基于实时计算。 GetTickCount
function通常用于此目的。请参阅How to get time difference in Inno Setup?
您的代码存在其他问题:
WizardForm.SelectTasksPage
)作为其父级。然后你不需要明确隐藏和显示它。ScaleX
和ScaleY
)
见Inno Setup Placing image/control on custom page。InnoCallback.dll
。请改用external '...k@files:InnoCallback.dll
声明。无需将其安装到{app}
(除非您稍后需要),请使用Flags: dontcopy
。ConditionTracker
应该是Boolean
,而不是string
。[Files]
Source: "InnoCallback.dll"; Flags: ignoreversion dontcopy
[Code]
type
TTimerProc = procedure(HandleW, msg, idEvent, TimeSys: LongWord);
function GetTickCount: DWord;
external 'GetTickCount@kernel32 stdcall';
function SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc: LongWord): LongWord;
external 'SetTimer@User32.dll stdcall';
function KillTimer(hWnd, nIDEvent: LongWord): LongWord;
external 'KillTimer@User32.dll stdcall';
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall delayload';
var
Timer: LongWord;
Done: Boolean;
TestingPB: TNewProgressBar;
InitialTime: DWord;
const
Duration = 10000;
procedure Install;
var
ErrorCode: Integer;
begin
if ShellExec('Open', 'Timeout.exe', '/T ' + IntToStr(Duration div 1000), '',
SW_HIDE, ewWaitUntilTerminated, ErrorCode) then
begin
Done := True;
end;
end;
procedure UpdateProgressBar(HandleW, msg, idEvent, TimeSys: LongWord);
begin
if Done then
begin
KillTimer(0, Timer);
TestingPB.State := npbsPaused;
TestingPB.Position := TestingPB.Max;
end
else
begin
TestingPB.Position := GetTickCount - InitialTime;
end;
end;
procedure InitializeWizard;
begin
TestingPB := TNewProgressBar.Create(WizardForm);
with TestingPB do
begin
Parent := WizardForm.SelectTasksPage;
Width := WizardForm.ProgressGauge.Width;
Left := WizardForm.ProgressGauge.Left;
Top := ScaleY(200);
Max := Duration;
Position := 0;
end;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectTasks then
begin
Timer := SetTimer(0, 0, 100, WrapTimerProc(@UpdateProgressBar, 4));
InitialTime := GetTickCount;
Install;
end
end;