
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
1785 lines
48 KiB
C
1785 lines
48 KiB
C
/*
|
|
* Ui.c
|
|
*
|
|
* This file is a part of NSIS.
|
|
*
|
|
* Copyright (C) 1999-2009 Nullsoft, Jeff Doozan and Contributors
|
|
*
|
|
* Licensed under the zlib/libpng license (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
*
|
|
* Licence details can be found in the file COPYING.
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty.
|
|
*
|
|
* Unicode support by Jim Park -- 08/10/2007
|
|
*/
|
|
|
|
#include <windowsx.h>
|
|
#include <shlobj.h>
|
|
#include <shellapi.h>
|
|
#include <shlwapi.h>
|
|
|
|
#include "../Platform.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "fileform.h"
|
|
#include "state.h"
|
|
#include "util.h"
|
|
#include "ui.h"
|
|
#include "exec.h"
|
|
#include "plugin.h"
|
|
#include "lang.h"
|
|
#include "components.h"
|
|
#include "api.h"
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
HICON g_hIcon;
|
|
#endif
|
|
|
|
int dlg_offset;
|
|
int ui_dlg_visible=0; // At start main window is not visible
|
|
int g_quit_flag; // set when Quit has been called (meaning bail out ASAP)
|
|
|
|
#if NSIS_MAX_INST_TYPES > 32 || NSIS_MAX_INST_TYPES < 1
|
|
#error invalid value for NSIS_MAX_INST_TYPES
|
|
#endif
|
|
|
|
int progress_bar_pos, progress_bar_len;
|
|
|
|
#if NSIS_MAX_STRLEN < 1024
|
|
static TCHAR g_tmp[4096];
|
|
#else
|
|
static TCHAR g_tmp[NSIS_MAX_STRLEN * 4];
|
|
#endif
|
|
|
|
static int m_page=-1,m_retcode,m_delta;
|
|
static page *g_this_page;
|
|
|
|
static void NSISCALL outernotify(int delta) {
|
|
if (delta==NOTIFY_BYE_BYE)
|
|
g_quit_flag++;
|
|
SendMessage(g_hwnd,WM_NOTIFY_OUTER_NEXT,(WPARAM)delta,0);
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
|
|
#ifdef NSIS_CONFIG_LICENSEPAGE
|
|
static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
#endif
|
|
static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static BOOL CALLBACK SelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static BOOL CALLBACK InstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
static BOOL CALLBACK UninstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
static DWORD WINAPI install_thread(LPVOID p);
|
|
|
|
void NSISCALL CleanUp();
|
|
|
|
HWND insthwnd, insthwnd2, insthwndbutton;
|
|
|
|
HWND m_curwnd;
|
|
static HWND m_bgwnd, m_hwndOK, m_hwndCancel;
|
|
|
|
static BOOL NSISCALL SetDlgItemTextFromLang_(HWND dlg, int id, int lid) {
|
|
return my_SetDialogItemText(dlg,id+1000,GetNSISStringTT(lid));
|
|
}
|
|
|
|
static void NSISCALL SetNextDef()
|
|
{
|
|
SendMessage(g_exec_flags.abort ? m_hwndCancel : m_hwndOK, BM_SETSTYLE, BS_DEFPUSHBUTTON, TRUE);
|
|
}
|
|
|
|
static void NSISCALL EnableNext(BOOL e)
|
|
{
|
|
EnableWindow(m_hwndOK, e);
|
|
}
|
|
|
|
static void NSISCALL SetActiveCtl(HWND hCtl)
|
|
{
|
|
SendMessage(g_hwnd, WM_NEXTDLGCTL, (WPARAM) hCtl, TRUE);
|
|
}
|
|
|
|
static void NSISCALL NotifyCurWnd(UINT uNotifyCode)
|
|
{
|
|
if (m_curwnd)
|
|
SendMessage(m_curwnd, uNotifyCode, 0, 0);
|
|
}
|
|
|
|
#define SetDlgItemTextFromLang(dlg,id,lid) SetDlgItemTextFromLang_(dlg,(id)-1000,lid)
|
|
|
|
#define SetUITextFromLang(it,la) SetDlgItemTextFromLang_(hwndDlg,(it)-1000,la)
|
|
#define SetUITextNT(it,text) my_SetDialogItemText(hwndDlg,it,text)
|
|
#define GetUIText(it,s) my_GetDialogItemText(it,s)
|
|
#define GetUIItem(it) GetDlgItem(hwndDlg,it)
|
|
|
|
#ifdef NSIS_CONFIG_ENHANCEDUI_SUPPORT
|
|
#define HandleStaticBkColor() _HandleStaticBkColor(uMsg, wParam, lParam)
|
|
static BOOL NSISCALL _HandleStaticBkColor(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if ((uMsg - WM_CTLCOLOREDIT) <= (WM_CTLCOLORSTATIC - WM_CTLCOLOREDIT))
|
|
{
|
|
ctlcolors *c = (ctlcolors *)GetWindowLongPtr((HWND)lParam, GWLP_USERDATA);
|
|
|
|
if (c) {
|
|
COLORREF text;
|
|
LOGBRUSH lh;
|
|
|
|
text = c->text;
|
|
if (c->flags & CC_TEXT_SYS)
|
|
text = GetSysColor(text);
|
|
if (c->flags & CC_TEXT)
|
|
SetTextColor((HDC)wParam, text);
|
|
|
|
SetBkMode((HDC)wParam, c->bkmode);
|
|
|
|
lh.lbColor = c->bkc;
|
|
if (c->flags & CC_BK_SYS)
|
|
lh.lbColor = GetSysColor(lh.lbColor);
|
|
if (c->flags & CC_BK)
|
|
SetBkColor((HDC)wParam, lh.lbColor);
|
|
|
|
if (c->flags & CC_BKB)
|
|
{
|
|
lh.lbStyle = c->lbStyle;
|
|
if (c->bkb)
|
|
DeleteObject(c->bkb);
|
|
c->bkb = CreateBrushIndirect(&lh);
|
|
}
|
|
|
|
return (BOOL)c->bkb;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#else
|
|
#define HandleStaticBkColor() 0
|
|
#endif//!NSIS_CONFIG_ENHANCEDUI_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_LOG
|
|
#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT)
|
|
void NSISCALL build_g_logfile()
|
|
{
|
|
mystrcat(addtrailingslash(mystrcpy(g_log_file,state_install_directory)),_T("install.log"));
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
int *cur_langtable;
|
|
|
|
static void NSISCALL set_language()
|
|
{
|
|
LANGID lang_mask=(LANGID)~0;
|
|
LANGID lang=myatoi(state_language);
|
|
char *language_table=0;
|
|
int lang_num;
|
|
int *selected_langtable=0;
|
|
|
|
// Jim Park: We are doing byte offsets to get to various data structures so
|
|
// no TCHARs here.
|
|
lang_again:
|
|
lang_num=g_blocks[NB_LANGTABLES].num;
|
|
while (lang_num--) {
|
|
language_table=((char*)g_blocks[NB_LANGTABLES].offset)+lang_num*g_header->langtable_size;
|
|
if (!((lang ^ *(LANGID*)language_table) & lang_mask)) {
|
|
dlg_offset=*(int*)(language_table+sizeof(LANGID));
|
|
g_exec_flags.rtl=*(int*)(language_table+sizeof(LANGID)+sizeof(int));
|
|
selected_langtable=(int*)(language_table+sizeof(LANGID)+2*sizeof(int));
|
|
break;
|
|
}
|
|
}
|
|
if (!selected_langtable) {
|
|
if (lang_mask == (LANGID)~0)
|
|
lang_mask=0x3ff; // primary lang
|
|
else // we already tried once and we still don't have a language table
|
|
lang_mask=0; // first lang
|
|
goto lang_again;
|
|
}
|
|
|
|
cur_langtable = selected_langtable;
|
|
|
|
myitoa(state_language, *(LANGID*)language_table);
|
|
{
|
|
TCHAR *caption = GetNSISString(g_caption,LANG_CAPTION);
|
|
#ifdef NSIS_SUPPORT_BGBG
|
|
my_SetWindowText(m_bgwnd, caption);
|
|
#endif
|
|
}
|
|
|
|
// reload section names
|
|
{
|
|
section *sec = g_sections;
|
|
int x = num_sections;
|
|
|
|
while (x--)
|
|
{
|
|
if (sec->name_ptr)
|
|
{
|
|
GetNSISString(sec->name, sec->name_ptr);
|
|
}
|
|
sec++;
|
|
}
|
|
}
|
|
}
|
|
|
|
FORCE_INLINE int NSISCALL ui_doinstall(void)
|
|
{
|
|
header *header = g_header;
|
|
static WNDCLASS wc; // richedit subclassing and bgbg creation
|
|
|
|
// detect default language
|
|
// more information at:
|
|
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_0xrn.asp
|
|
|
|
LANGID (WINAPI *GUDUIL)();
|
|
|
|
GUDUIL = myGetProcAddress(MGA_GetUserDefaultUILanguage);
|
|
if (GUDUIL)
|
|
{
|
|
// Windows ME/2000+
|
|
myitoa(state_language, GUDUIL());
|
|
}
|
|
else
|
|
{
|
|
static const TCHAR reg_9x_locale[] = _T("Control Panel\\Desktop\\ResourceLocale");
|
|
static const TCHAR reg_nt_locale_key[] = _T(".DEFAULT\\Control Panel\\International");
|
|
const TCHAR *reg_nt_locale_val = ®_9x_locale[30]; // = _T("Locale") with opt
|
|
|
|
state_language[0] = _T('0');
|
|
state_language[1] = _T('x');
|
|
state_language[2] = 0;
|
|
|
|
{
|
|
// Windows 9x
|
|
myRegGetStr(HKEY_CURRENT_USER, reg_9x_locale, NULL, g_tmp, 0);
|
|
}
|
|
|
|
if (!g_tmp[0])
|
|
{
|
|
// Windows NT
|
|
// This key exists on 9x as well, so it's only read if ResourceLocale wasn't found
|
|
myRegGetStr(HKEY_USERS, reg_nt_locale_key, reg_nt_locale_val, g_tmp, 0);
|
|
}
|
|
|
|
mystrcat(state_language, g_tmp);
|
|
}
|
|
|
|
// set default language
|
|
set_language();
|
|
|
|
// initialize auto close flag
|
|
g_exec_flags.autoclose=g_flags&CH_FLAGS_AUTO_CLOSE;
|
|
|
|
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
|
|
// initialize plugin api
|
|
g_exec_flags.plugin_api_version=NSISPIAPIVER_CURR;
|
|
#endif
|
|
|
|
// read install directory from registry
|
|
if (!is_valid_instpath(state_install_directory))
|
|
{
|
|
if (header->install_reg_key_ptr)
|
|
{
|
|
myRegGetStr(
|
|
(HKEY)header->install_reg_rootkey,
|
|
GetNSISStringNP(header->install_reg_key_ptr),
|
|
GetNSISStringNP(header->install_reg_value_ptr),
|
|
ps_tmpbuf,
|
|
0
|
|
);
|
|
if (ps_tmpbuf[0])
|
|
{
|
|
TCHAR *p=ps_tmpbuf;
|
|
TCHAR *e;
|
|
if (p[0]==_T('\"'))
|
|
{
|
|
TCHAR *p2;
|
|
p++;
|
|
p2 = findchar(p, _T('"'));
|
|
*p2 = 0;
|
|
}
|
|
// p is the path now, check for .exe extension
|
|
|
|
e=p+mystrlen(p)-4;
|
|
if (e > p)
|
|
{
|
|
// if filename ends in .exe, and is not a directory, remove the filename
|
|
if (!lstrcmpi(e, _T(".exe"))) // check extension
|
|
{
|
|
DWORD d;
|
|
d=GetFileAttributes(p);
|
|
if (d == INVALID_FILE_ATTRIBUTES || !(d&FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
// if there is no back-slash, the string will become empty, but that's ok because
|
|
// it would make an invalid instdir anyway
|
|
trimslashtoend(p);
|
|
}
|
|
}
|
|
}
|
|
mystrcpy(state_install_directory,addtrailingslash(p));
|
|
}
|
|
}
|
|
}
|
|
if (!is_valid_instpath(state_install_directory))
|
|
{
|
|
GetNSISString(state_install_directory,header->install_directory_ptr);
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_LOG
|
|
if (g_flags & CH_FLAGS_SILENT_LOG && !g_is_uninstaller)
|
|
{
|
|
#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT)
|
|
build_g_logfile();
|
|
#endif
|
|
log_dolog=1;
|
|
}
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
g_hIcon=LoadImage(g_hInstance,MAKEINTRESOURCE(IDI_ICON2),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_SHARED);
|
|
#ifdef NSIS_SUPPORT_BGBG
|
|
if (header->bg_color1 != -1)
|
|
{
|
|
LPCTSTR cn = _T("_Nb");
|
|
RECT vp;
|
|
extern LRESULT CALLBACK BG_WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
wc.lpfnWndProc = BG_WndProc;
|
|
wc.hInstance = g_hInstance;
|
|
wc.hIcon = g_hIcon;
|
|
//wc.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
wc.lpszClassName = cn;
|
|
|
|
if (!RegisterClass(&wc)) return 0;
|
|
|
|
SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0);
|
|
|
|
m_bgwnd = CreateWindowEx(WS_EX_TOOLWINDOW,cn,0,WS_POPUP,
|
|
vp.left,vp.top,vp.right-vp.left,vp.bottom-vp.top,0,NULL,g_hInstance,NULL);
|
|
}
|
|
|
|
#endif//NSIS_SUPPORT_BGBG
|
|
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
// Select language
|
|
if (ExecuteCallbackFunction(CB_ONINIT)) return 2;
|
|
set_language();
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
if (!g_exec_flags.silent)
|
|
#endif//NSIS_CONFIG_SILENT_SUPPORT
|
|
{
|
|
#ifdef NSIS_SUPPORT_BGBG
|
|
ShowWindow(m_bgwnd, SW_SHOW);
|
|
#endif//NSIS_SUPPORT_BGBG
|
|
|
|
#ifdef NSIS_CONFIG_LICENSEPAGE
|
|
{ // load richedit DLL
|
|
static const TCHAR riched20[]=_T("RichEd20");
|
|
static const TCHAR riched32[]=_T("RichEd32");
|
|
static const TCHAR richedit20a[]=_T("RichEdit20A");
|
|
static const TCHAR richedit[]=_T("RichEdit");
|
|
if (!LoadLibrary(riched20))
|
|
{
|
|
LoadLibrary(riched32);
|
|
}
|
|
|
|
// make richedit20a point to RICHEDIT
|
|
if (!GetClassInfo(NULL,richedit20a,&wc))
|
|
{
|
|
GetClassInfo(NULL,richedit,&wc);
|
|
wc.lpszClassName = richedit20a;
|
|
RegisterClass(&wc);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
{
|
|
int ret=DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_INST+dlg_offset),0,DialogProc);
|
|
#if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
|
|
ExecuteCallbackFunction(CB_ONGUIEND);
|
|
#endif
|
|
#ifdef NSIS_CONFIG_PLUGIN_SUPPORT
|
|
Plugins_SendMsgToAllPlugins(NSPIM_GUIUNLOAD);
|
|
#endif
|
|
return ret;
|
|
}
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
else
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
{
|
|
if (install_thread(NULL))
|
|
{
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
if (!g_quit_flag) ExecuteCallbackFunction(CB_ONINSTFAILED);
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS
|
|
return 2;
|
|
}
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
ExecuteCallbackFunction(CB_ONINSTSUCCESS);
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS
|
|
|
|
return 0;
|
|
}
|
|
#endif//NSIS_CONFIG_SILENT_SUPPORT
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
static int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
|
{
|
|
// lpData has the TCHAR* to 'dir'.
|
|
if (uMsg==BFFM_INITIALIZED)
|
|
{
|
|
my_GetDialogItemText(IDC_DIR,(TCHAR*)lpData);
|
|
SendMessage(hwnd,BFFM_SETSELECTION,(WPARAM)1,lpData);
|
|
}
|
|
if (uMsg==BFFM_SELCHANGED)
|
|
{
|
|
SendMessage(
|
|
hwnd,
|
|
BFFM_ENABLEOK,
|
|
0,
|
|
SHGetPathFromIDList((LPITEMIDLIST)lParam,(TCHAR*)lpData)
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
&& !ExecuteCallbackFunction(CB_ONVERIFYINSTDIR)
|
|
#endif
|
|
);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_INITDIALOG || uMsg == WM_NOTIFY_OUTER_NEXT)
|
|
{
|
|
page *this_page;
|
|
static DLGPROC winprocs[]=
|
|
{
|
|
#ifdef NSIS_CONFIG_LICENSEPAGE
|
|
LicenseProc,
|
|
#endif
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE
|
|
SelProc,
|
|
#endif
|
|
DirProc,
|
|
InstProc,
|
|
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
|
|
UninstProc
|
|
#endif
|
|
};
|
|
|
|
m_delta = wParam;
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
g_hwnd=hwndDlg;
|
|
m_hwndOK=GetDlgItem(hwndDlg,IDOK);
|
|
m_hwndCancel=GetDlgItem(hwndDlg,IDCANCEL);
|
|
SetDlgItemTextFromLang(hwndDlg,IDC_VERSTR,LANG_BRANDING);
|
|
SetClassLong(hwndDlg,GCL_HICON,(long)g_hIcon);
|
|
// use the following line instead of the above, if .rdata needs shirking
|
|
//SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM)g_hIcon);
|
|
#if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
|
|
g_quit_flag = ExecuteCallbackFunction(CB_ONGUIINIT);
|
|
#endif
|
|
//ShowWindow(hwndDlg, SW_SHOW);
|
|
m_delta = 1;
|
|
}
|
|
|
|
this_page=g_pages+m_page;
|
|
|
|
if (m_page>=0) {
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
// Call leave function. If Abort used don't move to the next page.
|
|
// But if quit called we must exit now
|
|
if (m_delta==1) if (ExecuteCodeSegment(this_page->leavefunc,NULL)) {
|
|
SendMessage(m_curwnd, WM_IN_UPDATEMSG, 0, 1);
|
|
return !g_quit_flag;
|
|
}
|
|
#endif
|
|
|
|
// if the last page was a custom page, wait for it to finish by itself.
|
|
// if it doesn't, it's a BAD plugin.
|
|
// plugins should react to WM_NOTIFY_OUTER_NEXT.
|
|
if (!this_page->dlg_id) return 0;
|
|
}
|
|
|
|
NotifyCurWnd(WM_NOTIFY_INIGO_MONTOYA);
|
|
|
|
nextPage:
|
|
m_page+=m_delta;
|
|
this_page+=m_delta;
|
|
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
if (m_page==g_blocks[NB_PAGES].num) ExecuteCallbackFunction(CB_ONINSTSUCCESS);
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS
|
|
|
|
if (g_quit_flag || (unsigned int)m_page >= (unsigned int)g_blocks[NB_PAGES].num)
|
|
{
|
|
DestroyWindow(m_curwnd);
|
|
g_hwnd = 0;
|
|
EndDialog(hwndDlg,m_retcode);
|
|
}
|
|
else
|
|
{
|
|
HWND hwndtmp;
|
|
|
|
int pflags = this_page->flags;
|
|
|
|
GetNSISString(state_click_next, this_page->clicknext);
|
|
SetDlgItemTextFromLang(hwndDlg, IDOK, this_page->next);
|
|
SetDlgItemTextFromLang(hwndDlg, IDC_BACK, this_page->back);
|
|
SetDlgItemTextFromLang(hwndDlg, IDCANCEL, this_page->cancel);
|
|
|
|
hwndtmp = GetDlgItem(hwndDlg, IDC_BACK);
|
|
|
|
if (g_exec_flags.abort)
|
|
{
|
|
pflags &= ~(PF_BACK_ENABLE | PF_NEXT_ENABLE);
|
|
pflags |= PF_CANCEL_ENABLE;
|
|
}
|
|
|
|
ShowWindow(hwndtmp, pflags & PF_BACK_SHOW);// SW_HIDE = 0, PF_BACK_SHOW = SW_SHOWNA = 8
|
|
EnableWindow(hwndtmp, pflags & PF_BACK_ENABLE);
|
|
EnableNext(pflags & PF_NEXT_ENABLE);
|
|
EnableWindow(m_hwndCancel, pflags & PF_CANCEL_ENABLE);
|
|
|
|
if (pflags & PF_CANCEL_ENABLE)
|
|
EnableMenuItem(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
|
|
else
|
|
EnableMenuItem(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
|
|
|
|
SendMessage(hwndtmp, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
|
|
|
|
if (g_exec_flags.abort)
|
|
{
|
|
SendMessage(hwndDlg, DM_SETDEFID, IDCANCEL, 0);
|
|
SetActiveCtl(m_hwndCancel);
|
|
}
|
|
else
|
|
{
|
|
SetActiveCtl(m_hwndOK);
|
|
}
|
|
|
|
mystrcpy(g_tmp,g_caption);
|
|
GetNSISString(g_tmp+mystrlen(g_tmp),this_page->caption);
|
|
my_SetWindowText(hwndDlg,g_tmp);
|
|
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
// custom page or user used abort in prefunc
|
|
if (ExecuteCodeSegment(this_page->prefunc, NULL) || !this_page->dlg_id) {
|
|
goto nextPage;
|
|
}
|
|
#endif //NSIS_SUPPORT_CODECALLBACKS
|
|
|
|
if (this_page->wndproc_id != PWP_COMPLETED)
|
|
{
|
|
DestroyWindow(m_curwnd);
|
|
}
|
|
else {
|
|
if (!g_exec_flags.abort && g_exec_flags.autoclose)
|
|
goto nextPage;
|
|
// no need to go to skipPage because PWP_COMPLETED always follows PWP_INSTFILES
|
|
return FALSE;
|
|
}
|
|
|
|
// update g_this_page for the dialog proc
|
|
g_this_page=this_page;
|
|
|
|
if (this_page->dlg_id > 0) // NSIS page
|
|
{
|
|
m_curwnd=CreateDialogParam(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(this_page->dlg_id+dlg_offset),
|
|
hwndDlg,winprocs[this_page->wndproc_id],(LPARAM)this_page
|
|
);
|
|
if (m_curwnd)
|
|
{
|
|
RECT r;
|
|
|
|
SetDlgItemTextFromLang(m_curwnd,IDC_INTROTEXT,this_page->parms[0]);
|
|
|
|
GetWindowRect(GetDlgItem(hwndDlg,IDC_CHILDRECT),&r);
|
|
ScreenToClient(hwndDlg,(LPPOINT)&r);
|
|
SetWindowPos(m_curwnd,0,r.left,r.top,0,0,SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOZORDER);
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
ExecuteCodeSegment(this_page->showfunc,NULL);
|
|
if (g_quit_flag)
|
|
return FALSE;
|
|
#endif //NSIS_SUPPORT_CODECALLBACKS
|
|
ShowWindow(m_curwnd,SW_SHOWNA);
|
|
NotifyCurWnd(WM_NOTIFY_START);
|
|
}
|
|
}
|
|
}
|
|
|
|
skipPage:
|
|
|
|
if (!ui_dlg_visible && m_curwnd)
|
|
{
|
|
ShowWindow(hwndDlg, SW_SHOWDEFAULT);
|
|
ui_dlg_visible = 1;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef NSIS_SUPPORT_BGBG
|
|
if (uMsg == WM_WINDOWPOSCHANGED)
|
|
{
|
|
SetWindowPos(m_bgwnd, hwndDlg, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
if (uMsg == WM_SIZE) {
|
|
ShowWindow(m_bgwnd, wParam == SIZE_MINIMIZED ? SW_HIDE : SW_SHOW);
|
|
}
|
|
#endif //NSIS_SUPPORT_BGBG
|
|
|
|
if (uMsg == WM_NOTIFY_CUSTOM_READY) {
|
|
DestroyWindow(m_curwnd);
|
|
m_curwnd = (HWND)wParam;
|
|
goto skipPage;
|
|
}
|
|
if (uMsg == WM_QUERYENDSESSION)
|
|
{
|
|
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
|
|
return TRUE;
|
|
}
|
|
if (uMsg == WM_COMMAND)
|
|
{
|
|
int id = LOWORD(wParam);
|
|
HWND hCtl = GetDlgItem(hwndDlg, id); // lParam might be NULL
|
|
if (hCtl)
|
|
{
|
|
SendMessage(hCtl, BM_SETSTATE, FALSE, 0);
|
|
if (!IsWindowEnabled(hCtl))
|
|
return 0;
|
|
}
|
|
|
|
if (id == IDOK)
|
|
{
|
|
outernotify(1);
|
|
}
|
|
else if (id == IDC_BACK && m_page>0)
|
|
{
|
|
outernotify(-1);
|
|
}
|
|
else if (id == IDCANCEL)
|
|
{
|
|
if (g_exec_flags.abort)
|
|
{
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
ExecuteCallbackFunction(CB_ONINSTFAILED);
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS
|
|
m_retcode=2;
|
|
outernotify(NOTIFY_BYE_BYE);
|
|
}
|
|
else
|
|
{
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
if (!ExecuteCallbackFunction(CB_ONUSERABORT))
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS
|
|
{
|
|
m_retcode=1;
|
|
outernotify(NOTIFY_BYE_BYE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Forward WM_COMMANDs to inner dialogs, can be custom ones.
|
|
// Without this, enter on buttons in inner dialogs won't work.
|
|
SendMessage(m_curwnd, WM_COMMAND, wParam, lParam);
|
|
}
|
|
}
|
|
return HandleStaticBkColor();
|
|
}
|
|
|
|
#define this_page ((page*)lParam)
|
|
|
|
#ifdef NSIS_CONFIG_LICENSEPAGE
|
|
|
|
#define _RICHEDIT_VER 0x0200
|
|
#include <richedit.h>
|
|
#undef _RICHEDIT_VER
|
|
static DWORD dwRead;
|
|
DWORD CALLBACK StreamLicense(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
|
|
{
|
|
lstrcpyn((LPTSTR)pbBuff,(LPTSTR)(dwCookie+dwRead),cb/sizeof(TCHAR));
|
|
*pcb=lstrlen((LPTSTR)pbBuff)*sizeof(TCHAR);
|
|
dwRead+=*pcb;
|
|
return 0;
|
|
}
|
|
#ifdef _UNICODE
|
|
// on-the-fly conversion of Unicode to ANSI (because Windows doesn't recognize Unicode RTF data)
|
|
DWORD CALLBACK StreamLicenseRTF(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
|
|
{
|
|
size_t len = lstrlen(((LPWSTR) dwCookie)+dwRead);
|
|
len = min(len, cb/sizeof(WCHAR));
|
|
*pcb=WideCharToMultiByte(CP_ACP,0,((LPWSTR) dwCookie)+dwRead,len,(char*)pbBuff,cb,NULL,NULL);
|
|
// RTF uses only ASCII characters, so we can assume "number of output bytes" = "number of source WChar consumed"
|
|
dwRead+=*pcb;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
page *m_this_page=g_this_page;
|
|
HWND hwLicense;
|
|
static int ignoreWMCommand;
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
TCHAR *l = (TCHAR *)GetNSISStringNP(GetNSISTab(this_page->parms[1]));
|
|
int lt = *l;
|
|
EDITSTREAM es = {
|
|
(DWORD_PTR)(++l),
|
|
0,
|
|
#ifdef _UNICODE
|
|
lt==SF_RTF?StreamLicenseRTF:StreamLicense
|
|
#else
|
|
StreamLicense
|
|
#endif
|
|
};
|
|
|
|
int selected = (this_page->flags & PF_LICENSE_SELECTED) | !(this_page->flags & PF_LICENSE_FORCE_SELECTION);
|
|
|
|
SetUITextFromLang(IDC_LICENSEAGREE,this_page->parms[2]);
|
|
SetUITextFromLang(IDC_LICENSEDISAGREE,this_page->parms[3]);
|
|
CheckDlgButton(hwndDlg,IDC_LICENSEAGREE+!selected,BST_CHECKED);
|
|
EnableNext(selected);
|
|
|
|
hwLicense=GetUIItem(IDC_EDIT1);
|
|
SetActiveCtl(hwLicense);
|
|
SendMessage(hwLicense,EM_AUTOURLDETECT,TRUE,0);
|
|
#define lbg g_header->license_bg
|
|
SendMessage(hwLicense,EM_SETBKGNDCOLOR,0,lbg>=0?lbg:GetSysColor(-lbg));
|
|
#undef lbg
|
|
SendMessage(hwLicense,EM_SETEVENTMASK,0,ENM_LINK|ENM_KEYEVENTS); //XGE 8th September 2002 Or'd in ENM_KEYEVENTS
|
|
dwRead=0;
|
|
SendMessage(hwLicense,EM_EXLIMITTEXT,0,mystrlen(l));
|
|
SendMessage(hwLicense,EM_STREAMIN,lt,(LPARAM)&es);
|
|
ignoreWMCommand = 0;
|
|
return FALSE;
|
|
}
|
|
if (uMsg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && !ignoreWMCommand) {
|
|
if (m_this_page->flags & PF_LICENSE_FORCE_SELECTION) {
|
|
int is = SendMessage(GetUIItem(IDC_LICENSEAGREE), BM_GETCHECK, 0, 0) & BST_CHECKED;
|
|
m_this_page->flags &= ~PF_LICENSE_SELECTED;
|
|
m_this_page->flags |= is;
|
|
EnableNext(is);
|
|
SetNextDef();
|
|
}
|
|
}
|
|
if (uMsg == WM_NOTIFY) {
|
|
hwLicense=GetUIItem(IDC_EDIT1);
|
|
#define nmhdr ((NMHDR *)lParam)
|
|
#define enlink ((ENLINK *)lParam)
|
|
#define msgfilter ((MSGFILTER *)lParam)
|
|
if (nmhdr->code==EN_LINK) {
|
|
if (enlink->msg==WM_LBUTTONDOWN) {
|
|
TEXTRANGE tr = {
|
|
{
|
|
enlink->chrg.cpMin,
|
|
enlink->chrg.cpMax,
|
|
},
|
|
ps_tmpbuf
|
|
};
|
|
if (tr.chrg.cpMax-tr.chrg.cpMin < sizeof(ps_tmpbuf)) {
|
|
SendMessage(hwLicense,EM_GETTEXTRANGE,0,(LPARAM)&tr);
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
ShellExecute(hwndDlg,_T("open"),tr.lpstrText,NULL,NULL,SW_SHOWNORMAL);
|
|
SetCursor(LoadCursor(0, IDC_ARROW));
|
|
}
|
|
}
|
|
}
|
|
//Ximon Eighteen 8th September 2002 Capture return key presses in the rich
|
|
//edit control now that the control gets the focus rather than the default
|
|
//push button. When the user presses return ask the outer dialog to move
|
|
//the installer onto the next page. MSDN docs say return non-zero if the
|
|
//rich edit control should NOT process this message, hence the return 1.
|
|
//
|
|
//This is required because the RichEdit control is eating all the key hits.
|
|
//It does try to release some and convert VK_ESCAPE to WM_CLOSE, VK_ENTER
|
|
//to a push on the default button and VM_TAB to WM_NEXTDLGCTL. But sadly it
|
|
//it sends all of these messages to its parent instead of just letting the
|
|
//dialog manager handle them. Instead of properly handling WM_GETDLGCODE,
|
|
//it mimics the dialog manager.
|
|
if (nmhdr->code==EN_MSGFILTER)
|
|
{
|
|
if (msgfilter->msg==WM_KEYDOWN)
|
|
{
|
|
if (msgfilter->wParam==VK_RETURN) {
|
|
SendMessage(g_hwnd, WM_COMMAND, IDOK, 0);
|
|
}
|
|
if (msgfilter->wParam==VK_ESCAPE) {
|
|
SendMessage(g_hwnd, WM_CLOSE, 0, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
#undef nmhdr
|
|
#undef enlink
|
|
#undef msgfilter
|
|
}
|
|
if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
|
|
{
|
|
ignoreWMCommand++;
|
|
}
|
|
return HandleStaticBkColor();
|
|
}
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
|
|
static BOOL CALLBACK UninstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
SetUITextFromLang(IDC_UNINSTFROM,this_page->parms[1]);
|
|
SetUITextNT(IDC_EDIT1,g_usrvars[this_page->parms[4]]);
|
|
}
|
|
return HandleStaticBkColor();
|
|
}
|
|
#endif
|
|
|
|
|
|
static void NSISCALL SetSizeText(int dlgItem, int prefix, unsigned kb)
|
|
{
|
|
TCHAR scalestr[32], byte[32];
|
|
unsigned sh = 20;
|
|
int scale = LANG_GIGA;
|
|
|
|
if (kb < 1024 * 1024) { sh = 10; scale = LANG_MEGA; }
|
|
if (kb < 1024) { sh = 0; scale = LANG_KILO; }
|
|
|
|
if (kb < (0xFFFFFFFF - ((1 << 20) / 20))) // check for overflow
|
|
kb += (1 << sh) / 20; // round numbers for better display (e.g. 1.59 => 1.6)
|
|
|
|
#if _MSC_VER == 1200 // patch #1982084
|
|
wsprintf(
|
|
GetNSISString(g_tmp, prefix) + mystrlen(g_tmp),
|
|
#else
|
|
GetNSISString(g_tmp, prefix);
|
|
wsprintf(
|
|
g_tmp + mystrlen(g_tmp),
|
|
#endif
|
|
_T("%u.%u%s%s"),
|
|
kb >> sh,
|
|
(((kb & 0x00FFFFFF) * 10) >> sh) % 10, // 0x00FFFFFF mask is used to
|
|
// prevent overflow that causes
|
|
// bad results
|
|
GetNSISString(scalestr, scale),
|
|
GetNSISString(byte, LANG_BYTE)
|
|
);
|
|
|
|
my_SetDialogItemText(m_curwnd,dlgItem,g_tmp);
|
|
}
|
|
|
|
static int NSISCALL _sumsecsfield(int idx)
|
|
{
|
|
int total = 0;
|
|
int x = num_sections;
|
|
section *s = g_sections;
|
|
while (x--)
|
|
{
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE
|
|
if (s->flags & SF_SELECTED)
|
|
#endif
|
|
total += ((int *)s)[idx];
|
|
s++;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
#define sumsecsfield(x) _sumsecsfield(SECTION_OFFSET(x))
|
|
|
|
static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static int dontsetdefstyle;
|
|
page *thispage = g_this_page;
|
|
TCHAR *dir = g_usrvars[thispage->parms[4]];
|
|
int browse_text = thispage->parms[3];
|
|
|
|
if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
|
|
{
|
|
GetUIText(IDC_DIR,dir);
|
|
validate_filename(dir);
|
|
#ifdef NSIS_CONFIG_LOG
|
|
#if !defined(NSIS_CONFIG_LOG_ODS) && !defined(NSIS_CONFIG_LOG_STDOUT)
|
|
build_g_logfile();
|
|
#endif
|
|
if (GetUIItem(IDC_CHECK1) != NULL)
|
|
log_dolog = IsDlgButtonChecked(hwndDlg,IDC_CHECK1);
|
|
#endif
|
|
}
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
HWND hDir = GetUIItem(IDC_DIR);
|
|
|
|
#ifdef NSIS_CONFIG_LOG
|
|
if (GetAsyncKeyState(VK_SHIFT)&0x8000)
|
|
{
|
|
HWND h=GetUIItem(IDC_CHECK1);
|
|
SetUITextFromLang(IDC_CHECK1,LANG_LOG_INSTALL_PROCESS);
|
|
ShowWindow(h,SW_SHOWNA);
|
|
}
|
|
#endif
|
|
if (validpathspec(dir) && !skip_root(dir))
|
|
addtrailingslash(dir);
|
|
|
|
// workaround for bug #1209843
|
|
//
|
|
// m_curwnd is only updated once WM_INITDIALOG returns.
|
|
// my_SetWindowText triggers an EN_CHANGE message that
|
|
// triggers a WM_IN_UPDATEMSG message that uses m_curwnd
|
|
// to get the selected directory (GetUIText).
|
|
// because m_curwnd is still outdated, dir varialble is
|
|
// filled with an empty string. by default, dir points
|
|
// to $INSTDIR.
|
|
//
|
|
// to solve this, m_curwnd is manually set to the correct
|
|
// window handle.
|
|
|
|
m_curwnd=hwndDlg;
|
|
|
|
my_SetWindowText(hDir,dir);
|
|
SetUITextFromLang(IDC_BROWSE,this_page->parms[2]);
|
|
SetUITextFromLang(IDC_SELDIRTEXT,this_page->parms[1]);
|
|
SetActiveCtl(hDir);
|
|
|
|
{
|
|
typedef HRESULT (WINAPI *SHAutoCompletePtr)(HWND, DWORD);
|
|
SHAutoCompletePtr fSHAutoComplete;
|
|
fSHAutoComplete = (SHAutoCompletePtr) myGetProcAddress(MGA_SHAutoComplete);
|
|
if (fSHAutoComplete)
|
|
{
|
|
fSHAutoComplete(hDir, SHACF_FILESYSTEM);
|
|
}
|
|
}
|
|
}
|
|
if (uMsg == WM_COMMAND)
|
|
{
|
|
int id=LOWORD(wParam);
|
|
if (id == IDC_DIR && HIWORD(wParam) == EN_CHANGE)
|
|
{
|
|
uMsg = WM_IN_UPDATEMSG;
|
|
}
|
|
if (id == IDC_BROWSE)
|
|
{
|
|
static TCHAR bt[NSIS_MAX_STRLEN];
|
|
BROWSEINFO bi = {0,};
|
|
ITEMIDLIST *idlist;
|
|
bi.hwndOwner = hwndDlg;
|
|
bi.pszDisplayName = g_tmp;
|
|
bi.lpfn = BrowseCallbackProc;
|
|
bi.lParam = (LPARAM)dir;
|
|
bi.lpszTitle = GetNSISString(bt, browse_text);
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
|
idlist = SHBrowseForFolder(&bi);
|
|
if (idlist)
|
|
{
|
|
// free idlist
|
|
CoTaskMemFree(idlist);
|
|
|
|
addtrailingslash(dir);
|
|
|
|
if (g_header->install_directory_auto_append &&
|
|
dir == state_install_directory) // only append to $INSTDIR (bug #1174184)
|
|
{
|
|
const TCHAR *post_str = ps_tmpbuf;
|
|
GetNSISStringTT(g_header->install_directory_auto_append);
|
|
// display name gives just the folder name
|
|
if (lstrcmpi(post_str, g_tmp))
|
|
{
|
|
mystrcat(dir, post_str);
|
|
}
|
|
}
|
|
|
|
dontsetdefstyle++;
|
|
SetUITextNT(IDC_DIR,dir);
|
|
}
|
|
else
|
|
{
|
|
uMsg = WM_IN_UPDATEMSG;
|
|
}
|
|
}
|
|
}
|
|
if (uMsg == WM_IN_UPDATEMSG || uMsg == WM_NOTIFY_START)
|
|
{
|
|
static TCHAR s[NSIS_MAX_STRLEN];
|
|
int error = 0;
|
|
int available_set = 0;
|
|
unsigned total, available;
|
|
|
|
GetUIText(IDC_DIR,dir);
|
|
if (!is_valid_instpath(dir))
|
|
error = NSIS_INSTDIR_INVALID;
|
|
|
|
/**
|
|
* This part is tricky. We need to make sure a few things:
|
|
*
|
|
* 1. GetDiskFreeSpaceEx is always called at least once for large HD.
|
|
* Even if skip_root() returned NULL (e.g. "C:").
|
|
* Note that trimslashtoend() will nullify "C:".
|
|
* 2. GetDiskFreeSpaceEx is called with the deepest valid directory.
|
|
* e.g. C:\drive when the user types C:\drive\folder1\folder2.
|
|
* This makes sure NTFS mount points are treated properly (#1946112).
|
|
* 3. `s' stays valid after the loop for GetDiskFreeSpace.
|
|
* This means there is no cutting beyond what skip_root() returns.
|
|
* Or `s' could be recreated when GetDiskFreeSpace is called.
|
|
* 4. If GetDiskFreeSpaceEx doesn't exist, GetDiskFreeSpace is used.
|
|
* 5. Both functions require a trailing backslash
|
|
* 6. `dir' is never modified.
|
|
*
|
|
*/
|
|
mystrcpy(s,dir);
|
|
|
|
// Test for and use the GetDiskFreeSpaceEx API
|
|
{
|
|
BOOL (WINAPI *GDFSE)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) =
|
|
myGetProcAddress(MGA_GetDiskFreeSpaceEx);
|
|
if (GDFSE)
|
|
{
|
|
ULARGE_INTEGER available64;
|
|
ULARGE_INTEGER a, b;
|
|
TCHAR *p;
|
|
TCHAR *pw = NULL;
|
|
while (pw != s) // trimslashtoend() cut the entire string
|
|
{
|
|
if (GDFSE(s, &available64, &a, &b))
|
|
{
|
|
#ifndef _NSIS_NO_INT64_SHR
|
|
available = (int)(available64.QuadPart >> 10);
|
|
#else
|
|
available = (int)(Int64ShrlMod32(available64.QuadPart, 10));
|
|
#endif
|
|
available_set++;
|
|
break;
|
|
}
|
|
|
|
if (pw)
|
|
// if pw was set, remove the backslash so trimslashtoend() will cut a new one
|
|
*pw = 0;
|
|
|
|
p = trimslashtoend(s); // trim last backslash
|
|
// bring it back, but make the next char null
|
|
pw = p;
|
|
*pw = 0;
|
|
--pw;
|
|
*pw = _T('\\');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!available_set)
|
|
{
|
|
DWORD spc, bps, fc, tc;
|
|
TCHAR *root;
|
|
|
|
// GetDiskFreeSpaceEx accepts any path, but GetDiskFreeSpace accepts only the root
|
|
mystrcpy(s,dir);
|
|
root=skip_root(s);
|
|
if (root)
|
|
*root=0;
|
|
|
|
// GetDiskFreeSpaceEx is not available
|
|
if (GetDiskFreeSpace(s, &spc, &bps, &fc, &tc))
|
|
{
|
|
available = (int)MulDiv(bps * spc, fc, 1 << 10);
|
|
available_set++;
|
|
}
|
|
}
|
|
|
|
total = (unsigned) sumsecsfield(size_kb);
|
|
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // available_set is checked first so available is initialized
|
|
#endif
|
|
if (available_set && available < total)
|
|
error = NSIS_INSTDIR_NOT_ENOUGH_SPACE;
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
if (LANG_STR_TAB(LANG_SPACE_REQ)) {
|
|
SetSizeText(IDC_SPACEREQUIRED,LANG_SPACE_REQ,total);
|
|
if (available_set)
|
|
SetSizeText(IDC_SPACEAVAILABLE,LANG_SPACE_AVAIL,available);
|
|
else
|
|
SetUITextNT(IDC_SPACEAVAILABLE,_T(""));
|
|
}
|
|
|
|
g_exec_flags.instdir_error = error;
|
|
|
|
#ifdef NSIS_SUPPORT_CODECALLBACKS
|
|
if (!error)
|
|
error = ExecuteCallbackFunction(CB_ONVERIFYINSTDIR);
|
|
#endif
|
|
|
|
if (thispage->flags & PF_DIR_NO_BTN_DISABLE)
|
|
error = 0;
|
|
|
|
EnableNext(!error);
|
|
if (!error && !dontsetdefstyle)
|
|
SetNextDef();
|
|
dontsetdefstyle = 0;
|
|
}
|
|
return HandleStaticBkColor();
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE
|
|
|
|
static void FORCE_INLINE NSISCALL RefreshComponents(HWND hwTree, HTREEITEM *items)
|
|
{
|
|
TVITEM item;
|
|
int i, flags, state;
|
|
section *sec;
|
|
|
|
item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED | TVIS_BOLD;
|
|
|
|
for (i = 0, sec = g_sections; i < num_sections; i++, sec++)
|
|
{
|
|
if (!items[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
flags = sec->flags;
|
|
|
|
item.hItem = items[i];
|
|
|
|
item.mask = TVIF_STATE;
|
|
|
|
if (flags & SF_NAMECHG)
|
|
{
|
|
item.mask |= TVIF_TEXT;
|
|
item.pszText = sec->name;
|
|
sec->flags &= ~SF_NAMECHG;
|
|
}
|
|
|
|
if (flags & SF_PSELECTED)
|
|
{
|
|
state = 3;
|
|
}
|
|
else
|
|
{
|
|
state = 1 + (flags & SF_SELECTED); // SF_SELECTED == 1
|
|
if (flags & SF_RO) state += 3;
|
|
}
|
|
|
|
item.state = (flags & SF_BOLD) << 1; // (SF_BOLD << 1) == 16 == TVIS_BOLD
|
|
item.state |= flags & SF_EXPAND; // TVIS_EXPANDED == SF_EXPAND
|
|
item.state |= INDEXTOSTATEIMAGEMASK(state);
|
|
|
|
// TVE_COLLAPSE = 1, TVE_EXPAND = 2
|
|
TreeView_Expand(hwTree, item.hItem, TVE_COLLAPSE + ((flags & SF_EXPAND) / SF_EXPAND));
|
|
|
|
TreeView_SetItem(hwTree, &item);
|
|
}
|
|
|
|
// workaround for bug #1397031
|
|
//
|
|
// windows 95 doesn't erase the background of the state image
|
|
// before it draws a new one. because of this parts of the old
|
|
// state image will show where the new state image is masked.
|
|
//
|
|
// to solve this, the following line forces the background to
|
|
// be erased. sadly, this redraws the entire control. it might
|
|
// be a good idea to figure out where the state images are and
|
|
// redraw only those.
|
|
|
|
InvalidateRect(hwTree, NULL, TRUE);
|
|
}
|
|
|
|
int NSISCALL TreeGetSelectedSection(HWND tree, BOOL mouse)
|
|
{
|
|
HTREEITEM hItem = TreeView_GetSelection(tree);
|
|
TVITEM item;
|
|
|
|
if (mouse)
|
|
{
|
|
TVHITTESTINFO ht;
|
|
DWORD dwpos = GetMessagePos();
|
|
|
|
ht.pt.x = GET_X_LPARAM(dwpos);
|
|
ht.pt.y = GET_Y_LPARAM(dwpos);
|
|
ScreenToClient(tree, &ht.pt);
|
|
|
|
{
|
|
const HTREEITEM UNUSED hDummy1 = TreeView_HitTest(tree, &ht);
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE_ALTERNATIVE
|
|
if (!(ht.flags & TVHT_ONITEMSTATEICON))
|
|
#else
|
|
if (!(ht.flags & (TVHT_ONITEMSTATEICON|TVHT_ONITEMLABEL|TVHT_ONITEMRIGHT|TVHT_ONITEM)))
|
|
#endif
|
|
return -1;
|
|
|
|
hItem = ht.hItem;
|
|
}
|
|
|
|
item.mask = TVIF_PARAM;
|
|
item.hItem = hItem;
|
|
TreeView_GetItem(tree, &item);
|
|
|
|
return (int) item.lParam;
|
|
}
|
|
|
|
void NSISCALL ExecuteCallbackFunctionWithr0Int(int num,int r0)
|
|
{
|
|
mystrcpy(g_tmp, g_usrvars[0]);
|
|
myitoa(g_usrvars[0], r0);
|
|
ExecuteCallbackFunction(num);
|
|
mystrcpy(g_usrvars[0], g_tmp);
|
|
}
|
|
|
|
static WNDPROC oldTreeWndProc;
|
|
static LPARAM last_selected_tree_item;
|
|
static DWORD WINAPI newTreeWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_CHAR && wParam == VK_SPACE) {
|
|
NotifyCurWnd(WM_TREEVIEW_KEYHACK);
|
|
return 0;
|
|
}
|
|
#if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
|
|
#ifndef NSIS_CONFIG_COMPONENTPAGE_ALTERNATIVE
|
|
if (uMsg == WM_MOUSEMOVE) {
|
|
if (IsWindowVisible(hwnd)) {
|
|
lParam = TreeGetSelectedSection(hwnd, TRUE);
|
|
uMsg = WM_NOTIFY_SELCHANGE;
|
|
}
|
|
}
|
|
#endif
|
|
if (uMsg == WM_NOTIFY_SELCHANGE) {
|
|
if (last_selected_tree_item != lParam)
|
|
{
|
|
last_selected_tree_item = lParam;
|
|
ExecuteCallbackFunctionWithr0Int(CB_ONMOUSEOVERSECTION,lParam);
|
|
}
|
|
}
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_ENHANCEDUI_SUPPORT
|
|
return CallWindowProc(oldTreeWndProc,hwnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
static BOOL CALLBACK SelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
const int wParamSelChangeNotifyInstTypeChanged = -1;
|
|
static HTREEITEM *hTreeItems;
|
|
static HIMAGELIST hImageList;
|
|
HWND hwndCombo1 = GetUIItem(IDC_COMBO1);
|
|
HWND hwndTree1 = GetUIItem(IDC_TREE1);
|
|
extern HWND g_SectionHack;// TODO: Can we remove this?
|
|
section *sections=g_sections;
|
|
int *install_types=g_header->install_types;
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
int doLines=0;
|
|
HTREEITEM Par;
|
|
HBITMAP hBMcheck1;
|
|
int x, i, noCombo=2;
|
|
|
|
g_SectionHack=hwndDlg;
|
|
|
|
hTreeItems=(HTREEITEM*)GlobalAlloc(GPTR,sizeof(HTREEITEM)*num_sections);
|
|
|
|
hBMcheck1=LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
|
|
|
|
last_selected_tree_item=-1;
|
|
oldTreeWndProc=(WNDPROC)SetWindowLongPtr(hwndTree1,GWLP_WNDPROC,(LONG_PTR)newTreeWndProc);
|
|
|
|
hImageList = ImageList_Create(16,16, ILC_COLOR32|ILC_MASK, 6, 0);
|
|
ImageList_AddMasked(hImageList,hBMcheck1,RGB(255,0,255));
|
|
|
|
{
|
|
const HIMAGELIST UNUSED hDummy1 = TreeView_SetImageList(hwndTree1, hImageList, TVSIL_STATE);
|
|
}
|
|
|
|
if (TreeView_GetItemHeight(hwndTree1) < 16)
|
|
TreeView_SetItemHeight(hwndTree1, 16);
|
|
|
|
DeleteObject(hBMcheck1);
|
|
|
|
for (i = 0; i < NSIS_MAX_INST_TYPES+1; i++)
|
|
{
|
|
if (install_types[i])
|
|
{
|
|
int j;
|
|
if (i != NSIS_MAX_INST_TYPES) noCombo = 0;
|
|
j=SendMessage(hwndCombo1,CB_ADDSTRING,0,(LPARAM)GetNSISStringTT(install_types[i]));
|
|
SendMessage(hwndCombo1,CB_SETITEMDATA,j,i);
|
|
}
|
|
}
|
|
|
|
SetUITextFromLang(IDC_TEXT1,this_page->parms[1+noCombo]);
|
|
SetUITextFromLang(IDC_TEXT2,this_page->parms[2+noCombo]);
|
|
|
|
Par=NULL;
|
|
|
|
for (x = 0; x < num_sections; x ++)
|
|
{
|
|
section *sec=sections+x;
|
|
|
|
if (sec->name[0])
|
|
{
|
|
TVINSERTSTRUCT tv;
|
|
|
|
tv.hParent = Par;
|
|
tv.hInsertAfter = TVI_LAST;
|
|
tv.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
|
|
tv.item.stateMask = TVIS_EXPANDED;
|
|
tv.item.lParam = x;
|
|
tv.item.pszText = sec->name;
|
|
|
|
tv.item.state = sec->flags & SF_EXPAND; // TVIS_EXPANDED == SF_EXPAND
|
|
|
|
if (sec->flags & SF_SECGRP)
|
|
{
|
|
tv.item.mask |= TVIF_CHILDREN;
|
|
tv.item.cChildren = 1;
|
|
Par = hTreeItems[x] = TreeView_InsertItem(hwndTree1, &tv);
|
|
doLines = 1;
|
|
}
|
|
else if (sec->flags & SF_SECGRPEND)
|
|
{
|
|
Par = TreeView_GetParent(hwndTree1, Par);
|
|
}
|
|
else
|
|
{
|
|
hTreeItems[x] = TreeView_InsertItem(hwndTree1, &tv);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!doLines)
|
|
{
|
|
SetWindowLongPtr(hwndTree1,GWL_STYLE,GetWindowLongPtr(hwndTree1,GWL_STYLE)&~(TVS_LINESATROOT));
|
|
}
|
|
|
|
if (!noCombo)
|
|
{
|
|
ShowWindow(hwndCombo1, SW_SHOW);
|
|
SetActiveCtl(hwndCombo1);
|
|
}
|
|
else
|
|
SetActiveCtl(hwndTree1);
|
|
}
|
|
|
|
if (uMsg == WM_NOTIFY_START)
|
|
{
|
|
wParam = 0;
|
|
lParam = 1;
|
|
uMsg = WM_IN_UPDATEMSG;
|
|
}
|
|
|
|
if (uMsg == WM_NOTIFY || uMsg == WM_TREEVIEW_KEYHACK)
|
|
{
|
|
LPNMHDR lpnmh = (LPNMHDR) lParam;
|
|
if (uMsg == WM_TREEVIEW_KEYHACK || lpnmh->idFrom == IDC_TREE1)
|
|
{
|
|
if (!(g_flags&CH_FLAGS_NO_CUSTOM) && (uMsg == WM_TREEVIEW_KEYHACK || lpnmh->code == NM_CLICK))
|
|
{
|
|
int secid = TreeGetSelectedSection(hwndTree1, uMsg != WM_TREEVIEW_KEYHACK);
|
|
|
|
if (secid >= 0)
|
|
{
|
|
int flags = sections[secid].flags;
|
|
|
|
if ((flags & SF_RO) == 0)
|
|
{
|
|
if ((flags & SF_PSELECTED))
|
|
{
|
|
flags ^= SF_TOGGLED;
|
|
|
|
if (flags & SF_TOGGLED)
|
|
{
|
|
flags |= SF_SELECTED;
|
|
}
|
|
else
|
|
{
|
|
flags &= ~SF_SELECTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flags ^= SF_SELECTED;
|
|
}
|
|
|
|
sections[secid].flags = flags;
|
|
|
|
SectionFlagsChanged(secid);
|
|
|
|
wParam = secid + 1;
|
|
lParam = !(g_flags & CH_FLAGS_COMP_ONLY_ON_CUSTOM);
|
|
uMsg = WM_IN_UPDATEMSG;
|
|
}
|
|
} // was valid click
|
|
} // was click or hack
|
|
#if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_ENHANCEDUI_SUPPORT)
|
|
if (lpnmh)
|
|
{
|
|
if (lpnmh->code == TVN_SELCHANGED)
|
|
{
|
|
SendMessage(hwndTree1, WM_NOTIFY_SELCHANGE, 0, ((LPNMTREEVIEW)lpnmh)->itemNew.lParam);
|
|
}
|
|
if (lpnmh->code == TVN_ITEMEXPANDED)
|
|
{
|
|
LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lpnmh;
|
|
if (pnmtv->action == TVE_EXPAND)
|
|
sections[pnmtv->itemNew.lParam].flags |= SF_EXPAND;
|
|
else
|
|
sections[pnmtv->itemNew.lParam].flags &= ~SF_EXPAND;
|
|
}
|
|
}
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_ENHANCEDUI_SUPPORT
|
|
}
|
|
}
|
|
|
|
if (uMsg == WM_COMMAND && LOWORD(wParam) == IDC_COMBO1 && HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
int t = SendMessage(hwndCombo1,CB_GETCURSEL,0,0);
|
|
if (t != CB_ERR)
|
|
{
|
|
int whichcfg = SendMessage(hwndCombo1, CB_GETITEMDATA, t, 0);
|
|
|
|
if (whichcfg == CB_ERR || !install_types[whichcfg])
|
|
whichcfg = NSIS_MAX_INST_TYPES;
|
|
|
|
SetInstType(whichcfg);
|
|
|
|
SendMessage(hwndDlg, WM_NOTIFY_INSTTYPE_CHANGED, 0, whichcfg);
|
|
|
|
wParam = wParamSelChangeNotifyInstTypeChanged;
|
|
lParam = 0;
|
|
uMsg = WM_IN_UPDATEMSG;
|
|
}
|
|
}
|
|
|
|
if (uMsg == WM_MOUSEMOVE)
|
|
{
|
|
SendMessage(hwndTree1, WM_MOUSEMOVE, 0, 0);
|
|
}
|
|
|
|
if (uMsg == WM_NOTIFY_INIGO_MONTOYA)
|
|
{
|
|
if (hImageList) ImageList_Destroy(hImageList);
|
|
if (hTreeItems) GlobalFree(hTreeItems);
|
|
hImageList = NULL;
|
|
hTreeItems = NULL;
|
|
g_SectionHack = NULL;
|
|
}
|
|
|
|
if (uMsg == WM_IN_UPDATEMSG)
|
|
{
|
|
RefreshSectionGroups();
|
|
|
|
#if defined(NSIS_SUPPORT_CODECALLBACKS) && defined(NSIS_CONFIG_COMPONENTPAGE)
|
|
if (wParam != 0)
|
|
{
|
|
int secid = wParam;
|
|
if (wParamSelChangeNotifyInstTypeChanged != secid) --secid;
|
|
ExecuteCallbackFunctionWithr0Int(CB_ONSELCHANGE,secid);
|
|
}
|
|
#endif//NSIS_SUPPORT_CODECALLBACKS && NSIS_CONFIG_COMPONENTPAGE
|
|
|
|
if (lParam)
|
|
{
|
|
int i, cbi;
|
|
int inst_type = GetInstType(hTreeItems);
|
|
SetInstType(inst_type);
|
|
|
|
for (i = 0, cbi = 0; i < inst_type; i++)
|
|
{
|
|
if (install_types[i])
|
|
{
|
|
cbi++;
|
|
}
|
|
}
|
|
|
|
SendMessage(hwndCombo1, CB_SETCURSEL, cbi, 0);
|
|
|
|
lParam = inst_type;
|
|
uMsg = WM_NOTIFY_INSTTYPE_CHANGED;
|
|
}
|
|
|
|
RefreshSectionGroups();
|
|
RefreshComponents(hwndTree1, hTreeItems);
|
|
|
|
if (LANG_STR_TAB(LANG_SPACE_REQ)) {
|
|
SetSizeText(IDC_SPACEREQUIRED,LANG_SPACE_REQ,sumsecsfield(size_kb));
|
|
}
|
|
}
|
|
|
|
if (uMsg == WM_NOTIFY_INSTTYPE_CHANGED)
|
|
{
|
|
if (g_flags & CH_FLAGS_COMP_ONLY_ON_CUSTOM)
|
|
{
|
|
int c = (lParam == NSIS_MAX_INST_TYPES ? 1 : 0) << 3;// SW_SHOWNA=8, SW_HIDE=0
|
|
ShowWindow(hwndTree1, c);
|
|
ShowWindow(GetUIItem(IDC_TEXT2), c);
|
|
}
|
|
}
|
|
|
|
return HandleStaticBkColor();
|
|
}
|
|
#endif//NSIS_CONFIG_COMPONENTPAGE
|
|
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
void NSISCALL update_status_text(int strtab, const TCHAR *text) {
|
|
static TCHAR tmp[NSIS_MAX_STRLEN*2];
|
|
LVITEM new_item;
|
|
HWND linsthwnd = insthwnd;
|
|
if (linsthwnd)
|
|
{
|
|
int updateflag = g_exec_flags.status_update;
|
|
int tmplen;
|
|
|
|
if (!(updateflag & 1))
|
|
GetNSISString(tmp, strtab);
|
|
|
|
tmplen = mystrlen(tmp);
|
|
|
|
if (text)
|
|
{
|
|
if (tmplen + mystrlen(text) >= sizeof(tmp)) return;
|
|
mystrcat(tmp, text);
|
|
}
|
|
|
|
if ((updateflag & 4) == 0) my_SetWindowText(insthwnd2, tmp);
|
|
if ((updateflag & 2) == 0)
|
|
{
|
|
new_item.mask = LVIF_TEXT;
|
|
new_item.pszText = tmp;
|
|
new_item.iItem = ListView_GetItemCount(linsthwnd) - (updateflag & 1);
|
|
new_item.iSubItem = 0;
|
|
// LVM_INSERTITEM - LVM_SETITEM = 1
|
|
SendMessage(linsthwnd, LVM_INSERTITEM - (updateflag & 1), 0, (LPARAM) &new_item);
|
|
ListView_EnsureVisible(linsthwnd, new_item.iItem, 0);
|
|
}
|
|
|
|
if (updateflag & 1)
|
|
tmp[tmplen] = 0;
|
|
}
|
|
}
|
|
|
|
static DWORD WINAPI install_thread(LPVOID p)
|
|
{
|
|
int m_inst_sec=num_sections;
|
|
HWND progresswnd = (HWND)p;
|
|
section *s = g_sections;
|
|
|
|
#if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
|
|
{
|
|
extern HRESULT g_hres;
|
|
g_hres|=OleInitialize(NULL);
|
|
}
|
|
#endif
|
|
|
|
// workaround for bug #1400995
|
|
//
|
|
// for an unexplained reason, MessageBox with MB_TOPMOST
|
|
// will fail, if no other messages were sent from this
|
|
// thread to the GUI thread before it.
|
|
//
|
|
// the source of the problem couldn't be found, so a
|
|
// WM_NULL is sent to work around it.
|
|
|
|
NotifyCurWnd(WM_NULL);
|
|
|
|
while (m_inst_sec--)
|
|
{
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE
|
|
if (s->flags&SF_SELECTED)
|
|
#endif
|
|
{
|
|
log_printf2(_T("Section: \"%s\""),s->name);
|
|
if (ExecuteCodeSegment(s->code,progresswnd))
|
|
{
|
|
g_exec_flags.abort++;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef NSIS_CONFIG_COMPONENTPAGE
|
|
else
|
|
{
|
|
log_printf2(_T("Skipping section: \"%s\""),s->name);
|
|
}
|
|
#endif
|
|
s++;
|
|
}
|
|
NotifyCurWnd(WM_NOTIFY_INSTPROC_DONE);
|
|
|
|
#if defined(NSIS_SUPPORT_ACTIVEXREG) || defined(NSIS_SUPPORT_CREATESHORTCUT)
|
|
OleUninitialize();
|
|
#endif
|
|
|
|
return g_exec_flags.abort;
|
|
}
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
static BOOL CALLBACK InstProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HWND linsthwnd=insthwnd;
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
RECT r;
|
|
LVCOLUMN lvc = {LVCF_WIDTH, 0, -1, 0, 0, -1};
|
|
int lb_bg=g_header->lb_bg,lb_fg=g_header->lb_fg;
|
|
|
|
insthwndbutton=GetUIItem(IDC_SHOWDETAILS);
|
|
insthwnd2=GetUIItem(IDC_INTROTEXT);
|
|
linsthwnd=insthwnd=GetUIItem(IDC_LIST1);
|
|
|
|
SetActiveCtl(insthwndbutton);
|
|
|
|
progress_bar_len=sumsecsfield(code_size);
|
|
progress_bar_pos=0;
|
|
|
|
log_printf3(_T("New install of \"%s\" to \"%s\""),GetNSISStringTT(LANG_NAME),state_install_directory);
|
|
|
|
GetClientRect(linsthwnd, &r);
|
|
lvc.cx = r.right - GetSystemMetrics(SM_CXHSCROLL);
|
|
ListView_InsertColumn(linsthwnd, 0, &lvc);
|
|
|
|
ListView_SetExtendedListViewStyleEx(linsthwnd, LVS_EX_LABELTIP, LVS_EX_LABELTIP);
|
|
if (lb_bg >= 0) {
|
|
ListView_SetBkColor(linsthwnd, lb_bg);
|
|
ListView_SetTextBkColor(linsthwnd, lb_bg);
|
|
}
|
|
if (lb_fg >= 0) {
|
|
ListView_SetTextColor(linsthwnd, lb_fg);
|
|
}
|
|
SetUITextFromLang(IDC_SHOWDETAILS,this_page->parms[1]);
|
|
if (g_flags&(CH_FLAGS_DETAILS_SHOWDETAILS|CH_FLAGS_DETAILS_NEVERSHOW))
|
|
{
|
|
ShowWindow(insthwndbutton,SW_HIDE);
|
|
if (!(g_flags&CH_FLAGS_DETAILS_NEVERSHOW)) ShowWindow(linsthwnd,SW_SHOWNA);
|
|
else insthwndbutton=NULL;
|
|
SetActiveCtl(insthwnd2);
|
|
}
|
|
|
|
{
|
|
HWND progresswnd=GetUIItem(IDC_PROGRESS);
|
|
SendMessage(progresswnd,PBM_SETRANGE,0,MAKELPARAM(0,30000));
|
|
if (g_flags&CH_FLAGS_PROGRESS_COLORED)
|
|
{
|
|
SendMessage(progresswnd,PBM_SETBARCOLOR,0,lb_fg);
|
|
SendMessage(progresswnd,PBM_SETBKCOLOR,0,lb_bg);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
if (uMsg == WM_NOTIFY_START) {
|
|
DWORD id;
|
|
CloseHandle(CreateThread(NULL,0,install_thread,GetUIItem(IDC_PROGRESS),0,&id));
|
|
}
|
|
if (uMsg == WM_COMMAND && LOWORD(wParam) == IDC_SHOWDETAILS)
|
|
{
|
|
ShowWindow(insthwndbutton,SW_HIDE);
|
|
ShowWindow(linsthwnd,SW_SHOWNA);
|
|
SetActiveCtl(linsthwnd);
|
|
}
|
|
if (uMsg == WM_NOTIFY_INSTPROC_DONE)
|
|
{
|
|
if (g_quit_flag)
|
|
{
|
|
m_retcode=2;
|
|
outernotify(NOTIFY_BYE_BYE);
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(g_hwnd,SW_SHOWNA);
|
|
if (!g_exec_flags.abort)
|
|
update_status_text(g_this_page->parms[2],0);
|
|
outernotify(1);
|
|
}
|
|
}
|
|
//>>>Ximon Eighteen aka Sunjammer 30th August 2002
|
|
//+++Popup "Copy Details To Clipboard" menu when RMB clicked in DetailView
|
|
if (uMsg == WM_CONTEXTMENU && wParam == (WPARAM) linsthwnd)
|
|
{
|
|
int count = ListView_GetItemCount(linsthwnd);
|
|
if (count > 0)
|
|
{
|
|
HMENU menu = CreatePopupMenu();
|
|
POINT pt;
|
|
AppendMenu(menu,MF_STRING,1,GetNSISStringTT(LANG_COPYDETAILS));
|
|
if (lParam == ((UINT)-1))
|
|
{
|
|
RECT r;
|
|
GetWindowRect(linsthwnd, &r);
|
|
pt.x = r.left;
|
|
pt.y = r.top;
|
|
}
|
|
else
|
|
{
|
|
pt.x = GET_X_LPARAM(lParam);
|
|
pt.y = GET_Y_LPARAM(lParam);
|
|
}
|
|
if (1==TrackPopupMenu(
|
|
menu,
|
|
TPM_NONOTIFY|TPM_RETURNCMD,
|
|
pt.x,
|
|
pt.y,
|
|
0,hwndDlg,0))
|
|
{
|
|
int i,total = 1; // 1 for the null char
|
|
LVITEM item;
|
|
HGLOBAL memory;
|
|
LPTSTR ptr;//,endPtr;
|
|
|
|
// 1st pass - determine clipboard memory required.
|
|
item.iSubItem = 0;
|
|
item.pszText = g_tmp;
|
|
item.cchTextMax = sizeof(g_tmp) - 1;
|
|
i = count;
|
|
while (i--)
|
|
// Add 2 for the CR/LF combination that must follow every line.
|
|
total += 2+SendMessage(linsthwnd,LVM_GETITEMTEXT,i,(LPARAM)&item);
|
|
|
|
// 2nd pass - store detail view strings on the clipboard
|
|
// Clipboard MSDN docs say mem must be GMEM_MOVEABLE
|
|
OpenClipboard(0);
|
|
EmptyClipboard();
|
|
memory = GlobalAlloc(GHND,total*sizeof(TCHAR));
|
|
ptr = GlobalLock(memory);
|
|
//endPtr = ptr+total-2; // -2 to allow for CR/LF
|
|
i = 0;
|
|
do {
|
|
item.pszText = ptr;
|
|
ptr += SendMessage(linsthwnd,LVM_GETITEMTEXT,i,(LPARAM)&item);
|
|
*ptr++ = _T('\r');
|
|
*ptr++ = _T('\n');
|
|
} while (++i < count);
|
|
// memory is auto zeroed when allocated with GHND - *ptr = 0;
|
|
GlobalUnlock(memory);
|
|
#ifdef _UNICODE
|
|
SetClipboardData(CF_UNICODETEXT,memory);
|
|
#else
|
|
SetClipboardData(CF_TEXT,memory);
|
|
#endif
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
//<<<
|
|
return HandleStaticBkColor();
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|