NSIS nsWindows 插件

新生代的用户界面设计工具

目录表

介绍

    nsWindows nsWindows 允许在安装程序中创建自定义窗口。居于内置的窗口之上,nsWindows 能够创建包含任何类型的以任意形式排列的控件的窗口。它能够创建简至仅一个控件的窗口,也能创建满足用户需求的版面。

    nsWindows 是一个新的 NSIS 插件,自版本 NSIS 2.42 被引入。nsWindows 不使用 INI 文件,因此执行速度要比 InstallOptions 快得多。与脚本的整合度更紧密也更自然了棗创建控件是通过使用插件的功能实现的,而通告则是直接在脚本中调用一个函数来实现的。不象 InstallOptions 那样,它没有预先定义的可能用到的控件类型并实现较低层次的 Windows API 访问,每一种类型的控件均能被创建并且窗口的定制具有更高的自由度。

    使用 nsWindows 越灵活的同时,没有 Win32 API 知识的用户就会觉得越复杂。这可通过创建预定义函数库解决。函数库在脚本中定义,可允许进行控件的创建和处理。这样,新手可以简易地体会其易用性,而高级用户仍可通过修改函数库来体会其核心功能的强大。

脚本指南,从零开始

    基本脚本

      在使用之初,让我们先创建一个基本的脚本作为我们的骨架。

      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Page instfiles
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

    自定义窗口

      现在轮廓已基本搞定,该让我们的 nsWindows 上场了!第一个调用必须总是 nsWindows::Create。它将在该窗口中创建一个对话框,并在堆栈中返回其 HWND 值。其结果必须从堆栈中被弹出以免堆栈出错。若结果为 error,对话框将不会被创建。

      nsWindows::Create 接受5个参数。它有一个特殊的功能,但为了保持此教程的简易性,最后一个参数值一般规定为 1018。

      HWND 是一个标识当前窗口唯一性的数字,可用于 SendMessage、SetCtlColors 和 Win32 API。

      !include nsWindows.nsh
                
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      
      Page custom nsWindowsPage
      Page instfiles
      
      Function nsWindowsPage
      	nsWindows::Create $hwndparent ${dwExStyle} ${dwStyle} "hello world" 1018
      	Pop $hWindow
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      FunctionEnd
      
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

    显示窗口

      现在窗口已经创建,该让她露脸了!这次使用的是 ${NSW_Show}。此函数直至用户点击关闭按钮后才会返回。

      !include nsWindows.nsh
      
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      
      Page custom nsWindowsPage
      Page instfiles
      
      Function nsWindowsPage
      	nsWindows::Create $hwndparent ${dwExStyle} ${dwStyle} "hello world" 1018
      	Pop $hWindow
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      	nsWindows::Show
      FunctionEnd
      
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

    添加控件

      此时编译并运行最后修改的脚本得到的将只是一个没有用处的空白窗口。因此我们也应当在该窗口上添加一些控件。要实现此目的,我们可使用头文件 nsWindows.nsh 中的宏 ${NSW_Create*}。这些宏,每个都带有 5 个参数 - x, y, width, height 和 text. 每个宏也都会返回一个值到堆栈,那就是新控件的 HWND。如同对话框的 HWND,它必须从堆栈中被弹出并保存下来。

      宏使用的所有尺寸单位均可使用以下三种单位类型中的任一种棗像素、对话框单位 或 对话框尺寸的百分比。你可以指定负值,这表示距离是从右端或底部算起。要使用对话框单位,数值后面必须加上后缀符 u。要使用百分比单位,数值后面必须加上百分符 - %。此外,有无其它的后缀符均表示像素。

      使用对话框单位作为尺寸单位,能够保证在用户不同的字体或 DPI 设置下均能完美地显示对话框。

      !include nsWindows.nsh
      !include LogicLib.nsh
      
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      Var Label
      Var Text
      
      Page custom nsWindowsPage
      Page instfiles
      
      Function nsWindowsPage
      
      	${NSW_CreateWindow} $hWindow "hello world" 1018
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      
      	${NSW_CreateLabel} 0 0 100% 12u "Hello, welcome to nsWindows!"
      	Pop $Label
      
      	${NSW_CreateText} 0 13u 100% -13u "Type something here..."
      	Pop $Text
      
      	${NSW_Show}
      
      FunctionEnd
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

      有效的能用 ${NSW_Create*} 来创建的控件类型为:

      • HLine
      • VLine
      • Label
      • Icon
      • Bitmap
      • BrowseButton
      • Link
      • Button
      • GroupBox
      • CheckBox
      • RadioButton
      • Text
      • Memo
      • Password
      • FileRequest
      • DirRequest
      • ComboBox
      • DropList
      • ListBox

    控件状态

      现在我们有了一些用户可以参与互动的控件,那么让我们看看用户到底对她们都干了些什么吧。要实现此目的,我们首先要添加一个离开回调 (leave callback) 函数到我们的窗口。在该函数中,我们需要知道我们所创建并显现在用户面前的 Text 控件的状态。要实现此目的,我们要使用宏 ${NSW_GetText}。对于 RadioButton 和 CheckBox 控件则要使用宏 ${NSW_GetState}

      注意并非所有的控件都支持 ${NSW_GetText},一些控件需要使用特定讯息(在 WinMessages.nsh 中定义)来进行特殊的处理。例如 ListBox 控件需要使用 LB_GETCURSELLB_GETTEXT。nsWindows.nsh 中的宏集将会及时地补充许许多多的宏来处理更多的此类事情。

      !include nsWindows.nsh
      !include LogicLib.nsh
      
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      Var Label
      Var Text
      
      Page custom nsWindowsPage
      Page instfiles
      
      Function nsWindowsPage
      
      	${NSW_CreateWindow} $hWindow "hello world" 1018
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      
      	${NSW_CreateLabel} 0 0 100% 12u "Hello, welcome to nsWindows!"
      	Pop $Label
      
      	${NSW_CreateText} 0 13u 100% -13u "Type something here..."
      	Pop $Text
      	
      	GetFunctionAddress $0 nsWindowsPageLeave
      	nsWindows::OnBack $0
      
      	${NSW_Show}
      
      FunctionEnd
      
      Function nsWindowsPageLeave
      
      	${NSW_GetText} $Text $0
      	MessageBox MB_OK "You typed:$\n$\n$0"
      
      FunctionEnd
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

    实时通告

      nsWindows 让人兴奋的新功能之一就是对话框状态改变时的回调函数通告。nsWindows 能够调用脚本中定义的一个函数以响应诸如文本区段的改变和某按钮的点击等用户行为。需求。要使得 nsWindows 通告我们事件的发生,我们可以使用 ${NSW_OnClick}${NSW_OnChange}。并非所有的控件都支持事件通告。例如 label 控件没有任何的通告。

      当回调函数被调用时,将在堆栈中返回控件的 HWND 值,其结果必须从堆栈中被弹出以免堆栈出错。在这个简易的脚本中似乎看不出有多大用处。但是在一个大型的脚本中几个控件关联到相同的回调函数,HWND 值能够区分出哪个控件触发了该事件。

      下面的例子将在用户输入 hello 到文本框中时通知用户。

      !include nsWindows.nsh
      !include LogicLib.nsh
      
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      Var Label
      Var Text
      
      Page custom nsWindowsPage
      Page instfiles
      
      Function nsWindowsPage
      
      	${NSW_CreateWindow} $hWindow "hello world" 1018
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      
      	${NSW_CreateLabel} 0 0 100% 12u "Hello, welcome to nsWindows!"
      	Pop $Label
      
      	${NSW_CreateText} 0 13u 100% -13u "Type something here..."
      	Pop $Text
      	${NSW_OnChange} $Text nsWindowsPageTextChange
      
      	GetFunctionAddress $0 nsWindowsPageLeave
      	nsWindows::OnBack $0
      
      	${NSW_Show}
      
      FunctionEnd
      
      Function nsWindowsPageLeave
      
      	${NSW_GetText} $Text $0
      	MessageBox MB_OK "You typed:$\n$\n$0"
      
      FunctionEnd
      
      Function nsWindowsPageTextChange
      
      	Pop $1 # $1 == $ Text
      
      	${NSW_GetText} $Text $0
      
      	${If} $0 == "hello"
      
      		MessageBox MB_OK "right back at ya!"
      
      	${EndIf}
      
      FunctionEnd
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

    储存数据

      到目前为止,我们有了一个具备一些基本输入控件的窗口。但是,当用户关闭窗口再重建时会发生什么情况呢?按照现有的代码,用户的输入将不会被储存下来。要储存它们,我们可以使用已有的离开回调函数来储存用户对的选择到变量并在下一次创建该控件时传递这些变量。更好的一个例子,我们也可以添加一个 Checkbox 控件到窗口,并使用 ${NSW_GetState}${NSW_SetState} 来获取和设置其状态。

      为了更直观一些,我们将要删除先前步骤中的一些通告。

      !include nsWindows.nsh
      !include LogicLib.nsh
      
      Name nsWindows
      OutFile nsWindows.exe
      
      XPStyle on
      
      Var hWindow
      Var Label
      Var Text
      Var Text_State
      Var Checkbox
      Var Checkbox_State
      
      Page custom nsWindowsPage
      Page license
      Page instfiles
      
      Function .onInit
      
      	StrCpy $Text_State "Type something here..."
      
      FunctionEnd
      
      Function nsWindowsPage
      
      	${NSW_CreateWindow} $hWindow "hello world" 1018
      
      	${If} $hWindow == error
      		Abort
      	${EndIf}
      
      	${NSW_CreateLabel} 0 0 100% 12u "Hello, welcome to nsWindows!"
      	Pop $Label
      
      	${NSW_CreateText} 0 13u 100% 12u $Text_State
      	Pop $Text
      
      	${NSW_CreateCheckbox} 0 30u 100% 10u "&Something"
      	Pop $Checkbox
      
      	${If} $Checkbox_State == ${BST_CHECKED}
      		${NSW_Check} $Checkbox
      	${EndIf}
      	
      	# alternative for the above ${If}:
      	#${NSW_SetState} $Checkbox_State
      
      	GetFunctionAddress $0 nsWindowsPageLeave
      	nsWindows::OnBack $0
      
      	${NSW_Show}
      
      FunctionEnd
      
      Function nsWindowsPageLeave
      
      	${NSW_GetText} $Text $Text_State
      	${NSW_GetState} $Checkbox $Checkbox_State
      	
      	StrCpy $R9 $hWindow
      	Call nsWindowsPage
      	
      	IsWindow $R9 0 +2
      		System::Call 'user32::DestroyWindow(i $R9)'
      
      FunctionEnd
      
      Section
      
      	DetailPrint "hello world"
      
      SectionEnd

