diff --git a/Contrib/nsDialogs/Readme.html b/Contrib/nsDialogs/Readme.html
index 16073b74..3095cc15 100644
--- a/Contrib/nsDialogs/Readme.html
+++ b/Contrib/nsDialogs/Readme.html
@@ -53,6 +53,8 @@ code
OnChange
OnClick
OnNotify
+OnTimer
+KillTimer
@@ -63,6 +65,8 @@ code
NSD_OnChange
NSD_OnClick
NSD_OnNotify
+NSD_OnTimer
+NSD_KillTimer
NSD_AddStyle
NSD_AddExStyle
NSD_GetText
@@ -281,6 +285,7 @@ SectionEnd
ComboBox
DropList
ListBox
+ProgressBar
Control State
@@ -585,6 +590,26 @@ SectionEnd
Returns nothing.
+OnTimer
+
+nsDialogs::OnTimer /NOUNLOAD function_address timer_interval
+
+Sets a timer that'd call the callback function for the given control every in a constant interval. Interval times are specified in milliseconds.
+
+Use GetFunctionAddress to get the address of the desired callback function.
+
+Returns nothing.
+
+KillTimer
+
+nsDialogs::KillTimer /NOUNLOAD function_address
+
+Kills a previously set timer.
+
+Use GetFunctionAddress to get the address of the desired callback function.
+
+Returns nothing.
+
Macro Reference
nsDialogs.nsh contains a lot of macros that can make nsDialogs usage a lot easier. Below is a description of each of those macros including purpose, syntax, input and output.
@@ -617,6 +642,7 @@ SectionEnd
${NSD_CreateComboBox}
${NSD_CreateDropList}
${NSD_CreateListBox}
+${NSD_CreateProgressBar}
Returns the new dialog's HWND on the stack or error.
@@ -649,6 +675,18 @@ SectionEnd
See OnNotify for more details.
+NSD_OnTimer
+
+${NSD_OnTimer} function_address timer_interval
+
+See OnTimer for more details.
+
+NSD_KillTimer
+
+${NSD_KillTimer} function_address
+
+See KillTimer for more details.
+
NSD_AddStyle
${NSD_AddStyle} control_HWND style
diff --git a/Contrib/nsDialogs/SConscript b/Contrib/nsDialogs/SConscript
index 44f9c471..c4175f53 100644
--- a/Contrib/nsDialogs/SConscript
+++ b/Contrib/nsDialogs/SConscript
@@ -28,6 +28,7 @@ docs = Split("""
examples = Split("""
example.nsi
InstallOptions.nsi
+ timer.nsi
welcome.nsi
""")
diff --git a/Contrib/nsDialogs/nsDialogs.c b/Contrib/nsDialogs/nsDialogs.c
index 0aed9a66..c28b5200 100644
--- a/Contrib/nsDialogs/nsDialogs.c
+++ b/Contrib/nsDialogs/nsDialogs.c
@@ -1,547 +1,588 @@
-#include
-
-#include "defs.h"
-#include "nsis.h"
-#include "input.h"
-#include "rtl.h"
-
-#ifndef ODS_NOACCEL
-#define ODS_NOACCEL 0x0100
-#define ODS_NOFOCUSRECT 0x0200
-#endif
-#ifndef DT_HIDEPREFIX
-#define DT_HIDEPREFIX 0x00100000
-#endif
-
-HINSTANCE g_hInstance;
-struct nsDialog g_dialog;
-extra_parameters* g_pluginParms;
-
-struct nsControl* NSDFUNC GetControl(HWND hwCtl)
-{
- unsigned id = (unsigned) GetProp(hwCtl, NSCONTROL_ID_PROP);
-
- if (id == 0 || id > g_dialog.controlCount)
- {
- return NULL;
- }
-
- return &g_dialog.controls[id - 1];
-}
-
-BOOL CALLBACK ParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- BOOL res;
-
- if (message == WM_NOTIFY_OUTER_NEXT)
- {
- if (wParam == (WPARAM)-1)
- {
- if (g_pluginParms->ExecuteCodeSegment(g_dialog.callbacks.onBack - 1, 0))
- {
- return 0;
- }
- }
- }
-
- res = CallWindowProc(g_dialog.parentOriginalWndproc, hwnd, message, wParam, lParam);
-
- if (message == WM_NOTIFY_OUTER_NEXT && !res)
- {
- DestroyWindow(g_dialog.hwDialog);
- HeapFree(GetProcessHeap(), 0, g_dialog.controls);
- g_dialog.hwDialog = NULL;
- g_dialog.controls = NULL;
- }
-
- return res;
-}
-
-LRESULT CALLBACK LinkWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- struct nsControl* ctl = GetControl(hwnd);
-
- if(ctl == NULL)
- return 0;
-
- if(message == WM_SETCURSOR)
- {
- SetCursor(LoadCursor(NULL, IDC_HAND));
- return TRUE;
- }
-
- return CallWindowProc(ctl->oldWndProc, hwnd, message, wParam, lParam);
-}
-
-BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- switch (uMsg)
- {
- // handle notifications
- case WM_COMMAND:
- {
- HWND hwCtl = GetDlgItem(hwndDlg, LOWORD(wParam));
- struct nsControl* ctl = GetControl(hwCtl);
-
- if (ctl == NULL)
- break;
-
- if (HIWORD(wParam) == BN_CLICKED && (ctl->type == NSCTL_BUTTON || ctl->type == NSCTL_LINK))
- {
- if (ctl->callbacks.onClick)
- {
- pushint((int) hwCtl);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onClick - 1, 0);
- }
- }
- else if (HIWORD(wParam) == EN_CHANGE && ctl->type == NSCTL_EDIT)
- {
- if (ctl->callbacks.onChange)
- {
- pushint((int) hwCtl);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
- }
- }
- else if (HIWORD(wParam) == LBN_SELCHANGE && ctl->type == NSCTL_LISTBOX)
- {
- if (ctl->callbacks.onChange)
- {
- pushint((int) hwCtl);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
- }
- }
- else if ((HIWORD(wParam) == CBN_EDITUPDATE || HIWORD(wParam) == CBN_SELCHANGE)
- && ctl->type == NSCTL_COMBOBOX)
- {
- if (ctl->callbacks.onChange)
- {
- pushint((int) hwCtl);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
- }
- }
- else if (HIWORD(wParam) == STN_CLICKED && ctl->type == NSCTL_STATIC)
- {
- if (ctl->callbacks.onClick)
- {
- pushint((int) hwCtl);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onClick - 1, 0);
- }
- }
-
- break;
- }
-
- case WM_NOTIFY:
- {
- LPNMHDR nmhdr = (LPNMHDR) lParam;
- struct nsControl* ctl = GetControl(nmhdr->hwndFrom);
-
- if (ctl == NULL)
- break;
-
- if (!ctl->callbacks.onNotify)
- break;
-
- pushint((int) nmhdr);
- pushint(nmhdr->code);
- pushint((int) nmhdr->hwndFrom);
- g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onNotify - 1, 0);
- }
-
- // handle links
- case WM_DRAWITEM:
- {
- DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
- RECT rc;
- char text[1024];
-
- // http://blogs.msdn.com/oldnewthing/archive/2005/05/03/414317.aspx#414357
- // says we should call SystemParametersInfo(SPI_GETKEYBOARDCUES,...) to make
- // sure, does not seem to be required, might be a win2k bug, or it might
- // only apply to menus
- BOOL hideFocus = (lpdis->itemState & ODS_NOFOCUSRECT);
- BOOL hideAccel = (lpdis->itemState & ODS_NOACCEL);
-
- struct nsControl* ctl = GetControl(lpdis->hwndItem);
- if (ctl == NULL)
- break;
-
- // We need lpdis->rcItem later
- rc = lpdis->rcItem;
-
- // Get button's text
- text[0] = '\0';
- GetWindowText(lpdis->hwndItem, text, 1024);
-
- // Calculate needed size of the control
- DrawText(lpdis->hDC, text, -1, &rc, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT);
-
- // Make some more room so the focus rect won't cut letters off
- rc.right = min(rc.right + 2, lpdis->rcItem.right);
-
- // Move rect to right if in RTL mode
- if (g_dialog.rtl)
- {
- rc.left += lpdis->rcItem.right - rc.right;
- rc.right += lpdis->rcItem.right - rc.right;
- }
-
- if (lpdis->itemAction & ODA_DRAWENTIRE)
- {
- DWORD xtraDrawStyle = (g_dialog.rtl ? DT_RTLREADING : 0);
- if (hideAccel)
- xtraDrawStyle |= DT_HIDEPREFIX;
-
- // Use blue unless the user has set another using SetCtlColors
- if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
- SetTextColor(lpdis->hDC, RGB(0,0,255));
-
- // Draw the text
- DrawText(lpdis->hDC, text, -1, &rc, xtraDrawStyle | DT_CENTER | DT_VCENTER | DT_WORDBREAK);
- }
-
- // Draw the focus rect if needed
- if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS))
- {
- // NB: when not in DRAWENTIRE mode, this will actually toggle the focus
- // rectangle since it's drawn in a XOR way
- if (!hideFocus)
- DrawFocusRect(lpdis->hDC, &rc);
- }
-
- return TRUE;
- }
-
- // handle colors
- case WM_CTLCOLORSTATIC:
- case WM_CTLCOLOREDIT:
- case WM_CTLCOLORDLG:
- case WM_CTLCOLORBTN:
- case WM_CTLCOLORLISTBOX:
- // let the NSIS window handle colors, it knows best
- return SendMessage(g_dialog.hwParent, uMsg, wParam, lParam);
-
- // bye bye
- case WM_DESTROY:
- {
- unsigned i;
- for (i = 0; i < g_dialog.controlCount; i++)
- {
- RemoveProp(g_dialog.controls[i].window, NSCONTROL_ID_PROP);
- }
- break;
- }
- }
-
- return FALSE;
-}
-
-void __declspec(dllexport) Create(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- HWND hwPlacementRect;
- RECT rcPlacement;
-
- EXDLL_INIT();
-
- g_dialog.hwParent = hwndParent;
- g_pluginParms = extra;
-
- hwPlacementRect = GetDlgItem(hwndParent, popint());
- GetWindowRect(hwPlacementRect, &rcPlacement);
- MapWindowPoints(NULL, hwndParent, (LPPOINT) &rcPlacement, 2);
-
- g_dialog.hwDialog = CreateDialog(g_hInstance, MAKEINTRESOURCE(1), hwndParent, DialogProc);
-
- if (g_dialog.hwDialog == NULL)
- {
- pushstring("error");
- return;
- }
-
- SetWindowPos(
- g_dialog.hwDialog,
- 0,
- rcPlacement.left,
- rcPlacement.top,
- rcPlacement.right - rcPlacement.left,
- rcPlacement.bottom - rcPlacement.top,
- SWP_NOZORDER | SWP_NOACTIVATE
- );
-
- g_dialog.parentOriginalWndproc = (WNDPROC) SetWindowLong(hwndParent, DWL_DLGPROC, (long) ParentProc);
-
- g_dialog.rtl = FALSE;
-
- g_dialog.controlCount = 0;
- g_dialog.controls = (struct nsControl*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0);
-
- pushint((int) g_dialog.hwDialog);
-}
-
-void __declspec(dllexport) CreateControl(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- char *className;
- char *text;
-
- HWND hwItem;
- int x, y, width, height;
- DWORD style, exStyle;
- size_t id;
-
- // get info from stack
-
- className = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_stringsize * 2);
- text = &className[g_stringsize];
-
- if (!className)
- {
- pushstring("error");
- return;
- }
-
- if (popstring(className, 0))
- {
- pushstring("error");
- HeapFree(GetProcessHeap(), 0, className);
- return;
- }
-
- style = (DWORD) popint();
- exStyle = (DWORD) popint();
-
- PopPlacement(&x, &y, &width, &height);
-
- if (popstring(text, 0))
- {
- pushstring("error");
- HeapFree(GetProcessHeap(), 0, className);
- return;
- }
-
- // create item descriptor
-
- id = g_dialog.controlCount;
- g_dialog.controlCount++;
- g_dialog.controls = (struct nsControl*) HeapReAlloc(
- GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- g_dialog.controls,
- g_dialog.controlCount * sizeof(struct nsControl));
-
- if (!lstrcmpi(className, "BUTTON"))
- g_dialog.controls[id].type = NSCTL_BUTTON;
- else if (!lstrcmpi(className, "EDIT"))
- g_dialog.controls[id].type = NSCTL_EDIT;
- else if (!lstrcmpi(className, "COMBOBOX"))
- g_dialog.controls[id].type = NSCTL_COMBOBOX;
- else if (!lstrcmpi(className, "LISTBOX"))
- g_dialog.controls[id].type = NSCTL_LISTBOX;
- else if (!lstrcmpi(className, "RichEdit"))
- g_dialog.controls[id].type = NSCTL_RICHEDIT;
- else if (!lstrcmpi(className, "RICHEDIT_CLASS"))
- g_dialog.controls[id].type = NSCTL_RICHEDIT2;
- else if (!lstrcmpi(className, "STATIC"))
- g_dialog.controls[id].type = NSCTL_STATIC;
- else if (!lstrcmpi(className, "LINK"))
- g_dialog.controls[id].type = NSCTL_LINK;
- else
- g_dialog.controls[id].type = NSCTL_UNKNOWN;
-
- // apply rtl to style
-
- ConvertStyleToRTL(g_dialog.controls[id].type, &style, &exStyle);
-
- // create item's window
-
- hwItem = CreateWindowEx(
- exStyle,
- lstrcmpi(className, "LINK") ? className : "BUTTON",
- text,
- style,
- x, y, width, height,
- g_dialog.hwDialog,
- (HMENU) (1200 + id),
- g_hInstance,
- NULL);
-
- g_dialog.controls[id].window = hwItem;
-
- // remember id
-
- SetProp(hwItem, NSCONTROL_ID_PROP, (HANDLE) (id + 1));
-
- // set font
-
- SendMessage(hwItem, WM_SETFONT, SendMessage(g_dialog.hwParent, WM_GETFONT, 0, 0), TRUE);
-
- // set the WndProc for the link control
-
- if(g_dialog.controls[id].type == NSCTL_LINK)
- g_dialog.controls[id].oldWndProc = (WNDPROC) SetWindowLong(hwItem, GWL_WNDPROC, (long) LinkWndProc);
-
- // push back result
-
- pushint((int) hwItem);
-
- // done
-
- HeapFree(GetProcessHeap(), 0, className);
-}
-
-// for backward compatibility (2.29 had CreateItem)
-void __declspec(dllexport) CreateItem(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- CreateControl(hwndParent, string_size, variables, stacktop, extra);
-}
-
-void __declspec(dllexport) SetUserData(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- HWND hwCtl;
- struct nsControl* ctl;
-
- // get info from stack
-
- hwCtl = (HWND) popint();
-
- if (!IsWindow(hwCtl))
- {
- popint(); // remove user data from stack
- return;
- }
-
- // get descriptor
-
- ctl = GetControl(hwCtl);
-
- if (ctl == NULL)
- return;
-
- // set user data
-
- popstring(ctl->userData, USERDATA_SIZE);
-}
-
-void __declspec(dllexport) GetUserData(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- HWND hwCtl;
- struct nsControl* ctl;
-
- // get info from stack
-
- hwCtl = (HWND) popint();
-
- if (!IsWindow(hwCtl))
- {
- pushstring("");
- return;
- }
-
- // get descriptor
-
- ctl = GetControl(hwCtl);
-
- if (ctl == NULL)
- {
- pushstring("");
- return;
- }
-
- // return user data
-
- pushstring(ctl->userData);
-}
-
-void NSDFUNC SetControlCallback(size_t callbackIdx)
-{
- HWND hwCtl;
- nsFunction callback;
- nsFunction* callbacks;
- struct nsControl* ctl;
-
- // get info from stack
-
- hwCtl = (HWND) popint();
- callback = (nsFunction) popint();
-
- if (!IsWindow(hwCtl))
- return;
-
- // get descriptor
-
- ctl = GetControl(hwCtl);
-
- if (ctl == NULL)
- return;
-
- // set callback
-
- callbacks = (nsFunction*) &ctl->callbacks;
- callbacks[callbackIdx] = callback;
-}
-
-void NSDFUNC SetDialogCallback(size_t callbackIdx)
-{
- nsFunction callback;
- nsFunction* callbacks;
-
- // get info from stack
-
- callback = (nsFunction) popint();
-
- // set callback
-
- callbacks = (nsFunction*) &g_dialog.callbacks;
- callbacks[callbackIdx] = callback;
-}
-
-
-void __declspec(dllexport) OnClick(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- SetControlCallback(CTL_CALLBACK_IDX(onClick));
-}
-
-void __declspec(dllexport) OnChange(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- SetControlCallback(CTL_CALLBACK_IDX(onChange));
-}
-
-void __declspec(dllexport) OnNotify(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- SetControlCallback(CTL_CALLBACK_IDX(onNotify));
-}
-
-void __declspec(dllexport) OnBack(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- SetDialogCallback(DLG_CALLBACK_IDX(onBack));
-}
-
-void __declspec(dllexport) Show(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
-{
- // tell NSIS to remove old inner dialog and pass handle of the new inner dialog
-
- SendMessage(hwndParent, WM_NOTIFY_CUSTOM_READY, (WPARAM) g_dialog.hwDialog, 0);
- ShowWindow(g_dialog.hwDialog, SW_SHOWNA);
-
- // message loop
-
- while (g_dialog.hwDialog)
- {
- MSG msg;
- GetMessage(&msg, NULL, 0, 0);
- if (!IsDialogMessage(g_dialog.hwDialog, &msg) && !IsDialogMessage(g_dialog.hwParent, &msg))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
-
- // reset wndproc
-
- SetWindowLong(hwndParent, DWL_DLGPROC, (long) g_dialog.parentOriginalWndproc);
-}
-
-BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
-{
- g_hInstance = (HINSTANCE) hInst;
- return TRUE;
-}
+#include
+
+#include "defs.h"
+#include "nsis.h"
+#include "input.h"
+#include "rtl.h"
+
+#ifndef ODS_NOACCEL
+#define ODS_NOACCEL 0x0100
+#define ODS_NOFOCUSRECT 0x0200
+#endif
+#ifndef DT_HIDEPREFIX
+#define DT_HIDEPREFIX 0x00100000
+#endif
+
+HINSTANCE g_hInstance;
+struct nsDialog g_dialog;
+extra_parameters* g_pluginParms;
+
+struct nsControl* NSDFUNC GetControl(HWND hwCtl)
+{
+ unsigned id = (unsigned) GetProp(hwCtl, NSCONTROL_ID_PROP);
+
+ if (id == 0 || id > g_dialog.controlCount)
+ {
+ return NULL;
+ }
+
+ return &g_dialog.controls[id - 1];
+}
+
+BOOL CALLBACK ParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ BOOL res;
+
+ if (message == WM_NOTIFY_OUTER_NEXT)
+ {
+ if (wParam == (WPARAM)-1)
+ {
+ if (g_pluginParms->ExecuteCodeSegment(g_dialog.callbacks.onBack - 1, 0))
+ {
+ return 0;
+ }
+ }
+ }
+
+ res = CallWindowProc(g_dialog.parentOriginalWndproc, hwnd, message, wParam, lParam);
+
+ if (message == WM_NOTIFY_OUTER_NEXT && !res)
+ {
+ DestroyWindow(g_dialog.hwDialog);
+ HeapFree(GetProcessHeap(), 0, g_dialog.controls);
+ g_dialog.hwDialog = NULL;
+ g_dialog.controls = NULL;
+ }
+
+ return res;
+}
+
+LRESULT CALLBACK LinkWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ struct nsControl* ctl = GetControl(hwnd);
+
+ if(ctl == NULL)
+ return 0;
+
+ if(message == WM_SETCURSOR)
+ {
+ SetCursor(LoadCursor(NULL, IDC_HAND));
+ return TRUE;
+ }
+
+ return CallWindowProc(ctl->oldWndProc, hwnd, message, wParam, lParam);
+}
+
+BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ // handle notifications
+ case WM_COMMAND:
+ {
+ HWND hwCtl = GetDlgItem(hwndDlg, LOWORD(wParam));
+ struct nsControl* ctl = GetControl(hwCtl);
+
+ if (ctl == NULL)
+ break;
+
+ if (HIWORD(wParam) == BN_CLICKED && (ctl->type == NSCTL_BUTTON || ctl->type == NSCTL_LINK))
+ {
+ if (ctl->callbacks.onClick)
+ {
+ pushint((int) hwCtl);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onClick - 1, 0);
+ }
+ }
+ else if (HIWORD(wParam) == EN_CHANGE && ctl->type == NSCTL_EDIT)
+ {
+ if (ctl->callbacks.onChange)
+ {
+ pushint((int) hwCtl);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
+ }
+ }
+ else if (HIWORD(wParam) == LBN_SELCHANGE && ctl->type == NSCTL_LISTBOX)
+ {
+ if (ctl->callbacks.onChange)
+ {
+ pushint((int) hwCtl);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
+ }
+ }
+ else if ((HIWORD(wParam) == CBN_EDITUPDATE || HIWORD(wParam) == CBN_SELCHANGE)
+ && ctl->type == NSCTL_COMBOBOX)
+ {
+ if (ctl->callbacks.onChange)
+ {
+ pushint((int) hwCtl);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onChange - 1, 0);
+ }
+ }
+ else if (HIWORD(wParam) == STN_CLICKED && ctl->type == NSCTL_STATIC)
+ {
+ if (ctl->callbacks.onClick)
+ {
+ pushint((int) hwCtl);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onClick - 1, 0);
+ }
+ }
+
+ break;
+ }
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR nmhdr = (LPNMHDR) lParam;
+ struct nsControl* ctl = GetControl(nmhdr->hwndFrom);
+
+ if (ctl == NULL)
+ break;
+
+ if (!ctl->callbacks.onNotify)
+ break;
+
+ pushint((int) nmhdr);
+ pushint(nmhdr->code);
+ pushint((int) nmhdr->hwndFrom);
+ g_pluginParms->ExecuteCodeSegment(ctl->callbacks.onNotify - 1, 0);
+ }
+
+ // handle links
+ case WM_DRAWITEM:
+ {
+ DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
+ RECT rc;
+ char text[1024];
+
+ // http://blogs.msdn.com/oldnewthing/archive/2005/05/03/414317.aspx#414357
+ // says we should call SystemParametersInfo(SPI_GETKEYBOARDCUES,...) to make
+ // sure, does not seem to be required, might be a win2k bug, or it might
+ // only apply to menus
+ BOOL hideFocus = (lpdis->itemState & ODS_NOFOCUSRECT);
+ BOOL hideAccel = (lpdis->itemState & ODS_NOACCEL);
+
+ struct nsControl* ctl = GetControl(lpdis->hwndItem);
+ if (ctl == NULL)
+ break;
+
+ // We need lpdis->rcItem later
+ rc = lpdis->rcItem;
+
+ // Get button's text
+ text[0] = '\0';
+ GetWindowText(lpdis->hwndItem, text, 1024);
+
+ // Calculate needed size of the control
+ DrawText(lpdis->hDC, text, -1, &rc, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT);
+
+ // Make some more room so the focus rect won't cut letters off
+ rc.right = min(rc.right + 2, lpdis->rcItem.right);
+
+ // Move rect to right if in RTL mode
+ if (g_dialog.rtl)
+ {
+ rc.left += lpdis->rcItem.right - rc.right;
+ rc.right += lpdis->rcItem.right - rc.right;
+ }
+
+ if (lpdis->itemAction & ODA_DRAWENTIRE)
+ {
+ DWORD xtraDrawStyle = (g_dialog.rtl ? DT_RTLREADING : 0);
+ if (hideAccel)
+ xtraDrawStyle |= DT_HIDEPREFIX;
+
+ // Use blue unless the user has set another using SetCtlColors
+ if (!GetWindowLong(lpdis->hwndItem, GWL_USERDATA))
+ SetTextColor(lpdis->hDC, RGB(0,0,255));
+
+ // Draw the text
+ DrawText(lpdis->hDC, text, -1, &rc, xtraDrawStyle | DT_CENTER | DT_VCENTER | DT_WORDBREAK);
+ }
+
+ // Draw the focus rect if needed
+ if (((lpdis->itemState & ODS_FOCUS) && (lpdis->itemAction & ODA_DRAWENTIRE)) || (lpdis->itemAction & ODA_FOCUS))
+ {
+ // NB: when not in DRAWENTIRE mode, this will actually toggle the focus
+ // rectangle since it's drawn in a XOR way
+ if (!hideFocus)
+ DrawFocusRect(lpdis->hDC, &rc);
+ }
+
+ return TRUE;
+ }
+
+ // handle colors
+ case WM_CTLCOLORSTATIC:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORLISTBOX:
+ // let the NSIS window handle colors, it knows best
+ return SendMessage(g_dialog.hwParent, uMsg, wParam, lParam);
+
+ // bye bye
+ case WM_DESTROY:
+ {
+ unsigned i;
+ for (i = 0; i < g_dialog.controlCount; i++)
+ {
+ RemoveProp(g_dialog.controls[i].window, NSCONTROL_ID_PROP);
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+void __declspec(dllexport) Create(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ HWND hwPlacementRect;
+ RECT rcPlacement;
+
+ EXDLL_INIT();
+
+ g_dialog.hwParent = hwndParent;
+ g_pluginParms = extra;
+
+ hwPlacementRect = GetDlgItem(hwndParent, popint());
+ GetWindowRect(hwPlacementRect, &rcPlacement);
+ MapWindowPoints(NULL, hwndParent, (LPPOINT) &rcPlacement, 2);
+
+ g_dialog.hwDialog = CreateDialog(g_hInstance, MAKEINTRESOURCE(1), hwndParent, DialogProc);
+
+ if (g_dialog.hwDialog == NULL)
+ {
+ pushstring("error");
+ return;
+ }
+
+ SetWindowPos(
+ g_dialog.hwDialog,
+ 0,
+ rcPlacement.left,
+ rcPlacement.top,
+ rcPlacement.right - rcPlacement.left,
+ rcPlacement.bottom - rcPlacement.top,
+ SWP_NOZORDER | SWP_NOACTIVATE
+ );
+
+ g_dialog.parentOriginalWndproc = (WNDPROC) SetWindowLong(hwndParent, DWL_DLGPROC, (long) ParentProc);
+
+ g_dialog.rtl = FALSE;
+
+ g_dialog.controlCount = 0;
+ g_dialog.controls = (struct nsControl*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0);
+
+ pushint((int) g_dialog.hwDialog);
+}
+
+void __declspec(dllexport) CreateControl(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ char *className;
+ char *text;
+
+ HWND hwItem;
+ int x, y, width, height;
+ DWORD style, exStyle;
+ size_t id;
+
+ // get info from stack
+
+ className = (char *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, g_stringsize * 2);
+ text = &className[g_stringsize];
+
+ if (!className)
+ {
+ pushstring("error");
+ return;
+ }
+
+ if (popstring(className, 0))
+ {
+ pushstring("error");
+ HeapFree(GetProcessHeap(), 0, className);
+ return;
+ }
+
+ style = (DWORD) popint();
+ exStyle = (DWORD) popint();
+
+ PopPlacement(&x, &y, &width, &height);
+
+ if (popstring(text, 0))
+ {
+ pushstring("error");
+ HeapFree(GetProcessHeap(), 0, className);
+ return;
+ }
+
+ // create item descriptor
+
+ id = g_dialog.controlCount;
+ g_dialog.controlCount++;
+ g_dialog.controls = (struct nsControl*) HeapReAlloc(
+ GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ g_dialog.controls,
+ g_dialog.controlCount * sizeof(struct nsControl));
+
+ if (!lstrcmpi(className, "BUTTON"))
+ g_dialog.controls[id].type = NSCTL_BUTTON;
+ else if (!lstrcmpi(className, "EDIT"))
+ g_dialog.controls[id].type = NSCTL_EDIT;
+ else if (!lstrcmpi(className, "COMBOBOX"))
+ g_dialog.controls[id].type = NSCTL_COMBOBOX;
+ else if (!lstrcmpi(className, "LISTBOX"))
+ g_dialog.controls[id].type = NSCTL_LISTBOX;
+ else if (!lstrcmpi(className, "RichEdit"))
+ g_dialog.controls[id].type = NSCTL_RICHEDIT;
+ else if (!lstrcmpi(className, "RICHEDIT_CLASS"))
+ g_dialog.controls[id].type = NSCTL_RICHEDIT2;
+ else if (!lstrcmpi(className, "STATIC"))
+ g_dialog.controls[id].type = NSCTL_STATIC;
+ else if (!lstrcmpi(className, "LINK"))
+ g_dialog.controls[id].type = NSCTL_LINK;
+ else
+ g_dialog.controls[id].type = NSCTL_UNKNOWN;
+
+ // apply rtl to style
+
+ ConvertStyleToRTL(g_dialog.controls[id].type, &style, &exStyle);
+
+ // create item's window
+
+ hwItem = CreateWindowEx(
+ exStyle,
+ lstrcmpi(className, "LINK") ? className : "BUTTON",
+ text,
+ style,
+ x, y, width, height,
+ g_dialog.hwDialog,
+ (HMENU) (1200 + id),
+ g_hInstance,
+ NULL);
+
+ g_dialog.controls[id].window = hwItem;
+
+ // remember id
+
+ SetProp(hwItem, NSCONTROL_ID_PROP, (HANDLE) (id + 1));
+
+ // set font
+
+ SendMessage(hwItem, WM_SETFONT, SendMessage(g_dialog.hwParent, WM_GETFONT, 0, 0), TRUE);
+
+ // set the WndProc for the link control
+
+ if(g_dialog.controls[id].type == NSCTL_LINK)
+ g_dialog.controls[id].oldWndProc = (WNDPROC) SetWindowLong(hwItem, GWL_WNDPROC, (long) LinkWndProc);
+
+ // push back result
+
+ pushint((int) hwItem);
+
+ // done
+
+ HeapFree(GetProcessHeap(), 0, className);
+}
+
+// for backward compatibility (2.29 had CreateItem)
+void __declspec(dllexport) CreateItem(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ CreateControl(hwndParent, string_size, variables, stacktop, extra);
+}
+
+void __declspec(dllexport) SetUserData(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ HWND hwCtl;
+ struct nsControl* ctl;
+
+ // get info from stack
+
+ hwCtl = (HWND) popint();
+
+ if (!IsWindow(hwCtl))
+ {
+ popint(); // remove user data from stack
+ return;
+ }
+
+ // get descriptor
+
+ ctl = GetControl(hwCtl);
+
+ if (ctl == NULL)
+ return;
+
+ // set user data
+
+ popstring(ctl->userData, USERDATA_SIZE);
+}
+
+void __declspec(dllexport) GetUserData(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ HWND hwCtl;
+ struct nsControl* ctl;
+
+ // get info from stack
+
+ hwCtl = (HWND) popint();
+
+ if (!IsWindow(hwCtl))
+ {
+ pushstring("");
+ return;
+ }
+
+ // get descriptor
+
+ ctl = GetControl(hwCtl);
+
+ if (ctl == NULL)
+ {
+ pushstring("");
+ return;
+ }
+
+ // return user data
+
+ pushstring(ctl->userData);
+}
+
+void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ // we use a timer proc instead of WM_TIMER to make sure no one messes with the ids but us
+ g_pluginParms->ExecuteCodeSegment(idEvent - 1, 0);
+}
+
+void __declspec(dllexport) CreateTimer(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ UINT callback;
+ UINT interval;
+
+ // get info from stack
+
+ callback = popint();
+ interval = popint();
+
+ if (!callback || !interval)
+ return;
+
+ // create timer
+
+ SetTimer(
+ g_dialog.hwDialog,
+ callback,
+ interval,
+ TimerProc);
+}
+
+void __declspec(dllexport) KillTimer(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ UINT id;
+
+ // get timer id from stack
+
+ id = popint();
+
+ // kill timer
+
+ KillTimer(g_dialog.hwDialog, id);
+}
+
+void NSDFUNC SetControlCallback(size_t callbackIdx)
+{
+ HWND hwCtl;
+ nsFunction callback;
+ nsFunction* callbacks;
+ struct nsControl* ctl;
+
+ // get info from stack
+
+ hwCtl = (HWND) popint();
+ callback = (nsFunction) popint();
+
+ if (!IsWindow(hwCtl))
+ return;
+
+ // get descriptor
+
+ ctl = GetControl(hwCtl);
+
+ if (ctl == NULL)
+ return;
+
+ // set callback
+
+ callbacks = (nsFunction*) &ctl->callbacks;
+ callbacks[callbackIdx] = callback;
+}
+
+void NSDFUNC SetDialogCallback(size_t callbackIdx)
+{
+ nsFunction callback;
+ nsFunction* callbacks;
+
+ // get info from stack
+
+ callback = (nsFunction) popint();
+
+ // set callback
+
+ callbacks = (nsFunction*) &g_dialog.callbacks;
+ callbacks[callbackIdx] = callback;
+}
+
+
+void __declspec(dllexport) OnClick(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ SetControlCallback(CTL_CALLBACK_IDX(onClick));
+}
+
+void __declspec(dllexport) OnChange(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ SetControlCallback(CTL_CALLBACK_IDX(onChange));
+}
+
+void __declspec(dllexport) OnNotify(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ SetControlCallback(CTL_CALLBACK_IDX(onNotify));
+}
+
+void __declspec(dllexport) OnBack(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ SetDialogCallback(DLG_CALLBACK_IDX(onBack));
+}
+
+void __declspec(dllexport) Show(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra)
+{
+ // tell NSIS to remove old inner dialog and pass handle of the new inner dialog
+
+ SendMessage(hwndParent, WM_NOTIFY_CUSTOM_READY, (WPARAM) g_dialog.hwDialog, 0);
+ ShowWindow(g_dialog.hwDialog, SW_SHOWNA);
+
+ // message loop
+
+ while (g_dialog.hwDialog)
+ {
+ MSG msg;
+ GetMessage(&msg, NULL, 0, 0);
+ if (!IsDialogMessage(g_dialog.hwDialog, &msg) && !IsDialogMessage(g_dialog.hwParent, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ // reset wndproc
+
+ SetWindowLong(hwndParent, DWL_DLGPROC, (long) g_dialog.parentOriginalWndproc);
+}
+
+BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+ g_hInstance = (HINSTANCE) hInst;
+ return TRUE;
+}
diff --git a/Contrib/nsDialogs/nsDialogs.nsh b/Contrib/nsDialogs/nsDialogs.nsh
index 6902836c..25c35f13 100644
--- a/Contrib/nsDialogs/nsDialogs.nsh
+++ b/Contrib/nsDialogs/nsDialogs.nsh
@@ -252,6 +252,10 @@ Header file for creating custom installer pages with nsDialogs
!define __NSD_ListBox_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${WS_VSCROLL}|${LBS_DISABLENOSCROLL}|${LBS_HASSTRINGS}|${LBS_NOINTEGRALHEIGHT}|${LBS_NOTIFY}
!define __NSD_ListBox_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE}
+!define __NSD_ProgressBar_CLASS msctls_progress32
+!define __NSD_ProgressBar_STYLE ${DEFAULT_STYLES}
+!define __NSD_ProgressBar_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE}
+
!macro __NSD_DefineControl NAME
!define NSD_Create${NAME} "nsDialogs::CreateControl /NOUNLOAD ${__NSD_${Name}_CLASS} ${__NSD_${Name}_STYLE} ${__NSD_${Name}_EXSTYLE}"
@@ -277,6 +281,7 @@ Header file for creating custom installer pages with nsDialogs
!insertmacro __NSD_DefineControl ComboBox
!insertmacro __NSD_DefineControl DropList
!insertmacro __NSD_DefineControl ListBox
+!insertmacro __NSD_DefineControl ProgressBar
!macro __NSD_OnControlEvent EVENT HWND FUNCTION
@@ -321,6 +326,32 @@ Header file for creating custom installer pages with nsDialogs
!insertmacro __NSD_DefineControlCallback Notify
!insertmacro __NSD_DefineDialogCallback Back
+!macro _NSD_CreateTimer FUNCTION INTERVAL
+
+ Push $0
+
+ GetFunctionAddress $0 "${FUNCTION}"
+ nsDialogs::CreateTimer /NOUNLOAD $0 "${INTERVAL}"
+
+ Pop $0
+
+!macroend
+
+!define NSD_CreateTimer `!insertmacro _NSD_CreateTimer`
+
+!macro _NSD_KillTimer FUNCTION
+
+ Push $0
+
+ GetFunctionAddress $0 "${FUNCTION}"
+ nsDialogs::KillTimer /NOUNLOAD $0
+
+ Pop $0
+
+!macroend
+
+!define NSD_KillTimer `!insertmacro _NSD_KillTimer`
+
!macro _NSD_AddStyle CONTROL STYLE
Push $0
diff --git a/Contrib/nsDialogs/timer.nsi b/Contrib/nsDialogs/timer.nsi
new file mode 100644
index 00000000..8ca00032
--- /dev/null
+++ b/Contrib/nsDialogs/timer.nsi
@@ -0,0 +1,117 @@
+!include nsDialogs.nsh
+
+!define PBM_SETPOS 0x0402
+!define PBM_DELTAPOS 0x0403
+!define PBM_GETPOS 1032
+
+!addplugindir "."
+
+Name "nsDialogs Example"
+OutFile "nsDialogs Example.exe"
+XpStyle on
+
+Var DIALOG
+Var TEXT
+Var PROGBAR
+Var PROGBAR2
+Var PROGBAR3
+Var BUTTON
+Var BUTTON2
+Var TIMERID
+Var TIMERID2
+
+Page custom nsDialogsPage
+
+Function OnTimer
+ Pop $0 ; Timer id
+
+ SendMessage $PROGBAR ${PBM_GETPOS} 0 0 $1
+ StrCmp $1 100 0 +3
+ SendMessage $PROGBAR ${PBM_SETPOS} 0 0
+ Goto +2
+ SendMessage $PROGBAR ${PBM_DELTAPOS} 10 0
+
+FunctionEnd
+
+Function OnTimer2
+ Pop $0 ; Timer id
+
+ SendMessage $PROGBAR2 ${PBM_GETPOS} 0 0 $1
+ StrCmp $1 100 0 +3
+ SendMessage $PROGBAR2 ${PBM_SETPOS} 0 0
+ Goto +2
+ SendMessage $PROGBAR2 ${PBM_DELTAPOS} 5 0
+
+FunctionEnd
+
+Function OnTimer3
+ Pop $0 ; Timer id
+
+ SendMessage $PROGBAR3 ${PBM_GETPOS} 0 0 $1
+ IntCmp $1 85 0 +4 0
+ nsDialogs::DestroyTimer /NOUNLOAD $0
+ MessageBox MB_OK "Timer 3 killed"
+ Goto +2
+ SendMessage $PROGBAR3 ${PBM_DELTAPOS} 2 0
+
+FunctionEnd
+
+Function OnClick
+ Pop $0
+
+ nsDialogs::DestroyTimer /NOUNLOAD $TIMERID
+
+FunctionEnd
+
+Function OnClick2
+ Pop $0
+
+ nsDialogs::DestroyTimer /NOUNLOAD $TIMERID2
+
+FunctionEnd
+
+Function nsDialogsPage
+
+ nsDialogs::Create /NOUNLOAD 1018
+ Pop $DIALOG
+
+ nsDialogs::CreateControl /NOUNLOAD "STATIC" ${DEFAULT_STYLES} ${WS_EX_TRANSPARENT} 0u 0u 100% 9u "nsDialogs timer example"
+ Pop $TEXT
+
+ nsDialogs::CreateControl /NOUNLOAD "msctls_progress32" ${DEFAULT_STYLES} "" 0u 10u 100% 12u ""
+ Pop $PROGBAR
+
+ nsDialogs::CreateControl /NOUNLOAD "BUTTON" ${DEFAULT_STYLES}|${WS_TABSTOP} "" 0u 25u 100u 14u "Kill Timer 1"
+ Pop $BUTTON
+ GetFunctionAddress $0 OnClick
+ nsDialogs::OnClick /NOUNLOAD $BUTTON $0
+
+ nsDialogs::CreateControl /NOUNLOAD "msctls_progress32" ${DEFAULT_STYLES} "" 0u 52u 100% 12u ""
+ Pop $PROGBAR2
+
+ nsDialogs::CreateControl /NOUNLOAD "BUTTON" ${DEFAULT_STYLES}|${WS_TABSTOP} "" 0u 67u 100u 14u "Kill Timer 2"
+ Pop $BUTTON2
+ GetFunctionAddress $0 OnClick2
+ nsDialogs::OnClick /NOUNLOAD $BUTTON2 $0
+
+ nsDialogs::CreateControl /NOUNLOAD "msctls_progress32" ${DEFAULT_STYLES} "" 0u 114u 100% 12u ""
+ Pop $PROGBAR3
+
+ GetFunctionAddress $0 OnTimer
+ nsDialogs::CreateTimer /NOUNLOAD 1000 $0
+ Pop $TIMERID
+
+ GetFunctionAddress $0 OnTimer2
+ nsDialogs::CreateTimer /NOUNLOAD 100 $0
+ Pop $TIMERID2
+
+ GetFunctionAddress $0 OnTimer3
+ nsDialogs::CreateTimer /NOUNLOAD 200 $0
+ Pop $0
+
+ nsDialogs::Show
+
+FunctionEnd
+
+Section
+SectionEnd
diff --git a/Include/WinMessages.nsh b/Include/WinMessages.nsh
index 859e92d3..e40c269a 100644
--- a/Include/WinMessages.nsh
+++ b/Include/WinMessages.nsh
@@ -39,6 +39,7 @@ SB Status bar window
SBM Scroll bar control
STM Static control
TCM Tab control
+PBM Progress bar
-----------------------------------
NOT included messages (WM_USER + X)
@@ -50,7 +51,6 @@ DTM Date and time picker control
HKM Hot key control
IPM IP address control
MCM Month calendar control
-PBM Progress bar
PGM Pager control
PSM Property sheet
RB Rebar control
@@ -579,5 +579,14 @@ UDM Up-down control
#Tab control#
!define TCM_FIRST 0x1300
+#Progress bar control#
+!define PBM_SETRANGE 0x0401
+!define PBM_SETPOS 0x0402
+!define PBM_DELTAPOS 0x0403
+!define PBM_SETSTEP 0x0404
+!define PBM_STEPIT 0x0405
+!define PBM_GETPOS 0x0408
+!define PBM_SETMARQUEE 0x040a
+
!verbose pop
!endif
\ No newline at end of file