
Compiler output is identical before & after this step git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6037 212acab6-be3b-0410-9dea-997c60f758d6
476 lines
11 KiB
C
476 lines
11 KiB
C
#include <windows.h>
|
|
#include <shlobj.h>
|
|
#include <nsis/pluginapi.h> // nsis plugin
|
|
#include "resource.h"
|
|
|
|
HINSTANCE g_hInstance;
|
|
|
|
HWND hwParent;
|
|
HWND hwChild;
|
|
HWND g_hwStartMenuSelect;
|
|
HWND g_hwDirList;
|
|
|
|
TCHAR buf[1024];
|
|
TCHAR text[1024];
|
|
TCHAR progname[1024];
|
|
TCHAR lastused[1024];
|
|
TCHAR checkbox[1024];
|
|
|
|
int autoadd;
|
|
int g_done;
|
|
int noicon;
|
|
int rtl;
|
|
|
|
void *lpWndProcOld;
|
|
|
|
void (__stdcall *validate_filename)(TCHAR *);
|
|
|
|
BOOL CALLBACK dlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static BOOL CALLBACK ParentWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
void AddFolderFromReg(int nFolder);
|
|
|
|
static UINT_PTR PluginCallback(enum NSPIM msg)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void __declspec(dllexport) Init(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
|
|
{
|
|
HWND hwStartMenuSelect;
|
|
|
|
hwParent = hwndParent;
|
|
|
|
validate_filename = extra->validate_filename;
|
|
|
|
EXDLL_INIT();
|
|
|
|
extra->RegisterPluginCallback(g_hInstance, PluginCallback);
|
|
|
|
g_done = 0;
|
|
noicon = 0;
|
|
rtl = 0;
|
|
autoadd = 0;
|
|
|
|
text[0] = 0;
|
|
progname[0] = 0;
|
|
lastused[0] = 0;
|
|
checkbox[0] = 0;
|
|
|
|
g_hwStartMenuSelect = NULL;
|
|
|
|
{
|
|
hwChild = GetDlgItem(hwndParent, 1018);
|
|
if (!hwChild)
|
|
{
|
|
pushstring(_T("error finding childwnd"));
|
|
return;
|
|
}
|
|
|
|
popstring(buf);
|
|
|
|
while (buf[0] == _T('/'))
|
|
{
|
|
if (!lstrcmpi(buf+1, _T("noicon")))
|
|
{
|
|
noicon = 1;
|
|
}
|
|
else if (!lstrcmpi(buf+1, _T("rtl")))
|
|
{
|
|
rtl = 1;
|
|
}
|
|
else if (!lstrcmpi(buf+1, _T("text")))
|
|
{
|
|
popstring(text);
|
|
}
|
|
else if (!lstrcmpi(buf+1, _T("autoadd")))
|
|
{
|
|
autoadd = 1;
|
|
}
|
|
else if (!lstrcmpi(buf+1, _T("lastused")))
|
|
{
|
|
popstring(lastused);
|
|
}
|
|
else if (!lstrcmpi(buf+1, _T("checknoshortcuts")))
|
|
{
|
|
popstring(checkbox);
|
|
}
|
|
|
|
if (popstring(buf))
|
|
{
|
|
*buf = 0;
|
|
}
|
|
}
|
|
|
|
if (*buf)
|
|
{
|
|
lstrcpy(progname, buf);
|
|
}
|
|
else
|
|
{
|
|
pushstring(_T("error reading parameters"));
|
|
return;
|
|
}
|
|
|
|
hwStartMenuSelect = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_DIALOG), hwndParent, dlgProc);
|
|
g_hwStartMenuSelect = hwStartMenuSelect;
|
|
if (!hwStartMenuSelect)
|
|
{
|
|
pushstring(_T("error creating dialog"));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
lpWndProcOld = (void *) SetWindowLong(hwndParent, DWL_DLGPROC, (long) ParentWndProc);
|
|
wsprintf(buf, _T("%u"), hwStartMenuSelect);
|
|
pushstring(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
void __declspec(dllexport) Show(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop)
|
|
{
|
|
HWND hwStartMenuSelect = g_hwStartMenuSelect;
|
|
|
|
if (!hwStartMenuSelect)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while (!g_done)
|
|
{
|
|
MSG msg;
|
|
GetMessage(&msg, NULL, 0, 0);
|
|
if (!IsDialogMessage(hwStartMenuSelect,&msg) && !IsDialogMessage(hwndParent,&msg) && !TranslateMessage(&msg))
|
|
DispatchMessage(&msg);
|
|
}
|
|
DestroyWindow(hwStartMenuSelect);
|
|
|
|
SetWindowLong(hwndParent, DWL_DLGPROC, (long) lpWndProcOld);
|
|
}
|
|
|
|
void __declspec(dllexport) Select(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
|
|
{
|
|
Init(hwndParent, string_size, variables, stacktop, extra);
|
|
if (g_hwStartMenuSelect)
|
|
{
|
|
popstring(buf);
|
|
Show(hwndParent, string_size, variables, stacktop);
|
|
}
|
|
}
|
|
|
|
static BOOL CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL bRes = CallWindowProc((long (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long))lpWndProcOld,hwnd,message,wParam,lParam);
|
|
if (message == WM_NOTIFY_OUTER_NEXT && !bRes)
|
|
{
|
|
// if leave function didn't abort (lRes != 0 in that case)
|
|
PostMessage(g_hwStartMenuSelect,WM_USER+666,wParam,0);
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
void AddRTLStyle(HWND hWnd, long dwStyle)
|
|
{
|
|
long s;
|
|
|
|
s = GetWindowLong(hWnd, GWL_STYLE);
|
|
SetWindowLong(hWnd, GWL_STYLE, s | dwStyle);
|
|
s = GetWindowLong(hWnd, GWL_EXSTYLE);
|
|
SetWindowLong(hWnd, GWL_EXSTYLE, s | WS_EX_RIGHT | WS_EX_RTLREADING);
|
|
}
|
|
|
|
#define ProgressiveSetWindowPos(hwWindow, x, cx, cy) \
|
|
MoveWindow( \
|
|
hwWindow, \
|
|
x, \
|
|
y_offset, \
|
|
cx, \
|
|
cy, \
|
|
FALSE \
|
|
); \
|
|
\
|
|
y_offset += cy + 3;
|
|
|
|
BOOL CALLBACK dlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND hwLocation = GetDlgItem(hwndDlg, IDC_LOCATION);
|
|
HWND hwDirList = GetDlgItem(hwndDlg, IDC_DIRLIST);
|
|
HWND hwCheckBox = GetDlgItem(hwndDlg, IDC_CHECK);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND hwIcon;
|
|
HWND hwText;
|
|
|
|
RECT dialog_r, temp_r;
|
|
|
|
HFONT hFont = (HFONT) SendMessage(hwParent, WM_GETFONT, 0, 0);
|
|
|
|
int y_offset = 0;
|
|
|
|
int width, height;
|
|
|
|
int baseUnitY;
|
|
|
|
// Init dialog unit conversion
|
|
|
|
{
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
|
|
hDC = GetDC(hwndDlg);
|
|
SelectObject(hDC, hFont);
|
|
|
|
GetTextMetrics(hDC, &tm);
|
|
baseUnitY = tm.tmHeight;
|
|
|
|
ReleaseDC(hwndDlg, hDC);
|
|
}
|
|
|
|
GetWindowRect(hwChild, &dialog_r);
|
|
ScreenToClient(hwParent, (LPPOINT) &dialog_r);
|
|
ScreenToClient(hwParent, ((LPPOINT) &dialog_r) + 1);
|
|
|
|
width = dialog_r.right - dialog_r.left;
|
|
height = dialog_r.bottom - dialog_r.top;
|
|
|
|
MoveWindow(
|
|
hwndDlg,
|
|
dialog_r.left,
|
|
dialog_r.top,
|
|
width,
|
|
height,
|
|
FALSE
|
|
);
|
|
|
|
hwIcon = GetDlgItem(hwndDlg, IDC_NSISICON);
|
|
hwText = GetDlgItem(hwndDlg, IDC_TEXT);
|
|
g_hwDirList = hwDirList;
|
|
|
|
SendMessage(hwndDlg, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
SendMessage(hwIcon, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
SendMessage(hwText, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
SendMessage(hwLocation, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
SendMessage(hwDirList, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
SendMessage(hwCheckBox, WM_SETFONT, (WPARAM) hFont, TRUE);
|
|
|
|
if (rtl)
|
|
{
|
|
AddRTLStyle(hwText, SS_RIGHT);
|
|
AddRTLStyle(hwLocation, ES_RIGHT);
|
|
AddRTLStyle(hwDirList, 0);
|
|
AddRTLStyle(hwCheckBox, BS_RIGHT | BS_LEFTTEXT);
|
|
}
|
|
|
|
GetClientRect(hwIcon, &temp_r);
|
|
|
|
if (!noicon)
|
|
{
|
|
SendMessage(
|
|
hwIcon,
|
|
STM_SETIMAGE,
|
|
IMAGE_ICON,
|
|
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(103))
|
|
);
|
|
|
|
MoveWindow(
|
|
hwIcon,
|
|
rtl ? width - temp_r.right : 0,
|
|
0,
|
|
temp_r.right,
|
|
temp_r.bottom,
|
|
FALSE
|
|
);
|
|
|
|
temp_r.right += 3;
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(hwIcon, SW_HIDE);
|
|
|
|
temp_r.right = 0;
|
|
}
|
|
|
|
if (rtl)
|
|
{
|
|
ProgressiveSetWindowPos(
|
|
hwText,
|
|
0,
|
|
width - temp_r.right,
|
|
3 * baseUnitY //MulDiv(24, baseUnitY, 8);
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ProgressiveSetWindowPos(
|
|
hwText,
|
|
temp_r.right,
|
|
width - temp_r.right + 3,
|
|
3 * baseUnitY //MulDiv(24, baseUnitY, 8);
|
|
);
|
|
}
|
|
|
|
SetWindowText(hwText, *text ? text : _T("Select the Start Menu folder in which you would like to create the program's shortcuts:"));
|
|
|
|
ProgressiveSetWindowPos(
|
|
hwLocation,
|
|
0,
|
|
width,
|
|
MulDiv(12, baseUnitY, 8)
|
|
);
|
|
|
|
if (*lastused == _T('>'))
|
|
{
|
|
CheckDlgButton(hwndDlg, IDC_CHECK, BST_CHECKED);
|
|
lstrcpy(lastused, lstrcpy(buf, lastused) + 1);
|
|
EnableWindow(hwDirList, FALSE);
|
|
EnableWindow(hwLocation, FALSE);
|
|
}
|
|
|
|
SetWindowText(hwLocation, *lastused ? lastused : progname);
|
|
|
|
temp_r.bottom = MulDiv(8, baseUnitY, 8);
|
|
|
|
ProgressiveSetWindowPos(
|
|
hwDirList,
|
|
0,
|
|
width,
|
|
height - y_offset - (*checkbox ? temp_r.bottom + 3 : 0)
|
|
);
|
|
|
|
if (*checkbox)
|
|
{
|
|
ProgressiveSetWindowPos(
|
|
hwCheckBox,
|
|
0,
|
|
width,
|
|
temp_r.bottom
|
|
);
|
|
|
|
ShowWindow(hwCheckBox, SW_SHOWNA);
|
|
SetWindowText(hwCheckBox, checkbox);
|
|
}
|
|
|
|
AddFolderFromReg(CSIDL_COMMON_PROGRAMS);
|
|
AddFolderFromReg(CSIDL_PROGRAMS);
|
|
|
|
// Tell NSIS to remove old inner dialog and pass handle of the new inner dialog
|
|
SendMessage(hwParent, WM_NOTIFY_CUSTOM_READY, (WPARAM)hwndDlg, 0);
|
|
ShowWindow(hwndDlg, SW_SHOWNA);
|
|
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK) == BST_CHECKED)
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) hwCheckBox, TRUE);
|
|
else
|
|
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) hwLocation, TRUE);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDC_DIRLIST && HIWORD(wParam) == LBN_SELCHANGE)
|
|
{
|
|
LRESULT selection = SendMessage(hwDirList, LB_GETCURSEL, 0, 0);
|
|
if (selection != LB_ERR)
|
|
{
|
|
SendMessage(hwDirList, LB_GETTEXT, selection, (WPARAM)buf);
|
|
if (autoadd)
|
|
lstrcat(lstrcat(buf, _T("\\")), progname);
|
|
SetWindowText(hwLocation, buf);
|
|
}
|
|
}
|
|
else if (LOWORD(wParam) == IDC_CHECK && HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
BOOL bEnable = IsDlgButtonChecked(hwndDlg, IDC_CHECK) != BST_CHECKED;
|
|
EnableWindow(hwDirList, bEnable);
|
|
EnableWindow(hwLocation, bEnable);
|
|
if (bEnable)
|
|
goto ValidateLocation;
|
|
*buf = _T('!'); //This only needs to be != 0, actual value does not matter
|
|
goto SetOkBtn;
|
|
}
|
|
else if (LOWORD(wParam) == IDC_LOCATION && HIWORD(wParam) == EN_CHANGE)
|
|
{
|
|
ValidateLocation:
|
|
GetWindowText(hwLocation, buf, MAX_PATH);
|
|
validate_filename(buf);
|
|
SetOkBtn:
|
|
EnableWindow(GetDlgItem(hwParent, IDOK), *buf != _T('\0'));
|
|
}
|
|
break;
|
|
case WM_USER+666:
|
|
g_done = 1;
|
|
if (wParam == NOTIFY_BYE_BYE)
|
|
pushstring(_T("cancel"));
|
|
else
|
|
{
|
|
GetWindowText(hwLocation, buf + 1, MAX_PATH);
|
|
validate_filename(buf);
|
|
if (IsDlgButtonChecked(hwndDlg, IDC_CHECK) == BST_CHECKED)
|
|
{
|
|
buf[0] = _T('>');
|
|
pushstring(buf);
|
|
}
|
|
else
|
|
{
|
|
pushstring(buf + 1);
|
|
}
|
|
pushstring(_T("success"));
|
|
}
|
|
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(hwParent, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
|
{
|
|
g_hInstance=hInst;
|
|
return TRUE;
|
|
}
|
|
|
|
void AddFolderFromReg(int nFolder)
|
|
{
|
|
//DWORD idx;
|
|
WIN32_FIND_DATA FileData;
|
|
HANDLE hSearch;
|
|
LPITEMIDLIST ppidl;
|
|
|
|
buf[0] = 0;
|
|
if (SHGetSpecialFolderLocation(hwParent, nFolder, &ppidl) == S_OK)
|
|
{
|
|
SHGetPathFromIDList(ppidl, buf);
|
|
CoTaskMemFree(ppidl);
|
|
}
|
|
|
|
if (!buf[0])
|
|
return;
|
|
|
|
lstrcat(buf, _T("\\*.*"));
|
|
hSearch = FindFirstFile(buf, &FileData);
|
|
if (hSearch != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (*(WORD*)FileData.cFileName != *(WORD*)_T("."))
|
|
{
|
|
if (*(WORD*)FileData.cFileName != *(WORD*)_T("..") || FileData.cFileName[2])
|
|
{
|
|
if (SendMessage(g_hwDirList, LB_FINDSTRINGEXACT, (WPARAM) -1, (LPARAM)FileData.cFileName) == LB_ERR)
|
|
SendMessage(g_hwDirList, LB_ADDSTRING, 0, (LPARAM)FileData.cFileName);
|
|
/*idx = */
|
|
/*SendMessage(hwDirList, LB_SETITEMDATA, (WPARAM)idx,
|
|
(LPARAM)ExtractAssociatedIcon(g_hInstance, FileData.cFileName, (WORD*)&idx));*/
|
|
}
|
|
}
|
|
}
|
|
} while (FindNextFile(hSearch, &FileData));
|
|
FindClose(hSearch);
|
|
}
|
|
}
|