函数参考

    Create

    nsWindows::Create HWND dwExStyle dwStyle Title rect

    ${NSW_CreateWindow} $hWindow Title rect

    ${NSW_CreateWindowEx} $hWindow HWND dwExStyle dwStyle Title rect

    新建一个窗口。

    $hWindow 用于保存新建窗口句柄的变量 。

    HWND 指定了新创建窗口的父窗口,通常是 $HWNDPARENT 。

    dwExStyle 指定了新创建窗口的扩展风格 。

    dwStyle 指定了新创建窗口的窗口风格 。

    Title 指定了新创建窗口的窗口名称。

    rect 指定了位置将被模仿的控件的标识符。此处通常使用 1018,用其模仿内建页面的创建。

    返回新对话框的 HWND 值到堆栈或 error

    CreateControl

    nsWindows::CreateControl class style extended_style x y width height text

    ${NSW_Create*} left top width height text

    在当前对话框中新建一个控件。此函数正常工作的前提条件是对话框必须存在,故 nsWindows::Create 必须在此函数之前调用。

    返回新控件的 HWND 值到堆栈或 error

    Show

    nsWindows::SHow

    ${NSW_Show}

    显示窗口。一旦调用它将结束 nsWindows::Create、nsWindows::CreateControl 及其它 nsWindows 函数。

    无返回值。

    SelectFileDialog

    nsWindows::SelectFileDialog mode initial_selection filter

    显示一个文件选择对话框。若 mode 设置为 save,将显示一个保存文件对话框,若 mode 设置为 open,将显示一个打开文件对话框。filter 为有效的文件过滤器列表,用 | 分隔。如果没有指定,则使用默认的 所有文件|*.*

    返回所选中的文件到堆栈,或当用户取消操作时返回空字串。

    SelectFolderDialog

    nsWindows::SelectFolderDialog title initial_selection

    显示一个文件夹选择对话框。

    返回所选中的文件夹到堆栈,或当用户取消操作时返回空字串。

    SetRTL

    nsWindows::SetRTL rtl_setting

    打开/关闭 从右到左 模式。若 rtl_setting = 0,关闭。若 rtl_setting = 1,打开。此函数必须在任何的 nsWindows::CreateControl 之前调用。

    无返回值。

    GetUserData

    nsWindows::GetUserData control_HWND

    返回与控件相关联的用户数据到堆栈。使用 nsWindows::SetUserData 设置此数据。

    SetUserData

    nsWindows::SetUserData control_HWND data

    关联数据到控件。使用 nsWindows::GetUserData 获取此数据。

    无返回值。

    SetTransParent

    nsWindows::SetTransparent control_HWND Transparency

    设置窗口的百分比透明度。注意:此函数仅能在 2K 或者以上系统中使用!

    无返回值。

    Transparency 为不透明度百分比,取值范围为0~100

    OnBack

    nsWindows::OnBack function_address

    设置关闭按钮的回调函数。此函数在用户点击关闭按钮时调用。在此函数中调用 Abort 能阻止用户回关闭该窗口。

    使用 GetFunctionAddress 获取期望的回调函数地址。

    无返回值。

    OnChange

    nsWindows::OnChange control_HWND function_address

    设置一个更改通告回调函数到所指定的控件。当控件状态被更改时,该函数将被调用,并返回控件的 HWND 值到堆栈。

    使用 GetFunctionAddress 获取期望的回调函数地址。

    无返回值。

    OnClick

    nsWindows::OnClick control_HWND function_address

    设置一个点击通告回调函数到所指定的控件。当控件被点击时,该函数将被调用,并返回控件的 HWND 值到堆栈。

    使用 GetFunctionAddress 获取期望的回调函数地址。

    无返回值。

    OnNotify

    nsWindows::OnNotify control_HWND function_address

    设置一个通告回调函数到所指定的控件。当控件接收到 WM_NOTIFY 讯息时,该函数将被调用,并返回控件的 HWND 值、通告代码和 MNHDR 结构指针到堆栈。

    使用 GetFunctionAddress 获取期望的回调函数地址。

    无返回值。

