NSIS:如何允许选择要安装的部分的多个用户选择屏幕?

时间:2016-06-06 21:20:07

标签: nsis

我试图创建一个安装程序,询问用户一系列问题,以决定安装哪些组件。每个选择(可能)都会影响以后选择中的可用选项(否则我只会做一个正常的组件页面 - 我不想给用户提供无效选项)。

我如何完成这样的事情?如果我只使用组件页面,则会显示所有选项,其中某些组合完全无效。我不想让用户选择那些。 是否可以省略组件页面?

这是我尝试的最简单的工作示例。 (对不起,我不能简化对话框代码。)

!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部分都不会运行。在处理程序和post函数中正确检测到对话框中的选择。但是,选择这些部分并不会导致它们运行。即使我添加了一个组件页面,也没有选择它们。

我查看了Selection.nsh,它所引用的示例(one-section.nsi)并没有真正做到我想要的,因为它使用了组件页面。 (我也不太清楚它是如何工作的。)

我做错了什么?我以什么方式误解了NSIS的工作方式?

1 个答案:

答案 0 :(得分:1)

正如idleberg所说,正确的语法是!insertmacro SelectSection ${Level1A},但是你得到一个警告,因为在你的.nsi中Section指令之后才会定义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 $0
${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 $1
${If} $1 <> ${BST_UNCHECKED}
    !insertmacro SelectSection ${Level1A}
    !insertmacro UnselectSection ${Level1B}
${Else}
    !insertmacro SelectSection ${Level1B}
    !insertmacro UnselectSection ${Level1A}
${EndIf}
FunctionEnd

如果有很多单选按钮,ProcessLevel1函数也可以实现为循环:

Function ProcessLevel1
StrCpy $0 ""
loop:
    FindWindow $0 "${__NSD_RadioButton_CLASS}" "" $hInnerDialog $0 
    System::Call "USER32::GetWindowLong(p$0,i${GWL_STYLE})i.r1"
    IntOp $1 $1 & ${BS_AUTORADIOBUTTON}
    ${If} $1 = ${BS_AUTORADIOBUTTON} ; Is it a auto radio button?
        nsDialogs::GetUserData $0 ; Get the section id
        Pop $2
        ${NSD_GetState} $0 $1
        ${If} $1 <> ${BST_UNCHECKED}
            !insertmacro SelectSection $2
        ${Else}
            !insertmacro UnselectSection $2
        ${EndIf}
    ${EndIf}
    IntCmp $0 0 "" loop loop
FunctionEnd