NSIS/Contrib/nsDialogs/nsDialogs.c
wizou 752d7d239a Jim Park's Unicode NSIS merging - Step 1 : switch to TCHARs where relevant.
Compiler output is identical before & after this step

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/branches/wizou@6036 212acab6-be3b-0410-9dea-997c60f758d6
2010-03-24 17:22:56 +00:00

600 lines
15 KiB
C

// Unicode support by Jim Park -- 08/10/2007
#include <windows.h>
#include <nsis/pluginapi.h> // nsis plugin
#include "defs.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;
TCHAR 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] = _T('\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;
}
static UINT_PTR PluginCallback(enum NSPIM msg)
{
return 0;
}
void __declspec(dllexport) Create(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
HWND hwPlacementRect;
RECT rcPlacement;
EXDLL_INIT();
extra->RegisterPluginCallback(g_hInstance, PluginCallback);
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(_T("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);
g_dialog.callbacks.onBack = 0;
pushint((int) g_dialog.hwDialog);
}
void __declspec(dllexport) CreateControl(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
TCHAR *className;
TCHAR *text;
HWND hwItem;
int x, y, width, height;
DWORD style, exStyle;
size_t id;
// get info from stack
className = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (g_stringsize * 2)*sizeof(TCHAR));
text = &className[g_stringsize];
if (!className)
{
pushstring(_T("error"));
return;
}
if (popstringn(className, 0))
{
pushstring(_T("error"));
HeapFree(GetProcessHeap(), 0, className);
return;
}
style = (DWORD) popint_or();
exStyle = (DWORD) popint_or();
PopPlacement(&x, &y, &width, &height);
if (popstringn(text, 0))
{
pushstring(_T("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, _T("BUTTON")))
g_dialog.controls[id].type = NSCTL_BUTTON;
else if (!lstrcmpi(className, _T("EDIT")))
g_dialog.controls[id].type = NSCTL_EDIT;
else if (!lstrcmpi(className, _T("COMBOBOX")))
g_dialog.controls[id].type = NSCTL_COMBOBOX;
else if (!lstrcmpi(className, _T("LISTBOX")))
g_dialog.controls[id].type = NSCTL_LISTBOX;
else if (!lstrcmpi(className, _T("RichEdit")))
g_dialog.controls[id].type = NSCTL_RICHEDIT;
else if (!lstrcmpi(className, _T("RICHEDIT_CLASS")))
g_dialog.controls[id].type = NSCTL_RICHEDIT2;
else if (!lstrcmpi(className, _T("STATIC")))
g_dialog.controls[id].type = NSCTL_STATIC;
else if (!lstrcmpi(className, _T("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, _T("LINK")) ? className : _T("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, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
CreateControl(hwndParent, string_size, variables, stacktop, extra);
}
void __declspec(dllexport) SetUserData(HWND hwndParent, int string_size, TCHAR *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
popstringn(ctl->userData, USERDATA_SIZE);
}
void __declspec(dllexport) GetUserData(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
HWND hwCtl;
struct nsControl* ctl;
// get info from stack
hwCtl = (HWND) popint();
if (!IsWindow(hwCtl))
{
pushstring(_T(""));
return;
}
// get descriptor
ctl = GetControl(hwCtl);
if (ctl == NULL)
{
pushstring(_T(""));
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, TCHAR *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 nsdKillTimer(HWND hwndParent, int string_size, TCHAR *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, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
SetControlCallback(CTL_CALLBACK_IDX(onClick));
}
void __declspec(dllexport) OnChange(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
SetControlCallback(CTL_CALLBACK_IDX(onChange));
}
void __declspec(dllexport) OnNotify(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
SetControlCallback(CTL_CALLBACK_IDX(onNotify));
}
void __declspec(dllexport) OnBack(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
{
SetDialogCallback(DLG_CALLBACK_IDX(onBack));
}
void __declspec(dllexport) Show(HWND hwndParent, int string_size, TCHAR *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;
}