宏参考

    nsWindows.nsh 包含了一系列的宏,这将使得 nsWindows 的使用变得更简单一些。下面是有关这些宏的用途、语法、输入和输出的简要介绍。

    NSW_Create*

    ${NSW_Create*} x y width height text

    在当前对话框中新建一个控件。此函数正常工作的前提条件是对话框必须存在,故 nsWindows::Create 必须在此函数之前调用。

    有效的变量:

    • ${NSW_CreateHLine}
    • ${NSW_CreateVLine}
    • ${NSW_CreateLabel}
    • ${NSW_CreateIcon}
    • ${NSW_CreateBitmap}
    • ${NSW_CreateBrowseButton}
    • ${NSW_CreateLink}
    • ${NSW_CreateButton}
    • ${NSW_CreateGroupBox}
    • ${NSW_CreateCheckBox}
    • ${NSW_CreateRadioButton}
    • ${NSW_CreateText}
    • ${NSW_CreateMemo}
    • ${NSW_CreatePassword}
    • ${NSW_CreateNumber}
    • ${NSW_CreateFileRequest}
    • ${NSW_CreateDirRequest}
    • ${NSW_CreateComboBox}
    • ${NSW_CreateDropList}
    • ${NSW_CreateListBox}

    返回新对话框的 HWND 值到堆栈或 error。

    NSW_OnBack

    ${NSW_OnBack} control_HWND function_address

    参阅 OnBack 了解更多资料。

    NSW_OnChange

    ${NSW_OnChange} control_HWND function_address

    参阅 OnChange 了解更多资料。

    参阅 Real-time Notification 了解使用实例。

    NSW_OnClick

    ${NSW_OnClick} control_HWND function_address

    参阅 OnClick 了解更多资料。

    NSW_OnNotify

    ${NSW_OnNotify} control_HWND function_address

    参阅 OnNotify 了解更多资料。

    NSW_AddStyle

    ${NSW_AddStyle} control_HWND style

    添加一个或多个窗口外观样式到控件。多个外观样式用分隔符 `|' 隔开。

    请到 MSDN 获取样式资料。

    NSW_AddExStyle

    ${NSW_AddExStyle} control_HWND style

    添加一个或多个窗口外观样式到控件。多个外观样式用分隔符 `|' 隔开。

    请到 MSDN 获取样式资料。

    NSW_GetText

    ${NSW_GetText} control_HWND output_variable

    返回某个控件的 text 状态并储存到 output_variable。尤其适用于 Text 控件。

    参阅 Control State 了解使用实例。

    NSW_SetText

    ${NSW_SetText} control_HWND text

    设置某个控件的 text 状态。

    NSW_SetTextLimit

    ${NSW_SetTextLimit} control_HWND limit

    设置 Text 控件的输入长度限制。

    NSW_GetState

    ${NSW_GetState} control_HWND output_variable

    返回 CheckBox 和 RadioButton 控件的状态。可能的输出值为 ${BST_CHECKED} 和 ${BST_UNCHECKED}。

    参阅 Memory 了解使用实例。

    NSW_SetState

    ${NSW_SetState} control_HWND state

    设置 CheckBox 和 RadioButton 控件的状态。可能的 state 参数数据为 ${BST_CHECKED} 和 ${BST_UNCHECKED}。

    参阅 Memory 了解使用实例。

    NSW_Check

    ${NSW_Check} control_HWND

    勾选一个 CheckBox 和 RadioButton 控件。等同于带 ${BST_CHECKED} 参数调用 ${NSW_SetState}。

    NSW_Uncheck

    ${NSW_Uncheck} control_HWND

    取消勾选一个 CheckBox 和 RadioButton 控件。等同于带 ${BST_UNCHECKED} 参数调用 ${NSW_SetState}。

    参阅 Memory 了解使用实例。

    NSW_CB_AddString

    ${NSW_CB_AddString} combo_HWND string

    添加一个字符串到组合框(ComboBox)。

    NSW_CB_SelectString

    ${NSW_CB_SelectString} combo_HWND string

    选择组合框(ComboBox)中的一个字符串。

    NSW_LB_AddString

    ${NSW_LB_AddString} combo_HWND string

    添加一个字符串到列表框(ListBox)。

    NSW_LB_SelectString

    ${NSW_LB_SelectString} combo_HWND string

    选择列表框(ListBox)中的一个字符串。

    NSW_SetFocus

    ${NSW_SetFocus} control_HWND

    将控件设置为焦点。

    NSW_SetImage

    ${NSW_SetImage} control_HWND image_path output_variable

    image_path 载入一个图像并显示在已使用 ${NSW_CreateBitmap} 创建的 control_HWND 位置上。图像句柄储存在 output_variable 中,一旦不需要时可使用 ${NSW_FreeImage} 释放。

    必须在图像被释放到用户系统之后才能调用此宏。推荐释放图像到 $PLUGINSDIR 。

    !include nsWindows.nsh
    
    Name nsWindows
    OutFile nsWindows.exe
    
    XPStyle on
    
    Page instfiles nsWindowsImage
    
    Var hWindow
    Var Image
    Var ImageHandle
    
    Function .onInit
    
    	InitPluginsDir
    	File /oname=$PLUGINSDIR\image.bmp "${NSISDIR}\Contrib\Graphics\Header\nsis-r.bmp"
    
    FunctionEnd
    
    Function nsWindowsImage
    
    	${NSW_CreateWindow} $hWindow "nsWindowsImage" 1018
    
    	${If} $hWindow == error
    		Abort
    	${EndIf}
    
    	${NSW_CreateBitmap} 0 0 100% 100% ""
    	Pop $Image
    	${NSW_SetImage} $Image $PLUGINSDIR\image.bmp $ImageHandle
    
    	${NSW_Show}
    
    ;	${NSW_FreeImage} $ImageHandle
    
    FunctionEnd
    
    Section
    SectionEnd

    NSW_SetStretchedImage

    ${NSW_SetStretchedImage} control_HWND image_path output_variable

    载入并显示一个图像,有点类似 ${NSW_SetImage},但它能拉伸图像以填充控件的位置范围。

    NSW_ClearImage

    ${NSW_ClearImage} control_HWND

    清除控件图像。

    NSW_FreeImage

    ${NSW_FreeImage} image_handle

    释放一个先前使用 ${NSW_SetImage}${NSW_SetStretchedImage} 加载的图像句柄。

常见问题

  • Q: nsWindows 能否处理 InstallOptions INI 文件?

    A: nsWindows.nsh 中包含的一个名为 CreateWindowFromINI 的函数能够根据 INI 文件创建 nsWindows 对话框。它能处理 InstallOptions 支持的各种控件类型,但暂不会处理 flags 标记或通告。Examples\nsWindows\InstallOptions.nsi 显现了此函数的使用方法。

    未来将也会有一个函数来创建脚本自身。