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

无论我选择什么,Level1ALevel1B 部分都不会得到 运行。对话框中的 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