diff --git a/grepWinNP3/README.md b/grepWinNP3/README.md index cd7735ede..6aa1f94ef 100644 --- a/grepWinNP3/README.md +++ b/grepWinNP3/README.md @@ -9,7 +9,7 @@ grepWin is a simple search and replace tool which can use [regular expressions]( In case you're not familiar with regular expressions, we have a very short [regular expression tutorial](https://tools.stefankueng.com/regexhelp.html) for you. -[![grepWin](https://raw.githubusercontent.com/stefankueng/grepWin/master/src/Resources/grepWin_search-small.png)](https://raw.githubusercontent.com/stefankueng/grepWin/master/src/Resources/grepWin_search.png) +[![grepWin](https://github.com/stefankueng/grepWin/raw/main/src/Resources/grepWin_search-small.png)](https://github.com/stefankueng/grepWin/raw/main/src/Resources/grepWin_search.png) # Command line parameters The command line parameters are listed on a [separate page](https://tools.stefankueng.com/grepWin_cmd.html). diff --git a/grepWinNP3/default.build b/grepWinNP3/default.build index c460c1b9e..15090e444 100644 --- a/grepWinNP3/default.build +++ b/grepWinNP3/default.build @@ -199,6 +199,7 @@ + @@ -216,6 +217,10 @@ + + ${verstringfull} +https://tools.stefankueng.com/grepWin.html + diff --git a/grepWinNP3/grepWinNP3.vcxproj b/grepWinNP3/grepWinNP3.vcxproj index 77f1a514f..4465ff7e9 100644 --- a/grepWinNP3/grepWinNP3.vcxproj +++ b/grepWinNP3/grepWinNP3.vcxproj @@ -342,16 +342,16 @@ - - - + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + \ No newline at end of file diff --git a/grepWinNP3/packages.config b/grepWinNP3/packages.config index 41afc80b8..594f8ed22 100644 --- a/grepWinNP3/packages.config +++ b/grepWinNP3/packages.config @@ -1,6 +1,6 @@  - - - + + + \ No newline at end of file diff --git a/grepWinNP3/sktoolslib_mod/FileDropTarget.h b/grepWinNP3/sktoolslib_mod/FileDropTarget.h index d757ef06a..1641c73fd 100644 --- a/grepWinNP3/sktoolslib_mod/FileDropTarget.h +++ b/grepWinNP3/sktoolslib_mod/FileDropTarget.h @@ -1,6 +1,6 @@ // sktoolslib - common files for SK tools -// Copyright (C) 2012-2013 - Stefan Kueng +// Copyright (C) 2012-2013, 2020 - Stefan Kueng // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -76,10 +76,12 @@ public: CFileDropTarget(HWND hTargetWnd) : CIDropTarget(hTargetWnd) , m_hParent(NULL) + , m_concat(0) {} CFileDropTarget(HWND hTargetWnd, HWND hParent) : CIDropTarget(hTargetWnd) , m_hParent(hParent) + , m_concat(0) { RegisterDragDrop(hTargetWnd, this); // create the supported format: @@ -90,6 +92,7 @@ public: ftetc.tymed = TYMED_HGLOBAL; AddSuportedFormat(ftetc); } + void SetMultipathConcatenate(wchar_t ch) { m_concat = ch; } virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/) { if (m_hParent && (pFmtEtc->cfFormat == CF_HDROP) && (medium.tymed == TYMED_HGLOBAL)) @@ -189,11 +192,22 @@ public: std::unique_ptr szFileName(new TCHAR[MAX_PATH_NEW]); UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + std::wstring concatPaths; for (UINT i = 0; i < cFiles; ++i) { DragQueryFile(hDrop, i, szFileName.get(), MAX_PATH_NEW); - ::SendMessage(m_hTargetWnd, WM_SETTEXT, 0, (LPARAM)szFileName.get()); + if (m_concat) + { + if (!concatPaths.empty()) + concatPaths += m_concat; + concatPaths += szFileName.get(); + } + else + ::SendMessage(m_hTargetWnd, WM_SETTEXT, 0, (LPARAM)szFileName.get()); } + if (!concatPaths.empty()) + ::SendMessage(m_hTargetWnd, WM_SETTEXT, 0, (LPARAM)concatPaths.c_str()); + //DragFinish(hDrop); // base class calls ReleaseStgMedium } GlobalUnlock(medium.hGlobal); @@ -202,4 +216,5 @@ public: } private: HWND m_hParent; + wchar_t m_concat; }; diff --git a/grepWinNP3/sktoolslib_mod/GDIHelpers.cpp b/grepWinNP3/sktoolslib_mod/GDIHelpers.cpp index 7de3feb3a..7d58273f1 100644 --- a/grepWinNP3/sktoolslib_mod/GDIHelpers.cpp +++ b/grepWinNP3/sktoolslib_mod/GDIHelpers.cpp @@ -1,6 +1,6 @@ // sktoolslib - common files for SK tools -// Copyright (C) 2012-2013, 2017 - Stefan Kueng +// Copyright (C) 2012-2013, 2017, 2020 - Stefan Kueng // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -259,7 +259,7 @@ bool GDIHelpers::ShortHexStringToCOLORREF(const std::string& s, COLORREF* clr) } } auto color = RGB(rgb[0], rgb[1], rgb[2]); - *clr = (RGB((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF)) | (color & 0xFF000000); + *clr = color; return true; } diff --git a/grepWinNP3/src/Resources/grepWin.rc b/grepWinNP3/src/Resources/grepWin.rc index e4cde53f0..25f4a83d3 100644 --- a/grepWinNP3/src/Resources/grepWin.rc +++ b/grepWinNP3/src/Resources/grepWin.rc @@ -41,15 +41,16 @@ IDI_GREPWIN ICON "grepWinNP3.ico" IDD_SEARCHDLG DIALOGEX 0, 0, 600, 339 STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "grepWinNP3" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN + LTEXT "Press F1 for help",IDC_HELPLABEL,362,50,104,8 + RTEXT "About grepWinNP3",IDC_ABOUTLINK,449,2,136,8 PUSHBUTTON "/",IDC_PATHMRU,14,20,11,12 EDITTEXT IDC_SEARCHPATH,31,20,536,12,ES_AUTOHSCROLL,WS_EX_ACCEPTFILES PUSHBUTTON "...",IDC_SEARCHPATHBROWSE,572,20,13,12 GROUPBOX "Search in",IDC_GROUPSEARCHIN,7,10,587,29 CONTROL "Regex search",IDC_REGEXRADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,84,50,100,10 CONTROL "Text search",IDC_TEXTRADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,198,50,105,10 - LTEXT "Press F1 for help",IDC_HELPLABEL,362,50,104,8 RTEXT "",IDC_REGEXOKLABEL,476,50,98,8 LTEXT "Search &for:",IDC_SEARCHFORLABEL,14,65,46,8 EDITTEXT IDC_SEARCHTEXT,83,64,484,12,ES_AUTOHSCROLL @@ -64,6 +65,7 @@ BEGIN PUSHBUTTON "Test regex",IDC_TESTREGEX,14,109,69,14 PUSHBUTTON "Add to Presets",IDC_ADDTOBOOKMARKS,117,109,76,14 PUSHBUTTON "Presets",IDC_BOOKMARKS,195,109,50,14 + CONTROL "",IDC_UPDATELINK,"SysLink",LWS_RIGHT | NOT WS_VISIBLE | WS_TABSTOP | WS_DISABLED,262,110,292,11 GROUPBOX "Search",IDC_GROUPSEARCHFOR,7,41,587,86 CONTROL "All sizes",IDC_ALLSIZERADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,14,139,103,10 CONTROL "Size is",IDC_SIZERADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,14,152,44,10 @@ -94,7 +96,6 @@ BEGIN GROUPBOX "Limit search",IDC_GROUPLIMITSEARCH,7,128,587,65 CONTROL "",IDC_RESULTLIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_BORDER | WS_TABSTOP,14,234,571,81 LTEXT "",IDC_SEARCHINFOLABEL,14,321,580,8 - RTEXT "About grepWinNP3",IDC_ABOUTLINK,449,2,136,8 GROUPBOX "Search results",IDC_GROUPSEARCHRESULTS,7,214,587,118 CONTROL "Files",IDC_RESULTFILES,"Button",BS_AUTORADIOBUTTON | WS_GROUP,84,222,89,10 CONTROL "Content",IDC_RESULTCONTENT,"Button",BS_AUTORADIOBUTTON,200,222,104,10 @@ -105,7 +106,7 @@ END IDD_REGEXTEST DIALOGEX 0, 0, 401, 316 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Regex Test" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN LTEXT "Paste text to test the regex with:",IDC_INFOLABEL,7,7,387,8 CONTROL "",IDC_TEXTCONTENT,"RichEdit20W",WS_BORDER | WS_VSCROLL | WS_TABSTOP | 0x1084,7,17,387,89 @@ -124,7 +125,7 @@ END IDD_NAME DIALOGEX 0, 0, 186, 65 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Preset name" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN LTEXT "Enter a name for the regex:",IDC_INFOLABEL,7,7,172,8 EDITTEXT IDC_NAME,7,20,172,14,ES_AUTOHSCROLL @@ -135,7 +136,7 @@ END IDD_BOOKMARKS DIALOGEX 0, 0, 240, 129 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Presets" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN CONTROL "",IDC_BOOKMARKS,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,16,226,85 DEFPUSHBUTTON "OK",IDOK,70,108,78,14 @@ -146,7 +147,7 @@ END IDD_ABOUT DIALOGEX 0, 0, 263, 86 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About grepWinNP3" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,206,65,50,14 ICON IDI_GREPWIN,IDC_STATIC,17,18,20,20,SS_CENTERIMAGE @@ -159,7 +160,7 @@ END IDD_MULTILINEEDIT DIALOGEX 0, 0, 317, 135 STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Dialog" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,157,114,73,14 PUSHBUTTON "Cancel",IDCANCEL,237,114,73,14 @@ -169,7 +170,7 @@ END IDD_SETTINGS DIALOGEX 0, 0, 317, 209 STYLE DS_SETFONT | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "grepWinNP3 Settings" -FONT 9, "MS Shell Dlg 2", 400, 0, 0x1 +FONT 9, "Segoe UI", 400, 0, 0x1 BEGIN GROUPBOX "Editor",IDC_EDITORGROUP,7,7,303,78 LTEXT "Command line to start an editor at a specific line:",IDC_STATIC1,13,19,288,8 @@ -188,8 +189,9 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,204,180,50,13 PUSHBUTTON "Cancel",IDCANCEL,260,180,50,13 CONTROL "Only one instance",IDC_ONLYONE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,143,150,10 - CONTROL "Dark mode",IDC_DARKMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,155,157,10 - LTEXT "",IDC_DARKMODEINFO,17,170,180,23,WS_DISABLED + CONTROL "Check for updates",IDC_DOUPDATECHECKS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP | WS_DISABLED,7,155,150,10 + CONTROL "Dark mode",IDC_DARKMODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,157,10 + LTEXT "",IDC_DARKMODEINFO,17,182,180,23,WS_DISABLED RTEXT "Max # of concurrent worker",IDC_TEXT_NUMOFWORKER,156,156,107,9,0,WS_EX_RIGHT EDITTEXT IDC_MAXNUMWORKER,271,154,31,13,ES_RIGHT | ES_NUMBER | WS_GROUP,WS_EX_RIGHT CONTROL "",IDC_SPIN_MAXWORKER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNLEFT | UDS_AUTOBUDDY | UDS_ARROWKEYS | WS_GROUP,271,154,10,13 @@ -429,6 +431,7 @@ BEGIN IDS_EXPORTPATHS "include file paths" IDS_EXPORTMATCHLINENUMBER "include match line numbers" IDS_EXPORTMATCHLINECONTENT "include match line text" + IDS_UPDATEAVAILABLE "grepWinNP3 %s is available" END #endif // Neutral resources diff --git a/grepWinNP3/src/Resources/grepWin_orig.rc b/grepWinNP3/src/Resources/grepWin_orig.rc index e91c29184..2b62f2ec0 100644 Binary files a/grepWinNP3/src/Resources/grepWin_orig.rc and b/grepWinNP3/src/Resources/grepWin_orig.rc differ diff --git a/grepWinNP3/src/SearchDlg.cpp b/grepWinNP3/src/SearchDlg.cpp index 096b80130..e7a2ef11c 100644 --- a/grepWinNP3/src/SearchDlg.cpp +++ b/grepWinNP3/src/SearchDlg.cpp @@ -51,6 +51,12 @@ #include "COMPtrs.h" #include "PreserveChdir.h" +#ifdef NP3_ALLOW_UPDATE +#include "TempFile.h" +#include "version.h" + +#endif + #include #include #include @@ -298,6 +304,7 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara m_pDropTarget->AddSuportedFormat(ftetc); ftetc.cfFormat=CF_HDROP; m_pDropTarget->AddSuportedFormat(ftetc); + m_pDropTarget->SetMultipathConcatenate('|'); m_editFilePatterns.Subclass(hwndDlg, IDC_PATTERN); m_editExcludeDirsPatterns.Subclass(hwndDlg, IDC_EXCLUDEDIRSPATTERN); @@ -452,6 +459,9 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara m_resizer.AddControl(hwndDlg, IDC_TESTREGEX, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_ADDTOBOOKMARKS, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_BOOKMARKS, RESIZER_TOPLEFT); +#include "TempFile.h" + m_resizer.AddControl(hwndDlg, IDC_UPDATELINK, RESIZER_TOPRIGHT); +#include "version.h" m_resizer.AddControl(hwndDlg, IDC_GROUPLIMITSEARCH, RESIZER_TOPLEFTRIGHT); m_resizer.AddControl(hwndDlg, IDC_ALLSIZERADIO, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_SIZERADIO, RESIZER_TOPLEFT); @@ -525,6 +535,19 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara } InitResultList(); +#ifdef NP3_ALLOW_UPDATE + bool doCheck = true; + if (bPortable) + doCheck = !!_wtoi(g_iniFile.GetValue(L"global", L"CheckForUpdates", L"1")); + else + doCheck = !!DWORD(CRegStdDWORD(L"Software\\grepWin\\CheckForUpdates", 1)); + if (doCheck) + { + m_updateCheckThread = std::move(std::thread([&]() { CheckForUpdates(); })); + ShowUpdateAvailable(); + } +#endif + if (hInitProtection) CloseHandle(hInitProtection); hInitProtection = nullptr; @@ -545,6 +568,10 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara return FALSE; case WM_CLOSE: { +#ifdef NP3_ALLOW_UPDATE + if (m_updateCheckThread.joinable()) + m_updateCheckThread.join(); +#endif if (!DWORD(CRegStdDWORD(L"Software\\grepWinNP3\\escclose", FALSE))) { if (IsEvaluationThreadRunning()) @@ -612,6 +639,24 @@ LRESULT CSearchDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara break; } break; +#ifdef NP3_ALLOW_UPDATE + case IDC_UPDATELINK: + switch (((LPNMHDR)lParam)->code) + { + case NM_CLICK: + case NM_RETURN: + { + PNMLINK pNMLink = (PNMLINK)lParam; + LITEM item = pNMLink->item; + if (item.iLink == 0) + { + ShellExecute(*this, L"open", item.szUrl, nullptr, nullptr, SW_SHOW); + } + break; + } + } + break; +#endif } } break; @@ -1008,6 +1053,10 @@ LRESULT CSearchDlg::DoCommand(int id, int msg) break; case IDCANCEL: { +#ifdef NP3_ALLOW_UPDATE + if (m_updateCheckThread.joinable()) + m_updateCheckThread.join(); +#endif if (DWORD(CRegStdDWORD(L"Software\\grepWinNP3\\escclose", FALSE))) { if (IsEvaluationThreadRunning()) @@ -1483,6 +1532,12 @@ LRESULT CSearchDlg::DoCommand(int id, int msg) exportlinenumbers = includeMatchLineNumbers ? 1 : 0; exportlinecontent = includeMatchLineTexts ? 1 : 0; } + SHELLEXECUTEINFO sei = { 0 }; + sei.cbSize = sizeof(SHELLEXECUTEINFO); + sei.lpVerb = TEXT("open"); + sei.lpFile = path.c_str(); + sei.nShow = SW_SHOWNORMAL; + ShellExecuteEx(&sei); } } } @@ -1977,7 +2032,7 @@ void CSearchDlg::DoListNotify(LPNMITEMACTIVATE lpNMItemActivate) CStringUtils::trim(matchtext); matchString += CStringUtils::Format(sFormat.c_str(), inf.matchlinesnumbers[i], matchtext.c_str()); } - if (inf.matchlines.size() >= 5) + if (inf.matchlines.size() > 5) { std::wstring sx = TranslatedString(hResource, IDS_XMOREMATCHES); std::wstring ssx = CStringUtils::Format(sx.c_str(), int(inf.matchlines.size() - 5)); @@ -3732,3 +3787,143 @@ bool CSearchDlg::FailedShowMessage(HRESULT hr) } return false; } + +#ifdef NP3_ALLOW_UPDATE +void CSearchDlg::CheckForUpdates(bool force) +{ + bool bNewerAvailable = false; + // check for newer versions + bool doCheck = true; + if (bPortable) + doCheck = !!_wtoi(g_iniFile.GetValue(L"global", L"CheckForUpdates", L"1")); + else + doCheck = !!DWORD(CRegStdDWORD(L"Software\\grepWin\\CheckForUpdates", 1)); + if (doCheck) + { + time_t now; + time(&now); + time_t last = 0; + if (bPortable) + { + last = _wtoll(g_iniFile.GetValue(L"global", L"CheckForUpdatesLast", L"0")); + } + else + { + last = _wtoll(((std::wstring)CRegStdString(L"Software\\grepWin\\CheckForUpdatesLast", L"0")).c_str()); + } + double days = std::difftime(now, last) / (60LL * 60LL * 24LL); + if ((days >= 7.0) || force) + { + std::wstring tempfile = CTempFiles::Instance().GetTempFilePath(true); + + std::wstring sCheckURL = L"https://raw.githubusercontent.com/stefankueng/grepWin/main/version.txt"; + HRESULT res = URLDownloadToFile(nullptr, sCheckURL.c_str(), tempfile.c_str(), 0, nullptr); + if (res == S_OK) + { + if (bPortable) + { + g_iniFile.SetValue(L"global", L"CheckForUpdatesLast", std::to_wstring(now).c_str()); + } + else + { + auto regLast = CRegStdString(L"Software\\grepWin\\CheckForUpdatesLast", L"0"); + regLast = std::to_wstring(now); + } + std::ifstream File; + File.open(tempfile.c_str()); + if (File.good()) + { + char line[1024]; + File.getline(line, sizeof(line)); + auto verLine = CUnicodeUtils::StdGetUnicode(line); + bNewerAvailable = IsVersionNewer(verLine); + File.getline(line, sizeof(line)); + auto updateurl = CUnicodeUtils::StdGetUnicode(line); + if (bNewerAvailable) + { + if (bPortable) + { + g_iniFile.SetValue(L"global", L"CheckForUpdatesVersion", verLine.c_str()); + g_iniFile.SetValue(L"global", L"CheckForUpdatesUrl", updateurl.c_str()); + } + else + { + auto regVersion = CRegStdString(L"Software\\grepWin\\CheckForUpdatesVersion", L""); + regVersion = verLine; + auto regUpdateUrl = CRegStdString(L"Software\\grepWin\\CheckForUpdatesUrl", L""); + regUpdateUrl = updateurl; + } + ShowUpdateAvailable(); + } + } + File.close(); + DeleteFile(tempfile.c_str()); + } + } + } +} + +void CSearchDlg::ShowUpdateAvailable() +{ + std::wstring sVersion; + std::wstring updateUrl; + if (bPortable) + { + sVersion = g_iniFile.GetValue(L"global", L"CheckForUpdatesVersion", L""); + updateUrl = g_iniFile.GetValue(L"global", L"CheckForUpdatesUrl", L""); + } + else + { + sVersion = CRegStdString(L"Software\\grepWin\\CheckForUpdatesVersion", L""); + updateUrl = CRegStdString(L"Software\\grepWin\\CheckForUpdatesUrl", L""); + } + if (IsVersionNewer(sVersion)) + { + auto sUpdateAvailable = TranslatedString(hResource, IDS_UPDATEAVAILABLE); + sUpdateAvailable = CStringUtils::Format(sUpdateAvailable.c_str(), sVersion.c_str()); + auto sLinkText = CStringUtils::Format(L"%s", updateUrl.c_str(), sUpdateAvailable.c_str()); + SetDlgItemText(*this, IDC_UPDATELINK, sLinkText.c_str()); + ShowWindow(GetDlgItem(*this, IDC_UPDATELINK), SW_SHOW); + } +} + +bool CSearchDlg::IsVersionNewer(const std::wstring& sVer) +{ + int major = 0; + int minor = 0; + int micro = 0; + int build = 0; + + const wchar_t* pLine = sVer.c_str(); + + major = _wtoi(pLine); + pLine = wcschr(pLine, '.'); + if (pLine) + { + pLine++; + minor = _wtoi(pLine); + pLine = wcschr(pLine, '.'); + if (pLine) + { + pLine++; + micro = _wtoi(pLine); + pLine = wcschr(pLine, '.'); + if (pLine) + { + pLine++; + build = _wtoi(pLine); + } + } + } + bool isNewer = false; + if (major > GREPWIN_VERMAJOR) + isNewer = true; + else if ((minor > GREPWIN_VERMINOR) && (major == GREPWIN_VERMAJOR)) + isNewer = true; + else if ((micro > GREPWIN_VERMICRO) && (minor == GREPWIN_VERMINOR) && (major == GREPWIN_VERMAJOR)) + isNewer = true; + else if ((build > GREPWIN_VERBUILD) && (micro == GREPWIN_VERMICRO) && (minor == GREPWIN_VERMINOR) && (major == GREPWIN_VERMAJOR)) + isNewer = true; + return isNewer; +} +#endif diff --git a/grepWinNP3/src/SearchDlg.h b/grepWinNP3/src/SearchDlg.h index aac0d6b91..14f00ea54 100644 --- a/grepWinNP3/src/SearchDlg.h +++ b/grepWinNP3/src/SearchDlg.h @@ -31,6 +31,9 @@ #include #include #include +#ifdef NP3_ALLOW_UPDATE +#include +#endif #define SEARCH_START (WM_APP+1) @@ -119,6 +122,11 @@ protected: void AutoSizeAllColumns(); int GetSelectedListIndex(int index); bool FailedShowMessage(HRESULT hr); +#ifdef NP3_ALLOW_UPDATE + void CheckForUpdates(bool force = false); + void ShowUpdateAvailable(); + bool IsVersionNewer(const std::wstring& sVer); +#endif private: static bool NameCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); static bool SizeCompareAsc(const CSearchInfo& Entry1, const CSearchInfo& Entry2); @@ -199,6 +207,10 @@ private: static UINT GREPWIN_STARTUPMSG; +#ifdef NP3_ALLOW_UPDATE + std::thread m_updateCheckThread; +#endif + CAutoComplete m_AutoCompleteFilePatterns; CAutoComplete m_AutoCompleteExcludeDirsPatterns; CAutoComplete m_AutoCompleteSearchPatterns; diff --git a/grepWinNP3/src/Settings.cpp b/grepWinNP3/src/Settings.cpp index 8d05aba9a..f75a8f4be 100644 --- a/grepWinNP3/src/Settings.cpp +++ b/grepWinNP3/src/Settings.cpp @@ -184,6 +184,9 @@ LRESULT CSettingsDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa SendDlgItemMessage(hwndDlg, IDC_BACKUPINFOLDER, BM_SETCHECK, bPortable ? g_iniFile.GetBoolValue(L"settings", L"backupinfolder", false) : !!DWORD(CRegStdDWORD(L"Software\\grepWinNP3\\backupinfolder", FALSE)) ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_NOWARNINGIFNOBACKUP, BM_SETCHECK, bPortable ? g_iniFile.GetBoolValue(L"settings", L"nowarnifnobackup", false) : !!DWORD(CRegStdDWORD(L"Software\\grepWin\\nowarnifnobackup", FALSE)) ? BST_CHECKED : BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_ONLYONE, BM_SETCHECK, bPortable ? g_iniFile.GetBoolValue(L"global", L"onlyone", false) : !!DWORD(CRegStdDWORD(L"Software\\grepWinNP3\\onlyone", FALSE)) ? BST_CHECKED : BST_UNCHECKED, 0); +#ifdef NP3_ALLOW_UPDATE + SendDlgItemMessage(hwndDlg, IDC_DOUPDATECHECKS, BM_SETCHECK, bPortable ? g_iniFile.GetBoolValue(L"global", L"CheckForUpdates", false) : !!DWORD(CRegStdDWORD(L"Software\\grepWinNP3\\CheckForUpdates", FALSE)) ? BST_CHECKED : BST_UNCHECKED, 0); +#endif SendDlgItemMessage(hwndDlg, IDC_DARKMODE, BM_SETCHECK, CTheme::Instance().IsDarkTheme() ? BST_CHECKED : BST_UNCHECKED, 0); EnableWindow(GetDlgItem(*this, IDC_DARKMODE), CTheme::Instance().IsDarkModeAllowed()); @@ -212,6 +215,9 @@ LRESULT CSettingsDlg::DlgFunc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa m_resizer.AddControl(hwndDlg, IDC_BACKUPINFOLDER, RESIZER_TOPLEFTRIGHT); m_resizer.AddControl(hwndDlg, IDC_NOWARNINGIFNOBACKUP, RESIZER_TOPLEFTRIGHT); m_resizer.AddControl(hwndDlg, IDC_ONLYONE, RESIZER_TOPLEFTRIGHT); +#ifdef NP3_ALLOW_UPDATE + m_resizer.AddControl(hwndDlg, IDC_DOUPDATECHECKS, RESIZER_TOPLEFTRIGHT); +#endif m_resizer.AddControl(hwndDlg, IDC_DARKMODE, RESIZER_TOPLEFT); m_resizer.AddControl(hwndDlg, IDC_DARKMODEINFO, RESIZER_TOPLEFTRIGHT); m_resizer.AddControl(hwndDlg, IDOK, RESIZER_BOTTOMRIGHT); @@ -302,6 +308,9 @@ LRESULT CSettingsDlg::DoCommand(int id, int /*msg*/) g_iniFile.SetBoolValue(L"settings", L"backupinfolder", (IsDlgButtonChecked(*this, IDC_BACKUPINFOLDER) == BST_CHECKED)); g_iniFile.SetBoolValue(L"settings", L"nowarnifnobackup", (IsDlgButtonChecked(*this, IDC_NOWARNINGIFNOBACKUP) == BST_CHECKED)); g_iniFile.SetBoolValue(L"global", L"onlyone", (IsDlgButtonChecked(*this, IDC_ONLYONE) == BST_CHECKED)); +#ifdef NP3_ALLOW_UPDATE + g_iniFile.SetBoolValue(L"global", L"CheckForUpdates", (IsDlgButtonChecked(*this, IDC_DOUPDATECHECKS) == BST_CHECKED)); +#endif g_iniFile.SetLongValue(L"global", L"MaxNumOfWorker", nWorker); } else @@ -314,6 +323,10 @@ LRESULT CSettingsDlg::DoCommand(int id, int /*msg*/) nowarn = (IsDlgButtonChecked(*this, IDC_NOWARNINGIFNOBACKUP) == BST_CHECKED); CRegStdDWORD regOnlyOne(L"Software\\grepWinNP3\\onlyone", FALSE); regOnlyOne = (IsDlgButtonChecked(*this, IDC_ONLYONE) == BST_CHECKED); +#ifdef NP3_ALLOW_UPDATE + CRegStdDWORD regCheckForUpdates(L"Software\\grepWinNP3\\CheckForUpdates", FALSE); + regCheckForUpdates = (IsDlgButtonChecked(*this, IDC_DOUPDATECHECKS) == BST_CHECKED); +#endif CRegStdDWORD nwrk(L"Software\\grepWinNP3\\MaxNumOfWorker", 1); nwrk = nWorker; } diff --git a/grepWinNP3/src/last/version.h b/grepWinNP3/src/last/version.h index d111c5506..717e9bc21 100644 --- a/grepWinNP3/src/last/version.h +++ b/grepWinNP3/src/last/version.h @@ -6,13 +6,13 @@ //#pragma message(__LOC__"Run the NAnt script to get proper version info") -#define FILEVER 2, 1, 1, 15 -#define PRODUCTVER 2, 1, 1, 15 -#define STRFILEVER "2.1.1.15\0" -#define STRPRODUCTVER "2.1.1.15\0" +#define FILEVER 2, 1, 2, 16 +#define PRODUCTVER 2, 1, 2, 16 +#define STRFILEVER "2.1.2.16\0" +#define STRPRODUCTVER "2.1.2.16\0" #define GREPWIN_VERMAJOR 2 #define GREPWIN_VERMINOR 1 -#define GREPWIN_VERMICRO 1 -#define GREPWIN_VERBUILD 15 -#define GREPWIN_VERDATE "2020-06-16" +#define GREPWIN_VERMICRO 2 +#define GREPWIN_VERBUILD 16 +#define GREPWIN_VERDATE "2020-07-02" diff --git a/grepWinNP3/src/resource.h b/grepWinNP3/src/resource.h index c47afffb1..cd260f191 100644 --- a/grepWinNP3/src/resource.h +++ b/grepWinNP3/src/resource.h @@ -78,6 +78,7 @@ #define IDS_EXPORTPATHS 165 #define IDS_EXPORTMATCHLINENUMBER 166 #define IDS_EXPORTMATCHLINECONTENT 167 +#define IDS_UPDATEAVAILABLE 168 #define IDC_SEARCHTEXT 1000 #define IDC_REGEXRADIO 1001 #define IDC_TEXTRADIO 1002 @@ -168,6 +169,8 @@ #define IDC_INVERSESEARCH 1091 #define IDC_SEARCHINFOUNDFILES 1092 #define IDC_EXPORT 1093 +#define IDC_UPDATELINK 1094 +#define IDC_DOUPDATECHECKS 1095 #define ID_REMOVEBOOKMARK 32771 #define ID_DUMMY_RENAMEPRESET 32774 #define ID_RENAMEBOOKMARK 32775 @@ -178,9 +181,9 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 168 +#define _APS_NEXT_RESOURCE_VALUE 169 #define _APS_NEXT_COMMAND_VALUE 32776 -#define _APS_NEXT_CONTROL_VALUE 1094 +#define _APS_NEXT_CONTROL_VALUE 1096 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/grepWinNP3/version.build.in b/grepWinNP3/version.build.in index 82aedf5ea..de8b03a13 100644 --- a/grepWinNP3/version.build.in +++ b/grepWinNP3/version.build.in @@ -4,7 +4,7 @@ - + diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp index 686d6633e..9a7d71ed8 100644 --- a/src/Config/Config.cpp +++ b/src/Config/Config.cpp @@ -93,6 +93,49 @@ constexpr bool SI_Success(const SI_Error rc) noexcept { // ============================================================================ + +bool CanAccessPath(LPCWSTR lpIniFilePath, DWORD genericAccessRights) +{ + bool bRet = false; + if (StrIsEmpty(lpIniFilePath)) { + return bRet; + } + DWORD length = 0; + SECURITY_INFORMATION const secInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; + + if (!::GetFileSecurity(lpIniFilePath, secInfo, NULL, 0, &length) && (ERROR_INSUFFICIENT_BUFFER == GetLastError())) { + PSECURITY_DESCRIPTOR security = static_cast(AllocMem(length, HEAP_ZERO_MEMORY)); + if (security && ::GetFileSecurity(lpIniFilePath, secInfo, security, length, &length)) { + HANDLE hToken = NULL; + if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken)) { + HANDLE hImpersonatedToken = NULL; + if (::DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) { + GENERIC_MAPPING mapping = {0xFFFFFFFF}; + PRIVILEGE_SET privileges = {0}; + DWORD grantedAccess = 0, privilegesLength = sizeof(privileges); + BOOL result = FALSE; + + mapping.GenericRead = FILE_GENERIC_READ; + mapping.GenericWrite = FILE_GENERIC_WRITE; + mapping.GenericExecute = FILE_GENERIC_EXECUTE; + mapping.GenericAll = FILE_ALL_ACCESS; + + ::MapGenericMask(&genericAccessRights, &mapping); + if (::AccessCheck(security, hImpersonatedToken, genericAccessRights, + &mapping, &privileges, &privilegesLength, &grantedAccess, &result)) { + bRet = (result == TRUE); + } + ::CloseHandle(hImpersonatedToken); + } + ::CloseHandle(hToken); + } + FreeMem(security); + } + } + return bRet; +} + + // ---------------------------------------------------------------------------- // No mechanism for EXCLUSIVE WRITE / SHARD READ: // cause we need completely synchronized exclusive access for READ _and_ WRITE @@ -265,13 +308,13 @@ extern "C" bool OpenSettingsFile(bool* keepCached) // extern "C" bool CloseSettingsFile(bool bSaveChanges, bool keepCached) { - if (StrIsEmpty(Globals.IniFile) || !IsIniFileCached()) { return false; } + if (!Globals.bCanSaveIniFile || !IsIniFileCached()) { return false; } - bool const ok = bSaveChanges ? SaveIniFileCache(Globals.IniFile) : true; + bool const bSaved = bSaveChanges ? SaveIniFileCache(Globals.IniFile) : false; if (!keepCached) { ResetIniFileCache(); } - return ok; + return bSaved; } @@ -961,7 +1004,9 @@ extern "C" bool CreateIniFile(LPCWSTR pszIniFilePath, DWORD* pdwFileSize_out) } if (pdwFileSize_out) { *pdwFileSize_out = dwFileSize; } - if (dwFileSize == 0UL) { + Globals.bCanSaveIniFile = CanAccessPath(pszIniFilePath, GENERIC_WRITE); + + if ((dwFileSize == 0UL) && Globals.bCanSaveIniFile) { // Set at least Application Name Section result = IniFileSetString(pszIniFilePath, _W(SAPPNAME), NULL, NULL); } @@ -999,7 +1044,7 @@ void LoadSettings() Globals.iCfgVersionRead = IniSectionGetInt(IniSecSettings, L"SettingsVersion", _ver); Defaults.SaveSettings = StrIsNotEmpty(Globals.IniFile); - Settings.SaveSettings = IniSectionGetBool(IniSecSettings, L"SaveSettings", Defaults.SaveSettings); + Settings.SaveSettings = Defaults.SaveSettings && IniSectionGetBool(IniSecSettings, L"SaveSettings", Defaults.SaveSettings); // --- first set "hard coded" .ini-Settings --- @@ -1979,7 +2024,7 @@ bool SaveAllSettings(bool bForceSaveSettings) { if (Flags.bDoRelaunchElevated) { return true; } // already saved before relaunch if (Flags.bSettingsFileSoftLocked) { return false; } - + WCHAR tchMsg[80]; GetLngString(IDS_MUI_SAVINGSETTINGS, tchMsg, COUNTOF(tchMsg)); @@ -1996,7 +2041,7 @@ __try { _SaveSettings(bForceSaveSettings); - if (StrIsNotEmpty(Globals.IniFile)) + if (Globals.bCanSaveIniFile) { if (!Settings.SaveRecentFiles) { // Cleanup unwanted MRUs @@ -2032,7 +2077,8 @@ __try { } // separate INI files for Style-Themes - if (Globals.idxSelectedTheme >= 2) { + if (Globals.idxSelectedTheme >= 2) + { Style_SaveSettings(bForceSaveSettings); } diff --git a/src/Config/Config.h b/src/Config/Config.h index bd0ebc5ed..77a0b85fc 100644 --- a/src/Config/Config.h +++ b/src/Config/Config.h @@ -28,6 +28,7 @@ extern "C" { bool FindIniFile(); bool TestIniFile(); +bool CanAccessPath(LPCWSTR lpIniFilePath, DWORD genericAccessRights); bool CreateIniFile(LPCWSTR pszIniFilePath, DWORD* pdwFileSize_out); void LoadSettings(); bool SaveWindowPositionSettings(bool bClearSettings); diff --git a/src/Dialogs.c b/src/Dialogs.c index 77ed14671..ce47ca702 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -287,7 +287,7 @@ static INT_PTR CALLBACK _InfoBoxLngDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, case IDIGNORE: case IDTRYAGAIN: case IDCONTINUE: - if (IsButtonChecked(hwnd, IDC_INFOBOXCHECK) && StrIsNotEmpty(lpMsgBox->lpstrSetting)) { + if (IsButtonChecked(hwnd, IDC_INFOBOXCHECK) && StrIsNotEmpty(lpMsgBox->lpstrSetting) ) { IniFileSetInt(Globals.IniFile, Constants.SectionSuppressedMessages, lpMsgBox->lpstrSetting, LOWORD(wParam)); } case IDNO: @@ -336,7 +336,9 @@ INT_PTR InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...) break; default: - IniFileDelete(Globals.IniFile, Constants.SectionSuppressedMessages, lpstrSetting, false); + if (Globals.bCanSaveIniFile) { + IniFileDelete(Globals.IniFile, Constants.SectionSuppressedMessages, lpstrSetting, false); + } break; } @@ -385,8 +387,7 @@ INT_PTR InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...) } msgBox.lpstrSetting = (LPWSTR)lpstrSetting; - msgBox.bDisableCheckBox = (StrIsEmpty(Globals.IniFile) || StrIsEmpty(lpstrSetting) || (iMode < 0)) ? true : false; - + msgBox.bDisableCheckBox = (!Globals.bCanSaveIniFile || StrIsEmpty(lpstrSetting) || (iMode < 0)) ? true : false; int idDlg; switch (uType & MB_TYPEMASK) { diff --git a/src/Helpers.c b/src/Helpers.c index dca8b3f89..6b72c6541 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -688,24 +688,22 @@ bool VerifyContrast(COLORREF cr1,COLORREF cr2) // IsFontAvailable() // Test if a certain font is installed on the system // -int CALLBACK EnumFontsProc(CONST LOGFONT *plf,CONST TEXTMETRIC *ptm,DWORD FontType,LPARAM lParam) +static int CALLBACK EnumFontsProc(CONST LOGFONT *plf,CONST TEXTMETRIC *ptm,DWORD FontType,LPARAM lParam) { - *((PBOOL)lParam) = true; UNUSED(plf); UNUSED(ptm); UNUSED(FontType); + *((PBOOL)lParam) = true; return 0; } bool IsFontAvailable(LPCWSTR lpszFontName) { BOOL fFound = FALSE; - - HDC hDC = GetDC(NULL); + HDC const hDC = GetDC(NULL); EnumFonts(hDC,lpszFontName,EnumFontsProc,(LPARAM)&fFound); ReleaseDC(NULL,hDC); - - return (bool)(fFound); + return fFound; } @@ -713,22 +711,12 @@ bool IsFontAvailable(LPCWSTR lpszFontName) // // IsCmdEnabled() // -bool IsCmdEnabled(HWND hwnd,UINT uId) +bool IsCmdEnabled(HWND hwnd, UINT uId) { - - HMENU hmenu; - UINT ustate; - - hmenu = GetMenu(hwnd); - - SendMessage(hwnd,WM_INITMENU,(WPARAM)hmenu,0); - - ustate = GetMenuState(hmenu,uId,MF_BYCOMMAND); - - if (ustate == 0xFFFFFFFF) { - return true; - } - return (!(ustate & (MF_GRAYED|MF_DISABLED))); + HMENU const hmenu = GetMenu(hwnd); + SendMessage(hwnd, WM_INITMENU,(WPARAM)hmenu, 0); + UINT const ustate = GetMenuState(hmenu, uId, MF_BYCOMMAND); + return ((ustate == 0xFFFFFFFF) ? true : (!(ustate & (MF_GRAYED | MF_DISABLED)))); } diff --git a/src/MuiLanguage.c b/src/MuiLanguage.c index d9d1504df..cccb9279d 100644 --- a/src/MuiLanguage.c +++ b/src/MuiLanguage.c @@ -293,12 +293,13 @@ void SetPreferredLanguage(LANGID iPreferredLanguageID) { StringCchCopyW(Settings2.PreferredLanguageLocaleName, COUNTOF(Settings2.PreferredLanguageLocaleName), szLocaleName); - if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, Defaults2.PreferredLanguageLocaleName) != 0) - { - IniFileSetString(Globals.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", Settings2.PreferredLanguageLocaleName); - } - else { - IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", false); + if (Globals.bCanSaveIniFile) { + if (StringCchCompareXIW(Settings2.PreferredLanguageLocaleName, Defaults2.PreferredLanguageLocaleName) != 0) { + IniFileSetString(Globals.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", Settings2.PreferredLanguageLocaleName); + } + else { + IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", false); + } } } } diff --git a/src/Notepad3.c b/src/Notepad3.c index 790a04ef4..1323ba300 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -1538,33 +1538,6 @@ LRESULT CALLBACK MainWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) { switch(umsg) { - // Quickly handle painting and sizing messages, found in ScintillaWin.cxx - // Cool idea, don't know if this has any effect... ;-) - case WM_MOVE: - case WM_MOUSEACTIVATE: - case WM_NCHITTEST: - case WM_NCCALCSIZE: - case WM_NCPAINT: - case WM_PAINT: - case WM_ERASEBKGND: - case WM_NCMOUSEMOVE: - case WM_NCLBUTTONDOWN: - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - case WM_TIMER: - case WM_KILLFOCUS: - case WM_ENTERIDLE: - return DefWindowProc(hwnd, umsg, wParam, lParam); - - // never send - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: - return DefWindowProc(hwnd, umsg, wParam, lParam); - - // ------------------------------------------------- - case WM_CREATE: return MsgCreate(hwnd, wParam, lParam); @@ -1719,7 +1692,7 @@ LRESULT CALLBACK MainWndProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) } return DefWindowProc(hwnd, umsg, wParam, lParam); } - return 0; // 0 = swallow message + return 0; } @@ -2166,25 +2139,29 @@ bool SelectExternalToolBar(HWND hwnd) StringCchCopy(szFile, COUNTOF(szFile), s_tchToolbarBitmap); PathRemoveExtension(szFile); StringCchCat(szFile, COUNTOF(szFile), L"Hot.bmp"); - if (PathIsExistingFile(szFile)) { - PathRelativeToApp(szFile, s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), true, true, true); - IniFileSetString(Globals.IniFile, L"Toolbar Images", L"BitmapHot", s_tchToolbarBitmapHot); - } - else { - StringCchCopy(s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), L""); - IniFileDelete(Globals.IniFile, L"Toolbar Images", L"BitmapHot", false); + if (Globals.bCanSaveIniFile) { + if (PathIsExistingFile(szFile)) { + PathRelativeToApp(szFile, s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), true, true, true); + IniFileSetString(Globals.IniFile, L"Toolbar Images", L"BitmapHot", s_tchToolbarBitmapHot); + } + else { + StringCchCopy(s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), L""); + IniFileDelete(Globals.IniFile, L"Toolbar Images", L"BitmapHot", false); + } } StringCchCopy(szFile, COUNTOF(szFile), s_tchToolbarBitmap); PathRemoveExtension(szFile); StringCchCat(szFile, COUNTOF(szFile), L"Disabled.bmp"); - if (PathIsExistingFile(szFile)) { - PathRelativeToApp(szFile, s_tchToolbarBitmapDisabled, COUNTOF(s_tchToolbarBitmapDisabled), true, true, true); - IniFileSetString(Globals.IniFile, L"Toolbar Images", L"BitmapDisabled", s_tchToolbarBitmapDisabled); - } - else { - StringCchCopy(s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), L""); - IniFileDelete(Globals.IniFile, L"Toolbar Images", L"BitmapDisabled", false); + if (Globals.bCanSaveIniFile) { + if (PathIsExistingFile(szFile)) { + PathRelativeToApp(szFile, s_tchToolbarBitmapDisabled, COUNTOF(s_tchToolbarBitmapDisabled), true, true, true); + IniFileSetString(Globals.IniFile, L"Toolbar Images", L"BitmapDisabled", s_tchToolbarBitmapDisabled); + } + else { + StringCchCopy(s_tchToolbarBitmapHot, COUNTOF(s_tchToolbarBitmapHot), L""); + IniFileDelete(Globals.IniFile, L"Toolbar Images", L"BitmapDisabled", false); + } } Settings.ToolBarTheme = 2; return true; @@ -3166,6 +3143,7 @@ LRESULT MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam) HMENU const hmenu = wParam ? (HMENU)wParam : GetMenu(hwnd); if (!hmenu) { return 0; } + bool const sav = Globals.bCanSaveIniFile; bool const ro = SciCall_GetReadOnly(); DocPos const iCurPos = SciCall_GetCurrentPos(); DocLn const iCurLine = SciCall_LineFromPosition(iCurPos); @@ -3456,12 +3434,12 @@ LRESULT MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam) CheckCmd(hmenu, IDM_VIEW_SCROLLPASTEOF, Settings.ScrollPastEOF); CheckCmd(hmenu, IDM_VIEW_SHOW_HYPLNK_CALLTIP, Settings.ShowHypLnkToolTip); - bool b = Flags.bReuseWindow; - CheckCmd(hmenu, IDM_VIEW_REUSEWINDOW, b); - b = Flags.bSingleFileInstance; - CheckCmd(hmenu, IDM_VIEW_SINGLEFILEINSTANCE, b); - b = Flags.bStickyWindowPosition; - CheckCmd(hmenu, IDM_VIEW_STICKYWINPOS, b); + CheckCmd(hmenu, IDM_VIEW_REUSEWINDOW, Flags.bReuseWindow); + EnableCmd(hmenu, IDM_VIEW_REUSEWINDOW, sav); + CheckCmd(hmenu, IDM_VIEW_SINGLEFILEINSTANCE, Flags.bSingleFileInstance); + EnableCmd(hmenu, IDM_VIEW_SINGLEFILEINSTANCE, sav); + CheckCmd(hmenu, IDM_VIEW_STICKYWINPOS, Flags.bStickyWindowPosition); + EnableCmd(hmenu, IDM_VIEW_STICKYWINPOS, sav); CheckCmd(hmenu, IDM_VIEW_ALWAYSONTOP, ((Settings.AlwaysOnTop || s_flagAlwaysOnTop == 2) && s_flagAlwaysOnTop != 1)); CheckCmd(hmenu, IDM_VIEW_MINTOTRAY, Settings.MinimizeToTray); @@ -3486,10 +3464,13 @@ LRESULT MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam) CheckCmd(hmenu, IDM_VIEW_SPLIT_UNDOTYPSEQ_LNBRK, Settings.SplitUndoTypingSeqOnLnBreak); CheckCmd(hmenu, IDM_VIEW_NOSAVERECENT, Settings.SaveRecentFiles); + EnableCmd(hmenu, IDM_VIEW_NOSAVERECENT, sav); CheckCmd(hmenu, IDM_VIEW_NOPRESERVECARET, Settings.PreserveCaretPos); - EnableCmd(hmenu, IDM_VIEW_NOPRESERVECARET, Settings.SaveRecentFiles); + EnableCmd(hmenu, IDM_VIEW_NOPRESERVECARET, Settings.SaveRecentFiles && sav); CheckCmd(hmenu, IDM_VIEW_NOSAVEFINDREPL, Settings.SaveFindReplace); + EnableCmd(hmenu, IDM_VIEW_NOSAVEFINDREPL, sav); CheckCmd(hmenu, IDM_VIEW_SAVEBEFORERUNNINGTOOLS, Settings.SaveBeforeRunningTools); + EnableCmd(hmenu, IDM_VIEW_SAVEBEFORERUNNINGTOOLS, sav); CheckCmd(hmenu, IDM_VIEW_CHANGENOTIFY, Settings.FileWatchingMode); @@ -3699,8 +3680,7 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) InfoBoxLng(MB_ICONWARNING, NULL, IDS_MUI_READONLY_MODIFY, PathFindFileName(Globals.CurrentFile)); } dwFileAttributes = GetFileAttributes(Globals.CurrentFile); - if (dwFileAttributes != INVALID_FILE_ATTRIBUTES) - s_bFileReadOnly = (dwFileAttributes & FILE_ATTRIBUTE_READONLY); + s_bFileReadOnly = (dwFileAttributes == INVALID_FILE_ATTRIBUTES) || (dwFileAttributes & FILE_ATTRIBUTE_READONLY); UpdateToolbar(); } @@ -5375,7 +5355,7 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) case IDM_VIEW_STICKYWINPOS: - { + if (IsCmdEnabled(hwnd, IDM_VIEW_STICKYWINPOS)) { Flags.bStickyWindowPosition = !Flags.bStickyWindowPosition; // toggle if (Flags.bStickyWindowPosition) { InfoBoxLng(MB_OK, L"MsgStickyWinPos", IDS_MUI_STICKYWINPOS); } @@ -5399,23 +5379,27 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) case IDM_VIEW_REUSEWINDOW: - Flags.bReuseWindow = !Flags.bReuseWindow; // reverse - if (Flags.bReuseWindow != DefaultFlags.bReuseWindow) { - IniFileSetBool(Globals.IniFile, Constants.Settings2_Section, L"ReuseWindow", Flags.bReuseWindow); - } - else { - IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"ReuseWindow", false); + if (IsCmdEnabled(hwnd, IDM_VIEW_REUSEWINDOW)) { + Flags.bReuseWindow = !Flags.bReuseWindow; // reverse + if (Flags.bReuseWindow != DefaultFlags.bReuseWindow) { + IniFileSetBool(Globals.IniFile, Constants.Settings2_Section, L"ReuseWindow", Flags.bReuseWindow); + } + else { + IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"ReuseWindow", false); + } } break; case IDM_VIEW_SINGLEFILEINSTANCE: - Flags.bSingleFileInstance = !Flags.bSingleFileInstance; // reverse - if (Flags.bSingleFileInstance != DefaultFlags.bSingleFileInstance) { - IniFileSetInt(Globals.IniFile, Constants.Settings2_Section, L"SingleFileInstance", Flags.bSingleFileInstance); - } - else { - IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"SingleFileInstance", false); + if (IsCmdEnabled(hwnd, IDM_VIEW_SINGLEFILEINSTANCE)) { + Flags.bSingleFileInstance = !Flags.bSingleFileInstance; // reverse + if (Flags.bSingleFileInstance != DefaultFlags.bSingleFileInstance) { + IniFileSetInt(Globals.IniFile, Constants.Settings2_Section, L"SingleFileInstance", Flags.bSingleFileInstance); + } + else { + IniFileDelete(Globals.IniFile, Constants.Settings2_Section, L"SingleFileInstance", false); + } } break; @@ -5543,9 +5527,7 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) if (IsCmdEnabled(hwnd, IDM_VIEW_SAVESETTINGSNOW)) { bool bCreateFailure = false; - if (StrIsEmpty(Globals.IniFile)) { - if (StrIsNotEmpty(Globals.IniFileDefault)) { StringCchCopy(Globals.IniFile, COUNTOF(Globals.IniFile), Globals.IniFileDefault); if (CreateIniFile(Globals.IniFile, NULL)) { @@ -6123,7 +6105,9 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam) WININFO const wi = GetMyWindowPlacement(Globals.hwndMain, NULL); WCHAR tchDefWinPos[80]; StringCchPrintf(tchDefWinPos, COUNTOF(tchDefWinPos), L"%i,%i,%i,%i,%i", wi.x, wi.y, wi.cx, wi.cy, wi.max); - IniFileSetString(Globals.IniFile, Constants.Settings2_Section, L"DefaultWindowPosition", tchDefWinPos); + if (Globals.bCanSaveIniFile) { + IniFileSetString(Globals.IniFile, Constants.Settings2_Section, L"DefaultWindowPosition", tchDefWinPos); + } g_DefWinInfo = GetWinInfoByFlag(-1); // use current win pos as new default } break; @@ -8862,7 +8846,7 @@ void UpdateMarginWidth() void UpdateSaveSettingsCmds() { CheckCmd(Globals.hMainMenu, IDM_VIEW_SAVESETTINGS, Settings.SaveSettings && !Flags.bSettingsFileSoftLocked); - EnableCmd(Globals.hMainMenu, IDM_VIEW_SAVESETTINGS, StrIsNotEmpty(Globals.IniFile) && !Flags.bSettingsFileSoftLocked); + EnableCmd(Globals.hMainMenu, IDM_VIEW_SAVESETTINGS, Globals.bCanSaveIniFile && !Flags.bSettingsFileSoftLocked); EnableCmd(Globals.hMainMenu, IDM_VIEW_SAVESETTINGSNOW, (StrIsNotEmpty(Globals.IniFile) || StrIsNotEmpty(Globals.IniFileDefault)) && !Flags.bSettingsFileSoftLocked); EnableCmd(Globals.hMainMenu, CMD_OPENINIFILE, StrIsNotEmpty(Globals.IniFile) && !Flags.bSettingsFileSoftLocked); } @@ -9334,7 +9318,7 @@ bool FileIO(bool fLoad,LPWSTR pszFileName, } DWORD const dwFileAttributes = GetFileAttributes(pszFileName); - s_bFileReadOnly = ((dwFileAttributes != INVALID_FILE_ATTRIBUTES) && (dwFileAttributes & FILE_ATTRIBUTE_READONLY)); + s_bFileReadOnly = ((dwFileAttributes == INVALID_FILE_ATTRIBUTES) || (dwFileAttributes & FILE_ATTRIBUTE_READONLY)); EndWaitCursor(); @@ -9939,9 +9923,8 @@ bool FileSave(bool bSaveAlways, bool bAsk, bool bSaveAs, bool bSaveCopy, bool bP // Read only... if (!bSaveAs && !bSaveCopy && StrIsNotEmpty(Globals.CurrentFile)) { - DWORD dwFileAttributes = GetFileAttributes(Globals.CurrentFile); - if (dwFileAttributes != INVALID_FILE_ATTRIBUTES) - s_bFileReadOnly = (dwFileAttributes & FILE_ATTRIBUTE_READONLY); + DWORD const dwFileAttributes = GetFileAttributes(Globals.CurrentFile); + s_bFileReadOnly = (dwFileAttributes == INVALID_FILE_ATTRIBUTES) || (dwFileAttributes & FILE_ATTRIBUTE_READONLY); if (s_bFileReadOnly) { INT_PTR const answer = InfoBoxLng(MB_YESNO | MB_ICONWARNING, NULL, IDS_MUI_READONLY_SAVE, PathFindFileName(Globals.CurrentFile)); if ((IDOK == answer) || (IDYES == answer)) { diff --git a/src/Notepad3.vcxproj b/src/Notepad3.vcxproj index d3e005072..b52cac74d 100644 --- a/src/Notepad3.vcxproj +++ b/src/Notepad3.vcxproj @@ -434,7 +434,12 @@ - + + true + true + true + true + @@ -545,7 +550,12 @@ - + + true + true + true + true + diff --git a/src/Styles.c b/src/Styles.c index 899e81d3d..eb7fe8479 100644 --- a/src/Styles.c +++ b/src/Styles.c @@ -174,8 +174,6 @@ static void _FillThemesMenuTable() { Theme_Files[0].rid = IDM_THEMES_DEFAULT; // factory default Theme_Files[1].rid = IDM_THEMES_FILE_ITEM; // NP3.ini settings - // names are filled by Style_InsertThemesMenu() - StringCchCopy(Theme_Files[1].szFilePath, COUNTOF(Theme_Files[1].szFilePath), Globals.IniFile); unsigned iTheme = 1; // Standard @@ -183,6 +181,8 @@ static void _FillThemesMenuTable() // find "themes" sub-dir (side-by-side to Notepad3.ini) if (StrIsNotEmpty(Globals.IniFile)) { StringCchCopy(tchThemeDir, COUNTOF(tchThemeDir), Globals.IniFile); + // names are filled by Style_InsertThemesMenu() + StringCchCopy(Theme_Files[iTheme].szFilePath, COUNTOF(Theme_Files[iTheme].szFilePath), Globals.IniFile); } else if (StrIsNotEmpty(Globals.IniFileDefault)) { StringCchCopy(tchThemeDir, COUNTOF(tchThemeDir), Globals.IniFileDefault); @@ -232,16 +232,6 @@ static void _FillThemesMenuTable() -//============================================================================= -// -// Style_SetIniFile() -// -void Style_SetIniFile(LPCWSTR szIniFile) -{ - StringCchCopy(Theme_Files[1].szFilePath, COUNTOF(Theme_Files[1].szFilePath), szIniFile); - _FillThemesMenuTable(); -} - //============================================================================= // @@ -484,8 +474,6 @@ void Style_Load() _FillThemesMenuTable(); - // get theme name from settings - unsigned iTheme = 1; if (StrIsNotEmpty(Globals.SelectedThemeName)) { for (; iTheme < ThemeItems_CountOf(); ++iTheme) diff --git a/src/Styles.h b/src/Styles.h index 9195de16e..e61a4b5ac 100644 --- a/src/Styles.h +++ b/src/Styles.h @@ -39,7 +39,6 @@ void Style_ToIniSection(bool bForceAll, bool bIsStdIniFile); bool Style_ExportToFile(const WCHAR* szFile, bool bForceAll); unsigned ThemeItems_CountOf(); -void Style_SetIniFile(LPCWSTR szIniFile); bool Style_InsertThemesMenu(HMENU hMenuBar); void Style_DynamicThemesMenuCmd(int cmd); diff --git a/src/TypeDefs.h b/src/TypeDefs.h index 0acb9cfdb..a3a6f647d 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -293,6 +293,7 @@ typedef struct _globals_t HINSTANCE hInstance; HINSTANCE hPrevInst; HINSTANCE hLngResContainer; + bool bCanSaveIniFile; int iAvailLngCount; bool bPrefLngNotAvail; HWND hwndMain;