我正在尝试创建一个安装程序,询问用户一系列问题,以决定安装哪些组件。 每个选择(可能)会影响以后选择中的可用选项(否则我只会做一个普通的组件页面 - 我不想给用户提供无效选项)。
我如何完成这样的事情? 如果我只使用组件页面,则会显示所有选项,其中一些组合完全无效。 我不想让用户选择那些。 是否可以省略组件页面?
这是我正在尝试的最小工作示例。 (对不起,很长时间,我无法真正简化对话框代码。)
!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部分都不会运行。 在处理程序和post函数中正确检测到对话框中的选择。 但是,选择这些部分不会导致它们运行。 即使我添加了组件页面,也没有选择它们。
我查看了Selection.nsh ,它引用的示例(one-section.nsi)并没有真正做到我想要的,因为它使用了组件页面。 (我也不太清楚它是如何工作的。)
我究竟做错了什么? 我以什么方式误解了NSIS的工作方式?
I'm attempting to create an installer that asks the user a series of questions to decide which components to install. Each choice (potentially) influences the available options in later choices (else I would just do a normal components page—I don't want to give the user invalid options).
How do I accomplish such a thing? If I just use the components page, all the options are shown, some combinations of which are completely invalid. I don't want to let the user select those. Is it possible to leave out the components page?
Here's a minimal working example of what I'm trying. (Sorry it's long, I couldn't really simplify the dialog code.)
!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" SectionEndNo matter what I choose, neither Level1A nor Level1B sections get run. The selection from the dialog is correctly detected in the handler and the post function. However, selecting the sections isn't causing them to run. Even if I add a components page, neither of them is selected.
I looked in Selection.nsh, and the example it refers to (one-section.nsi) doesn't really do what I want, because it uses the components page. (I also don't understand quite how it works.)
What am I doing wrong? In what way am I misunderstanding the way NSIS is supposed to work?
最满意答案
正如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 FunctionEndAs idleberg says, the correct syntax is !insertmacro SelectSection ${Level1A} but you get a warning because the section id is not defined until after its Section instruction in your .nsi. You need to move the functions that use ${Level1A} below the sections in your source code:
!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} FunctionEndThe ProcessLevel1 function can also be implemented as a loop if there are many radio buttons:
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 FunctionEndNSIS:如何允许多个用户选择屏幕选择要安装的部分?(NSIS: How do I allow multiple user choice screens that select the sections to install?)我正在尝试创建一个安装程序,询问用户一系列问题,以决定安装哪些组件。 每个选择(可能)会影响以后选择中的可用选项(否则我只会做一个普通的组件页面 - 我不想给用户提供无效选项)。
我如何完成这样的事情? 如果我只使用组件页面,则会显示所有选项,其中一些组合完全无效。 我不想让用户选择那些。 是否可以省略组件页面?
这是我正在尝试的最小工作示例。 (对不起,很长时间,我无法真正简化对话框代码。)
!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部分都不会运行。 在处理程序和post函数中正确检测到对话框中的选择。 但是,选择这些部分不会导致它们运行。 即使我添加了组件页面,也没有选择它们。
我查看了Selection.nsh ,它引用的示例(one-section.nsi)并没有真正做到我想要的,因为它使用了组件页面。 (我也不太清楚它是如何工作的。)
我究竟做错了什么? 我以什么方式误解了NSIS的工作方式?
I'm attempting to create an installer that asks the user a series of questions to decide which components to install. Each choice (potentially) influences the available options in later choices (else I would just do a normal components page—I don't want to give the user invalid options).
How do I accomplish such a thing? If I just use the components page, all the options are shown, some combinations of which are completely invalid. I don't want to let the user select those. Is it possible to leave out the components page?
Here's a minimal working example of what I'm trying. (Sorry it's long, I couldn't really simplify the dialog code.)
!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" SectionEndNo matter what I choose, neither Level1A nor Level1B sections get run. The selection from the dialog is correctly detected in the handler and the post function. However, selecting the sections isn't causing them to run. Even if I add a components page, neither of them is selected.
I looked in Selection.nsh, and the example it refers to (one-section.nsi) doesn't really do what I want, because it uses the components page. (I also don't understand quite how it works.)
What am I doing wrong? In what way am I misunderstanding the way NSIS is supposed to work?
最满意答案
正如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 FunctionEndAs idleberg says, the correct syntax is !insertmacro SelectSection ${Level1A} but you get a warning because the section id is not defined until after its Section instruction in your .nsi. You need to move the functions that use ${Level1A} below the sections in your source code:
!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} FunctionEndThe ProcessLevel1 function can also be implemented as a loop if there are many radio buttons:
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
发布评论