NSIS nsDialogs 插件
介绍
nsDialogs nsDialogs 允许在安装程序中创建自定义页面。居于内置的页面之上,nsDialogs 能够创建包含任何类型的以任意形式排列的控件的页面。它能够创建简至仅一个控件的页面,也能创建满足用户需求的版面。例如,Modern UI 2 使用 nsDialogs 来创建欢迎和完成页面。
nsDialogs 是一个新的 NSIS 插件,自版本 NSIS 2.29 作为 InstallOptions 的替代品被引入。nsDialogs 不使用 INI 文件,因此执行速度要比 InstallOptions 快得多。与脚本的整合度更紧密也更自然了棗创建控件是通过使用插件的功能实现的,而通告则是直接在脚本中调用一个函数来实现的。不象 InstallOptions 那样,它没有预先定义的可能用到的控件类型并实现较低层次的 Windows API 访问,每一种类型的控件均能被创建并且页面的定制具有更高的自由度。
使用 nsDialogs 越灵活的同时,没有 Win32 API 知识的用户就会觉得越复杂。这可通过创建预定义函数库解决。函数库在脚本中定义,可允许进行控件的创建和处理。这样,新手可以简易地体会其易用性,而高级用户仍可通过修改函数库来体会其核心功能的强大。
脚本指南,从零开始
- HLine
- VLine
- Label
- Icon
- Bitmap
- BrowseButton
- Link
- Button
- GroupBox
- CheckBox
- RadioButton
- Text
- Password
- FileRequest
- DirRequest
- ComboBox
- DropList
- ListBox
基本脚本
在使用之初,让我们先创建一个基本的脚本作为我们的骨架。
Name nsDialogs OutFile nsDialogs.exe XPStyle on Page instfiles Section DetailPrint "hello world" SectionEnd
自定义页面
其次,我们将要添加一个自定义页面,在此我们可以使用 nsDialogs。nsDialogs 不能用于区段或自定义页面函数之外的任何函数中。
Name nsDialogs OutFile nsDialogs.exe XPStyle on Page custom nsDialogsPage Page instfiles Function nsDialogsPage FunctionEnd Section DetailPrint "hello world" SectionEnd
创建页面
现在轮廓已基本搞定,该让我们的 nsDialogs 上场了!第一个调用必须总是 nsDialogs::Create。它将在该页面中创建一个对话框,并在堆栈中返回其 HWND 值。其结果必须从堆栈中被弹出以免堆栈出错。若结果为 error,对话框将不会被创建。
nsDialogs::Create 类似 nsDialogs::Show 之外的其它函数,必须带 /NOUNLOAD 调用。
nsDialogs::Create 接受一个参数。它有一个特殊的功能,但为了保持此教程的简易性,参数值总是规定为 1018。
HWND 是一个标识当前对话框唯一性的数字,可用于 SendMessage、SetCtlColors 和 Win32 API。
!include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Page custom nsDialogsPage Page instfiles Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} FunctionEnd Section DetailPrint "hello world" SectionEnd
显示页面
现在页面已经创建,该让她露脸了!这次使用的是 nsDialogs::Show。此函数直至用户点击下一步、上一步或取消按钮后才会返回。
!include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Page custom nsDialogsPage Page instfiles Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} nsDialogs::Show FunctionEnd Section DetailPrint "hello world" SectionEnd
添加控件
此时编译并运行最后修改的脚本得到的将只是一个没有用处的空白页面。因此我们也应当在该页面上添加一些控件。要实现此目的,我们可使用头文件 nsDialogs.nsh 中的宏 ${NSD_Create*}。这些宏,每个都带有 5 个参数 - x, y, width, height 和 text. 每个宏也都会返回一个值到堆栈,那就是新控件的 HWND。如同对话框的 HWND,它必须从堆栈中被弹出并保存下来。
宏使用的所有尺寸单位均可使用以下三种单位类型中的任一种棗像素、对话框单位 或 对话框尺寸的百分比。你可以指定负值,这表示距离是从右端或底部算起。要使用对话框单位,数值后面必须加上后缀符 u。要使用百分比单位,数值后面必须加上百分符 - %。此外,有无其它的后缀符均表示像素。
使用对话框单位作为尺寸单位,能够保证在用户不同的字体或 DPI 设置下均能完美地显示对话框。
!include nsDialogs.nsh !include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Var Label Var Text Page custom nsDialogsPage Page instfiles Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!" Pop $Label ${NSD_CreateText} 0 13u 100% -13u "Type something here..." Pop $Text nsDialogs::Show FunctionEnd Section DetailPrint "hello world" SectionEnd
有效的能用 ${NSD_Create*} 来创建的控件类型为:
控件状态
现在我们有了一些用户可以参与互动的控件,那么让我们看看用户到底对她们都干了些什么吧。要实现此目的,我们首先要添加一个离开回调 (leave callback) 函数到我们的页面。在该函数中,我们需要知道我们所创建并显现在用户面前的 Text 控件的状态。要实现此目的,我们要使用宏 ${NSD_GetText}。对于 RadioButton 和 CheckBox 控件则要使用宏 ${NSD_GetState}。
注意并非所有的控件都支持 ${NSD_GetText},一些控件需要使用特定讯息(在 WinMessages.nsh 中定义)来进行特殊的处理。例如 ListBox 控件需要使用 LB_GETCURSEL 和 LB_GETTEXT。nsDialogs.nsh 中的宏集将会及时地补充许许多多的宏来处理更多的此类事情。
!include nsDialogs.nsh !include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Var Label Var Text Page custom nsDialogsPage nsDialogsPageLeave Page instfiles Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!" Pop $Label ${NSD_CreateText} 0 13u 100% -13u "Type something here..." Pop $Text nsDialogs::Show FunctionEnd Function nsDialogsPageLeave ${NSD_GetText} $Text $0 MessageBox MB_OK "You typed:$\n$\n$0" FunctionEnd Section DetailPrint "hello world" SectionEnd
实时通告
nsDialogs 让人兴奋的新功能之一就是对话框状态改变时的回调函数通告。nsDialogs 能够调用脚本中定义的一个函数以响应诸如文本区段的改变和某按钮的点击等用户行为。需求。要使得 nsDialogs 通告我们事件的发生,我们可以使用 ${NSD_OnClick} 和 ${NSD_OnChange}。并非所有的控件都支持事件通告。例如 label 控件没有任何的通告。
当回调函数被调用时,将在堆栈中返回控件的 HWND 值,其结果必须从堆栈中被弹出以免堆栈出错。在这个简易的脚本中似乎看不出有多大用处。但是在一个大型的脚本中几个控件关联到相同的回调函数,HWND 值能够区分出哪个控件触发了该事件。
下面的例子将在用户输入 hello 到文本框中时通知用户。
!include nsDialogs.nsh !include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Var Label Var Text Page custom nsDialogsPage nsDialogsPageLeave Page instfiles Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!" Pop $Label ${NSD_CreateText} 0 13u 100% -13u "Type something here..." Pop $Text ${NSD_OnChange} $Text nsDialogsPageTextChange nsDialogs::Show FunctionEnd Function nsDialogsPageLeave ${NSD_GetText} $Text $0 MessageBox MB_OK "You typed:$\n$\n$0" FunctionEnd Function nsDialogsPageTextChange Pop $1 # $1 == $ Text ${NSD_GetText} $Text $0 ${If} $0 == "hello" MessageBox MB_OK "right back at ya!" ${EndIf} FunctionEnd Section DetailPrint "hello world" SectionEnd
储存数据
到目前为止,我们有了一个具备一些基本输入控件的页面。但是,当用户进入下一个页面后而又返回到前一页面时会发生什么情况呢?按照现有的代码,用户的输入将不会被储存下来。要储存它们,我们可以使用已有的离开回调函数来储存用户对的选择到变量并在下一次创建该控件时传递这些变量。更好的一个例子,我们也可以添加一个 Checkbox 控件到页面,并使用 ${NSD_GetState} 和 ${NSD_SetState} 来获取和设置其状态。
为了更直观一些,我们将要删除先前步骤中的一些通告。
!include nsDialogs.nsh !include LogicLib.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Var Dialog Var Label Var Text Var Text_State Var Checkbox Var Checkbox_State Page custom nsDialogsPage nsDialogsPageLeave Page license Page instfiles Function .onInit StrCpy $Text_State "Type something here..." FunctionEnd Function nsDialogsPage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateLabel} 0 0 100% 12u "Hello, welcome to nsDialogs!" Pop $Label ${NSD_CreateText} 0 13u 100% 12u $Text_State Pop $Text ${NSD_CreateCheckbox} 0 30u 100% 10u "&Something" Pop $Checkbox ${If} $Checkbox_State == ${BST_CHECKED} ${NSD_Check} $Checkbox ${EndIf} # alternative for the above ${If}: #${NSD_SetState} $Checkbox_State nsDialogs::Show FunctionEnd Function nsDialogsPageLeave ${NSD_GetText} $Text $Text_State ${NSD_GetState} $Checkbox $Checkbox_State FunctionEnd Section DetailPrint "hello world" SectionEnd
函数参考
Create
nsDialogs::Create /NOUNLOAD rect
新建一个对话框。rect 指定了位置将被模仿的控件的标识符。此处通常使用 1018,用其模仿内建页面的创建。Modern UI 也用 1040 来控制欢迎和完成页面。
返回新对话框的 HWND 值到堆栈或 error。
CreateControl
nsDialogs::CreateControl /NOUNLOAD class style extended_style x y width height text
在当前对话框中新建一个控件。此函数正常工作的前提条件是对话框必须存在,故 nsDialogs::Create 必须在此函数之前调用。
返回新控件的 HWND 值到堆栈或 error。
Show
nsDialogs::Show
显示页面。一旦调用它将结束 nsDialogs::Create、nsDialogs::CreateControl 及其它 nsDialogs 函数。
无返回值。
SelectFileDialog
nsDialogs::SelectFileDialog /NOUNLOAD mode initial_selection filter
显示一个文件选择对话框。若 mode 设置为 save,将显示一个保存文件对话框,若 mode 设置为 open,将显示一个打开文件对话框。filter 为有效的文件过滤器列表,用 | 分隔。如果没有指定,则使用默认的 所有文件|*.*。
返回所选中的文件到堆栈,或当用户取消操作时返回空字串。
SelectFolderDialog
nsDialogs::SelectFolderDialog /NOUNLOAD title initial_selection
显示一个文件夹选择对话框。
返回所选中的文件夹到堆栈,或当用户取消操作时返回空字串。
SetRTL
nsDialogs::SetRTL /NOUNLOAD rtl_setting
打开/关闭 从右到左 模式。若 rtl_setting = 0,关闭。若 rtl_setting = 1,打开。此函数必须在任何的 nsDialogs::CreateControl 之前调用。
无返回值。
GetUserData
nsDialogs::GetUserData /NOUNLOAD control_HWND
返回与控件相关联的用户数据到堆栈。使用 nsDialogs::SetUserData 设置此数据。
SetUserData
nsDialogs::SetUserData /NOUNLOAD control_HWND data
关联数据到控件。使用 nsDialogs::GetUserData 获取此数据。
无返回值。
OnBack
nsDialogs::OnBack /NOUNLOAD function_address
设置上一步按钮的回调函数。此函数在用户点击上一步按钮时调用。在此函数中调用 Abort 能阻止用户回到前一个页面。
使用 GetFunctionAddress 获取期望的回调函数地址。
无返回值。
OnChange
nsDialogs::OnChange /NOUNLOAD control_HWND function_address
设置一个更改通告回调函数到所指定的控件。当控件状态被更改时,该函数将被调用,并返回控件的 HWND 值到堆栈。
使用 GetFunctionAddress 获取期望的回调函数地址。
无返回值。
OnClick
nsDialogs::OnClick /NOUNLOAD control_HWND function_address
设置一个点击通告回调函数到所指定的控件。当控件被点击时,该函数将被调用,并返回控件的 HWND 值到堆栈。
使用 GetFunctionAddress 获取期望的回调函数地址。
无返回值。
OnNotify
nsDialogs::OnNotify /NOUNLOAD control_HWND function_address
设置一个通告回调函数到所指定的控件。当控件接收到 WM_NOTIFY 讯息时,该函数将被调用,并返回控件的 HWND 值、通告代码和 MNHDR 结构指针到堆栈。
使用 GetFunctionAddress 获取期望的回调函数地址。
无返回值。
宏参考
- ${NSD_CreateHLine}
- ${NSD_CreateVLine}
- ${NSD_CreateLabel}
- ${NSD_CreateIcon}
- ${NSD_CreateBitmap}
- ${NSD_CreateBrowseButton}
- ${NSD_CreateLink}
- ${NSD_CreateButton}
- ${NSD_CreateGroupBox}
- ${NSD_CreateCheckBox}
- ${NSD_CreateRadioButton}
- ${NSD_CreateText}
- ${NSD_CreatePassword}
- ${NSD_CreateNumber}
- ${NSD_CreateFileRequest}
- ${NSD_CreateDirRequest}
- ${NSD_CreateComboBox}
- ${NSD_CreateDropList}
- ${NSD_CreateListBox}
nsDialogs.nsh 包含了一系列的宏,这将使得 nsDialogs 的使用变得更简单一些。下面是有关这些宏的用途、语法、输入和输出的简要介绍。
NSD_Create*
${NSD_Create*} x y width height text
在当前对话框中新建一个控件。此函数正常工作的前提条件是对话框必须存在,故 nsDialogs::Create 必须在此函数之前调用。
有效的变量:
返回新对话框的 HWND 值到堆栈或 error。
NSD_OnBack
${NSD_OnBack} control_HWND function_address
参阅 OnBack 了解更多资料。
NSD_OnChange
${NSD_OnChange} control_HWND function_address
参阅 OnChange 了解更多资料。
参阅 Real-time Notification 了解使用实例。
NSD_OnClick
${NSD_OnClick} control_HWND function_address
参阅 OnClick 了解更多资料。
NSD_OnNotify
${NSD_OnNotify} control_HWND function_address
参阅 OnNotify 了解更多资料。
NSD_AddStyle
${NSD_AddStyle} control_HWND style
添加一个或多个窗口外观样式到控件。多个外观样式用分隔符 `|' 隔开。
请到 MSDN 获取样式资料。
NSD_AddExStyle
${NSD_AddExStyle} control_HWND style
添加一个或多个窗口外观样式到控件。多个外观样式用分隔符 `|' 隔开。
请到 MSDN 获取样式资料。
NSD_GetText
${NSD_GetText} control_HWND output_variable
返回某个控件的 text 状态并储存到 output_variable。尤其适用于 Text 控件。
参阅 Control State 了解使用实例。
NSD_SetText
${NSD_SetText} control_HWND text
设置某个控件的 text 状态。
NSD_SetTextLimit
${NSD_SetTextLimit} control_HWND limit
设置 Text 控件的输入长度限制。
NSD_GetState
${NSD_GetState} control_HWND output_variable
返回 CheckBox 和 RadioButton 控件的状态。可能的输出值为 ${BST_CHECKED} 和 ${BST_UNCHECKED}。
参阅 Memory 了解使用实例。
NSD_SetState
${NSD_SetState} control_HWND state
设置 CheckBox 和 RadioButton 控件的状态。可能的 state 参数数据为 ${BST_CHECKED} 和 ${BST_UNCHECKED}。
参阅 Memory 了解使用实例。
NSD_Check
${NSD_Check} control_HWND
勾选一个 CheckBox 和 RadioButton 控件。等同于带 ${BST_CHECKED} 参数调用 ${NSD_SetState}。
NSD_Uncheck
${NSD_Uncheck} control_HWND
取消勾选一个 CheckBox 和 RadioButton 控件。等同于带 ${BST_UNCHECKED} 参数调用 ${NSD_SetState}。
参阅 Memory 了解使用实例。
NSD_CB_AddString
${NSD_CB_AddString} combo_HWND string
添加一个字符串到组合框。
NSD_CB_SelectString
${NSD_CB_SelectString} combo_HWND string
选择组合框中的一个字符串。
NSD_LB_AddString
${NSD_LB_AddString} combo_HWND string
添加一个字符串到列表框。
NSD_LB_SelectString
${NSD_LB_SelectString} combo_HWND string
选择列表框中的一个字符串。
NSD_SetFocus
${NSD_SetFocus} control_HWND
将控件设置为焦点。
NSD_SetImage
${NSD_SetImage} control_HWND image_path output_variable
自 image_path 载入一个图像并显示在已使用 ${NSD_CreateBitmap} 创建的 control_HWND 位置上。图像句柄储存在 output_variable 中,一旦不需要时可使用 ${NSD_FreeImage} 释放。
必须在图像被释放到用户系统之后才能调用此宏。推荐释放图像到 $PLUGINSDIR 。
!include nsDialogs.nsh Name nsDialogs OutFile nsDialogs.exe XPStyle on Page custom nsDialogsImage Page instfiles Var Dialog Var Image Var ImageHandle Function .onInit InitPluginsDir File /oname=$PLUGINSDIR\image.bmp "${NSISDIR}\Contrib\Graphics\Header\nsis-r.bmp" FunctionEnd Function nsDialogsImage nsDialogs::Create /NOUNLOAD 1018 Pop $Dialog ${If} $Dialog == error Abort ${EndIf} ${NSD_CreateBitmap} 0 0 100% 100% "" Pop $Image ${NSD_SetImage} $Image $PLUGINSDIR\image.bmp $ImageHandle nsDialogs::Show ${NSD_FreeImage} $ImageHandle FunctionEnd Section SectionEnd
NSD_SetStretchedImage
${NSD_SetStretchedImage} control_HWND image_path output_variable
载入并显示一个图像,有点类似 ${NSD_SetImage},但它能拉伸图像以填充控件的位置范围。
NSD_ClearImage
${NSD_ClearImage} control_HWND
清除控件图像。
NSD_FreeImage
${NSD_FreeImage} image_handle
释放一个先前使用 ${NSD_SetImage} 或 ${NSD_SetStretchedImage} 加载的图像句柄。
常见问题
- Q: nsDialogs 能否处理 InstallOptions INI 文件?
A: nsDialogs.nsh 中包含的一个名为 CreateDialogFromINI 的函数能够根据 INI 文件创建 nsDialogs 对话框。它能处理 InstallOptions 支持的各种控件类型,但暂不会处理 flags 标记或通告。Examples\nsDialogs\InstallOptions.nsi 显现了此函数的使用方法。
未来将也会有一个函数来创建脚本自身。