Inno Setup - 自动提交卸载提示
Inno Setup - Automatically submitting uninstall prompts
我想隐藏卸载程序的第一条和最后一条消息。此代码适用于 inno setup 的修改版本(Inno Setup Ultra 5.5.1.ee2),但不能很好地隐藏第一条消息(短暂出现并消失):
function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: PansiChar): HWND;
external 'FindWindowExA@user32.dll stdcall';
const
BM_CLICK = [=10=]F5;
var
Timer: TTimer;
msg: string;
Wnd, WndEx: HWND;
procedure OnTimer(Sender: TObject);
begin
Wnd:= FindWindowByWindowName(msg);
if Wnd > 0 then
begin
WndEx:= FindWindowEx(Wnd, 0,'Button', '');
if WndEx > 0 then
begin
PostMessage(WndEx, BM_CLICK, 0, 0);
Timer.Enabled:= False;
end;
end;
end;
function InitializeUninstall:boolean;
begin
Result := True;
msg:= SetupMessage(msgUninstallAppFullTitle);
StringChange(msg, '%1', '{#SetupSetting('AppName')}');
OnTimer(nil);
Timer:= TTimer.Create(nil);
with Timer do
begin
OnTimer:= @OnTimer;
Interval:= 1;
Enabled:= True;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep=usPostUninstall then
begin
OnTimer(nil);
Timer:= TTimer.Create(nil);
with Timer do
begin
OnTimer:= @OnTimer;
Interval:= 1;
Enabled:= True;
end;
end;
end;
如何修改此代码以正确使用当前正式版本的 Inno Setup 并正确隐藏这两个消息?
首先,我必须说,我完全不同意这种说法。但无论如何这都是一个有趣的问题,该实现可能对其他更合适的情况有用。
也无法避免消息的短暂出现。该解决方案使 UI 自动化,因此需要 UI 才能工作。这也是我不喜欢它的原因之一。
[Setup]
AppName=My Program
[Code]
const
BM_CLICK = [=10=]F5;
function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: string): HWND;
external 'FindWindowExW@user32.dll 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';
var
UpcomingMessage: string;
SubmitMessageTimer: LongWord;
SubmitMessagePossible: Boolean;
procedure SubmitMessageProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
WindowHandle, ButtonHandle: HWND;
begin
{ TODO: Cancel the timer, if the message does not appear within few seconds }
WindowHandle := FindWindowByWindowName(UpcomingMessage);
if WindowHandle > 0 then
begin
Log(Format('Found message window "%s"', [UpcomingMessage]));
ButtonHandle := FindWindowEx(WindowHandle, 0, 'Button', '');
if ButtonHandle > 0 then
begin
Log('Found button');
PostMessage(ButtonHandle, BM_CLICK, 0, 0);
KillTimer(0, SubmitMessageTimer);
SubmitMessageTimer := 0;
end;
end;
end;
procedure SubmitUpcomingMessage(Msg: string);
begin
if not SubmitMessagePossible then
begin
Log('Cannot submit message');
end
else
begin
if SubmitMessageTimer > 0 then
KillTimer(0, SubmitMessageTimer);
Log(Format('Want to automatically submit message "%s"', [Msg]));
UpcomingMessage := Msg;
SubmitMessageTimer := SetTimer(0, 0, 100, CreateCallback(@SubmitMessageProc));
end;
end;
function FmtSetupMessageWithAppName(const ID: TSetupMessageID): string;
begin
Result := FmtMessage(SetupMessage(ID), ['{#SetupSetting('AppName')}']);
end;
function InitializeUninstall:boolean;
begin
Result := True;
SubmitMessagePossible :=
FileCopy(
ExpandConstant('{app}\InnoCallback.dll'),
ExpandConstant('{%TEMP}\InnoCallback.dll'), False);
SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
end;
end;
对于 CreateCallback
function,您需要 Inno Setup 6。
如果您受困于 Inno Setup 5,您可以使用 InnoTools InnoCallback library (the code needs Unicode version of Inno Setup 5). But using an external DLL library from an uninstaller is tricky and has its drawbacks. See 中的 WrapCallback
功能。
有关解决问题的不同方法,请参阅 Changing uninstall confirmation prompt。
我想隐藏卸载程序的第一条和最后一条消息。此代码适用于 inno setup 的修改版本(Inno Setup Ultra 5.5.1.ee2),但不能很好地隐藏第一条消息(短暂出现并消失):
function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: PansiChar): HWND;
external 'FindWindowExA@user32.dll stdcall';
const
BM_CLICK = [=10=]F5;
var
Timer: TTimer;
msg: string;
Wnd, WndEx: HWND;
procedure OnTimer(Sender: TObject);
begin
Wnd:= FindWindowByWindowName(msg);
if Wnd > 0 then
begin
WndEx:= FindWindowEx(Wnd, 0,'Button', '');
if WndEx > 0 then
begin
PostMessage(WndEx, BM_CLICK, 0, 0);
Timer.Enabled:= False;
end;
end;
end;
function InitializeUninstall:boolean;
begin
Result := True;
msg:= SetupMessage(msgUninstallAppFullTitle);
StringChange(msg, '%1', '{#SetupSetting('AppName')}');
OnTimer(nil);
Timer:= TTimer.Create(nil);
with Timer do
begin
OnTimer:= @OnTimer;
Interval:= 1;
Enabled:= True;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep=usPostUninstall then
begin
OnTimer(nil);
Timer:= TTimer.Create(nil);
with Timer do
begin
OnTimer:= @OnTimer;
Interval:= 1;
Enabled:= True;
end;
end;
end;
如何修改此代码以正确使用当前正式版本的 Inno Setup 并正确隐藏这两个消息?
首先,我必须说,我完全不同意这种说法。但无论如何这都是一个有趣的问题,该实现可能对其他更合适的情况有用。
也无法避免消息的短暂出现。该解决方案使 UI 自动化,因此需要 UI 才能工作。这也是我不喜欢它的原因之一。
[Setup]
AppName=My Program
[Code]
const
BM_CLICK = [=10=]F5;
function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: string): HWND;
external 'FindWindowExW@user32.dll 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';
var
UpcomingMessage: string;
SubmitMessageTimer: LongWord;
SubmitMessagePossible: Boolean;
procedure SubmitMessageProc(
H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
WindowHandle, ButtonHandle: HWND;
begin
{ TODO: Cancel the timer, if the message does not appear within few seconds }
WindowHandle := FindWindowByWindowName(UpcomingMessage);
if WindowHandle > 0 then
begin
Log(Format('Found message window "%s"', [UpcomingMessage]));
ButtonHandle := FindWindowEx(WindowHandle, 0, 'Button', '');
if ButtonHandle > 0 then
begin
Log('Found button');
PostMessage(ButtonHandle, BM_CLICK, 0, 0);
KillTimer(0, SubmitMessageTimer);
SubmitMessageTimer := 0;
end;
end;
end;
procedure SubmitUpcomingMessage(Msg: string);
begin
if not SubmitMessagePossible then
begin
Log('Cannot submit message');
end
else
begin
if SubmitMessageTimer > 0 then
KillTimer(0, SubmitMessageTimer);
Log(Format('Want to automatically submit message "%s"', [Msg]));
UpcomingMessage := Msg;
SubmitMessageTimer := SetTimer(0, 0, 100, CreateCallback(@SubmitMessageProc));
end;
end;
function FmtSetupMessageWithAppName(const ID: TSetupMessageID): string;
begin
Result := FmtMessage(SetupMessage(ID), ['{#SetupSetting('AppName')}']);
end;
function InitializeUninstall:boolean;
begin
Result := True;
SubmitMessagePossible :=
FileCopy(
ExpandConstant('{app}\InnoCallback.dll'),
ExpandConstant('{%TEMP}\InnoCallback.dll'), False);
SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
end;
end;
对于 CreateCallback
function,您需要 Inno Setup 6。
如果您受困于 Inno Setup 5,您可以使用 InnoTools InnoCallback library (the code needs Unicode version of Inno Setup 5). But using an external DLL library from an uninstaller is tricky and has its drawbacks. See WrapCallback
功能。
有关解决问题的不同方法,请参阅 Changing uninstall confirmation prompt。