NSIS/Contrib/nsDialogs/nsDialogs.c
anders_k 7cc150c464 MakeNSIS can now generate Unicode or Ansi installers based on a script attribute. SCons generates both Ansi and Unicode stubs and plugins.
The official plugins are now stored in architecture specific subdirectories under NSIS\Plugins. !AddPluginDir also gained a new (optional) architecture flag because MakeNSIS now stores separate plugin information for each target architecture. Storing plugins in the root of the Plugins directory is no longer supported.

MinGW does not implement the unicode CRT startup functions so the entry point functions and linker parameters had to be changed. The unicode tools use the ansi entry point and a small helper function that calls into the real code: _tmain has full argc+argv emulation while wWinMain does not pass the command line parameters. The stubs do not use any CRT functions and have no CRT or unicode helper code, they call our entry point directly.



git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6269 212acab6-be3b-0410-9dea-997c60f758d6
2012-10-13 01:47:50 +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 (!GetWindowLongPtr(lpdis->hwndItem, GWLP_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) SetWindowLongPtr(hwndParent, DWLP_DLGPROC, (LONG_PTR) 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) SetWindowLongPtr(hwItem, GWLP_WNDPROC, (LONG_PTR) 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
SetWindowLongPtr(hwndParent, DWLP_DLGPROC, (LONG_PTR) g_dialog.parentOriginalWndproc);
}
BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
g_hInstance = hInst;
return TRUE;
}