NSIS:如何允许 select 部分安装的多个用户选择屏幕?
NSIS: How do I allow multiple user choice screens that select the sections to install?
我正在尝试创建一个安装程序,它会询问用户一系列问题来决定安装哪些组件。每个选择(可能)都会影响以后选择中的可用选项(否则我只会做一个普通的组件页面——我不想给用户无效的选项)。
我如何完成这样的事情?如果我只使用组件页面,则会显示所有选项,其中一些组合是完全无效的。我不想让用户 select 那些。 是否可以省略组件页面?
这是我正在尝试的最小工作示例。 (对不起,太长了,我真的没法简化对话代码。)
!include nsDialogs.nsh
!include Sections.nsh
Name "mwe"
OutFile "mwe.exe"
InstallDir C:\mwe
Var hwnd
Var Level1Opt
Page custom SelectLevel1Opt ProcessLevel1
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hwnd
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop $hwnd
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 A"
${NSD_OnClick} $hwnd SetLevel1
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 B"
${NSD_OnClick} $hwnd SetLevel1
nsDialogs::Show
FunctionEnd
Function SetLevel1
Pop $hwnd
nsDialogs::GetUserData $hwnd
Pop $Level1Opt
MessageBox MB_OK "Selected: $Level1Opt"
FunctionEnd
Function ProcessLevel1
${If} $Level1Opt == "Level 1 A"
!insertmacro SelectSection Level1A
${ElseIf} $Level1Opt == "Level 1 B"
!insertmacro SelectSection Level1B
${EndIf}
FunctionEnd
Page directory
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
无论我选择什么,Level1A
和 Level1B
部分都不会得到 运行。对话框中的 selection 在处理程序和 post 函数中被正确检测到。但是,select 编辑这些部分并不会导致它们 运行。即使我添加了一个组件页面,它们都不是 selected.
我查看了 Selection.nsh
,它引用的示例 (one-section.nsi) 并没有真正按照我的要求执行,因为它使用了组件页面。 (我也不太明白它是如何工作的。)
我做错了什么?我以何种方式误解了 NSIS 的工作方式?
正如 idleberg 所说,正确的语法是 !insertmacro SelectSection ${Level1A}
但您会收到警告,因为在您的 .nsi 中它的 Section
指令之后才定义节 ID。您需要将使用 ${Level1A}
的函数移至源代码部分下方:
!include nsDialogs.nsh
!include Sections.nsh
Page custom SelectLevel1Opt ProcessLevel1
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "a" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "b" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
Var hInnerDialog
Var hL1A
Var hL1B
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hInnerDialog
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop [=10=]
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hL1A
nsDialogs::SetUserData $hL1A ${Level1A} ; Only used by the generic function
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hL1B
nsDialogs::SetUserData $hL1B ${Level1B} ; Only used by the generic function
nsDialogs::Show
FunctionEnd
Function ProcessLevel1
${NSD_GetState} $hL1A
${If} <> ${BST_UNCHECKED}
!insertmacro SelectSection ${Level1A}
!insertmacro UnselectSection ${Level1B}
${Else}
!insertmacro SelectSection ${Level1B}
!insertmacro UnselectSection ${Level1A}
${EndIf}
FunctionEnd
ProcessLevel1函数如果单选按钮很多也可以循环实现:
Function ProcessLevel1
StrCpy [=11=] ""
loop:
FindWindow [=11=] "${__NSD_RadioButton_CLASS}" "" $hInnerDialog [=11=]
System::Call "USER32::GetWindowLong(p[=11=],i${GWL_STYLE})i.r1"
IntOp & ${BS_AUTORADIOBUTTON}
${If} = ${BS_AUTORADIOBUTTON} ; Is it a auto radio button?
nsDialogs::GetUserData [=11=] ; Get the section id
Pop
${NSD_GetState} [=11=]
${If} <> ${BST_UNCHECKED}
!insertmacro SelectSection
${Else}
!insertmacro UnselectSection
${EndIf}
${EndIf}
IntCmp [=11=] 0 "" loop loop
FunctionEnd
我正在尝试创建一个安装程序,它会询问用户一系列问题来决定安装哪些组件。每个选择(可能)都会影响以后选择中的可用选项(否则我只会做一个普通的组件页面——我不想给用户无效的选项)。
我如何完成这样的事情?如果我只使用组件页面,则会显示所有选项,其中一些组合是完全无效的。我不想让用户 select 那些。 是否可以省略组件页面?
这是我正在尝试的最小工作示例。 (对不起,太长了,我真的没法简化对话代码。)
!include nsDialogs.nsh
!include Sections.nsh
Name "mwe"
OutFile "mwe.exe"
InstallDir C:\mwe
Var hwnd
Var Level1Opt
Page custom SelectLevel1Opt ProcessLevel1
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hwnd
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop $hwnd
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 A"
${NSD_OnClick} $hwnd SetLevel1
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hwnd
nsDialogs::SetUserData $hwnd "Level 1 B"
${NSD_OnClick} $hwnd SetLevel1
nsDialogs::Show
FunctionEnd
Function SetLevel1
Pop $hwnd
nsDialogs::GetUserData $hwnd
Pop $Level1Opt
MessageBox MB_OK "Selected: $Level1Opt"
FunctionEnd
Function ProcessLevel1
${If} $Level1Opt == "Level 1 A"
!insertmacro SelectSection Level1A
${ElseIf} $Level1Opt == "Level 1 B"
!insertmacro SelectSection Level1B
${EndIf}
FunctionEnd
Page directory
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
无论我选择什么,Level1A
和 Level1B
部分都不会得到 运行。对话框中的 selection 在处理程序和 post 函数中被正确检测到。但是,select 编辑这些部分并不会导致它们 运行。即使我添加了一个组件页面,它们都不是 selected.
我查看了 Selection.nsh
,它引用的示例 (one-section.nsi) 并没有真正按照我的要求执行,因为它使用了组件页面。 (我也不太明白它是如何工作的。)
我做错了什么?我以何种方式误解了 NSIS 的工作方式?
正如 idleberg 所说,正确的语法是 !insertmacro SelectSection ${Level1A}
但您会收到警告,因为在您的 .nsi 中它的 Section
指令之后才定义节 ID。您需要将使用 ${Level1A}
的函数移至源代码部分下方:
!include nsDialogs.nsh
!include Sections.nsh
Page custom SelectLevel1Opt ProcessLevel1
Page instfiles
Section ""
MessageBox MB_OK "Common Install"
SectionEnd
Section /o "a" Level1A
MessageBox MB_OK "Level 1 A"
SectionEnd
Section /o "b" Level1B
MessageBox MB_OK "Level 1 B"
SectionEnd
Var hInnerDialog
Var hL1A
Var hL1B
Function SelectLevel1Opt
nsDialogs::Create 1018
pop $hInnerDialog
${NSD_CreateLabel} 0 0 100% 12u "Please select level 1 option"
Pop [=10=]
${NSD_CreateRadioButton} 10% 12u 100% 12u "Level 1 A"
Pop $hL1A
nsDialogs::SetUserData $hL1A ${Level1A} ; Only used by the generic function
${NSD_CreateRadioButton} 10% 24u 100% 12u "Level 1 B"
Pop $hL1B
nsDialogs::SetUserData $hL1B ${Level1B} ; Only used by the generic function
nsDialogs::Show
FunctionEnd
Function ProcessLevel1
${NSD_GetState} $hL1A
${If} <> ${BST_UNCHECKED}
!insertmacro SelectSection ${Level1A}
!insertmacro UnselectSection ${Level1B}
${Else}
!insertmacro SelectSection ${Level1B}
!insertmacro UnselectSection ${Level1A}
${EndIf}
FunctionEnd
ProcessLevel1函数如果单选按钮很多也可以循环实现:
Function ProcessLevel1
StrCpy [=11=] ""
loop:
FindWindow [=11=] "${__NSD_RadioButton_CLASS}" "" $hInnerDialog [=11=]
System::Call "USER32::GetWindowLong(p[=11=],i${GWL_STYLE})i.r1"
IntOp & ${BS_AUTORADIOBUTTON}
${If} = ${BS_AUTORADIOBUTTON} ; Is it a auto radio button?
nsDialogs::GetUserData [=11=] ; Get the section id
Pop
${NSD_GetState} [=11=]
${If} <> ${BST_UNCHECKED}
!insertmacro SelectSection
${Else}
!insertmacro UnselectSection
${EndIf}
${EndIf}
IntCmp [=11=] 0 "" loop loop
FunctionEnd