2011-11-21 17:06:17 +00:00
|
|
|
/*
|
2011-12-05 11:36:02 +00:00
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
2011-11-21 17:06:17 +00:00
|
|
|
* Standard Dialog Routines (Browse for folder, About, etc)
|
2017-01-01 15:30:03 +00:00
|
|
|
* Copyright © 2011-2017 Pete Batard <pete@akeo.ie>
|
2011-11-21 17:06:17 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2011-11-21 20:12:23 +00:00
|
|
|
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <shlobj.h>
|
|
|
|
#include <commdlg.h>
|
2012-11-08 20:36:48 +00:00
|
|
|
#include <richedit.h>
|
2011-11-21 17:06:17 +00:00
|
|
|
|
|
|
|
#include "rufus.h"
|
2016-02-24 16:10:54 +00:00
|
|
|
#include "missing.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "resource.h"
|
2011-11-21 17:06:17 +00:00
|
|
|
#include "msapi_utf8.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "localization.h"
|
|
|
|
|
2012-12-02 03:50:08 +00:00
|
|
|
#include "registry.h"
|
2015-01-25 00:56:38 +00:00
|
|
|
#include "settings.h"
|
2011-11-21 17:06:17 +00:00
|
|
|
#include "license.h"
|
|
|
|
|
2014-05-12 21:44:10 +00:00
|
|
|
PF_TYPE_DECL(WINAPI, HRESULT, SHCreateItemFromParsingName, (PCWSTR, IBindCtx*, REFIID, void **));
|
|
|
|
PF_TYPE_DECL(WINAPI, LPITEMIDLIST, SHSimpleIDListFromPath, (PCWSTR pszPath));
|
|
|
|
#define INIT_VISTA_SHELL32 PF_INIT(SHCreateItemFromParsingName, Shell32)
|
|
|
|
#define INIT_XP_SHELL32 PF_INIT(SHSimpleIDListFromPath, Shell32)
|
|
|
|
#define IS_VISTA_SHELL32_AVAILABLE (pfSHCreateItemFromParsingName != NULL)
|
2011-11-21 17:06:17 +00:00
|
|
|
|
|
|
|
/* Globals */
|
|
|
|
static HICON hMessageIcon = (HICON)INVALID_HANDLE_VALUE;
|
|
|
|
static char* szMessageText = NULL;
|
|
|
|
static char* szMessageTitle = NULL;
|
2017-07-11 16:43:51 +00:00
|
|
|
static char **szDialogItem;
|
|
|
|
static int nDialogItems;
|
2011-11-21 17:06:17 +00:00
|
|
|
static HWND hBrowseEdit;
|
2015-05-08 22:37:22 +00:00
|
|
|
extern HWND hUpdatesDlg;
|
2015-07-06 21:04:38 +00:00
|
|
|
static WNDPROC pOrgBrowseWndproc;
|
2012-11-29 02:59:52 +00:00
|
|
|
static const SETTEXTEX friggin_microsoft_unicode_amateurs = {ST_DEFAULT, CP_UTF8};
|
2012-11-29 23:14:36 +00:00
|
|
|
static BOOL notification_is_question;
|
2012-12-02 03:50:08 +00:00
|
|
|
static const notification_info* notification_more_info;
|
2015-01-25 00:56:38 +00:00
|
|
|
static BOOL settings_commcheck = FALSE;
|
2015-05-14 23:36:42 +00:00
|
|
|
static WNDPROC update_original_proc = NULL;
|
2016-07-09 15:20:58 +00:00
|
|
|
static HWINEVENTHOOK fp_weh = NULL;
|
|
|
|
static char *fp_title_str = "Microsoft Windows", *fp_button_str = "Format disk";
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2016-01-11 13:06:33 +00:00
|
|
|
extern loc_cmd* selected_locale;
|
|
|
|
|
2016-12-13 14:21:51 +00:00
|
|
|
/*
|
|
|
|
* https://blogs.msdn.microsoft.com/oldnewthing/20040802-00/?p=38283/
|
|
|
|
*/
|
|
|
|
void SetDialogFocus(HWND hDlg, HWND hCtrl)
|
|
|
|
{
|
|
|
|
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hCtrl, TRUE);
|
|
|
|
}
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
/*
|
|
|
|
* We need a sub-callback to read the content of the edit box on exit and update
|
|
|
|
* our path, else if what the user typed does match the selection, it is discarded.
|
|
|
|
* Talk about a convoluted way of producing an intuitive folder selection dialog
|
|
|
|
*/
|
|
|
|
INT CALLBACK BrowseDlgCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch(message) {
|
|
|
|
case WM_DESTROY:
|
|
|
|
GetWindowTextU(hBrowseEdit, szFolderPath, sizeof(szFolderPath));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT)CallWindowProc(pOrgBrowseWndproc, hDlg, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Main BrowseInfo callback to set the initial directory and populate the edit control
|
|
|
|
*/
|
|
|
|
INT CALLBACK BrowseInfoCallback(HWND hDlg, UINT message, LPARAM lParam, LPARAM pData)
|
|
|
|
{
|
|
|
|
char dir[MAX_PATH];
|
|
|
|
wchar_t* wpath;
|
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
|
|
|
|
switch(message) {
|
|
|
|
case BFFM_INITIALIZED:
|
|
|
|
pOrgBrowseWndproc = (WNDPROC)SetWindowLongPtr(hDlg, GWLP_WNDPROC, (LONG_PTR)BrowseDlgCallback);
|
|
|
|
// Windows hides the full path in the edit box by default, which is bull.
|
|
|
|
// Get a handle to the edit control to fix that
|
|
|
|
hBrowseEdit = FindWindowExA(hDlg, NULL, "Edit", NULL);
|
|
|
|
SetWindowTextU(hBrowseEdit, szFolderPath);
|
2016-12-13 14:21:51 +00:00
|
|
|
SetDialogFocus(hDlg, hBrowseEdit);
|
2011-11-21 17:06:17 +00:00
|
|
|
// On XP, BFFM_SETSELECTION can't be used with a Unicode Path in SendMessageW
|
|
|
|
// or a pidl (at least with MinGW) => must use SendMessageA
|
|
|
|
if (nWindowsVersion <= WINDOWS_XP) {
|
|
|
|
SendMessageLU(hDlg, BFFM_SETSELECTION, (WPARAM)TRUE, szFolderPath);
|
|
|
|
} else {
|
|
|
|
// On Windows 7, MinGW only properly selects the specified folder when using a pidl
|
|
|
|
wpath = utf8_to_wchar(szFolderPath);
|
2014-05-12 21:44:10 +00:00
|
|
|
pidl = (*pfSHSimpleIDListFromPath)(wpath);
|
2011-11-21 17:06:17 +00:00
|
|
|
safe_free(wpath);
|
|
|
|
// NB: see http://connect.microsoft.com/VisualStudio/feedback/details/518103/bffm-setselection-does-not-work-with-shbrowseforfolder-on-windows-7
|
|
|
|
// for details as to why we send BFFM_SETSELECTION twice.
|
|
|
|
SendMessageW(hDlg, BFFM_SETSELECTION, (WPARAM)FALSE, (LPARAM)pidl);
|
|
|
|
Sleep(100);
|
|
|
|
PostMessageW(hDlg, BFFM_SETSELECTION, (WPARAM)FALSE, (LPARAM)pidl);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BFFM_SELCHANGED:
|
|
|
|
// Update the status
|
|
|
|
if (SHGetPathFromIDListU((LPITEMIDLIST)lParam, dir)) {
|
|
|
|
SendMessageLU(hDlg, BFFM_SETSTATUSTEXT, 0, dir);
|
|
|
|
SetWindowTextU(hBrowseEdit, dir);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Browse for a folder and update the folder edit box
|
|
|
|
* Will use the newer IFileOpenDialog if *compiled* for Vista or later
|
|
|
|
*/
|
|
|
|
void BrowseForFolder(void) {
|
|
|
|
|
|
|
|
BROWSEINFOW bi;
|
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
WCHAR *wpath;
|
|
|
|
size_t i;
|
|
|
|
HRESULT hr;
|
|
|
|
IShellItem *psi = NULL;
|
|
|
|
IShellItem *si_path = NULL; // Automatically freed
|
|
|
|
IFileOpenDialog *pfod = NULL;
|
|
|
|
WCHAR *fname;
|
|
|
|
char* tmp_path = NULL;
|
|
|
|
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing++;
|
2016-03-23 16:56:49 +00:00
|
|
|
if (nWindowsVersion >= WINDOWS_VISTA) {
|
|
|
|
INIT_VISTA_SHELL32;
|
|
|
|
if (IS_VISTA_SHELL32_AVAILABLE) {
|
|
|
|
hr = CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
|
|
|
|
&IID_IFileOpenDialog, (LPVOID)&pfod);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
uprintf("CoCreateInstance for FileOpenDialog failed: error %X\n", hr);
|
|
|
|
pfod = NULL; // Just in case
|
|
|
|
goto fallback;
|
|
|
|
}
|
|
|
|
hr = pfod->lpVtbl->SetOptions(pfod, FOS_PICKFOLDERS);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr);
|
|
|
|
goto fallback;
|
|
|
|
}
|
|
|
|
// Set the initial folder (if the path is invalid, will simply use last)
|
|
|
|
wpath = utf8_to_wchar(szFolderPath);
|
|
|
|
// The new IFileOpenDialog makes us split the path
|
|
|
|
fname = NULL;
|
|
|
|
if ((wpath != NULL) && (wcslen(wpath) >= 1)) {
|
|
|
|
for (i = wcslen(wpath) - 1; i != 0; i--) {
|
|
|
|
if (wpath[i] == L'\\') {
|
|
|
|
wpath[i] = 0;
|
|
|
|
fname = &wpath[i + 1];
|
|
|
|
break;
|
|
|
|
}
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
if (wpath != NULL) {
|
2016-03-25 16:38:01 +00:00
|
|
|
pfod->lpVtbl->SetFolder(pfod, si_path);
|
2016-03-23 16:56:49 +00:00
|
|
|
}
|
|
|
|
if (fname != NULL) {
|
2016-03-25 16:38:01 +00:00
|
|
|
pfod->lpVtbl->SetFileName(pfod, fname);
|
2016-03-23 16:56:49 +00:00
|
|
|
}
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
safe_free(wpath);
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
hr = pfod->lpVtbl->Show(pfod, hMainDialog);
|
2011-11-21 17:06:17 +00:00
|
|
|
if (SUCCEEDED(hr)) {
|
2016-03-23 16:56:49 +00:00
|
|
|
hr = pfod->lpVtbl->GetResult(pfod, &psi);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
psi->lpVtbl->GetDisplayName(psi, SIGDN_FILESYSPATH, &wpath);
|
|
|
|
tmp_path = wchar_to_utf8(wpath);
|
|
|
|
CoTaskMemFree(wpath);
|
|
|
|
if (tmp_path == NULL) {
|
|
|
|
uprintf("Could not convert path\n");
|
|
|
|
} else {
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(szFolderPath, tmp_path);
|
2016-03-23 16:56:49 +00:00
|
|
|
safe_free(tmp_path);
|
|
|
|
}
|
2011-11-21 17:06:17 +00:00
|
|
|
} else {
|
2016-03-23 16:56:49 +00:00
|
|
|
uprintf("Failed to set folder option for FileOpenDialog: error %X\n", hr);
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
} else if ((hr & 0xFFFF) != ERROR_CANCELLED) {
|
|
|
|
// If it's not a user cancel, assume the dialog didn't show and fallback
|
|
|
|
uprintf("Could not show FileOpenDialog: error %X\n", hr);
|
|
|
|
goto fallback;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
pfod->lpVtbl->Release(pfod);
|
|
|
|
dialog_showing--;
|
|
|
|
return;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
fallback:
|
2016-03-23 16:56:49 +00:00
|
|
|
if (pfod != NULL) {
|
|
|
|
pfod->lpVtbl->Release(pfod);
|
|
|
|
}
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
INIT_XP_SHELL32;
|
|
|
|
memset(&bi, 0, sizeof(BROWSEINFOW));
|
|
|
|
bi.hwndOwner = hMainDialog;
|
2013-10-15 21:58:27 +00:00
|
|
|
bi.lpszTitle = utf8_to_wchar(lmprintf(MSG_106));
|
2011-11-21 17:06:17 +00:00
|
|
|
bi.lpfn = BrowseInfoCallback;
|
|
|
|
// BIF_NONEWFOLDERBUTTON = 0x00000200 is unknown on MinGW
|
|
|
|
bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS |
|
|
|
|
BIF_DONTGOBELOWDOMAIN | BIF_EDITBOX | 0x00000200;
|
|
|
|
pidl = SHBrowseForFolderW(&bi);
|
|
|
|
if (pidl != NULL) {
|
|
|
|
CoTaskMemFree(pidl);
|
|
|
|
}
|
2013-10-15 21:58:27 +00:00
|
|
|
safe_free(bi.lpszTitle);
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing--;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
2012-02-02 13:16:49 +00:00
|
|
|
/*
|
|
|
|
* Return the UTF8 path of a file selected through a load or save dialog
|
|
|
|
* Will use the newer IFileOpenDialog if *compiled* for Vista or later
|
|
|
|
* All string parameters are UTF-8
|
2014-03-17 20:42:10 +00:00
|
|
|
* IMPORTANT NOTE: On Vista and later, remember that you need to call
|
|
|
|
* CoInitializeEx() for *EACH* thread you invoke FileDialog from, as
|
|
|
|
* GetDisplayName() will return error 0x8001010E otherwise.
|
2012-02-02 13:16:49 +00:00
|
|
|
*/
|
2014-05-22 00:52:25 +00:00
|
|
|
char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
|
2012-02-02 13:16:49 +00:00
|
|
|
{
|
|
|
|
DWORD tmp;
|
|
|
|
OPENFILENAMEA ofn;
|
|
|
|
char selected_name[MAX_PATH];
|
2013-10-15 21:58:27 +00:00
|
|
|
char *ext_string = NULL, *all_files = NULL;
|
2014-05-22 00:52:25 +00:00
|
|
|
size_t i, j, ext_strlen;
|
2012-02-02 13:16:49 +00:00
|
|
|
BOOL r;
|
|
|
|
char* filepath = NULL;
|
|
|
|
HRESULT hr = FALSE;
|
2012-02-24 18:46:02 +00:00
|
|
|
IFileDialog *pfd = NULL;
|
2012-02-02 13:16:49 +00:00
|
|
|
IShellItem *psiResult;
|
2016-03-25 16:38:01 +00:00
|
|
|
COMDLG_FILTERSPEC* filter_spec = NULL;
|
2012-02-02 13:16:49 +00:00
|
|
|
wchar_t *wpath = NULL, *wfilename = NULL;
|
|
|
|
IShellItem *si_path = NULL; // Automatically freed
|
|
|
|
|
2014-05-22 00:52:25 +00:00
|
|
|
if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL))
|
|
|
|
return NULL;
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing++;
|
2014-05-22 00:52:25 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
if (nWindowsVersion >= WINDOWS_VISTA) {
|
|
|
|
INIT_VISTA_SHELL32;
|
|
|
|
filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC));
|
|
|
|
if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) {
|
|
|
|
// Setup the file extension filter table
|
|
|
|
for (i = 0; i < ext->count; i++) {
|
|
|
|
filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
|
|
|
|
filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
|
|
|
|
}
|
|
|
|
filter_spec[i].pszSpec = L"*.*";
|
|
|
|
filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
hr = CoCreateInstance(save ? &CLSID_FileSaveDialog : &CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
|
|
|
|
&IID_IFileDialog, (LPVOID)&pfd);
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
SetLastError(hr);
|
|
|
|
uprintf("CoCreateInstance for FileOpenDialog failed: %s\n", WindowsErrorString());
|
|
|
|
pfd = NULL; // Just in case
|
|
|
|
goto fallback;
|
|
|
|
}
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
// Set the file extension filters
|
|
|
|
pfd->lpVtbl->SetFileTypes(pfd, (UINT)ext->count + 1, filter_spec);
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
// Set the default directory
|
|
|
|
wpath = utf8_to_wchar(path);
|
|
|
|
hr = (*pfSHCreateItemFromParsingName)(wpath, NULL, &IID_IShellItem, (LPVOID)&si_path);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
pfd->lpVtbl->SetFolder(pfd, si_path);
|
|
|
|
}
|
|
|
|
safe_free(wpath);
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
// Set the default filename
|
|
|
|
wfilename = utf8_to_wchar((ext->filename == NULL) ? "" : ext->filename);
|
|
|
|
if (wfilename != NULL) {
|
|
|
|
pfd->lpVtbl->SetFileName(pfd, wfilename);
|
|
|
|
}
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
// Display the dialog
|
|
|
|
hr = pfd->lpVtbl->Show(pfd, hMainDialog);
|
2012-02-02 13:16:49 +00:00
|
|
|
|
2016-03-23 16:56:49 +00:00
|
|
|
// Cleanup
|
|
|
|
safe_free(wfilename);
|
|
|
|
for (i = 0; i < ext->count; i++) {
|
|
|
|
safe_free(filter_spec[i].pszSpec);
|
|
|
|
safe_free(filter_spec[i].pszName);
|
|
|
|
}
|
2014-05-22 00:52:25 +00:00
|
|
|
safe_free(filter_spec[i].pszName);
|
2016-03-23 16:56:49 +00:00
|
|
|
safe_free(filter_spec);
|
2012-02-02 13:16:49 +00:00
|
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
2016-03-23 16:56:49 +00:00
|
|
|
// Obtain the result of the user's interaction with the dialog.
|
|
|
|
hr = pfd->lpVtbl->GetResult(pfd, &psiResult);
|
2012-02-02 13:16:49 +00:00
|
|
|
if (SUCCEEDED(hr)) {
|
2016-03-23 16:56:49 +00:00
|
|
|
hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &wpath);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
filepath = wchar_to_utf8(wpath);
|
|
|
|
CoTaskMemFree(wpath);
|
|
|
|
} else {
|
|
|
|
SetLastError(hr);
|
|
|
|
uprintf("Unable to access file path: %s\n", WindowsErrorString());
|
|
|
|
}
|
|
|
|
psiResult->lpVtbl->Release(psiResult);
|
2012-02-02 13:16:49 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
} else if ((hr & 0xFFFF) != ERROR_CANCELLED) {
|
|
|
|
// If it's not a user cancel, assume the dialog didn't show and fallback
|
|
|
|
SetLastError(hr);
|
|
|
|
uprintf("Could not show FileOpenDialog: %s\n", WindowsErrorString());
|
|
|
|
goto fallback;
|
2012-02-02 13:16:49 +00:00
|
|
|
}
|
2016-03-23 16:56:49 +00:00
|
|
|
pfd->lpVtbl->Release(pfd);
|
|
|
|
dialog_showing--;
|
|
|
|
return filepath;
|
2012-02-02 13:16:49 +00:00
|
|
|
}
|
2016-03-25 16:38:01 +00:00
|
|
|
fallback:
|
|
|
|
safe_free(filter_spec);
|
2016-03-23 16:56:49 +00:00
|
|
|
if (pfd != NULL) {
|
|
|
|
pfd->lpVtbl->Release(pfd);
|
|
|
|
}
|
2012-02-02 13:16:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&ofn, 0, sizeof(ofn));
|
|
|
|
ofn.lStructSize = sizeof(ofn);
|
|
|
|
ofn.hwndOwner = hMainDialog;
|
2014-05-22 00:52:25 +00:00
|
|
|
// Selected File name
|
2015-02-13 00:37:21 +00:00
|
|
|
static_sprintf(selected_name, "%s", (ext->filename == NULL)?"":ext->filename);
|
2012-02-02 13:16:49 +00:00
|
|
|
ofn.lpstrFile = selected_name;
|
|
|
|
ofn.nMaxFile = MAX_PATH;
|
|
|
|
// Set the file extension filters
|
2013-10-15 21:58:27 +00:00
|
|
|
all_files = lmprintf(MSG_107);
|
2014-05-22 00:52:25 +00:00
|
|
|
ext_strlen = 0;
|
|
|
|
for (i=0; i<ext->count; i++) {
|
|
|
|
ext_strlen += safe_strlen(ext->description[i]) + 2*safe_strlen(ext->extension[i]) + sizeof(" ()\r\r");
|
|
|
|
}
|
|
|
|
ext_strlen += safe_strlen(all_files) + sizeof(" (*.*)\r*.*\r");
|
|
|
|
ext_string = (char*)malloc(ext_strlen+1);
|
2013-01-20 23:34:13 +00:00
|
|
|
if (ext_string == NULL)
|
|
|
|
return NULL;
|
2014-06-03 21:42:42 +00:00
|
|
|
ext_string[0] = 0;
|
2014-05-22 00:52:25 +00:00
|
|
|
for (i=0, j=0; i<ext->count; i++) {
|
|
|
|
j += _snprintf(&ext_string[j], ext_strlen-j, "%s (%s)\r%s\r", ext->description[i], ext->extension[i], ext->extension[i]);
|
|
|
|
}
|
|
|
|
j = _snprintf(&ext_string[j], ext_strlen-j, "%s (*.*)\r*.*\r", all_files);
|
2012-02-02 13:16:49 +00:00
|
|
|
// Microsoft could really have picked a better delimiter!
|
|
|
|
for (i=0; i<ext_strlen; i++) {
|
2017-03-10 18:07:48 +00:00
|
|
|
// Since the VS Code Analysis tool is dumb...
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#pragma warning(suppress: 6385)
|
|
|
|
#endif
|
2012-02-02 13:16:49 +00:00
|
|
|
if (ext_string[i] == '\r') {
|
2017-03-10 18:07:48 +00:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#pragma warning(suppress: 6386)
|
|
|
|
#endif
|
2012-02-02 13:16:49 +00:00
|
|
|
ext_string[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ofn.lpstrFilter = ext_string;
|
2014-05-22 00:52:25 +00:00
|
|
|
ofn.nFilterIndex = 1;
|
2012-02-02 13:16:49 +00:00
|
|
|
ofn.lpstrInitialDir = path;
|
2014-03-17 20:42:10 +00:00
|
|
|
ofn.Flags = OFN_OVERWRITEPROMPT | options;
|
2012-02-02 13:16:49 +00:00
|
|
|
// Show Dialog
|
|
|
|
if (save) {
|
|
|
|
r = GetSaveFileNameU(&ofn);
|
|
|
|
} else {
|
|
|
|
r = GetOpenFileNameU(&ofn);
|
|
|
|
}
|
|
|
|
if (r) {
|
|
|
|
filepath = safe_strdup(selected_name);
|
|
|
|
} else {
|
|
|
|
tmp = CommDlgExtendedError();
|
|
|
|
if (tmp != 0) {
|
2013-10-15 21:58:27 +00:00
|
|
|
uprintf("Could not select file for %s. Error %X\n", save?"save":"open", tmp);
|
2012-02-02 13:16:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
safe_free(ext_string);
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing--;
|
2012-02-02 13:16:49 +00:00
|
|
|
return filepath;
|
|
|
|
}
|
|
|
|
|
2011-12-08 12:14:21 +00:00
|
|
|
/*
|
|
|
|
* Create the application status bar
|
|
|
|
*/
|
|
|
|
void CreateStatusBar(void)
|
|
|
|
{
|
2015-07-06 21:04:38 +00:00
|
|
|
SIZE sz = {0, 0};
|
2011-12-08 12:14:21 +00:00
|
|
|
RECT rect;
|
2015-07-06 21:04:38 +00:00
|
|
|
LONG x, y, width, height;
|
2015-06-30 22:22:10 +00:00
|
|
|
int edge[3];
|
2015-07-06 21:04:38 +00:00
|
|
|
TBBUTTON tbbStatusToolbarButtons[1];
|
|
|
|
TBBUTTONINFO tbi;
|
2015-07-02 21:46:26 +00:00
|
|
|
HFONT hFont;
|
2015-07-06 21:04:38 +00:00
|
|
|
HDC hDC;
|
2015-07-02 21:46:26 +00:00
|
|
|
|
|
|
|
// Create the status bar (WS_CLIPSIBLINGS since we have an overlapping button)
|
2017-04-04 16:26:45 +00:00
|
|
|
hStatus = CreateWindowExW(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | SBARS_TOOLTIPS | WS_CLIPSIBLINGS,
|
2015-07-02 21:46:26 +00:00
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hMainDialog,
|
|
|
|
(HMENU)IDC_STATUS, hMainInstance, NULL);
|
2011-12-08 12:14:21 +00:00
|
|
|
|
2015-07-02 21:46:26 +00:00
|
|
|
// Keep track of the status bar height
|
|
|
|
GetClientRect(hStatus, &rect);
|
|
|
|
height = rect.bottom;
|
2011-12-08 12:14:21 +00:00
|
|
|
|
2015-07-06 21:04:38 +00:00
|
|
|
// Set the font we'll use to display the '#' sign in the toolbar button
|
|
|
|
hFont = CreateFontA(-MulDiv(10, GetDeviceCaps(GetDC(hMainDialog), LOGPIXELSY), 72),
|
|
|
|
0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
|
|
|
|
0, 0, PROOF_QUALITY, 0, (nWindowsVersion >= WINDOWS_VISTA)?"Segoe UI":"Arial Unicode MS");
|
|
|
|
|
|
|
|
// Find the width of our hash sign
|
|
|
|
hDC = GetDC(hMainDialog);
|
|
|
|
SelectObject(hDC, hFont);
|
|
|
|
GetTextExtentPoint32W(hDC, L"#", 1, &sz);
|
|
|
|
if (hDC != NULL)
|
|
|
|
ReleaseDC(hMainDialog, hDC);
|
|
|
|
|
2015-06-30 22:22:10 +00:00
|
|
|
// Create 3 status areas
|
2011-12-08 12:14:21 +00:00
|
|
|
GetClientRect(hMainDialog, &rect);
|
2015-07-06 21:04:38 +00:00
|
|
|
edge[1] = rect.right - (int)(SB_TIMER_SECTION_SIZE * fScale);
|
|
|
|
edge[0] = edge[1] - (8 + sz.cx + 8 + 1); // There's 8 absolute pixels on right and left of the text
|
2015-06-30 22:22:10 +00:00
|
|
|
edge[2] = rect.right;
|
2015-07-02 21:46:26 +00:00
|
|
|
SendMessage(hStatus, SB_SETPARTS, (WPARAM)ARRAYSIZE(edge), (LPARAM)&edge);
|
2015-06-30 22:22:10 +00:00
|
|
|
|
|
|
|
// NB: To add an icon on the status bar, you can use something like this:
|
2015-07-02 21:46:26 +00:00
|
|
|
// SendMessage(hStatus, SB_SETICON, (WPARAM) 1, (LPARAM)LoadImage(GetLibraryHandle("rasdlg"),
|
|
|
|
// MAKEINTRESOURCE(50), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED));
|
|
|
|
|
|
|
|
// This is supposed to create a toolips for a statusbar section (when SBARS_TOOLTIPS is in use)... but doesn't :(
|
|
|
|
// SendMessageLU(hStatus, SB_SETTIPTEXT, (WPARAM)2, (LPARAM)"HELLO");
|
|
|
|
|
2015-07-06 21:04:38 +00:00
|
|
|
// Compute the dimensions for the hash button
|
|
|
|
x = edge[0];
|
2015-07-09 00:20:21 +00:00
|
|
|
if (nWindowsVersion <= WINDOWS_XP) {
|
|
|
|
x -= 1;
|
|
|
|
height -= 2;
|
|
|
|
}
|
2015-07-06 21:04:38 +00:00
|
|
|
y = rect.bottom - height + 1;
|
|
|
|
width = edge[1] - edge[0] - 1;
|
|
|
|
// How I wish there was a way to figure out how to make Windows controls look good
|
|
|
|
// at all scales, without adding all these crappy empirical adjustments...
|
|
|
|
if ((fScale > 1.20f) && (fScale <2.40f))
|
|
|
|
height -= 1;
|
|
|
|
if (nWindowsVersion <= WINDOWS_7)
|
|
|
|
height += 1;
|
|
|
|
|
|
|
|
// Create the status toolbar
|
2017-04-04 16:26:45 +00:00
|
|
|
hStatusToolbar = CreateWindowExW(WS_EX_TRANSPARENT, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_TABSTOP | WS_DISABLED |
|
2015-07-06 21:04:38 +00:00
|
|
|
TBSTYLE_LIST | CCS_NOPARENTALIGN | CCS_NODIVIDER | CCS_NORESIZE,
|
|
|
|
x, y, width, height, hMainDialog, (HMENU)IDC_STATUS_TOOLBAR, hMainInstance, NULL);
|
|
|
|
|
|
|
|
// Set the button properties
|
|
|
|
SendMessage(hStatusToolbar, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
|
|
SendMessage(hStatusToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_MIXEDBUTTONS);
|
|
|
|
SendMessage(hStatusToolbar, TB_SETIMAGELIST, 0, (LPARAM)NULL);
|
2015-10-18 20:31:47 +00:00
|
|
|
SendMessage(hStatusToolbar, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)NULL);
|
|
|
|
SendMessage(hStatusToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(0,0));
|
2015-07-06 21:04:38 +00:00
|
|
|
|
|
|
|
// Set our text
|
|
|
|
memset(tbbStatusToolbarButtons, 0, sizeof(TBBUTTON));
|
|
|
|
tbbStatusToolbarButtons[0].idCommand = IDC_HASH;
|
|
|
|
tbbStatusToolbarButtons[0].fsStyle = BTNS_SHOWTEXT;
|
|
|
|
tbbStatusToolbarButtons[0].fsState = TBSTATE_ENABLED;
|
|
|
|
tbbStatusToolbarButtons[0].iString = (INT_PTR)L"#";
|
|
|
|
SendMessage(hStatusToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
|
|
|
|
SendMessage(hStatusToolbar, TB_ADDBUTTONS, (WPARAM)1, (LPARAM)&tbbStatusToolbarButtons);
|
|
|
|
|
|
|
|
SendMessage(hStatusToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(width, height - 1));
|
|
|
|
// Yeah, you'd think that TB_SETBUTTONSIZE would work for the width... but you'd be wrong.
|
|
|
|
// The only working method that actually enforces the requested width is TB_SETBUTTONINFO
|
|
|
|
tbi.cbSize = sizeof(tbi);
|
|
|
|
tbi.dwMask = TBIF_SIZE | TBIF_COMMAND;
|
|
|
|
tbi.cx = (WORD)width;
|
|
|
|
tbi.idCommand = IDC_HASH;
|
|
|
|
SendMessage(hStatusToolbar, TB_SETBUTTONINFO, (WPARAM)IDC_HASH, (LPARAM)&tbi);
|
|
|
|
|
|
|
|
// Need to resend the positioning for the toolbar to become active... One of Windows' mysteries
|
|
|
|
// Also use this opportunity to set our Z-order for tab stop
|
|
|
|
SetWindowPos(hStatusToolbar, GetDlgItem(hMainDialog, IDCANCEL), x, y, width, height, 0);
|
|
|
|
ShowWindow(hStatusToolbar, SW_SHOWNORMAL);
|
2011-12-08 12:14:21 +00:00
|
|
|
}
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
/*
|
|
|
|
* Center a dialog with regards to the main application Window or the desktop
|
2013-10-24 21:57:34 +00:00
|
|
|
* See http://msdn.microsoft.com/en-us/library/windows/desktop/ms644996.aspx#init_box
|
2011-11-21 17:06:17 +00:00
|
|
|
*/
|
|
|
|
void CenterDialog(HWND hDlg)
|
|
|
|
{
|
|
|
|
HWND hParent;
|
2013-10-24 21:57:34 +00:00
|
|
|
RECT rc, rcDlg, rcParent;
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
if ((hParent = GetParent(hDlg)) == NULL) {
|
2011-11-21 17:06:17 +00:00
|
|
|
hParent = GetDesktopWindow();
|
|
|
|
}
|
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
GetWindowRect(hParent, &rcParent);
|
|
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
|
|
CopyRect(&rc, &rcParent);
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
// Offset the parent and dialog box rectangles so that right and bottom
|
|
|
|
// values represent the width and height, and then offset the parent again
|
|
|
|
// to discard space taken up by the dialog box.
|
|
|
|
OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
|
|
|
|
OffsetRect(&rc, -rc.left, -rc.top);
|
|
|
|
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
SetWindowPos(hDlg, HWND_TOP, rcParent.left + (rc.right / 2), rcParent.top + (rc.bottom / 2) - 25, 0, 0, SWP_NOSIZE);
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
// http://stackoverflow.com/questions/431470/window-border-width-and-height-in-win32-how-do-i-get-it
|
|
|
|
SIZE GetBorderSize(HWND hDlg)
|
|
|
|
{
|
|
|
|
RECT rect = {0, 0, 0, 0};
|
|
|
|
SIZE size = {0, 0};
|
|
|
|
WINDOWINFO wi;
|
|
|
|
wi.cbSize = sizeof(WINDOWINFO);
|
|
|
|
|
|
|
|
GetWindowInfo(hDlg, &wi);
|
|
|
|
|
|
|
|
AdjustWindowRectEx(&rect, wi.dwStyle, FALSE, wi.dwExStyle);
|
|
|
|
size.cx = rect.right - rect.left;
|
|
|
|
size.cy = rect.bottom - rect.top;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2015-08-22 14:18:25 +00:00
|
|
|
void ResizeMoveCtrl(HWND hDlg, HWND hCtrl, int dx, int dy, int dw, int dh, float scale)
|
2013-10-15 21:58:27 +00:00
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
POINT point;
|
2014-10-29 18:27:17 +00:00
|
|
|
SIZE border;
|
2013-10-15 21:58:27 +00:00
|
|
|
|
|
|
|
GetWindowRect(hCtrl, &rect);
|
2015-10-19 21:14:08 +00:00
|
|
|
point.x = (right_to_left_mode && (hDlg != hCtrl))?rect.right:rect.left;
|
2013-10-15 21:58:27 +00:00
|
|
|
point.y = rect.top;
|
2015-09-25 23:30:16 +00:00
|
|
|
if (hDlg != hCtrl)
|
|
|
|
ScreenToClient(hDlg, &point);
|
2013-10-15 21:58:27 +00:00
|
|
|
GetClientRect(hCtrl, &rect);
|
|
|
|
|
2014-10-29 18:27:17 +00:00
|
|
|
// If the control has any borders (dialog, edit box), take them into account
|
|
|
|
border = GetBorderSize(hCtrl);
|
2015-08-22 14:18:25 +00:00
|
|
|
MoveWindow(hCtrl, point.x + (int)(scale*(float)dx), point.y + (int)(scale*(float)dy),
|
|
|
|
(rect.right - rect.left) + (int)(scale*(float)dw + border.cx),
|
|
|
|
(rect.bottom - rect.top) + (int)(scale*(float)dh + border.cy), TRUE);
|
2013-10-15 21:58:27 +00:00
|
|
|
InvalidateRect(hCtrl, NULL, TRUE);
|
|
|
|
}
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
/*
|
|
|
|
* License callback
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK LicenseCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2016-12-05 10:52:37 +00:00
|
|
|
long style;
|
|
|
|
HWND hLicense;
|
2011-11-21 17:06:17 +00:00
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2016-12-05 10:52:37 +00:00
|
|
|
hLicense = GetDlgItem(hDlg, IDC_LICENSE_TEXT);
|
2013-10-15 21:58:27 +00:00
|
|
|
apply_localization(IDD_LICENSE, hDlg);
|
2011-11-21 17:06:17 +00:00
|
|
|
CenterDialog(hDlg);
|
2016-12-05 10:52:37 +00:00
|
|
|
// Suppress any inherited RTL flags
|
|
|
|
style = GetWindowLong(hLicense, GWL_EXSTYLE);
|
|
|
|
style &= ~(WS_EX_RTLREADING | WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR);
|
|
|
|
SetWindowLong(hLicense, GWL_EXSTYLE, style);
|
|
|
|
style = GetWindowLong(hLicense, GWL_STYLE);
|
|
|
|
style &= ~(ES_RIGHT);
|
|
|
|
SetWindowLong(hLicense, GWL_STYLE, style);
|
2011-11-21 17:06:17 +00:00
|
|
|
SetDlgItemTextA(hDlg, IDC_LICENSE_TEXT, gplv3);
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
case IDCANCEL:
|
2013-10-15 21:58:27 +00:00
|
|
|
reset_localization(IDD_LICENSE);
|
2011-11-21 17:06:17 +00:00
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* About dialog callback
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2015-09-25 23:30:16 +00:00
|
|
|
int i, dy;
|
2012-11-29 02:59:52 +00:00
|
|
|
const int edit_id[2] = {IDC_ABOUT_BLURB, IDC_ABOUT_COPYRIGHTS};
|
2013-10-15 21:58:27 +00:00
|
|
|
char about_blurb[2048];
|
2012-11-29 02:59:52 +00:00
|
|
|
const char* edit_text[2] = {about_blurb, additional_copyrights};
|
|
|
|
HWND hEdit[2];
|
2012-11-08 20:36:48 +00:00
|
|
|
TEXTRANGEW tr;
|
|
|
|
ENLINK* enl;
|
2015-09-25 23:30:16 +00:00
|
|
|
RECT rect;
|
|
|
|
REQRESIZE* rsz;
|
2012-11-08 20:36:48 +00:00
|
|
|
wchar_t wUrl[256];
|
2015-10-18 20:56:24 +00:00
|
|
|
static BOOL resized_already = TRUE;
|
2012-11-08 20:36:48 +00:00
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2015-10-18 20:56:24 +00:00
|
|
|
resized_already = FALSE;
|
2013-10-15 21:58:27 +00:00
|
|
|
// Execute dialog localization
|
|
|
|
apply_localization(IDD_ABOUTBOX, hDlg);
|
2012-12-05 01:53:10 +00:00
|
|
|
SetTitleBarIcon(hDlg);
|
2011-11-21 17:06:17 +00:00
|
|
|
CenterDialog(hDlg);
|
2015-01-25 00:56:38 +00:00
|
|
|
if (settings_commcheck)
|
2012-12-02 03:50:08 +00:00
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_UPDATES), SW_SHOW);
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(about_blurb, about_blurb_format, lmprintf(MSG_174|MSG_RTF),
|
2015-10-21 23:40:24 +00:00
|
|
|
lmprintf(MSG_175|MSG_RTF, rufus_version[0], rufus_version[1], rufus_version[2]),
|
2017-01-01 15:30:03 +00:00
|
|
|
right_to_left_mode?"Akeo \\\\ Pete Batard 2011-2017 © Copyright":"Copyright © 2011-2017 Pete Batard / Akeo",
|
2015-10-21 23:40:24 +00:00
|
|
|
lmprintf(MSG_176|MSG_RTF), lmprintf(MSG_177|MSG_RTF), lmprintf(MSG_178|MSG_RTF));
|
2012-11-29 02:59:52 +00:00
|
|
|
for (i=0; i<ARRAYSIZE(hEdit); i++) {
|
|
|
|
hEdit[i] = GetDlgItem(hDlg, edit_id[i]);
|
|
|
|
SendMessage(hEdit[i], EM_AUTOURLDETECT, 1, 0);
|
|
|
|
/* Can't use SetDlgItemText, because it only works with RichEdit20A... and VS insists
|
|
|
|
* on reverting to RichEdit20W as soon as you edit the dialog. You can try all the W
|
|
|
|
* methods you want, it JUST WON'T WORK unless you use EM_SETTEXTEX. Also see:
|
|
|
|
* http://blog.kowalczyk.info/article/eny/Setting-unicode-rtf-text-in-rich-edit-control.html */
|
|
|
|
SendMessageA(hEdit[i], EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)edit_text[i]);
|
|
|
|
SendMessage(hEdit[i], EM_SETSEL, -1, -1);
|
2015-09-25 23:30:16 +00:00
|
|
|
SendMessage(hEdit[i], EM_SETEVENTMASK, 0, ENM_LINK|((i==0)?ENM_REQUESTRESIZE:0));
|
2012-11-29 02:59:52 +00:00
|
|
|
SendMessage(hEdit[i], EM_SETBKGNDCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
|
|
|
|
}
|
2015-05-08 22:37:22 +00:00
|
|
|
// Need to send an explicit SetSel to avoid being positioned at the end of richedit control when tabstop is used
|
|
|
|
SendMessage(hEdit[1], EM_SETSEL, 0, 0);
|
2015-09-25 23:30:16 +00:00
|
|
|
SendMessage(hEdit[0], EM_REQUESTRESIZE, 0, 0);
|
2011-11-21 17:06:17 +00:00
|
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
|
|
switch (((LPNMHDR)lParam)->code) {
|
2015-09-25 23:30:16 +00:00
|
|
|
case EN_REQUESTRESIZE:
|
2015-10-18 20:56:24 +00:00
|
|
|
if (!resized_already) {
|
|
|
|
resized_already = TRUE;
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, edit_id[0]), &rect);
|
|
|
|
dy = rect.bottom - rect.top;
|
|
|
|
rsz = (REQRESIZE *)lParam;
|
|
|
|
dy -= rsz->rc.bottom - rsz->rc.top;
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, edit_id[0]), 0, 0, 0, -dy, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, edit_id[1]), 0, -dy, 0, dy, 1.0f);
|
|
|
|
}
|
2015-09-25 23:30:16 +00:00
|
|
|
break;
|
2012-11-08 20:36:48 +00:00
|
|
|
case EN_LINK:
|
|
|
|
enl = (ENLINK*) lParam;
|
|
|
|
if (enl->msg == WM_LBUTTONUP) {
|
|
|
|
tr.lpstrText = wUrl;
|
|
|
|
tr.chrg.cpMin = enl->chrg.cpMin;
|
|
|
|
tr.chrg.cpMax = enl->chrg.cpMax;
|
|
|
|
SendMessageW(enl->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
|
2013-01-09 21:54:28 +00:00
|
|
|
wUrl[ARRAYSIZE(wUrl)-1] = 0;
|
2012-11-08 20:36:48 +00:00
|
|
|
ShellExecuteW(hDlg, L"open", wUrl, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
}
|
|
|
|
break;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
case IDCANCEL:
|
2013-10-15 21:58:27 +00:00
|
|
|
reset_localization(IDD_ABOUTBOX);
|
2011-11-21 17:06:17 +00:00
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case IDC_ABOUT_LICENSE:
|
2015-07-03 22:42:45 +00:00
|
|
|
MyDialogBox(hMainInstance, IDD_LICENSE, hDlg, LicenseCallback);
|
2011-11-21 17:06:17 +00:00
|
|
|
break;
|
2012-12-02 03:50:08 +00:00
|
|
|
case IDC_ABOUT_UPDATES:
|
2015-07-03 22:42:45 +00:00
|
|
|
MyDialogBox(hMainInstance, IDD_UPDATE_POLICY, hDlg, UpdateCallback);
|
2012-12-02 03:50:08 +00:00
|
|
|
break;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INT_PTR CreateAboutBox(void)
|
|
|
|
{
|
2012-12-07 00:54:40 +00:00
|
|
|
INT_PTR r;
|
|
|
|
dialog_showing++;
|
2015-07-03 22:42:45 +00:00
|
|
|
r = MyDialogBox(hMainInstance, IDD_ABOUTBOX, hMainDialog, AboutCallback);
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing--;
|
|
|
|
return r;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We use our own MessageBox for notifications to have greater control (center, no close button, etc)
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
LRESULT loc;
|
|
|
|
int i;
|
|
|
|
// Prevent resizing
|
|
|
|
static LRESULT disabled[9] = { HTLEFT, HTRIGHT, HTTOP, HTBOTTOM, HTSIZE,
|
|
|
|
HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT };
|
2015-06-21 16:59:59 +00:00
|
|
|
static HBRUSH background_brush, separator_brush;
|
2014-01-03 01:52:20 +00:00
|
|
|
// To use the system message font
|
|
|
|
NONCLIENTMETRICS ncm;
|
|
|
|
HFONT hDlgFont;
|
2011-11-21 17:06:17 +00:00
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2017-07-24 15:25:18 +00:00
|
|
|
if (nWindowsVersion >= WINDOWS_VISTA) { // of course, this stuff doesn't work on XP!
|
|
|
|
// Get the system message box font. See http://stackoverflow.com/a/6057761
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
|
|
|
|
// will be the wrong size for previous versions, so we need to adjust it.
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
|
2014-01-03 01:52:20 +00:00
|
|
|
ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
|
2017-07-24 15:25:18 +00:00
|
|
|
#endif
|
|
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
|
|
|
|
hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));
|
|
|
|
// Set the dialog to use the system message box font
|
|
|
|
SendMessage(hDlg, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_NOTIFICATION_TEXT), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_MORE_INFO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDYES), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDNO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
2014-01-03 01:52:20 +00:00
|
|
|
}
|
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
apply_localization(IDD_NOTIFICATION, hDlg);
|
2015-09-20 23:20:19 +00:00
|
|
|
background_brush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
2015-06-21 16:59:59 +00:00
|
|
|
separator_brush = CreateSolidBrush(GetSysColor(COLOR_3DLIGHT));
|
2012-12-05 01:53:10 +00:00
|
|
|
SetTitleBarIcon(hDlg);
|
2011-11-21 17:06:17 +00:00
|
|
|
CenterDialog(hDlg);
|
|
|
|
// Change the default icon
|
|
|
|
if (Static_SetIcon(GetDlgItem(hDlg, IDC_NOTIFICATION_ICON), hMessageIcon) == 0) {
|
2012-05-30 23:32:25 +00:00
|
|
|
uprintf("Could not set dialog icon\n");
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
// Set the dialog title
|
|
|
|
if (szMessageTitle != NULL) {
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(hDlg, szMessageTitle);
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2012-11-29 23:14:36 +00:00
|
|
|
// Enable/disable the buttons and set text
|
|
|
|
if (!notification_is_question) {
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDNO), lmprintf(MSG_006));
|
2012-11-29 23:14:36 +00:00
|
|
|
} else {
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDYES), SW_SHOW);
|
|
|
|
}
|
2012-12-02 03:50:08 +00:00
|
|
|
if ((notification_more_info != NULL) && (notification_more_info->callback != NULL)) {
|
2012-11-29 23:14:36 +00:00
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_MORE_INFO), SW_SHOW);
|
|
|
|
}
|
2011-11-21 17:06:17 +00:00
|
|
|
// Set the control text
|
|
|
|
if (szMessageText != NULL) {
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_NOTIFICATION_TEXT), szMessageText);
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
|
// Change the background colour for static text and icon
|
|
|
|
SetBkMode((HDC)wParam, TRANSPARENT);
|
|
|
|
if ((HWND)lParam == GetDlgItem(hDlg, IDC_NOTIFICATION_LINE)) {
|
|
|
|
return (INT_PTR)separator_brush;
|
|
|
|
}
|
2015-06-21 16:59:59 +00:00
|
|
|
return (INT_PTR)background_brush;
|
2011-11-21 17:06:17 +00:00
|
|
|
case WM_NCHITTEST:
|
|
|
|
// Check coordinates to prevent resize actions
|
|
|
|
loc = DefWindowProc(hDlg, message, wParam, lParam);
|
|
|
|
for(i = 0; i < 9; i++) {
|
|
|
|
if (loc == disabled[i]) {
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
case IDCANCEL:
|
2012-11-29 23:14:36 +00:00
|
|
|
case IDYES:
|
|
|
|
case IDNO:
|
2011-11-21 17:06:17 +00:00
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
|
return (INT_PTR)TRUE;
|
2012-11-29 23:14:36 +00:00
|
|
|
case IDC_MORE_INFO:
|
2012-12-02 03:50:08 +00:00
|
|
|
if (notification_more_info != NULL)
|
2015-07-03 22:42:45 +00:00
|
|
|
MyDialogBox(hMainInstance, notification_more_info->id, hDlg, notification_more_info->callback);
|
2012-11-29 23:14:36 +00:00
|
|
|
break;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display a custom notification
|
|
|
|
*/
|
2012-12-02 03:50:08 +00:00
|
|
|
BOOL Notification(int type, const notification_info* more_info, char* title, char* format, ...)
|
2011-11-21 17:06:17 +00:00
|
|
|
{
|
2012-11-29 23:14:36 +00:00
|
|
|
BOOL ret;
|
2011-12-04 19:47:27 +00:00
|
|
|
va_list args;
|
2012-12-07 00:54:40 +00:00
|
|
|
|
|
|
|
dialog_showing++;
|
2011-12-04 19:47:27 +00:00
|
|
|
szMessageText = (char*)malloc(MAX_PATH);
|
|
|
|
if (szMessageText == NULL) return FALSE;
|
2017-06-24 16:23:06 +00:00
|
|
|
szMessageTitle = safe_strdup(title);
|
|
|
|
if (szMessageTitle == NULL) return FALSE;
|
2011-12-04 19:47:27 +00:00
|
|
|
va_start(args, format);
|
|
|
|
safe_vsnprintf(szMessageText, MAX_PATH-1, format, args);
|
|
|
|
va_end(args);
|
|
|
|
szMessageText[MAX_PATH-1] = 0;
|
2012-12-02 03:50:08 +00:00
|
|
|
notification_more_info = more_info;
|
2012-11-29 23:14:36 +00:00
|
|
|
notification_is_question = FALSE;
|
2011-12-04 19:47:27 +00:00
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
switch(type) {
|
2017-07-16 21:42:19 +00:00
|
|
|
case MSG_WARNING_QUESTION:
|
|
|
|
notification_is_question = TRUE;
|
|
|
|
// Fall through
|
2011-11-21 17:06:17 +00:00
|
|
|
case MSG_WARNING:
|
|
|
|
hMessageIcon = LoadIcon(NULL, IDI_WARNING);
|
|
|
|
break;
|
|
|
|
case MSG_ERROR:
|
|
|
|
hMessageIcon = LoadIcon(NULL, IDI_ERROR);
|
|
|
|
break;
|
2012-11-29 23:14:36 +00:00
|
|
|
case MSG_QUESTION:
|
|
|
|
hMessageIcon = LoadIcon(NULL, IDI_QUESTION);
|
|
|
|
notification_is_question = TRUE;
|
|
|
|
break;
|
2011-11-21 17:06:17 +00:00
|
|
|
case MSG_INFO:
|
|
|
|
default:
|
|
|
|
hMessageIcon = LoadIcon(NULL, IDI_INFORMATION);
|
|
|
|
break;
|
|
|
|
}
|
2015-07-03 22:42:45 +00:00
|
|
|
ret = (MyDialogBox(hMainInstance, IDD_NOTIFICATION, hMainDialog, NotificationCallback) == IDYES);
|
2012-11-29 02:59:52 +00:00
|
|
|
safe_free(szMessageText);
|
2017-06-24 16:23:06 +00:00
|
|
|
safe_free(szMessageTitle);
|
2012-12-07 00:54:40 +00:00
|
|
|
dialog_showing--;
|
2012-11-29 02:59:52 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-22 14:18:25 +00:00
|
|
|
/*
|
2017-07-11 16:43:51 +00:00
|
|
|
* Custom dialog for radio button selection dialog
|
|
|
|
*/
|
2015-08-22 14:18:25 +00:00
|
|
|
INT_PTR CALLBACK SelectionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
LRESULT loc;
|
|
|
|
int i, dh, r = -1;
|
|
|
|
// Prevent resizing
|
|
|
|
static LRESULT disabled[9] = { HTLEFT, HTRIGHT, HTTOP, HTBOTTOM, HTSIZE,
|
|
|
|
HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT };
|
|
|
|
static HBRUSH background_brush, separator_brush;
|
|
|
|
// To use the system message font
|
|
|
|
NONCLIENTMETRICS ncm;
|
2017-01-18 13:46:16 +00:00
|
|
|
RECT rect, rect2;
|
2015-08-22 14:18:25 +00:00
|
|
|
HFONT hDlgFont;
|
|
|
|
HWND hCtrl;
|
2015-08-22 14:57:23 +00:00
|
|
|
HDC hDC;
|
2015-08-22 14:18:25 +00:00
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2016-12-13 14:21:51 +00:00
|
|
|
// Don't overflow our max radio button
|
2017-07-11 16:43:51 +00:00
|
|
|
if (nDialogItems > (IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1 + 1)) {
|
2017-01-18 13:46:16 +00:00
|
|
|
uprintf("Warning: Too many options requested for Selection (%d vs %d)",
|
2017-07-11 16:43:51 +00:00
|
|
|
nDialogItems, IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1);
|
|
|
|
nDialogItems = IDC_SELECTION_CHOICEMAX - IDC_SELECTION_CHOICE1;
|
2016-12-13 14:21:51 +00:00
|
|
|
}
|
|
|
|
// TODO: This shouldn't be needed when using DS_SHELLFONT
|
2015-08-22 14:18:25 +00:00
|
|
|
// Get the system message box font. See http://stackoverflow.com/a/6057761
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
|
|
|
|
// will be the wrong size for previous versions, so we need to adjust it.
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
|
|
|
|
if (nWindowsVersion >= WINDOWS_VISTA) {
|
|
|
|
// In versions of Windows prior to Vista, the iPaddedBorderWidth member
|
|
|
|
// is not present, so we need to subtract its size from cbSize.
|
|
|
|
ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
|
|
|
|
hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));
|
|
|
|
// Set the dialog to use the system message box font
|
|
|
|
SendMessage(hDlg, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_SELECTION_TEXT), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
2017-07-11 16:43:51 +00:00
|
|
|
for (i = 0; i < nDialogItems; i++)
|
2016-12-13 14:21:51 +00:00
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
2015-08-22 14:18:25 +00:00
|
|
|
SendMessage(GetDlgItem(hDlg, IDYES), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDNO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
|
|
|
|
apply_localization(IDD_SELECTION, hDlg);
|
2015-09-20 23:20:19 +00:00
|
|
|
background_brush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
2015-08-22 14:18:25 +00:00
|
|
|
separator_brush = CreateSolidBrush(GetSysColor(COLOR_3DLIGHT));
|
|
|
|
SetTitleBarIcon(hDlg);
|
|
|
|
CenterDialog(hDlg);
|
|
|
|
// Change the default icon and set the text
|
|
|
|
Static_SetIcon(GetDlgItem(hDlg, IDC_SELECTION_ICON), LoadIcon(NULL, IDI_QUESTION));
|
|
|
|
SetWindowTextU(hDlg, szMessageTitle);
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007));
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_TEXT), szMessageText);
|
2017-07-11 16:43:51 +00:00
|
|
|
for (i = 0; i < nDialogItems; i++) {
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), szDialogItem[i]);
|
2016-12-13 14:21:51 +00:00
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), SW_SHOW);
|
|
|
|
}
|
2015-08-22 14:18:25 +00:00
|
|
|
// Move/Resize the controls as needed to fit our text
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_SELECTION_TEXT);
|
2015-08-22 14:57:23 +00:00
|
|
|
hDC = GetDC(hCtrl);
|
|
|
|
SelectFont(hDC, hDlgFont); // Yes, you *MUST* reapply the font to the DC, even after SetWindowText!
|
2015-08-22 14:18:25 +00:00
|
|
|
GetWindowRect(hCtrl, &rect);
|
|
|
|
dh = rect.bottom - rect.top;
|
2015-08-22 14:57:23 +00:00
|
|
|
DrawTextU(hDC, szMessageText, -1, &rect, DT_CALCRECT | DT_WORDBREAK);
|
2015-08-22 14:18:25 +00:00
|
|
|
dh = rect.bottom - rect.top - dh;
|
2015-08-22 14:57:23 +00:00
|
|
|
if (hDC != NULL)
|
|
|
|
ReleaseDC(hCtrl, hDC);
|
2015-08-22 14:18:25 +00:00
|
|
|
ResizeMoveCtrl(hDlg, hCtrl, 0, 0, 0, dh, 1.0f);
|
2017-07-11 16:43:51 +00:00
|
|
|
for (i = 0; i < nDialogItems; i++)
|
2016-12-13 14:21:51 +00:00
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i), 0, dh, 0, 0, 1.0f);
|
2017-07-11 16:43:51 +00:00
|
|
|
if (nDialogItems > 2) {
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), &rect);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + nDialogItems - 1), &rect2);
|
|
|
|
dh += rect2.top - rect.top;
|
2016-12-13 14:21:51 +00:00
|
|
|
}
|
2015-08-22 14:18:25 +00:00
|
|
|
ResizeMoveCtrl(hDlg, hDlg, 0, 0, 0, dh, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, -1), 0, 0, 0, dh, 1.0f); // IDC_STATIC = -1
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_SELECTION_LINE), 0, dh, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDOK), 0, dh, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDCANCEL), 0, dh, 0, 0, 1.0f);
|
|
|
|
|
|
|
|
// Set the radio selection
|
|
|
|
Button_SetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1), BST_CHECKED);
|
|
|
|
Button_SetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE2), BST_UNCHECKED);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
|
// Change the background colour for static text and icon
|
|
|
|
SetBkMode((HDC)wParam, TRANSPARENT);
|
|
|
|
if ((HWND)lParam == GetDlgItem(hDlg, IDC_NOTIFICATION_LINE)) {
|
|
|
|
return (INT_PTR)separator_brush;
|
|
|
|
}
|
|
|
|
return (INT_PTR)background_brush;
|
|
|
|
case WM_NCHITTEST:
|
|
|
|
// Check coordinates to prevent resize actions
|
|
|
|
loc = DefWindowProc(hDlg, message, wParam, lParam);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
if (loc == disabled[i]) {
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
2017-07-11 16:43:51 +00:00
|
|
|
for (i = 0; (i < nDialogItems) &&
|
2016-12-13 14:21:51 +00:00
|
|
|
(Button_GetCheck(GetDlgItem(hDlg, IDC_SELECTION_CHOICE1 + i)) != BST_CHECKED); i++);
|
2017-07-11 16:43:51 +00:00
|
|
|
if (i < nDialogItems)
|
2016-12-13 14:21:51 +00:00
|
|
|
r = i + 1;
|
2015-08-22 14:18:25 +00:00
|
|
|
// Fall through
|
|
|
|
case IDNO:
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hDlg, r);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-07-11 16:43:51 +00:00
|
|
|
* Display an item selection dialog
|
|
|
|
*/
|
|
|
|
int SelectionDialog(char* title, char* message, char** choices, int size)
|
2015-08-22 14:18:25 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
dialog_showing++;
|
|
|
|
szMessageTitle = title;
|
|
|
|
szMessageText = message;
|
2017-07-11 16:43:51 +00:00
|
|
|
szDialogItem = choices;
|
|
|
|
nDialogItems = size;
|
2015-08-22 14:18:25 +00:00
|
|
|
ret = (int)MyDialogBox(hMainInstance, IDD_SELECTION, hMainDialog, SelectionCallback);
|
|
|
|
dialog_showing--;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-11 16:43:51 +00:00
|
|
|
/*
|
|
|
|
* Custom dialog for list dialog
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK ListCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
LRESULT loc;
|
|
|
|
int i, dh, r = -1;
|
|
|
|
// Prevent resizing
|
|
|
|
static LRESULT disabled[9] = { HTLEFT, HTRIGHT, HTTOP, HTBOTTOM, HTSIZE,
|
|
|
|
HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT };
|
|
|
|
static HBRUSH background_brush, separator_brush;
|
|
|
|
// To use the system message font
|
|
|
|
NONCLIENTMETRICS ncm;
|
|
|
|
RECT rect, rect2;
|
|
|
|
HFONT hDlgFont;
|
|
|
|
HWND hCtrl;
|
|
|
|
HDC hDC;
|
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
// Don't overflow our max radio button
|
|
|
|
if (nDialogItems > (IDC_LIST_ITEMMAX - IDC_LIST_ITEM1 + 1)) {
|
|
|
|
uprintf("Warning: Too many items requested for List (%d vs %d)",
|
|
|
|
nDialogItems, IDC_LIST_ITEMMAX - IDC_LIST_ITEM1);
|
|
|
|
nDialogItems = IDC_LIST_ITEMMAX - IDC_LIST_ITEM1;
|
|
|
|
}
|
|
|
|
// TODO: This shouldn't be needed when using DS_SHELLFONT
|
|
|
|
// Get the system message box font. See http://stackoverflow.com/a/6057761
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
|
|
|
|
// will be the wrong size for previous versions, so we need to adjust it.
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
|
|
|
|
if (nWindowsVersion >= WINDOWS_VISTA) {
|
|
|
|
// In versions of Windows prior to Vista, the iPaddedBorderWidth member
|
|
|
|
// is not present, so we need to subtract its size from cbSize.
|
|
|
|
ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
|
|
|
|
hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));
|
|
|
|
// Set the dialog to use the system message box font
|
|
|
|
SendMessage(hDlg, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_LIST_TEXT), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
for (i = 0; i < nDialogItems; i++)
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_LIST_ITEM1 + i), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDYES), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
SendMessage(GetDlgItem(hDlg, IDNO), WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(TRUE, 0));
|
|
|
|
|
|
|
|
apply_localization(IDD_LIST, hDlg);
|
|
|
|
background_brush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
|
|
|
separator_brush = CreateSolidBrush(GetSysColor(COLOR_3DLIGHT));
|
|
|
|
SetTitleBarIcon(hDlg);
|
|
|
|
CenterDialog(hDlg);
|
|
|
|
// Change the default icon and set the text
|
|
|
|
Static_SetIcon(GetDlgItem(hDlg, IDC_LIST_ICON), LoadIcon(NULL, IDI_EXCLAMATION));
|
|
|
|
SetWindowTextU(hDlg, szMessageTitle);
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDCANCEL), lmprintf(MSG_007));
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_LIST_TEXT), szMessageText);
|
|
|
|
for (i = 0; i < nDialogItems; i++) {
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_LIST_ITEM1 + i), szDialogItem[i]);
|
|
|
|
ShowWindow(GetDlgItem(hDlg, IDC_LIST_ITEM1 + i), SW_SHOW);
|
|
|
|
}
|
|
|
|
// Move/Resize the controls as needed to fit our text
|
|
|
|
hCtrl = GetDlgItem(hDlg, IDC_LIST_TEXT);
|
|
|
|
hDC = GetDC(hCtrl);
|
|
|
|
SelectFont(hDC, hDlgFont); // Yes, you *MUST* reapply the font to the DC, even after SetWindowText!
|
|
|
|
GetWindowRect(hCtrl, &rect);
|
|
|
|
dh = rect.bottom - rect.top;
|
|
|
|
DrawTextU(hDC, szMessageText, -1, &rect, DT_CALCRECT | DT_WORDBREAK);
|
|
|
|
dh = rect.bottom - rect.top - dh;
|
|
|
|
if (hDC != NULL)
|
|
|
|
ReleaseDC(hCtrl, hDC);
|
|
|
|
ResizeMoveCtrl(hDlg, hCtrl, 0, 0, 0, dh, 1.0f);
|
|
|
|
for (i = 0; i < nDialogItems; i++)
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_LIST_ITEM1 + i), 0, dh, 0, 0, 1.0f);
|
|
|
|
if (nDialogItems > 1) {
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_LIST_ITEM1), &rect);
|
|
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_LIST_ITEM1 + nDialogItems - 1), &rect2);
|
|
|
|
dh += rect2.top - rect.top;
|
|
|
|
}
|
|
|
|
ResizeMoveCtrl(hDlg, hDlg, 0, 0, 0, dh, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, -1), 0, 0, 0, dh, 1.0f); // IDC_STATIC = -1
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_LIST_LINE), 0, dh, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDOK), 0, dh, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDCANCEL), 0, dh, 0, 0, 1.0f);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
|
// Change the background colour for static text and icon
|
|
|
|
SetBkMode((HDC)wParam, TRANSPARENT);
|
|
|
|
if ((HWND)lParam == GetDlgItem(hDlg, IDC_NOTIFICATION_LINE)) {
|
|
|
|
return (INT_PTR)separator_brush;
|
|
|
|
}
|
|
|
|
return (INT_PTR)background_brush;
|
|
|
|
case WM_NCHITTEST:
|
|
|
|
// Check coordinates to prevent resize actions
|
|
|
|
loc = DefWindowProc(hDlg, message, wParam, lParam);
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
|
|
if (loc == disabled[i]) {
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
case IDNO:
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hDlg, r);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display a dialog with a list of items
|
|
|
|
*/
|
|
|
|
void ListDialog(char* title, char* message, char** items, int size)
|
|
|
|
{
|
|
|
|
dialog_showing++;
|
|
|
|
szMessageTitle = title;
|
|
|
|
szMessageText = message;
|
|
|
|
szDialogItem = items;
|
|
|
|
nDialogItems = size;
|
|
|
|
MyDialogBox(hMainInstance, IDD_LIST, hMainDialog, ListCallback);
|
|
|
|
dialog_showing--;
|
|
|
|
}
|
|
|
|
|
2012-02-02 13:16:49 +00:00
|
|
|
static struct {
|
2012-05-21 10:11:42 +00:00
|
|
|
HWND hTip; // Tooltip handle
|
|
|
|
HWND hCtrl; // Handle of the control the tooltip belongs to
|
2011-11-21 17:06:17 +00:00
|
|
|
WNDPROC original_proc;
|
|
|
|
LPWSTR wstring;
|
|
|
|
} ttlist[MAX_TOOLTIPS] = { {0} };
|
|
|
|
|
|
|
|
INT_PTR CALLBACK TooltipCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
LPNMTTDISPINFOW lpnmtdi;
|
|
|
|
int i = MAX_TOOLTIPS;
|
|
|
|
|
|
|
|
// Make sure we have an original proc
|
|
|
|
for (i=0; i<MAX_TOOLTIPS; i++) {
|
|
|
|
if (ttlist[i].hTip == hDlg) break;
|
|
|
|
}
|
2016-05-30 16:32:49 +00:00
|
|
|
if (i == MAX_TOOLTIPS)
|
2011-11-21 17:06:17 +00:00
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
|
2016-05-30 16:32:49 +00:00
|
|
|
switch (message) {
|
2011-11-21 17:06:17 +00:00
|
|
|
case WM_NOTIFY:
|
|
|
|
switch (((LPNMHDR)lParam)->code) {
|
|
|
|
case TTN_GETDISPINFOW:
|
|
|
|
lpnmtdi = (LPNMTTDISPINFOW)lParam;
|
|
|
|
lpnmtdi->lpszText = ttlist[i].wstring;
|
|
|
|
SendMessage(hDlg, TTM_SETMAXTIPWIDTH, 0, 300);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2016-05-30 16:32:49 +00:00
|
|
|
#ifdef _DEBUG
|
|
|
|
// comctl32 causes issues if the tooltips are not being manipulated from the same thread as their parent controls
|
|
|
|
if (GetCurrentThreadId() != MainThreadId)
|
|
|
|
uprintf("Warning: Tooltip callback is being called from wrong thread");
|
|
|
|
#endif
|
2011-11-21 17:06:17 +00:00
|
|
|
return CallWindowProc(ttlist[i].original_proc, hDlg, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a tooltip for the control passed as first parameter
|
|
|
|
* duration sets the duration in ms. Use -1 for default
|
|
|
|
* message is an UTF-8 string
|
|
|
|
*/
|
2012-05-21 10:11:42 +00:00
|
|
|
BOOL CreateTooltip(HWND hControl, const char* message, int duration)
|
2011-11-21 17:06:17 +00:00
|
|
|
{
|
|
|
|
TOOLINFOW toolInfo = {0};
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( (hControl == NULL) || (message == NULL) ) {
|
2012-05-21 10:11:42 +00:00
|
|
|
return FALSE;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
2012-05-21 10:11:42 +00:00
|
|
|
// Destroy existing tooltip if any
|
|
|
|
DestroyTooltip(hControl);
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
// Find an empty slot
|
|
|
|
for (i=0; i<MAX_TOOLTIPS; i++) {
|
|
|
|
if (ttlist[i].hTip == NULL) break;
|
|
|
|
}
|
2013-10-24 21:57:34 +00:00
|
|
|
if (i >= MAX_TOOLTIPS) {
|
|
|
|
uprintf("Maximum number of tooltips reached (%d)\n", MAX_TOOLTIPS);
|
2012-05-21 10:11:42 +00:00
|
|
|
return FALSE;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the tooltip window
|
2017-04-04 16:26:45 +00:00
|
|
|
ttlist[i].hTip = CreateWindowExW(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
|
2011-11-21 17:06:17 +00:00
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hMainDialog, NULL,
|
|
|
|
hMainInstance, NULL);
|
|
|
|
|
|
|
|
if (ttlist[i].hTip == NULL) {
|
2012-05-21 10:11:42 +00:00
|
|
|
return FALSE;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2012-05-21 10:11:42 +00:00
|
|
|
ttlist[i].hCtrl = hControl;
|
2011-11-21 17:06:17 +00:00
|
|
|
|
|
|
|
// Subclass the tooltip to handle multiline
|
|
|
|
ttlist[i].original_proc = (WNDPROC)SetWindowLongPtr(ttlist[i].hTip, GWLP_WNDPROC, (LONG_PTR)TooltipCallback);
|
|
|
|
|
|
|
|
// Set the string to display (can be multiline)
|
|
|
|
ttlist[i].wstring = utf8_to_wchar(message);
|
|
|
|
|
|
|
|
// Set tooltip duration (ms)
|
|
|
|
PostMessage(ttlist[i].hTip, TTM_SETDELAYTIME, (WPARAM)TTDT_AUTOPOP, (LPARAM)duration);
|
|
|
|
|
|
|
|
// Associate the tooltip to the control
|
|
|
|
toolInfo.cbSize = sizeof(toolInfo);
|
|
|
|
toolInfo.hwnd = ttlist[i].hTip; // Set to the tooltip itself to ease up subclassing
|
2014-05-15 22:51:33 +00:00
|
|
|
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS | ((right_to_left_mode)?TTF_RTLREADING:0);
|
2015-07-02 21:46:26 +00:00
|
|
|
// set TTF_NOTBUTTON and TTF_CENTERTIP if it isn't a button
|
|
|
|
if (!(SendMessage(hControl, WM_GETDLGCODE, 0, 0) & DLGC_BUTTON))
|
|
|
|
toolInfo.uFlags |= 0x80000000L | TTF_CENTERTIP;
|
|
|
|
|
2011-11-21 17:06:17 +00:00
|
|
|
toolInfo.uId = (UINT_PTR)hControl;
|
|
|
|
toolInfo.lpszText = LPSTR_TEXTCALLBACKW;
|
|
|
|
SendMessageW(ttlist[i].hTip, TTM_ADDTOOLW, 0, (LPARAM)&toolInfo);
|
|
|
|
|
2012-05-21 10:11:42 +00:00
|
|
|
return TRUE;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
2012-05-21 10:11:42 +00:00
|
|
|
/* Destroy a tooltip. hCtrl = handle of the control the tooltip is associated with */
|
|
|
|
void DestroyTooltip(HWND hControl)
|
2011-11-21 17:06:17 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2012-05-21 10:11:42 +00:00
|
|
|
if (hControl == NULL) return;
|
2011-11-21 17:06:17 +00:00
|
|
|
for (i=0; i<MAX_TOOLTIPS; i++) {
|
2012-05-21 10:11:42 +00:00
|
|
|
if (ttlist[i].hCtrl == hControl) break;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
2013-10-24 21:57:34 +00:00
|
|
|
if (i >= MAX_TOOLTIPS) return;
|
2012-05-21 10:11:42 +00:00
|
|
|
DestroyWindow(ttlist[i].hTip);
|
2011-11-21 17:06:17 +00:00
|
|
|
safe_free(ttlist[i].wstring);
|
|
|
|
ttlist[i].original_proc = NULL;
|
|
|
|
ttlist[i].hTip = NULL;
|
2012-05-21 10:11:42 +00:00
|
|
|
ttlist[i].hCtrl = NULL;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DestroyAllTooltips(void)
|
|
|
|
{
|
2013-10-24 21:57:34 +00:00
|
|
|
int i, j;
|
2011-11-21 17:06:17 +00:00
|
|
|
|
2013-10-24 21:57:34 +00:00
|
|
|
for (i=0, j=0; i<MAX_TOOLTIPS; i++) {
|
2011-11-21 17:06:17 +00:00
|
|
|
if (ttlist[i].hTip == NULL) continue;
|
2013-10-24 21:57:34 +00:00
|
|
|
j++;
|
2011-11-21 17:06:17 +00:00
|
|
|
DestroyWindow(ttlist[i].hTip);
|
|
|
|
safe_free(ttlist[i].wstring);
|
2013-10-24 21:57:34 +00:00
|
|
|
ttlist[i].original_proc = NULL;
|
|
|
|
ttlist[i].hTip = NULL;
|
|
|
|
ttlist[i].hCtrl = NULL;
|
2011-11-21 17:06:17 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-01 19:19:12 +00:00
|
|
|
|
2012-05-31 12:05:12 +00:00
|
|
|
/* Determine if a Windows is being displayed or not */
|
|
|
|
BOOL IsShown(HWND hDlg)
|
|
|
|
{
|
2013-01-09 21:54:28 +00:00
|
|
|
WINDOWPLACEMENT placement = {0};
|
|
|
|
placement.length = sizeof(WINDOWPLACEMENT);
|
2012-05-31 12:05:12 +00:00
|
|
|
if (!GetWindowPlacement(hDlg, &placement))
|
|
|
|
return FALSE;
|
|
|
|
switch (placement.showCmd) {
|
|
|
|
case SW_SHOWNORMAL:
|
|
|
|
case SW_SHOWMAXIMIZED:
|
|
|
|
case SW_SHOW:
|
|
|
|
case SW_SHOWDEFAULT:
|
|
|
|
return TRUE;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-22 11:30:22 +00:00
|
|
|
/* Compute the width of a dropdown list entry */
|
2012-03-01 19:19:12 +00:00
|
|
|
LONG GetEntryWidth(HWND hDropDown, const char *entry)
|
2015-10-18 20:31:47 +00:00
|
|
|
{
|
2012-03-01 19:19:12 +00:00
|
|
|
HDC hDC;
|
2012-11-03 17:22:28 +00:00
|
|
|
HFONT hFont, hDefFont = NULL;
|
2012-03-01 19:19:12 +00:00
|
|
|
SIZE size;
|
|
|
|
|
|
|
|
hDC = GetDC(hDropDown);
|
|
|
|
hFont = (HFONT)SendMessage(hDropDown, WM_GETFONT, 0, 0);
|
|
|
|
if (hFont != NULL)
|
|
|
|
hDefFont = (HFONT)SelectObject(hDC, hFont);
|
2015-10-18 20:31:47 +00:00
|
|
|
|
2014-12-03 18:44:00 +00:00
|
|
|
if (!GetTextExtentPointU(hDC, entry, &size))
|
|
|
|
size.cx = 0;
|
2012-03-01 19:19:12 +00:00
|
|
|
|
|
|
|
if (hFont != NULL)
|
|
|
|
SelectObject(hDC, hDefFont);
|
|
|
|
|
2015-07-06 21:04:38 +00:00
|
|
|
if (hDC != NULL)
|
|
|
|
ReleaseDC(hDropDown, hDC);
|
2012-03-01 19:19:12 +00:00
|
|
|
return size.cx;
|
|
|
|
}
|
2012-03-29 17:16:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Windows 7 taskbar icon handling (progress bar overlay, etc)
|
|
|
|
* Some platforms don't have these, so we redefine
|
|
|
|
*/
|
|
|
|
typedef enum MY_STPFLAG
|
|
|
|
{
|
|
|
|
MY_STPF_NONE = 0,
|
|
|
|
MY_STPF_USEAPPTHUMBNAILALWAYS = 0x1,
|
|
|
|
MY_STPF_USEAPPTHUMBNAILWHENACTIVE = 0x2,
|
|
|
|
MY_STPF_USEAPPPEEKALWAYS = 0x4,
|
|
|
|
MY_STPF_USEAPPPEEKWHENACTIVE = 0x8
|
|
|
|
} MY_STPFLAG;
|
|
|
|
|
|
|
|
typedef enum MY_THUMBBUTTONMASK
|
|
|
|
{
|
|
|
|
MY_THB_BITMAP = 0x1,
|
|
|
|
MY_THB_ICON = 0x2,
|
|
|
|
MY_THB_TOOLTIP = 0x4,
|
|
|
|
MY_THB_FLAGS = 0x8
|
|
|
|
} MY_THUMBBUTTONMASK;
|
|
|
|
|
|
|
|
typedef enum MY_THUMBBUTTONFLAGS
|
|
|
|
{
|
|
|
|
MY_THBF_ENABLED = 0,
|
|
|
|
MY_THBF_DISABLED = 0x1,
|
|
|
|
MY_THBF_DISMISSONCLICK = 0x2,
|
|
|
|
MY_THBF_NOBACKGROUND = 0x4,
|
|
|
|
MY_THBF_HIDDEN = 0x8,
|
|
|
|
MY_THBF_NONINTERACTIVE = 0x10
|
|
|
|
} MY_THUMBBUTTONFLAGS;
|
|
|
|
|
|
|
|
typedef struct MY_THUMBBUTTON
|
|
|
|
{
|
|
|
|
MY_THUMBBUTTONMASK dwMask;
|
|
|
|
UINT iId;
|
|
|
|
UINT iBitmap;
|
|
|
|
HICON hIcon;
|
|
|
|
WCHAR szTip[260];
|
|
|
|
MY_THUMBBUTTONFLAGS dwFlags;
|
|
|
|
} MY_THUMBBUTTON;
|
|
|
|
|
|
|
|
/*
|
|
|
|
typedef enum MY_TBPFLAG
|
|
|
|
{
|
|
|
|
TASKBAR_NOPROGRESS = 0,
|
|
|
|
TASKBAR_INDETERMINATE = 0x1,
|
|
|
|
TASKBAR_NORMAL = 0x2,
|
|
|
|
TASKBAR_ERROR = 0x4,
|
|
|
|
TASKBAR_PAUSED = 0x8
|
|
|
|
} MY_TBPFLAG;
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma push_macro("INTERFACE")
|
|
|
|
#undef INTERFACE
|
|
|
|
#define INTERFACE my_ITaskbarList3
|
|
|
|
DECLARE_INTERFACE_(my_ITaskbarList3, IUnknown) {
|
|
|
|
STDMETHOD (QueryInterface) (THIS_ REFIID riid, LPVOID *ppvObj) PURE;
|
|
|
|
STDMETHOD_(ULONG, AddRef) (THIS) PURE;
|
|
|
|
STDMETHOD_(ULONG, Release) (THIS) PURE;
|
|
|
|
STDMETHOD (HrInit) (THIS) PURE;
|
|
|
|
STDMETHOD (AddTab) (THIS_ HWND hwnd) PURE;
|
|
|
|
STDMETHOD (DeleteTab) (THIS_ HWND hwnd) PURE;
|
|
|
|
STDMETHOD (ActivateTab) (THIS_ HWND hwnd) PURE;
|
|
|
|
STDMETHOD (SetActiveAlt) (THIS_ HWND hwnd) PURE;
|
|
|
|
STDMETHOD (MarkFullscreenWindow) (THIS_ HWND hwnd, int fFullscreen) PURE;
|
|
|
|
STDMETHOD (SetProgressValue) (THIS_ HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) PURE;
|
|
|
|
STDMETHOD (SetProgressState) (THIS_ HWND hwnd, TASKBAR_PROGRESS_FLAGS tbpFlags) PURE;
|
|
|
|
STDMETHOD (RegisterTab) (THIS_ HWND hwndTab,HWND hwndMDI) PURE;
|
|
|
|
STDMETHOD (UnregisterTab) (THIS_ HWND hwndTab) PURE;
|
|
|
|
STDMETHOD (SetTabOrder) (THIS_ HWND hwndTab, HWND hwndInsertBefore) PURE;
|
|
|
|
STDMETHOD (SetTabActive) (THIS_ HWND hwndTab, HWND hwndMDI, DWORD dwReserved) PURE;
|
|
|
|
STDMETHOD (ThumbBarAddButtons) (THIS_ HWND hwnd, UINT cButtons, MY_THUMBBUTTON* pButton) PURE;
|
|
|
|
STDMETHOD (ThumbBarUpdateButtons) (THIS_ HWND hwnd, UINT cButtons, MY_THUMBBUTTON* pButton) PURE;
|
|
|
|
STDMETHOD (ThumbBarSetImageList) (THIS_ HWND hwnd, HIMAGELIST himl) PURE;
|
|
|
|
STDMETHOD (SetOverlayIcon) (THIS_ HWND hwnd, HICON hIcon, LPCWSTR pszDescription) PURE;
|
|
|
|
STDMETHOD (SetThumbnailTooltip) (THIS_ HWND hwnd, LPCWSTR pszTip) PURE;
|
|
|
|
STDMETHOD (SetThumbnailClip) (THIS_ HWND hwnd, RECT *prcClip) PURE;
|
|
|
|
};
|
2015-10-18 20:31:47 +00:00
|
|
|
const IID my_IID_ITaskbarList3 =
|
2012-03-29 17:16:06 +00:00
|
|
|
{ 0xea1afb91, 0x9e28, 0x4b86, { 0x90, 0xe9, 0x9e, 0x9f, 0x8a, 0x5e, 0xef, 0xaf } };
|
2015-10-18 20:31:47 +00:00
|
|
|
const IID my_CLSID_TaskbarList =
|
2012-03-29 17:16:06 +00:00
|
|
|
{ 0x56fdf344, 0xfd6d, 0x11d0, { 0x95, 0x8a ,0x0, 0x60, 0x97, 0xc9, 0xa0 ,0x90 } };
|
|
|
|
|
|
|
|
static my_ITaskbarList3* ptbl = NULL;
|
|
|
|
|
2012-06-04 16:35:32 +00:00
|
|
|
// Create a taskbar icon progressbar
|
2012-03-29 17:16:06 +00:00
|
|
|
BOOL CreateTaskbarList(void)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
2012-06-04 16:35:32 +00:00
|
|
|
if (nWindowsVersion < WINDOWS_7)
|
|
|
|
// Only valid for Windows 7 or later
|
|
|
|
return FALSE;
|
2012-03-29 17:16:06 +00:00
|
|
|
hr = CoCreateInstance(&my_CLSID_TaskbarList, NULL, CLSCTX_ALL, &my_IID_ITaskbarList3, (LPVOID)&ptbl);
|
|
|
|
if (FAILED(hr)) {
|
2012-05-30 23:32:25 +00:00
|
|
|
uprintf("CoCreateInstance for TaskbarList failed: error %X\n", hr);
|
2012-03-29 17:16:06 +00:00
|
|
|
ptbl = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL SetTaskbarProgressState(TASKBAR_PROGRESS_FLAGS tbpFlags)
|
|
|
|
{
|
|
|
|
if (ptbl == NULL)
|
|
|
|
return FALSE;
|
|
|
|
return !FAILED(ptbl->lpVtbl->SetProgressState(ptbl, hMainDialog, tbpFlags));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL SetTaskbarProgressValue(ULONGLONG ullCompleted, ULONGLONG ullTotal)
|
|
|
|
{
|
|
|
|
if (ptbl == NULL)
|
|
|
|
return FALSE;
|
|
|
|
return !FAILED(ptbl->lpVtbl->SetProgressValue(ptbl, hMainDialog, ullCompleted, ullTotal));
|
|
|
|
}
|
|
|
|
#pragma pop_macro("INTERFACE")
|
2012-11-29 23:14:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update policy and settings dialog callback
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2015-09-25 23:30:16 +00:00
|
|
|
int dy;
|
|
|
|
RECT rect;
|
|
|
|
REQRESIZE* rsz;
|
2012-12-02 03:50:08 +00:00
|
|
|
HWND hPolicy;
|
|
|
|
static HWND hFrequency, hBeta;
|
2012-12-16 00:29:37 +00:00
|
|
|
int32_t freq;
|
2013-10-15 21:58:27 +00:00
|
|
|
char update_policy_text[4096];
|
2015-10-18 20:56:24 +00:00
|
|
|
static BOOL resized_already = TRUE;
|
2012-11-29 23:14:36 +00:00
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2015-10-18 20:56:24 +00:00
|
|
|
resized_already = FALSE;
|
2015-05-08 22:37:22 +00:00
|
|
|
hUpdatesDlg = hDlg;
|
2013-10-15 21:58:27 +00:00
|
|
|
apply_localization(IDD_UPDATE_POLICY, hDlg);
|
2012-12-05 01:53:10 +00:00
|
|
|
SetTitleBarIcon(hDlg);
|
2012-11-29 23:14:36 +00:00
|
|
|
CenterDialog(hDlg);
|
2012-12-02 03:50:08 +00:00
|
|
|
hFrequency = GetDlgItem(hDlg, IDC_UPDATE_FREQUENCY);
|
2012-12-16 00:29:37 +00:00
|
|
|
hBeta = GetDlgItem(hDlg, IDC_INCLUDE_BETAS);
|
2013-10-15 21:58:27 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_013)), -1));
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_030, lmprintf(MSG_014))), 86400));
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_015)), 604800));
|
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_016)), 2629800));
|
2015-01-25 00:56:38 +00:00
|
|
|
freq = ReadSetting32(SETTING_UPDATE_INTERVAL);
|
2012-12-09 21:17:17 +00:00
|
|
|
EnableWindow(GetDlgItem(hDlg, IDC_CHECK_NOW), (freq != 0));
|
2012-12-16 00:29:37 +00:00
|
|
|
EnableWindow(hBeta, (freq >= 0));
|
2012-12-07 00:54:40 +00:00
|
|
|
switch(freq) {
|
|
|
|
case -1:
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 0));
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
case 86400:
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 1));
|
|
|
|
break;
|
|
|
|
case 604800:
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 2));
|
|
|
|
break;
|
|
|
|
case 2629800:
|
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 3));
|
|
|
|
break;
|
|
|
|
default:
|
2013-10-15 21:58:27 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, lmprintf(MSG_017)), freq));
|
2012-12-07 00:54:40 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hFrequency, 4));
|
|
|
|
break;
|
|
|
|
}
|
2013-10-15 21:58:27 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_AddStringU(hBeta, lmprintf(MSG_008)));
|
|
|
|
IGNORE_RETVAL(ComboBox_AddStringU(hBeta, lmprintf(MSG_009)));
|
2015-01-25 00:56:38 +00:00
|
|
|
IGNORE_RETVAL(ComboBox_SetCurSel(hBeta, ReadSettingBool(SETTING_INCLUDE_BETAS)?0:1));
|
2012-12-02 03:50:08 +00:00
|
|
|
hPolicy = GetDlgItem(hDlg, IDC_POLICY);
|
2012-11-29 23:14:36 +00:00
|
|
|
SendMessage(hPolicy, EM_AUTOURLDETECT, 1, 0);
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(update_policy_text, update_policy, lmprintf(MSG_179|MSG_RTF),
|
2015-10-21 23:40:24 +00:00
|
|
|
lmprintf(MSG_180|MSG_RTF), lmprintf(MSG_181|MSG_RTF), lmprintf(MSG_182|MSG_RTF), lmprintf(MSG_183|MSG_RTF),
|
|
|
|
lmprintf(MSG_184|MSG_RTF), lmprintf(MSG_185|MSG_RTF), lmprintf(MSG_186|MSG_RTF));
|
2013-10-15 21:58:27 +00:00
|
|
|
SendMessageA(hPolicy, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update_policy_text);
|
2012-11-29 23:14:36 +00:00
|
|
|
SendMessage(hPolicy, EM_SETSEL, -1, -1);
|
2015-09-25 23:30:16 +00:00
|
|
|
SendMessage(hPolicy, EM_SETEVENTMASK, 0, ENM_LINK|ENM_REQUESTRESIZE);
|
2012-11-29 23:14:36 +00:00
|
|
|
SendMessageA(hPolicy, EM_SETBKGNDCOLOR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
|
2015-09-25 23:30:16 +00:00
|
|
|
SendMessage(hPolicy, EM_REQUESTRESIZE, 0, 0);
|
|
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
2015-10-18 20:56:24 +00:00
|
|
|
if ((((LPNMHDR)lParam)->code == EN_REQUESTRESIZE) && (!resized_already)) {
|
|
|
|
resized_already = TRUE;
|
2015-09-25 23:30:16 +00:00
|
|
|
hPolicy = GetDlgItem(hDlg, IDC_POLICY);
|
|
|
|
GetWindowRect(hPolicy, &rect);
|
|
|
|
dy = rect.bottom - rect.top;
|
|
|
|
rsz = (REQRESIZE *)lParam;
|
2015-10-18 20:31:47 +00:00
|
|
|
dy -= rsz->rc.bottom - rsz->rc.top + 6; // add the border
|
2015-09-25 23:30:16 +00:00
|
|
|
ResizeMoveCtrl(hDlg, hDlg, 0, 0, 0, -dy, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, hPolicy, 0, 0, 0, -dy, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDS_UPDATE_SETTINGS_GRP), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDS_UPDATE_FREQUENCY_TXT), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_UPDATE_FREQUENCY), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDS_INCLUDE_BETAS_TXT), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_INCLUDE_BETAS), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDS_CHECK_NOW_GRP), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDC_CHECK_NOW), 0, -dy, 0, 0, 1.0f);
|
|
|
|
ResizeMoveCtrl(hDlg, GetDlgItem(hDlg, IDCANCEL), 0, -dy, 0, 0, 1.0f);
|
|
|
|
}
|
2012-11-29 23:14:36 +00:00
|
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
2012-12-02 03:50:08 +00:00
|
|
|
case IDCLOSE:
|
2012-11-29 23:14:36 +00:00
|
|
|
case IDCANCEL:
|
2013-10-15 21:58:27 +00:00
|
|
|
reset_localization(IDD_UPDATE_POLICY);
|
2012-11-29 23:14:36 +00:00
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
2015-05-08 22:37:22 +00:00
|
|
|
hUpdatesDlg = NULL;
|
2012-11-29 23:14:36 +00:00
|
|
|
return (INT_PTR)TRUE;
|
2012-12-09 20:36:29 +00:00
|
|
|
case IDC_CHECK_NOW:
|
|
|
|
CheckForUpdates(TRUE);
|
|
|
|
return (INT_PTR)TRUE;
|
2012-12-02 03:50:08 +00:00
|
|
|
case IDC_UPDATE_FREQUENCY:
|
|
|
|
if (HIWORD(wParam) != CBN_SELCHANGE)
|
|
|
|
break;
|
2012-12-16 22:42:30 +00:00
|
|
|
freq = (int32_t)ComboBox_GetItemData(hFrequency, ComboBox_GetCurSel(hFrequency));
|
2015-01-25 00:56:38 +00:00
|
|
|
WriteSetting32(SETTING_UPDATE_INTERVAL, (DWORD)freq);
|
2012-12-16 00:29:37 +00:00
|
|
|
EnableWindow(hBeta, (freq >= 0));
|
2012-12-02 03:50:08 +00:00
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
case IDC_INCLUDE_BETAS:
|
|
|
|
if (HIWORD(wParam) != CBN_SELCHANGE)
|
|
|
|
break;
|
2015-01-25 00:56:38 +00:00
|
|
|
WriteSettingBool(SETTING_INCLUDE_BETAS, ComboBox_GetCurSel(hBeta) == 0);
|
2012-12-02 03:50:08 +00:00
|
|
|
return (INT_PTR)TRUE;
|
2012-11-29 23:14:36 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
2012-12-02 03:50:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initial update check setup
|
|
|
|
*/
|
|
|
|
BOOL SetUpdateCheck(void)
|
|
|
|
{
|
|
|
|
BOOL enable_updates;
|
2016-02-24 16:10:54 +00:00
|
|
|
uint64_t commcheck = _GetTickCount64();
|
2012-12-02 03:50:08 +00:00
|
|
|
notification_info more_info = { IDD_UPDATE_POLICY, UpdateCallback };
|
2012-12-16 22:42:30 +00:00
|
|
|
char filename[MAX_PATH] = "", exename[] = APPLICATION_NAME ".exe";
|
|
|
|
size_t fn_len, exe_len;
|
2012-12-02 03:50:08 +00:00
|
|
|
|
2015-01-25 00:56:38 +00:00
|
|
|
// Test if we can read and write settings. If not, forget it.
|
2016-02-24 16:10:54 +00:00
|
|
|
WriteSetting64(SETTING_COMM_CHECK, commcheck);
|
|
|
|
if (ReadSetting64(SETTING_COMM_CHECK) != commcheck)
|
2012-12-02 03:50:08 +00:00
|
|
|
return FALSE;
|
2015-01-25 00:56:38 +00:00
|
|
|
settings_commcheck = TRUE;
|
2012-12-02 03:50:08 +00:00
|
|
|
|
|
|
|
// If the update interval is not set, this is the first time we run so prompt the user
|
2015-01-25 00:56:38 +00:00
|
|
|
if (ReadSetting32(SETTING_UPDATE_INTERVAL) == 0) {
|
2012-12-16 22:42:30 +00:00
|
|
|
|
|
|
|
// Add a hack for people who'd prefer the app not to prompt about update settings on first run.
|
|
|
|
// If the executable is called "rufus.exe", without version, we disable the prompt
|
|
|
|
GetModuleFileNameU(NULL, filename, sizeof(filename));
|
|
|
|
fn_len = safe_strlen(filename);
|
|
|
|
exe_len = safe_strlen(exename);
|
2014-11-27 23:24:50 +00:00
|
|
|
#if !defined(_DEBUG) // Don't allow disabling update prompt, unless it's a release
|
2012-12-16 22:42:30 +00:00
|
|
|
if ((fn_len > exe_len) && (safe_stricmp(&filename[fn_len-exe_len], exename) == 0)) {
|
|
|
|
uprintf("Short name used - Disabling initial update policy prompt\n");
|
|
|
|
enable_updates = TRUE;
|
|
|
|
} else {
|
2014-11-27 23:24:50 +00:00
|
|
|
#endif
|
2013-10-15 21:58:27 +00:00
|
|
|
enable_updates = Notification(MSG_QUESTION, &more_info, lmprintf(MSG_004), lmprintf(MSG_005));
|
2014-11-27 23:24:50 +00:00
|
|
|
#if !defined(_DEBUG)
|
2012-12-16 22:42:30 +00:00
|
|
|
}
|
2014-11-27 23:24:50 +00:00
|
|
|
#endif
|
2012-12-02 03:50:08 +00:00
|
|
|
if (!enable_updates) {
|
2015-01-25 00:56:38 +00:00
|
|
|
WriteSetting32(SETTING_UPDATE_INTERVAL, -1);
|
2012-12-02 03:50:08 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
// If the user hasn't set the interval in the dialog, set to default
|
2015-01-25 00:56:38 +00:00
|
|
|
if ( (ReadSetting32(SETTING_UPDATE_INTERVAL) == 0) ||
|
|
|
|
((ReadSetting32(SETTING_UPDATE_INTERVAL) == -1) && enable_updates) )
|
|
|
|
WriteSetting32(SETTING_UPDATE_INTERVAL, 86400);
|
2012-12-02 03:50:08 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
2012-12-04 01:47:45 +00:00
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
static void CreateStaticFont(HDC dc, HFONT* hyperlink_font) {
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
LOGFONT lf;
|
|
|
|
|
|
|
|
if (*hyperlink_font != NULL)
|
|
|
|
return;
|
|
|
|
GetTextMetrics(dc, &tm);
|
|
|
|
lf.lfHeight = tm.tmHeight;
|
|
|
|
lf.lfWidth = 0;
|
|
|
|
lf.lfEscapement = 0;
|
|
|
|
lf.lfOrientation = 0;
|
|
|
|
lf.lfWeight = tm.tmWeight;
|
|
|
|
lf.lfItalic = tm.tmItalic;
|
|
|
|
lf.lfUnderline = TRUE;
|
|
|
|
lf.lfStrikeOut = tm.tmStruckOut;
|
|
|
|
lf.lfCharSet = tm.tmCharSet;
|
|
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
lf.lfQuality = DEFAULT_QUALITY;
|
|
|
|
lf.lfPitchAndFamily = tm.tmPitchAndFamily;
|
|
|
|
GetTextFace(dc, LF_FACESIZE, lf.lfFaceName);
|
|
|
|
*hyperlink_font = CreateFontIndirect(&lf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Work around the limitations of edit control, to display a hand cursor for hyperlinks
|
|
|
|
* NB: The LTEXT control must have SS_NOTIFY attribute for this to work
|
|
|
|
*/
|
2015-05-14 23:36:42 +00:00
|
|
|
INT_PTR CALLBACK update_subclass_callback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
2013-10-15 21:58:27 +00:00
|
|
|
{
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_SETCURSOR:
|
|
|
|
if ((HWND)wParam == GetDlgItem(hDlg, IDC_WEBSITE)) {
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_HAND));
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-05-14 23:36:42 +00:00
|
|
|
return CallWindowProc(update_original_proc, hDlg, message, wParam, lParam);
|
2013-10-15 21:58:27 +00:00
|
|
|
}
|
|
|
|
|
2012-12-04 01:47:45 +00:00
|
|
|
/*
|
|
|
|
* New version notification dialog
|
|
|
|
*/
|
|
|
|
INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2013-12-02 18:24:54 +00:00
|
|
|
char cmdline[] = APPLICATION_NAME " -w 150";
|
2012-12-06 01:40:44 +00:00
|
|
|
static char* filepath = NULL;
|
|
|
|
static int download_status = 0;
|
2015-10-13 22:29:30 +00:00
|
|
|
LONG i;
|
|
|
|
HWND hNotes;
|
2012-12-06 01:40:44 +00:00
|
|
|
STARTUPINFOA si;
|
|
|
|
PROCESS_INFORMATION pi;
|
2013-10-15 21:58:27 +00:00
|
|
|
HFONT hyperlink_font = NULL;
|
2014-05-22 21:46:36 +00:00
|
|
|
EXT_DECL(dl_ext, NULL, __VA_GROUP__("*.exe"), __VA_GROUP__(lmprintf(MSG_037)));
|
2012-12-04 01:47:45 +00:00
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
2013-10-15 21:58:27 +00:00
|
|
|
apply_localization(IDD_NEW_VERSION, hDlg);
|
2012-12-06 01:40:44 +00:00
|
|
|
download_status = 0;
|
2012-12-05 01:53:10 +00:00
|
|
|
SetTitleBarIcon(hDlg);
|
2012-12-04 01:47:45 +00:00
|
|
|
CenterDialog(hDlg);
|
2013-10-15 21:58:27 +00:00
|
|
|
// Subclass the callback so that we can change the cursor
|
2015-05-14 23:36:42 +00:00
|
|
|
update_original_proc = (WNDPROC)SetWindowLongPtr(hDlg, GWLP_WNDPROC, (LONG_PTR)update_subclass_callback);
|
2012-12-04 01:47:45 +00:00
|
|
|
hNotes = GetDlgItem(hDlg, IDC_RELEASE_NOTES);
|
|
|
|
SendMessage(hNotes, EM_AUTOURLDETECT, 1, 0);
|
2012-12-05 01:53:10 +00:00
|
|
|
SendMessageA(hNotes, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update.release_notes);
|
2012-12-04 01:47:45 +00:00
|
|
|
SendMessage(hNotes, EM_SETSEL, -1, -1);
|
|
|
|
SendMessage(hNotes, EM_SETEVENTMASK, 0, ENM_LINK);
|
2015-10-18 20:31:47 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_YOUR_VERSION), lmprintf(MSG_018,
|
2015-02-08 22:36:57 +00:00
|
|
|
rufus_version[0], rufus_version[1], rufus_version[2]));
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_LATEST_VERSION), lmprintf(MSG_019,
|
2015-02-08 22:36:57 +00:00
|
|
|
update.version[0], update.version[1], update.version[2]));
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD_URL), update.download_url);
|
2013-01-09 21:54:28 +00:00
|
|
|
SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000);
|
2012-12-06 01:40:44 +00:00
|
|
|
if (update.download_url == NULL)
|
|
|
|
EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE);
|
2012-12-04 01:47:45 +00:00
|
|
|
break;
|
2013-10-15 21:58:27 +00:00
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
|
if ((HWND)lParam != GetDlgItem(hDlg, IDC_WEBSITE))
|
|
|
|
return FALSE;
|
|
|
|
// Change the font for the hyperlink
|
|
|
|
SetBkMode((HDC)wParam, TRANSPARENT);
|
|
|
|
CreateStaticFont((HDC)wParam, &hyperlink_font);
|
|
|
|
SelectObject((HDC)wParam, hyperlink_font);
|
|
|
|
SetTextColor((HDC)wParam, RGB(0,0,125)); // DARK_BLUE
|
|
|
|
return (INT_PTR)CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
|
2012-12-04 01:47:45 +00:00
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDCLOSE:
|
|
|
|
case IDCANCEL:
|
2014-11-01 01:38:40 +00:00
|
|
|
if (download_status != 1) {
|
|
|
|
reset_localization(IDD_NEW_VERSION);
|
|
|
|
safe_free(filepath);
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
|
}
|
2012-12-04 01:47:45 +00:00
|
|
|
return (INT_PTR)TRUE;
|
2013-10-15 21:58:27 +00:00
|
|
|
case IDC_WEBSITE:
|
|
|
|
ShellExecuteA(hDlg, "open", RUFUS_URL, NULL, NULL, SW_SHOWNORMAL);
|
|
|
|
break;
|
2012-12-16 22:42:30 +00:00
|
|
|
case IDC_DOWNLOAD: // Also doubles as abort and launch function
|
2012-12-06 01:40:44 +00:00
|
|
|
switch(download_status) {
|
|
|
|
case 1: // Abort
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
|
2014-11-01 01:38:40 +00:00
|
|
|
download_status = 0;
|
2012-12-06 01:40:44 +00:00
|
|
|
break;
|
|
|
|
case 2: // Launch newer version and close this one
|
2014-11-01 01:38:40 +00:00
|
|
|
Sleep(1000); // Add a delay on account of antivirus scanners
|
2015-10-13 22:29:30 +00:00
|
|
|
|
|
|
|
if (ValidateSignature(hDlg, filepath) != NO_ERROR)
|
|
|
|
break;
|
|
|
|
|
2012-12-06 01:40:44 +00:00
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
memset(&pi, 0, sizeof(pi));
|
|
|
|
si.cb = sizeof(si);
|
2013-11-30 17:39:38 +00:00
|
|
|
if (!CreateProcessU(filepath, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_214);
|
2012-12-06 01:40:44 +00:00
|
|
|
uprintf("Failed to launch new application: %s\n", WindowsErrorString());
|
|
|
|
} else {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_213);
|
2012-12-06 01:40:44 +00:00
|
|
|
PostMessage(hDlg, WM_COMMAND, (WPARAM)IDCLOSE, 0);
|
|
|
|
PostMessage(hMainDialog, WM_CLOSE, 0, 0);
|
2012-12-05 01:53:10 +00:00
|
|
|
}
|
2012-12-06 01:40:44 +00:00
|
|
|
break;
|
|
|
|
default: // Download
|
2013-12-02 18:24:54 +00:00
|
|
|
if (update.download_url == NULL) {
|
|
|
|
uprintf("Could not get download URL\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (i=(int)strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--);
|
2014-05-22 00:52:25 +00:00
|
|
|
dl_ext.filename = &update.download_url[i+1];
|
|
|
|
filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR);
|
2013-12-02 18:24:54 +00:00
|
|
|
if (filepath == NULL) {
|
|
|
|
uprintf("Could not get save path\n");
|
|
|
|
break;
|
|
|
|
}
|
2015-05-08 22:37:22 +00:00
|
|
|
// Opening the File Dialog will make us lose tabbing focus - set it back
|
|
|
|
SendMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, IDC_DOWNLOAD), TRUE);
|
2013-12-02 18:24:54 +00:00
|
|
|
DownloadFileThreaded(update.download_url, filepath, hDlg);
|
2012-12-06 01:40:44 +00:00
|
|
|
break;
|
2012-12-04 01:47:45 +00:00
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
break;
|
2014-05-19 22:25:00 +00:00
|
|
|
case UM_PROGRESS_INIT:
|
2014-11-01 01:38:40 +00:00
|
|
|
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
|
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_038));
|
2012-12-06 01:40:44 +00:00
|
|
|
FormatStatus = 0;
|
|
|
|
download_status = 1;
|
|
|
|
return (INT_PTR)TRUE;
|
2014-05-19 22:25:00 +00:00
|
|
|
case UM_PROGRESS_EXIT:
|
2014-11-01 01:38:40 +00:00
|
|
|
EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
|
2012-12-06 01:40:44 +00:00
|
|
|
if (wParam) {
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_039));
|
2012-12-06 01:40:44 +00:00
|
|
|
download_status = 2;
|
|
|
|
} else {
|
2013-10-15 21:58:27 +00:00
|
|
|
SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), lmprintf(MSG_040));
|
2012-12-06 01:40:44 +00:00
|
|
|
download_status = 0;
|
|
|
|
}
|
|
|
|
return (INT_PTR)TRUE;
|
2012-12-04 01:47:45 +00:00
|
|
|
}
|
|
|
|
return (INT_PTR)FALSE;
|
|
|
|
}
|
|
|
|
|
2012-12-05 01:53:10 +00:00
|
|
|
void DownloadNewVersion(void)
|
2012-12-04 01:47:45 +00:00
|
|
|
{
|
2015-07-03 22:42:45 +00:00
|
|
|
MyDialogBox(hMainInstance, IDD_NEW_VERSION, hMainDialog, NewVersionCallback);
|
2012-12-05 01:53:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetTitleBarIcon(HWND hDlg)
|
|
|
|
{
|
|
|
|
int i16, s16, s32;
|
|
|
|
HICON hSmallIcon, hBigIcon;
|
|
|
|
|
|
|
|
// High DPI scaling
|
|
|
|
i16 = GetSystemMetrics(SM_CXSMICON);
|
|
|
|
// Adjust icon size lookup
|
|
|
|
s16 = i16;
|
|
|
|
s32 = (int)(32.0f*fScale);
|
|
|
|
if (s16 >= 54)
|
|
|
|
s16 = 64;
|
|
|
|
else if (s16 >= 40)
|
|
|
|
s16 = 48;
|
|
|
|
else if (s16 >= 28)
|
|
|
|
s16 = 32;
|
|
|
|
else if (s16 >= 20)
|
|
|
|
s16 = 24;
|
|
|
|
if (s32 >= 54)
|
|
|
|
s32 = 64;
|
|
|
|
else if (s32 >= 40)
|
|
|
|
s32 = 48;
|
|
|
|
else if (s32 >= 28)
|
|
|
|
s32 = 32;
|
|
|
|
else if (s32 >= 20)
|
|
|
|
s32 = 24;
|
|
|
|
|
|
|
|
// Create the title bar icon
|
|
|
|
hSmallIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s16, s16, 0);
|
|
|
|
SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
|
|
|
|
hBigIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s32, s32, 0);
|
|
|
|
SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)hBigIcon);
|
2012-12-04 01:47:45 +00:00
|
|
|
}
|
2014-11-28 22:42:22 +00:00
|
|
|
|
|
|
|
// Return the onscreen size of the text displayed by a control
|
|
|
|
SIZE GetTextSize(HWND hCtrl)
|
|
|
|
{
|
|
|
|
SIZE sz = {0, 0};
|
|
|
|
HDC hDC;
|
2014-12-15 18:42:21 +00:00
|
|
|
wchar_t *wstr = NULL;
|
2014-11-28 22:42:22 +00:00
|
|
|
int len;
|
|
|
|
HFONT hFont;
|
|
|
|
|
2015-05-14 23:36:42 +00:00
|
|
|
// Compute the size of the text
|
2014-11-28 22:42:22 +00:00
|
|
|
hDC = GetDC(hCtrl);
|
|
|
|
if (hDC == NULL)
|
|
|
|
goto out;
|
|
|
|
hFont = (HFONT)SendMessageA(hCtrl, WM_GETFONT, 0, 0);
|
|
|
|
if (hFont == NULL)
|
|
|
|
goto out;
|
|
|
|
SelectObject(hDC, hFont);
|
|
|
|
len = GetWindowTextLengthW(hCtrl);
|
|
|
|
if (len <= 0)
|
|
|
|
goto out;
|
|
|
|
wstr = calloc(len + 1, sizeof(wchar_t));
|
|
|
|
if (wstr == NULL)
|
|
|
|
goto out;
|
|
|
|
if (GetWindowTextW(hCtrl, wstr, len + 1) > 0)
|
|
|
|
GetTextExtentPoint32W(hDC, wstr, len, &sz);
|
|
|
|
out:
|
|
|
|
safe_free(wstr);
|
|
|
|
if (hDC != NULL)
|
|
|
|
ReleaseDC(hCtrl, hDC);
|
|
|
|
return sz;
|
|
|
|
}
|
2015-07-03 22:42:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The following is used to work around dialog template limitations when switching from LTR to RTL
|
|
|
|
* or switching the font. This avoids having to multiply similar templates in the RC.
|
|
|
|
* TODO: Can we use http://stackoverflow.com/questions/6057239/which-font-is-the-default-for-mfc-dialog-controls?
|
|
|
|
* TODO: We are supposed to use Segoe with font size 9 in Vista or later
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Produce a dialog template from our RC, and update its RTL and Font settings dynamically
|
|
|
|
// See http://blogs.msdn.com/b/oldnewthing/archive/2004/06/21/163596.aspx as well as
|
|
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms645389.aspx for a description
|
|
|
|
// of the Dialog structure
|
|
|
|
LPCDLGTEMPLATE GetDialogTemplate(int Dialog_ID)
|
|
|
|
{
|
|
|
|
int i;
|
2016-02-05 22:24:47 +00:00
|
|
|
const char thai_id[] = "th-TH";
|
2015-07-03 22:42:45 +00:00
|
|
|
size_t len;
|
|
|
|
DWORD size;
|
|
|
|
DWORD* dwBuf;
|
|
|
|
WCHAR* wBuf;
|
|
|
|
LPCDLGTEMPLATE rcTemplate = (LPCDLGTEMPLATE) GetResource(hMainInstance, MAKEINTRESOURCEA(Dialog_ID),
|
|
|
|
_RT_DIALOG, get_name_from_id(Dialog_ID), &size, TRUE);
|
2015-08-27 17:37:04 +00:00
|
|
|
|
|
|
|
if ((size == 0) || (rcTemplate == NULL)) {
|
|
|
|
safe_free(rcTemplate);
|
2015-07-03 22:42:45 +00:00
|
|
|
return NULL;
|
2015-08-27 17:37:04 +00:00
|
|
|
}
|
2015-07-03 22:42:45 +00:00
|
|
|
if (right_to_left_mode) {
|
|
|
|
// Add the RTL styles into our RC copy, so that we don't have to multiply dialog definitions in the RC
|
|
|
|
dwBuf = (DWORD*)rcTemplate;
|
|
|
|
dwBuf[2] = WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL;
|
|
|
|
}
|
2015-12-30 14:27:52 +00:00
|
|
|
|
2016-01-11 13:06:33 +00:00
|
|
|
// All our dialogs are set to use 'Segoe UI Symbol' by default:
|
|
|
|
// 1. So that we can replace the font name with 'MS Shell Dlg' (XP) or 'Segoe UI'
|
|
|
|
// 2. So that Thai displays properly on RTF controls as it won't work with regular
|
|
|
|
// 'Segoe UI'... but Cyrillic won't work with 'Segoe UI Symbol'
|
2015-12-30 14:27:52 +00:00
|
|
|
|
2016-01-11 13:06:33 +00:00
|
|
|
// If 'Segoe UI Symbol' is available, and we are using Thai, we're done here
|
2016-01-12 17:53:08 +00:00
|
|
|
if (IsFontAvailable("Segoe UI Symbol") && (selected_locale != NULL)
|
2016-02-05 22:24:47 +00:00
|
|
|
&& (safe_strcmp(selected_locale->txt[0], thai_id) == 0))
|
2015-12-30 14:27:52 +00:00
|
|
|
return rcTemplate;
|
|
|
|
|
2016-01-11 13:06:33 +00:00
|
|
|
// 'Segoe UI Symbol' cannot be used => Fall back to the best we have
|
2015-07-03 22:42:45 +00:00
|
|
|
wBuf = (WCHAR*)rcTemplate;
|
|
|
|
wBuf = &wBuf[14]; // Move to class name
|
|
|
|
// Skip class name and title
|
|
|
|
for (i = 0; i<2; i++) {
|
|
|
|
if (*wBuf == 0xFFFF)
|
|
|
|
wBuf = &wBuf[2]; // Ordinal
|
|
|
|
else
|
|
|
|
wBuf = &wBuf[wcslen(wBuf) + 1]; // String
|
|
|
|
}
|
|
|
|
// NB: to change the font size to 9, you can use
|
|
|
|
// wBuf[0] = 0x0009;
|
|
|
|
wBuf = &wBuf[3];
|
|
|
|
// Make sure we are where we want to be and adjust the font
|
|
|
|
if (wcscmp(L"Segoe UI Symbol", wBuf) == 0) {
|
|
|
|
uintptr_t src, dst, start = (uintptr_t)rcTemplate;
|
|
|
|
// We can't simply zero the characters we don't want, as the size of the font
|
|
|
|
// string determines the next item lookup. So we must memmove the remaining of
|
|
|
|
// our buffer. Oh, and those items are DWORD aligned.
|
2016-08-29 17:17:15 +00:00
|
|
|
if ((nWindowsVersion > WINDOWS_XP) && IsFontAvailable("Segoe UI")) {
|
2015-12-30 14:27:52 +00:00
|
|
|
// 'Segoe UI Symbol' -> 'Segoe UI'
|
2015-07-03 22:42:45 +00:00
|
|
|
wBuf[8] = 0;
|
2015-12-30 14:27:52 +00:00
|
|
|
} else {
|
|
|
|
wcscpy(wBuf, L"MS Shell Dlg");
|
2015-07-03 22:42:45 +00:00
|
|
|
}
|
|
|
|
len = wcslen(wBuf);
|
|
|
|
wBuf[len + 1] = 0;
|
|
|
|
dst = (uintptr_t)&wBuf[len + 2];
|
|
|
|
dst &= ~3;
|
|
|
|
src = (uintptr_t)&wBuf[17];
|
|
|
|
src &= ~3;
|
|
|
|
memmove((void*)dst, (void*)src, size - (src - start));
|
|
|
|
} else {
|
|
|
|
uprintf("Could not locate font for %s!", get_name_from_id(Dialog_ID));
|
|
|
|
}
|
|
|
|
return rcTemplate;
|
|
|
|
}
|
|
|
|
|
|
|
|
HWND MyCreateDialog(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC lpDialogFunc)
|
|
|
|
{
|
|
|
|
LPCDLGTEMPLATE rcTemplate = GetDialogTemplate(Dialog_ID);
|
|
|
|
HWND hDlg = CreateDialogIndirect(hInstance, rcTemplate, hWndParent, lpDialogFunc);
|
|
|
|
safe_free(rcTemplate);
|
|
|
|
return hDlg;
|
|
|
|
}
|
|
|
|
|
|
|
|
INT_PTR MyDialogBox(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC lpDialogFunc)
|
|
|
|
{
|
2017-02-06 12:07:00 +00:00
|
|
|
INT_PTR ret;
|
2015-07-03 22:42:45 +00:00
|
|
|
LPCDLGTEMPLATE rcTemplate = GetDialogTemplate(Dialog_ID);
|
2017-02-06 12:07:00 +00:00
|
|
|
|
|
|
|
// A DialogBox doesn't handle reduce/restore so it won't pass restore messages to the
|
|
|
|
// main dialog if the main dialog was minimized. This can result in situations where the
|
|
|
|
// user cannot restore the main window if a new dialog prompt was triggered while the
|
|
|
|
// main dialog was reduced => Ensure the main dialog is visible before we display anything.
|
|
|
|
ShowWindow(hMainDialog, SW_NORMAL);
|
|
|
|
|
|
|
|
ret = DialogBoxIndirect(hMainInstance, rcTemplate, hWndParent, lpDialogFunc);
|
2015-07-03 22:42:45 +00:00
|
|
|
safe_free(rcTemplate);
|
|
|
|
return ret;
|
|
|
|
}
|
2016-07-09 15:20:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The following function calls are used to automatically detect and close the native
|
|
|
|
* Windows format prompt "You must format the disk in drive X:". To do that, we use an
|
|
|
|
* event hook that gets triggered whenever a window is placed in the foreground.
|
|
|
|
* In that hook, we look for a dialog that has style WS_POPUPWINDOW and has the relevant
|
|
|
|
* title. However, because the title in itself is too generic (the expectation is that
|
|
|
|
* it will be "Microsoft Windows") we also enumerate all the child controls from that
|
|
|
|
* prompt, using another callback, until we find one that contains the text we expect
|
|
|
|
* for the "Format disk" button.
|
|
|
|
* Oh, and since all of these strings are localized, we must first pick them up from
|
|
|
|
* the relevant mui (something like "C:\Windows\System32\en-GB\shell32.dll.mui")
|
|
|
|
*/
|
|
|
|
static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam)
|
|
|
|
{
|
|
|
|
char str[128];
|
|
|
|
BOOL *found = (BOOL*)lParam;
|
|
|
|
|
|
|
|
if (GetWindowTextU(hWnd, str, sizeof(str)) == 0)
|
|
|
|
return TRUE;
|
|
|
|
if (safe_strcmp(str, fp_button_str) == 0)
|
|
|
|
*found = TRUE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CALLBACK FormatPromptHook(HWINEVENTHOOK hWinEventHook, DWORD Event, HWND hWnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
|
|
|
|
{
|
|
|
|
char str[128];
|
|
|
|
BOOL found;
|
|
|
|
|
|
|
|
if (Event == EVENT_SYSTEM_FOREGROUND) {
|
|
|
|
if (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUPWINDOW) {
|
|
|
|
str[0] = 0;
|
|
|
|
GetWindowTextU(hWnd, str, sizeof(str));
|
|
|
|
if (safe_strcmp(str, fp_title_str) == 0) {
|
|
|
|
found = FALSE;
|
|
|
|
EnumChildWindows(hWnd, FormatPromptCallback, (LPARAM)&found);
|
|
|
|
if (found) {
|
|
|
|
SendMessage(hWnd, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0);
|
|
|
|
uprintf("Closed Windows format prompt");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL SetFormatPromptHook(void)
|
|
|
|
{
|
|
|
|
HMODULE mui_lib;
|
|
|
|
char mui_path[MAX_PATH];
|
|
|
|
static char title_str[128], button_str[128];
|
|
|
|
|
|
|
|
if (fp_weh != NULL)
|
|
|
|
return TRUE; // No need to set again if active
|
|
|
|
|
|
|
|
// Fetch the localized strings in the relevant
|
|
|
|
static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", system_dir, GetCurrentMUI());
|
|
|
|
mui_lib = LoadLibraryU(mui_path);
|
|
|
|
if (mui_lib != NULL) {
|
|
|
|
// 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text)
|
|
|
|
// 4125 = "Microsoft Windows" (dialog title)
|
|
|
|
// 4126 = "Format disk" (button)
|
|
|
|
if (LoadStringU(mui_lib, 4125, title_str, sizeof(title_str)) > 0)
|
|
|
|
fp_title_str = title_str;
|
|
|
|
else
|
|
|
|
uprintf("Warning: Could not locate localized format prompt title string in '%s': %s", mui_path, WindowsErrorString());
|
|
|
|
if (LoadStringU(mui_lib, 4126, button_str, sizeof(button_str)) > 0)
|
|
|
|
fp_button_str = button_str;
|
|
|
|
else
|
|
|
|
uprintf("Warning: Could not locate localized format prompt button string in '%s': %s", mui_path, WindowsErrorString());
|
|
|
|
FreeLibrary(mui_lib);
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_weh = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL,
|
|
|
|
FormatPromptHook, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
|
|
|
|
return (fp_weh != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClrFormatPromptHook(void) {
|
|
|
|
UnhookWinEvent(fp_weh);
|
|
|
|
fp_weh = NULL;
|
|
|
|
}
|
2016-12-13 14:21:51 +00:00
|
|
|
|
2017-07-04 13:51:25 +00:00
|
|
|
void FlashTaskbar(HANDLE handle)
|
|
|
|
{
|
|
|
|
FLASHWINFO pf;
|
|
|
|
|
|
|
|
if (handle == NULL)
|
|
|
|
return;
|
|
|
|
pf.cbSize = sizeof(FLASHWINFO);
|
|
|
|
pf.hwnd = handle;
|
|
|
|
// Could also use FLASHW_ALL to flash the main dialog)
|
|
|
|
pf.dwFlags = FLASHW_TIMER | FLASHW_TRAY;
|
|
|
|
pf.uCount = 5;
|
|
|
|
pf.dwTimeout = 75;
|
|
|
|
FlashWindowEx(&pf);
|
|
|
|
}
|
|
|
|
|
2016-12-13 14:21:51 +00:00
|
|
|
#ifdef RUFUS_TEST
|
2017-04-27 22:06:42 +00:00
|
|
|
static __inline LPWORD lpwAlign(LPWORD addr)
|
2016-12-13 14:21:51 +00:00
|
|
|
{
|
|
|
|
return (LPWORD)((((uintptr_t)addr) + 3) & (~3));
|
|
|
|
}
|
|
|
|
|
|
|
|
INT_PTR CALLBACK SelectionDynCallback(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
int r = -1;
|
|
|
|
switch (message) {
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case IDOK:
|
|
|
|
r = 0;
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hwndDlg, r);
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SelectionDyn(char* title, char* message, char** szChoice, int nChoices)
|
|
|
|
{
|
|
|
|
#define ID_RADIO 12345
|
|
|
|
LPCWSTR lpwszTypeFace = L"MS Shell Dlg";
|
|
|
|
LPDLGTEMPLATEA lpdt;
|
|
|
|
LPDLGITEMTEMPLATEA lpdit;
|
|
|
|
LPCWSTR lpwszCaption;
|
|
|
|
LPWORD lpw;
|
|
|
|
LPWSTR lpwsz;
|
|
|
|
int i, ret, nchar;
|
|
|
|
|
|
|
|
lpdt = (LPDLGTEMPLATE)calloc(512 + nChoices * 256, 1);
|
|
|
|
|
|
|
|
// Set up a dialog window
|
|
|
|
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION | DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
|
|
|
|
lpdt->cdit = 2 + nChoices;
|
|
|
|
lpdt->x = 10;
|
|
|
|
lpdt->y = 10;
|
|
|
|
lpdt->cx = 300;
|
|
|
|
lpdt->cy = 100;
|
|
|
|
|
|
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms645394.aspx:
|
|
|
|
// In a standard template for a dialog box, the DLGTEMPLATE structure is always immediately followed by
|
|
|
|
// three variable-length arrays that specify the menu, class, and title for the dialog box.
|
|
|
|
// When the DS_SETFONT style is specified, these arrays are also followed by a 16-bit value specifying
|
|
|
|
// point size and another variable-length array specifying a typeface name. Each array consists of one
|
|
|
|
// or more 16-bit elements. The menu, class, title, and font arrays must be aligned on WORD boundaries.
|
|
|
|
lpw = (LPWORD)(&lpdt[1]);
|
|
|
|
*lpw++ = 0; // No menu
|
|
|
|
*lpw++ = 0; // Default dialog class
|
|
|
|
lpwsz = (LPWSTR)lpw;
|
|
|
|
nchar = MultiByteToWideChar(CP_UTF8, 0, title, -1, lpwsz, 50);
|
|
|
|
lpw += nchar;
|
|
|
|
|
|
|
|
// Set point size and typeface name if required
|
|
|
|
if (lpdt->style & (DS_SETFONT | DS_SHELLFONT)) {
|
|
|
|
*lpw++ = 8;
|
|
|
|
for (lpwsz = (LPWSTR)lpw, lpwszCaption = lpwszTypeFace; (*lpwsz++ = *lpwszCaption++) != 0; );
|
|
|
|
lpw = (LPWORD)lpwsz;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add an OK button
|
|
|
|
lpw = lpwAlign(lpw);
|
|
|
|
lpdit = (LPDLGITEMTEMPLATE)lpw;
|
|
|
|
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
|
|
|
|
lpdit->x = 10;
|
|
|
|
lpdit->y = 70;
|
|
|
|
lpdit->cx = 50;
|
|
|
|
lpdit->cy = 14;
|
|
|
|
lpdit->id = IDOK;
|
|
|
|
|
|
|
|
lpw = (LPWORD)(&lpdit[1]);
|
|
|
|
*lpw++ = 0xFFFF;
|
|
|
|
*lpw++ = 0x0080; // Button class
|
|
|
|
|
|
|
|
lpwsz = (LPWSTR)lpw;
|
|
|
|
nchar = MultiByteToWideChar(CP_UTF8, 0, "OK", -1, lpwsz, 50);
|
|
|
|
lpw += nchar;
|
|
|
|
*lpw++ = 0; // No creation data
|
|
|
|
|
|
|
|
// Add a Cancel button
|
|
|
|
lpw = lpwAlign(lpw);
|
|
|
|
lpdit = (LPDLGITEMTEMPLATE)lpw;
|
|
|
|
lpdit->x = 90;
|
|
|
|
lpdit->y = 70;
|
|
|
|
lpdit->cx = 50;
|
|
|
|
lpdit->cy = 14;
|
|
|
|
lpdit->id = IDCANCEL;
|
|
|
|
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
|
|
|
|
|
|
|
|
lpw = (LPWORD)(&lpdit[1]);
|
|
|
|
*lpw++ = 0xFFFF;
|
|
|
|
*lpw++ = 0x0080;
|
|
|
|
|
|
|
|
lpwsz = (LPWSTR)lpw;
|
|
|
|
nchar = MultiByteToWideChar(CP_UTF8, 0, lmprintf(MSG_007), -1, lpwsz, 50);
|
|
|
|
lpw += nchar;
|
|
|
|
*lpw++ = 0;
|
|
|
|
|
|
|
|
// Add radio buttons
|
|
|
|
for (i = 0; i < nChoices; i++) {
|
|
|
|
lpw = lpwAlign(lpw);
|
|
|
|
lpdit = (LPDLGITEMTEMPLATE)lpw;
|
|
|
|
lpdit->x = 10;
|
|
|
|
lpdit->y = 10 + 15 * i;
|
|
|
|
lpdit->cx = 40;
|
|
|
|
lpdit->cy = 20;
|
|
|
|
lpdit->id = ID_RADIO;
|
|
|
|
lpdit->style = WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | (i == 0 ? WS_GROUP : 0);
|
|
|
|
|
|
|
|
lpw = (LPWORD)(&lpdit[1]);
|
|
|
|
*lpw++ = 0xFFFF;
|
|
|
|
*lpw++ = 0x0080;
|
|
|
|
|
|
|
|
lpwsz = (LPWSTR)lpw;
|
|
|
|
nchar = MultiByteToWideChar(CP_UTF8, 0, szChoice[i], -1, lpwsz, 150);
|
|
|
|
lpw += nchar;
|
|
|
|
*lpw++ = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = (int)DialogBoxIndirect(hMainInstance, (LPDLGTEMPLATE)lpdt, hMainDialog, (DLGPROC)SelectionDynCallback);
|
|
|
|
free(lpdt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|