From dba6bb42109d3455dce196b20f8531de6e2521dd Mon Sep 17 00:00:00 2001 From: kichik Date: Sat, 29 Nov 2008 17:56:54 +0000 Subject: [PATCH] applied patch #2135855 - Timer support for nsDialogs also added progress bar support for the example git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@5803 212acab6-be3b-0410-9dea-997c60f758d6 --- Contrib/nsDialogs/Readme.html | 38 ++ Contrib/nsDialogs/SConscript | 1 + Contrib/nsDialogs/nsDialogs.c | 1135 ++++++++++++++++--------------- Contrib/nsDialogs/nsDialogs.nsh | 31 + Contrib/nsDialogs/timer.nsi | 117 ++++ Include/WinMessages.nsh | 11 +- 6 files changed, 785 insertions(+), 548 deletions(-) create mode 100644 Contrib/nsDialogs/timer.nsi 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