static INT_PTR 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(); }
static INT_PTR 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); #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #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; #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #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; }
static INT_PTR CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { page *m_this_page=g_this_page; HWND hwLicense; #define LicIgnoreWMCommand g_cbLicRead // g_cbLicRead is only used in WM_INITDIALOG during EM_STREAMIN 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 SendMessage(hwLicense,EM_EXLIMITTEXT,0,mystrlen(l)); g_cbLicRead = 0; SendMessage(hwLicense,EM_STREAMIN,lt,(LPARAM)&es); LicIgnoreWMCommand = 0; return FALSE; } if (uMsg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && !LicIgnoreWMCommand) { 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 < COUNTOF(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) { LicIgnoreWMCommand++; } return HandleStaticBkColor(); }
static INT_PTR 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, StreamLicense }; 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)/sizeof(*ps_tmpbuf))) { SendMessage(hwLicense,EM_GETTEXTRANGE,0,(LPARAM)&tr); SetCursor(LoadCursor(0, IDC_WAIT)); ShellExecute(hwndDlg,TEXT("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. 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(); }
static INT_PTR 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; static const TCHAR shlwapi[] = TEXT("shlwapi.dll"); static const char shac[] = "SHAutoComplete"; fSHAutoComplete = (SHAutoCompletePtr) myGetProcAddress((TCHAR *)shlwapi, (char *) shac); 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 FreePIDL(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]; TCHAR *p; int error = 0; int available_set = 0; unsigned total, available = 0xFFFFFFFF; GetUIText(IDC_DIR,dir); if (!is_valid_instpath(dir)) error = NSIS_INSTDIR_INVALID; mystrcpy(s,dir); p=skip_root(s); if (p) *p=0; // Test for and use the GetDiskFreeSpaceEx API { #ifdef UNICODE BOOL (WINAPI *GDFSE)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) = myGetProcAddress(L"KERNEL32.dll", "GetDiskFreeSpaceExW"); #else BOOL (WINAPI *GDFSE)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) = myGetProcAddress("KERNEL32.dll", "GetDiskFreeSpaceExA"); #endif if (GDFSE) { ULARGE_INTEGER available64; ULARGE_INTEGER a, b; 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++; } } } if (!available_set) { // GetDiskFreeSpaceEx is not available DWORD spc, bps, fc, tc; if (GetDiskFreeSpace(s, &spc, &bps, &fc, &tc)) { available = (int)MulDiv(bps * spc, fc, 1 << 10); available_set++; } } total = (unsigned) sumsecsfield(size_kb); if (available < total) error = NSIS_INSTDIR_NOT_ENOUGH_SPACE; 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,TEXT("")); } 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; }
static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { page *thispage = g_this_page; char *dir = g_usrvars[thispage->parms[4]]; int browse_text = thispage->parms[3]; if (uMsg == WM_NOTIFY_INIGO_MONTOYA) { GetUIText(IDC_DIR,dir,NSIS_MAX_STRLEN); validate_filename(dir); #ifdef NSIS_CONFIG_LOG #ifndef NSIS_CONFIG_LOG_ODS build_g_logfile(); #endif log_dolog = IsDlgButtonChecked(hwndDlg,IDC_CHECK1); #endif } if (uMsg == WM_INITDIALOG) { #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); SetUITextNT(IDC_DIR,dir); SetUITextFromLang(IDC_BROWSE,this_page->parms[2]); SetUITextFromLang(IDC_SELDIRTEXT,this_page->parms[1]); } if (uMsg == WM_COMMAND) { int id=LOWORD(wParam); if (id == IDC_DIR && HIWORD(wParam) == EN_CHANGE) { uMsg = WM_IN_UPDATEMSG; } if (id == IDC_BROWSE) { char name[MAX_PATH]; BROWSEINFO bi = {0,}; ITEMIDLIST *idlist; bi.hwndOwner = hwndDlg; bi.pszDisplayName = name; bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM)dir; bi.lpszTitle = GetNSISStringTT(browse_text); #ifndef BIF_NEWDIALOGSTYLE #define BIF_NEWDIALOGSTYLE 0x0040 #endif bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; idlist = SHBrowseForFolder(&bi); if (idlist) { // Get and free idlist my_PIDL2Path(name, idlist); if (g_header->install_directory_auto_append) { const char *post_str=ps_tmpbuf; GetNSISStringTT(g_header->install_directory_auto_append); // name gives just the folder name if (lstrcmpi(post_str,name)) { lstrcat(addtrailingslash(dir),post_str); } } SetUITextNT(IDC_DIR,dir); } } } if (uMsg == WM_IN_UPDATEMSG || uMsg == WM_NOTIFY_START) { static char s[NSIS_MAX_STRLEN]; char *p; int error = 0; int total, available=-1; DWORD spc,bps,fc,tc; GetUIText(IDC_DIR,dir,NSIS_MAX_STRLEN); if (!is_valid_instpath(dir)) error = NSIS_INSTDIR_INVALID; mystrcpy(s,dir); p=skip_root(s); if (p) *p=0; if (GetDiskFreeSpace(s,&spc,&bps,&fc,&tc)) { DWORD r=MulDiv(bps*spc,fc,1<<10); if (r > 0x7fffffff) r=0x7fffffff; available=(int)r; } total = getreqsize(); if ((unsigned int)available < (unsigned int)total) error = NSIS_INSTDIR_NOT_ENOUGH_SPACE; if (LANG_STR_TAB(LANG_SPACE_REQ)) { SetUITextNT(IDC_SPACEREQUIRED,inttosizestr(total,GetNSISString(s,LANG_SPACE_REQ))); if (available != -1) SetUITextNT(IDC_SPACEAVAILABLE,inttosizestr(available,GetNSISString(s,LANG_SPACE_AVAIL))); else SetUITextNT(IDC_SPACEAVAILABLE,""); } g_exec_flags.instdir_error = error; #ifdef NSIS_SUPPORT_CODECALLBACKS if (!error) error = ExecuteCodeSegment(g_header->code_onVerifyInstDir,NULL); #endif if (thispage->flags & PF_DIR_NO_BTN_DISABLE) error = 0; EnableWindow(m_hwndOK, !error); } return HandleStaticBkColor(); }
static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { page *m_this_page=g_this_page; HWND hwLicense; if (uMsg == WM_INITDIALOG) { char *l = (char *)GetNSISStringNP(GetNSISTab(this_page->parms[1])); int lt = *l; EDITSTREAM es = { (DWORD)(++l), 0, StreamLicense }; 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]); SendMessage(GetUIItem(IDC_LICENSEAGREE+!selected),BM_SETCHECK,BST_CHECKED,0); EnableWindow(m_hwndOK,selected); hwLicense=GetUIItem(IDC_EDIT1); 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); //XGE 5th September 2002 - place the initial focus in the richedit control SetFocus(hwLicense); return FALSE; //End Xge } if (uMsg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED) { 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; EnableWindow( m_hwndOK, is ); } } 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,"open",tr.lpstrText,NULL,NULL,SW_SHOWNORMAL); SetCursor(LoadCursor(0,IDC_ARROW)); } } if (enlink->msg==WM_SETCURSOR) { #ifndef IDC_HAND #define IDC_HAND MAKEINTRESOURCE(32649) #endif SetCursor(LoadCursor(0,IDC_HAND)); } } //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. if (nmhdr->code==EN_MSGFILTER) { if (msgfilter->msg==WM_KEYDOWN) { if (msgfilter->wParam==VK_RETURN && IsWindowEnabled(m_hwndOK)) { outernotify(1); } if (msgfilter->wParam==VK_ESCAPE) { SendMessage(g_hwnd, WM_CLOSE, 0, 0); } return 1; } } #undef nmhdr #undef enlink #undef msgfilter } return HandleStaticBkColor(); }
static BOOL CALLBACK SelProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HTREEITEM *hTreeItems; static HIMAGELIST hImageList; HWND hwndCombo1 = GetUIItem(IDC_COMBO1); HWND hwndTree1 = GetUIItem(IDC_TREE1); extern HWND g_SectionHack; section *sections=g_sections; if (uMsg == WM_INITDIALOG) { int doLines=0; HTREEITEM Par; HBITMAP hBMcheck1; int x, lastGoodX, i, noCombo=2; g_SectionHack=hwndDlg; if (hTreeItems) GlobalFree(hTreeItems); hTreeItems=(HTREEITEM*)my_GlobalAlloc(sizeof(HTREEITEM)*num_sections); hBMcheck1=LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); oldTreeWndProc=SetWindowLong(hwndTree1,GWL_WNDPROC,(DWORD)newTreeWndProc); if (hImageList) ImageList_Destroy(hImageList); hImageList = ImageList_Create(16,16, ILC_COLOR32|ILC_MASK, 6, 0); ImageList_AddMasked(hImageList,hBMcheck1,RGB(255,0,255)); TreeView_SetImageList(hwndTree1, hImageList, TVSIL_STATE); #ifndef TVM_SETITEMHEIGHT #define TVM_SETITEMHEIGHT (TV_FIRST + 27) #endif #ifndef TVM_GETITEMHEIGHT #define TVM_GETITEMHEIGHT (TV_FIRST + 28) #endif if (SendMessage(hwndTree1, TVM_GETITEMHEIGHT, 0, 0) < 16) SendMessage(hwndTree1, TVM_SETITEMHEIGHT, 16, 0); DeleteObject(hBMcheck1); for (i = 0; i < NSIS_MAX_INST_TYPES+1; i++) { if (g_header->install_types[i]) { int j; if (i != NSIS_MAX_INST_TYPES) noCombo = 0; GetNSISString(g_tmp,g_header->install_types[i]); j=SendMessage(hwndCombo1,CB_ADDSTRING,0,(LPARAM)g_tmp); SendMessage(hwndCombo1,CB_SETITEMDATA,j,i); if (i == g_exec_flags.cur_insttype) SendMessage(hwndCombo1, CB_SETCURSEL, j, 0); } } if (!noCombo) ShowWindow(hwndCombo1,SW_SHOW); SetUITextFromLang(IDC_TEXT1,this_page->parms[1+noCombo]); SetUITextFromLang(IDC_TEXT2,this_page->parms[2+noCombo]); Par=NULL; for (lastGoodX = x = 0; x < num_sections; x ++) { section *sec=sections+x; if (sec->name_ptr) { TVINSERTSTRUCT tv; tv.hParent=Par; tv.hInsertAfter=TVI_LAST; tv.item.mask=TVIF_PARAM|TVIF_TEXT|TVIF_STATE; tv.item.lParam=x; tv.item.pszText=GetNSISStringTT(sec->name_ptr); tv.item.stateMask=TVIS_STATEIMAGEMASK|TVIS_EXPANDED|TVIS_BOLD; { int l=1; // Sf_SELECTED == 1 l += sec->flags & SF_SELECTED; //if (sec->flags & SF_SELECTED) l++; if (sec->flags & SF_RO) l+=3; tv.item.state=INDEXTOSTATEIMAGEMASK(l); } //if (sec->flags&SF_BOLD) { // SF_BOLD << 1 == 16 == TVIS_BOLD tv.item.state|=(sec->flags&SF_BOLD)<<1; } if (sec->flags&SF_SUBSEC) { tv.item.mask|=TVIF_CHILDREN; tv.item.cChildren=1; //if (sec->flags&SF_EXPAND) // TVIS_EXPANDED == SF_EXPAND tv.item.state|=sec->flags&SF_EXPAND; Par = hTreeItems[x] = TreeView_InsertItem(hwndTree1,&tv); doLines=1; } else if (sec->flags&SF_SUBSECEND) { SetParentState(hwndTree1,hTreeItems[lastGoodX]); Par=TreeView_GetParent(hwndTree1,Par); } else { lastGoodX = x; hTreeItems[x] = TreeView_InsertItem(hwndTree1,&tv); } } } if (!doLines) { SetWindowLong(hwndTree1,GWL_STYLE,GetWindowLong(hwndTree1,GWL_STYLE)&~(TVS_LINESATROOT)); } SendMessage(hwndTree1,WM_VSCROLL,SB_TOP,0); uMsg = g_exec_flags.insttype_changed ? WM_NOTIFY_INSTTYPE_CHANGE : WM_IN_UPDATEMSG; } if (uMsg == WM_NOTIFY_SECTEXT) // update text { int x=wParam; int ns=lParam; TVITEM tv; if (tv.hItem=hTreeItems[x]) { tv.mask=TVIF_TEXT; tv.pszText=GetNSISStringTT(ns); TreeView_SetItem(hwndTree1,&tv); } } if (uMsg == WM_NOTIFY_SECFLAGS) // change flags { int flags = sections[wParam].flags; TVITEM tvItem; if (!(tvItem.hItem = hTreeItems[wParam])) return 0; tvItem.mask = TVIF_STATE; tvItem.stateMask = TVIS_BOLD; tvItem.state = 0; //if (flags&SF_BOLD) tvItem.state |= TVIS_BOLD; // SF_BOLD << 1 == 16 == TVIS_BOLD tvItem.state|=(flags&SF_BOLD)<<1; TreeView_SetItem(hwndTree1, &tvItem); TreeView_Expand(hwndTree1, tvItem.hItem, flags & SF_EXPAND ? TVE_EXPAND : TVE_COLLAPSE); if ((flags & (SF_PSELECTED | SF_SELECTED)) != SF_PSELECTED) { CheckTreeItem(hwndTree1, tvItem.hItem, flags & SF_SELECTED); } } 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)) { TVITEM tvItem; if (uMsg != WM_TREEVIEW_KEYHACK) tvItem.hItem=TreeHitTest(hwndTree1); else tvItem.hItem=TreeView_GetSelection(hwndTree1); if (tvItem.hItem) { int iState; tvItem.mask = TVIF_STATE|TVIF_PARAM; TreeView_GetItem(hwndTree1, &tvItem); iState = tvItem.state >> 12; if (iState < 4) // not RO { if (iState == 2) // already checked { sections[tvItem.lParam].flags&=~SF_SELECTED; CheckTreeItem(hwndTree1,tvItem.hItem,0); } else { sections[tvItem.lParam].flags|=SF_SELECTED; CheckTreeItem(hwndTree1,tvItem.hItem,1); } lParam = 0; wParam = 1; uMsg = WM_IN_UPDATEMSG; } // not ro } // was valid click } // was click or hack
static BOOL CALLBACK DirProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static int dontsetdefstyle; page *thispage = g_this_page; char *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 #ifndef NSIS_CONFIG_LOG_ODS build_g_logfile(); #endif log_dolog = IsDlgButtonChecked(hwndDlg,IDC_CHECK1); #endif } if (uMsg == WM_INITDIALOG) { #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); SetUITextNT(IDC_DIR,dir); SetUITextFromLang(IDC_BROWSE,this_page->parms[2]); SetUITextFromLang(IDC_SELDIRTEXT,this_page->parms[1]); SetActiveCtl(GetUIItem(IDC_DIR)); } if (uMsg == WM_COMMAND) { int id=LOWORD(wParam); if (id == IDC_DIR && HIWORD(wParam) == EN_CHANGE) { uMsg = WM_IN_UPDATEMSG; } if (id == IDC_BROWSE) { BROWSEINFO bi = {0,}; ITEMIDLIST *idlist; bi.hwndOwner = hwndDlg; bi.pszDisplayName = g_tmp; bi.lpfn = BrowseCallbackProc; bi.lParam = (LPARAM)dir; bi.lpszTitle = GetNSISStringTT(browse_text); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; idlist = SHBrowseForFolder(&bi); if (idlist) { // free idlist FreePIDL(idlist); if (g_header->install_directory_auto_append) { const char *post_str = ps_tmpbuf; GetNSISStringTT(g_header->install_directory_auto_append); // display name gives just the folder name if (lstrcmpi(post_str, g_tmp)) { lstrcat(addtrailingslash(dir), post_str); } } dontsetdefstyle++; SetUITextNT(IDC_DIR,dir); } } } if (uMsg == WM_IN_UPDATEMSG || uMsg == WM_NOTIFY_START) { static char s[NSIS_MAX_STRLEN]; char *p; int error = 0; int available_set=0; unsigned total, available; HMODULE hLib; GetUIText(IDC_DIR,dir); if (!is_valid_instpath(dir)) error = NSIS_INSTDIR_INVALID; mystrcpy(s,dir); p=skip_root(s); if (p) *p=0; // Test for and use the GetDiskFreeSpaceEx API hLib = GetModuleHandle("KERNEL32.dll"); if (hLib) { BOOL (WINAPI *GDFSE)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER) = (void*)GetProcAddress(hLib, "GetDiskFreeSpaceExA"); if (GDFSE) { ULARGE_INTEGER available64; ULARGE_INTEGER a, b; if (GDFSE(s, &available64, &a, &b)) { available = (int)(available64.QuadPart >> 10); available_set++; } } } if (!available_set) { // GetDiskFreeSpaceEx is not available DWORD spc, bps, fc, tc; if (GetDiskFreeSpace(s, &spc, &bps, &fc, &tc)) { available = (int)MulDiv(bps * spc, fc, 1 << 10); available_set++; } } total = (unsigned) sumsecsfield(size_kb); if (available < total) error = NSIS_INSTDIR_NOT_ENOUGH_SPACE; if (LANG_STR_TAB(LANG_SPACE_REQ)) { SetUITextNT(IDC_SPACEREQUIRED,inttosizestr(total,GetNSISString(s,LANG_SPACE_REQ))); // Did we get a usable value above? if (available >= 0) SetUITextNT(IDC_SPACEAVAILABLE,inttosizestr(available,GetNSISString(s,LANG_SPACE_AVAIL))); else SetUITextNT(IDC_SPACEAVAILABLE,""); } 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; }
static BOOL CALLBACK LicenseProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { page *m_this_page=g_this_page; HWND hwLicense; static int ignoreWMCommand; EDITSTREAM es; es.dwError = 0; if (uMsg == WM_INITDIALOG) { TCHAR *l = (TCHAR *)GetNSISStringNP(GetNSISTab(this_page->parms[1])); // First char contains SF_RTF or SF_TEXT (SF_UNICODE) int lt = *l; int selected; bCookieNuked = FALSE; // SF_UNICODE is never set for ANSI NSIS if (lt & SF_UNICODE) { es.dwCookie = (DWORD_PTR)(++l); es.pfnCallback = StreamLicenseW; } else { es.pfnCallback = StreamLicenseA; #ifdef _UNICODE { // If Unicode support, then even though this is straight ASCII coming // in, it was encoded as WCHAR and therefore must be turned back to // ASCII. char* tmp = WideCharToAnsi(++l); // How do we nuke tmp so we don't get a memory leak? // Well, we need to teach StreamLicenseA to do that for us. bManageCookie = TRUE; es.dwCookie = (DWORD_PTR) tmp; } #else bManageCookie = FALSE; es.dwCookie = (DWORD_PTR)(++l); #endif } 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(); }