Compare commits

...

7 Commits

Author SHA1 Message Date
xomx
4b0fc8d316 Improve Notepad++ UAC operations largely
This native implementation of UAC (User Account Control) operations in Notepad++ is designed not only to substitute the deprecated & problematic NppSaveAsAdminPlugin - which interferes with the FlushFileBuffers WINAPI used by Notepad++ - but also to support any future Notepad++ feature which may require elevated privileges.

When a user attempts an operation that fails due to indufficient rights, the system performs only that specific requested action with elevated privileges. After completing it, the elevated Notepad++ instance immediately exits, returning the user to his/her original Notepad++ instance seamlessly, as if nothing unusual occured.

This mechanism is independent of any Notepad++ features such as backup-snapshot or multi-instance mode. All UAC-related operations are executed at the very beginning of the wWinMain function, ensuring they are not affected by mutex handling, or other internal logic.

Importantly, this approach eliminates the need for a separate signed helper executable like NppAdminAcess.exe. Everything is handled within the main Notepad++ project, just as before.

In this commit, the NPP_UAC_SAVE, NPP_UAC_SETFILEATTRIBUTES & NPP_UAC_MOVEFILE are implemented.

Summary of the changes:

added last _dwErrorCode in:
.\PowerEditor\src\MISC\Common\FileInterface.h
.\PowerEditor\src\MISC\Common\FileInterface.cpp

FileManager::saveBuffer adjustment for the NPP_UAC_SAVE_SIGN in:
.\PowerEditor\src\ScintillaComponent\Buffer.cpp

N++ UAC ops signatures definitions & new invokeNppUacOp common func, toggleReadOnlyFlagFromFileAttributes func adjustment for the NPP_UAC_SETFILEATTRIBUTES_SIGN in:
.\PowerEditor\src\MISC\Common\Common.h
.\PowerEditor\src\MISC\Common\Common.cpp

only to fix Notepad_plus::doSave for isEndSessionCritical() in:
.\PowerEditor\src\NppIO.cpp

added getLastFileErrorState() & m_dwLastFileError in:
.\PowerEditor\src\Utf8_16.h
.\PowerEditor\src\Utf8_16.cpp

UAC ops handling at the very start of wWinMain + added new NPP_UAC_ handling nppUacSave and nppUacSetFileAttributes funcs in:
.\PowerEditor\src\winmain.cpp

Fix #886, fix #8655, fix #9561, fix #10302, fix #14990, fix #15008, fix #15137, fix #15323, close #16933
2025-09-02 19:20:59 +02:00
Don HO
dc58d41359 Enhance Column Editor
1. Change the order of GUI items to make the insert mode (dec/hex/oct/bin) more explicit.
2. Reduce the showing time of the warning baloon tip from ~10 seconds to 3.5 seconds.
3. Use ESC keystroke to cancel the warning baloon tip.

ref: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/16931#issuecomment-3236582042

Note that while the baloon tip showing then clicking on the upper-right 'X', the dialog won't be closed. Instead, the baloon tip will be cancel.
Curiously, clicking on the "Cancel" button under the same context closes the dialog.
The reason could be, while the "Cancel" button being clicked, the focus is changed and the system hides the baloon tip. Whereas the click on the upper-right 'X' doesn't make the focus changed, then the system does nothing.
Anyway such behaviour is a bug, but can happen very rarily.

Close #16959
2025-08-31 12:26:19 +02:00
Don Ho
06750919ac Fix column editor egression: insert column with bad parameters
The regression was introduced by: 1a0e8bea75

Ref: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/16931#issuecomment-3236873787

Close #16951
2025-08-29 18:52:55 +02:00
PeterCJ
1a0e8bea75 Use radix for GUI input fields to match the output in Column Editor
Use hex/oct/bin for GUI input fields, to match the output, and allow choosing a-f vs A-F for output.

Fix #16912, close #16931
2025-08-29 13:15:47 +02:00
PeterCJ
dab30de9c6 Fix font size inconsistencies
No fontSize definitions except in Default Style, and Default Style always = 10pt

Fix #16924, close #16928
2025-08-20 14:07:05 +02:00
Alan Kilborn
5933f791c4 Prevent stale search-result from making selection inside a multibyte character
Fix #16879, close #16897
2025-08-17 22:40:35 +02:00
Don HO
4467a4c99e Notepad++ 8.8.5 release 2025-08-14 01:32:08 +02:00
44 changed files with 894 additions and 294 deletions

View File

@ -1,3 +1,8 @@
Notepad++ v8.8.5 regression-fix:
1. Fix "Edit with Notepad++" context menu not being installed correctly regression.
Notepad++ v8.8.4 vulnerability-fixes, bug-fixes & new enhancement:
1. Fix -notabbar & asNotepad.xml stop hiding tabbar regression (from v8.7.9).
@ -14,7 +19,7 @@ Notepad++ v8.8.4 vulnerability-fixes, bug-fixes & new enhancement:
Get more info on
https://notepad-plus-plus.org/downloads/v8.8.4/
https://notepad-plus-plus.org/downloads/v8.8.5/
Included plugins:

View File

@ -1,6 +1,6 @@
echo off
rem This file is part of Notepad++ project
rem Copyright (C)2021 Don HO <don.h@free.fr>
rem Copyright (C)2025 Don HO <don.h@free.fr>
rem
rem This program is free software: you can redistribute it and/or modify
rem it under the terms of the GNU General Public License as published by
@ -34,18 +34,18 @@ If ErrorLevel 1 goto End
%signBinary% ..\binarm64\notepad++.exe
If ErrorLevel 1 goto End
%signBinarySha256% ..\bin\NppShell.x86.dll
If ErrorLevel 1 goto End
%signBinarySha256% ..\bin64\NppShell.msix
If ErrorLevel 1 goto End
%signBinarySha256% ..\bin64\NppShell.x64.dll
If ErrorLevel 1 goto End
%signBinarySha256% ..\binarm64\NppShell.msix
If ErrorLevel 1 goto End
%signBinarySha256% ..\binarm64\NppShell.arm64.dll
If ErrorLevel 1 goto End
REM %signBinarySha256% ..\bin\NppShell.x86.dll
REM If ErrorLevel 1 goto End
REM
REM %signBinarySha256% ..\bin64\NppShell.msix
REM If ErrorLevel 1 goto End
REM %signBinarySha256% ..\bin64\NppShell.x64.dll
REM If ErrorLevel 1 goto End
REM
REM %signBinarySha256% ..\binarm64\NppShell.msix
REM If ErrorLevel 1 goto End
REM %signBinarySha256% ..\binarm64\NppShell.arm64.dll
REM If ErrorLevel 1 goto End
%signBinary% ..\bin\plugins\Config\nppPluginList.dll
If ErrorLevel 1 goto End

View File

@ -1053,7 +1053,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="37A8ED" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="37A8ED" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="E5C138" bgColor="4C4A41" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="E5C138" bgColor="4C4A41" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="4C4A41" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="4C4A41" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1094,6 +1094,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="BDAE9D" bgColor="2A211C" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="BDAE9D" bgColor="2A211C" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="BDAE9D" bgColor="2A211C" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1043,7 +1043,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="FFFFFF" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1084,6 +1084,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="BDAE9D" />
<WidgetStyle name="Document map" styleID="0" fgColor="F8F8F8" bgColor="0C1021" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="0C1021" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="0C1021" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1043,7 +1043,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="A7A7A7" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="A7A7A7" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1084,6 +1084,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="C3BE98" bgColor="1A0F0B" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="C3BE98" bgColor="1A0F0B" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="C3BE98" bgColor="1A0F0B" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1162,7 +1162,7 @@ Installation : Copy this file to "%APPDATA%\Notepad++\themes" and in a portable
<WidgetStyle name="Caret colour" styleID="2069" fgColor="A7A7A7" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="A7A7A7" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="8F8F8F" bgColor="363636" fontName="" fontStyle="0" fontSize="9" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="8F8F8F" bgColor="363636" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="363636" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="363636" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1203,6 +1203,6 @@ Installation : Copy this file to "%APPDATA%\Notepad++\themes" and in a portable
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="C7C7C7" bgColor="2E2E2E" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="C7C7C7" bgColor="2E2E2E" fontName="Source Code Pro" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="C7C7C7" bgColor="2E2E2E" fontName="Source Code Pro" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1822,6 +1822,6 @@ License: GPL2
<WidgetStyle name="Document map" styleID="0" fgColor="000000" bgColor="FFFFFF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Non-printing characters custom color" styleID="0" fgColor="5F5F5F" />
<WidgetStyle name="Global override" styleID="0" fgColor="DCDCCC" bgColor="3F3F3F" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="DCDCCC" bgColor="3F3F3F" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1038,7 +1038,7 @@ https://notepad-plus-plus.org/donate/
</LexerStyles>
<GlobalStyles>
<!-- Attention : Don't modify the name of styleID="0" -->
<WidgetStyle name="Default Style" styleID="32" fgColor="FFFFFF" bgColor="000000" fontName="Courier New" fontStyle="0" fontSize="9" />
<WidgetStyle name="Default Style" styleID="32" fgColor="FFFFFF" bgColor="000000" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Indent guideline style" styleID="37" fgColor="C0C0C0" bgColor="000000" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Brace highlight style" styleID="34" fgColor="00FF00" bgColor="000000" fontName="" fontStyle="1" fontSize="" />
<WidgetStyle name="Bad brace colour" styleID="35" fgColor="FF0000" bgColor="000000" fontName="" fontStyle="1" fontSize="" />
@ -1091,6 +1091,6 @@ https://notepad-plus-plus.org/donate/
<WidgetStyle name="Document map" styleID="0" fgColor="FF8000" bgColor="FFFFFF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Non-printing characters custom color" styleID="0" fgColor="FF8080" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFFFF" bgColor="000000" fontName="Courier New" fontStyle="0" fontSize="9" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFFFF" bgColor="000000" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1062,6 +1062,6 @@ so your enhanced file can be included in Notepad++ future release.
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="000000" bgColor="FFB0FF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FFB0FF" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FFB0FF" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1219,6 +1219,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="B7975D" bgColor="2B0F01" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="B7975D" bgColor="2B0F01" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="B7975D" bgColor="2B0F01" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1048,7 +1048,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="FFFFFF" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1089,6 +1089,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="FFFFFF" bgColor="222C28" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFFFF" bgColor="222C28" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFFFF" bgColor="222C28" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1064,7 +1064,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="F8F8F0" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="F8F8F0" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1105,6 +1105,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="F8F8F2" bgColor="272822" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F2" bgColor="272822" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F2" bgColor="272822" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1219,6 +1219,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="F2C476" bgColor="58693D" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="F2C476" bgColor="58693D" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="F2C476" bgColor="58693D" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1216,6 +1216,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="000000" bgColor="BA9C80" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="000000" bgColor="BA9C80" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="000000" bgColor="BA9C80" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1121,6 +1121,6 @@ Notepad++ Custom Style
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="E0E2E4" bgColor="293134" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="E0E2E4" bgColor="293134" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="E0E2E4" bgColor="293134" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1060,7 +1060,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="8BA7A7" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="8BA7A7" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1101,6 +1101,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="F8F8F8" bgColor="0B161D" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="0B161D" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="0B161D" fontName="DejaVu Sans Mono" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -899,7 +899,7 @@ http://sourceforge.net/donate/index.php?group_id=95717
<WidgetStyle name="Caret colour" styleID="2069" fgColor="FFFFFF" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="FFFFFF" bgColor="1F4661" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="FFFFFF" bgColor="1F4661" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="1F4661" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="1F4661" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -940,6 +940,6 @@ http://sourceforge.net/donate/index.php?group_id=95717
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="FFFFFF" bgColor="112435" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1227,6 +1227,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="808040" />
<WidgetStyle name="Document map" styleID="0" fgColor="657B83" bgColor="FDF6E3" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="657B83" bgColor="FDF6E3" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="657B83" bgColor="FDF6E3" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1619,6 +1619,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="839496" bgColor="002B36" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="839496" bgColor="002B36" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="839496" bgColor="002B36" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1049,7 +1049,7 @@ Credits:
<WidgetStyle name="Caret colour" styleID="2069" fgColor="A7A7A7" />
<WidgetStyle name="Multi-edit carets color" styleID="0" fgColor="A7A7A7" />
<WidgetStyle name="Edge colour" styleID="0" fgColor="EEEEEC" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="8" />
<WidgetStyle name="Line number margin" styleID="33" fgColor="EEEEEC" bgColor="2E3436" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Bookmark margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History margin" styleID="0" bgColor="2E3436" />
<WidgetStyle name="Change History modified" styleID="0" fgColor="FF8000" bgColor="FF8000" />
@ -1090,6 +1090,6 @@ Credits:
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="F8F8F8" bgColor="141414" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="141414" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="F8F8F8" bgColor="141414" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1060,6 +1060,6 @@ http://sourceforge.net/donate/index.php?group_id=95717
<WidgetStyle name="URL hovered" styleID="0" fgColor="FFFFFF" />
<WidgetStyle name="Document map" styleID="0" fgColor="FFFFFF" bgColor="000000" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1789,6 +1789,6 @@ License: GPL2
<WidgetStyle name="URL hovered" styleID="0" fgColor="A3DCA3" />
<WidgetStyle name="Document map" styleID="0" fgColor="000000" bgColor="FFFFFF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="DCDCCC" bgColor="3F3F3F" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="DCDCCC" bgColor="3F3F3F" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1216,6 +1216,6 @@ Installation:
<WidgetStyle name="URL hovered" styleID="0" fgColor="808040" />
<WidgetStyle name="Document map" styleID="0" fgColor="5F5F00" bgColor="D7D7AF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="808080" />
<WidgetStyle name="Global override" styleID="0" fgColor="5F5F00" bgColor="D7D7AF" fontName="Consolas" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="5F5F00" bgColor="D7D7AF" fontName="Consolas" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -1537,7 +1537,25 @@ bool toggleReadOnlyFlagFromFileAttributes(const wchar_t* fileFullPath, bool& isC
}
else
{
// probably the ERROR_ACCESS_DENIED (5) (TODO: UAC-prompt candidate)
if (::GetLastError() == ERROR_ACCESS_DENIED)
{
// try to set elevated
// (notepad++.exe #UAC-SETFILEATTRIBUTES# attrib_flags_number_str dest_file_path)
wstring strCmdLineParams = NPP_UAC_SETFILEATTRIBUTES_SIGN;
strCmdLineParams += L" \"" + to_wstring(dwFileAttribs) + L"\" \"";
strCmdLineParams += fileFullPath;
strCmdLineParams += L"\"";
DWORD dwNppUacOpError = invokeNppUacOp(strCmdLineParams);
if (dwNppUacOpError == NO_ERROR)
{
isChangedToReadOnly = (dwFileAttribs & FILE_ATTRIBUTE_READONLY) != 0;
return true;
}
else
{
::SetLastError(dwNppUacOpError); // set that as our current thread one for a possible reporting later
}
}
return false;
}
}
@ -2154,3 +2172,40 @@ void ControlInfoTip::hide()
}
#pragma warning(default:4996)
DWORD invokeNppUacOp(std::wstring& strCmdLineParams)
{
if ((strCmdLineParams.length() == 0) || (strCmdLineParams.length() > (USHRT_MAX / sizeof(WCHAR))))
{
// no cmdline or it exceeds the current max WinOS 32767 WCHARs
return ERROR_INVALID_PARAMETER;
}
wchar_t wszNppFullPath[MAX_PATH]{};
::SetLastError(NO_ERROR);
if (!::GetModuleFileName(NULL, wszNppFullPath, MAX_PATH) || (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
return ::GetLastError();
}
SHELLEXECUTEINFOW sei{};
sei.cbSize = sizeof(SHELLEXECUTEINFOW);
sei.lpVerb = L"runas"; // UAC prompt
sei.nShow = SW_SHOWNORMAL;
sei.fMask = SEE_MASK_NOCLOSEPROCESS; // sei.hProcess member receives the launched process handle
sei.lpFile = wszNppFullPath;
sei.lpParameters = strCmdLineParams.c_str();
if (!::ShellExecuteExW(&sei))
return ::GetLastError();
// wait for the elevated Notepad++ process to finish
DWORD dwError = NO_ERROR;
if (sei.hProcess) // beware - do not check here for the INVALID_HANDLE_VALUE (valid GetCurrentProcess() pseudohandle)
{
::WaitForSingleObject(sei.hProcess, INFINITE);
::GetExitCodeProcess(sei.hProcess, &dwError);
::CloseHandle(sei.hProcess);
}
return dwError;
}

View File

@ -331,3 +331,9 @@ private:
ControlInfoTip(const ControlInfoTip&) = delete;
ControlInfoTip& operator=(const ControlInfoTip&) = delete;
};
#define NPP_UAC_SAVE_SIGN L"#UAC-SAVE#"
#define NPP_UAC_SETFILEATTRIBUTES_SIGN L"#UAC-SETFILEATTRIBUTES#"
#define NPP_UAC_MOVEFILE_SIGN L"#UAC-MOVEFILE#"
DWORD invokeNppUacOp(std::wstring& strCmdLineParams);

View File

@ -54,7 +54,10 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname)
{
bool isFromNetwork = PathIsNetworkPath(fname);
if (isFromNetwork && isTimeoutReached) // The file doesn't exist, and the file is a network file, plus the network problem has been detected due to timeout
return; // In this case, we don't call createFile to prevent hanging
{
_dwErrorCode = ERROR_FILE_NOT_FOUND; // store
return; // In this case, we don't call createFile to prevent hanging
}
}
_hFile = ::CreateFileW(fname, _accessParam, _shareParam, NULL, dispParam, _attribParam, NULL);
@ -68,6 +71,9 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname)
_hFile = ::CreateFileW(fname, _accessParam, _shareParam, NULL, dispParam, _attribParam, NULL);
}
if (_hFile == INVALID_HANDLE_VALUE)
_dwErrorCode = ::GetLastError(); // store
if (fileExists && (dispParam == CREATE_ALWAYS) && (_hFile != INVALID_HANDLE_VALUE))
{
// restore back the original creation date & attributes
@ -91,7 +97,7 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname)
else
{
msg += " failed to open, CreateFileW ErrorCode: ";
msg += std::to_string(::GetLastError());
msg += std::to_string(_dwErrorCode);
}
writeLog(nppIssueLog.c_str(), msg.c_str());
}
@ -100,11 +106,13 @@ Win32_IO_File::Win32_IO_File(const wchar_t *fname)
void Win32_IO_File::close()
{
_dwErrorCode = NO_ERROR; // reset
if (isOpened())
{
NppParameters& nppParam = NppParameters::getInstance();
DWORD flushError = NOERROR;
DWORD flushError = NO_ERROR;
if (_written)
{
if (!::FlushFileBuffers(_hFile))
@ -159,7 +167,14 @@ Please try using another storage and also check if your saved data is not corrup
}
}
}
::CloseHandle(_hFile);
_dwErrorCode = flushError; // store possible flushing error 1st
if (!::CloseHandle(_hFile))
{
if (!flushError)
_dwErrorCode = ::GetLastError(); // store
}
_hFile = INVALID_HANDLE_VALUE;
@ -194,6 +209,8 @@ Please try using another storage and also check if your saved data is not corrup
bool Win32_IO_File::write(const void *wbuf, size_t buf_size)
{
_dwErrorCode = NO_ERROR; // reset
if (!isOpened() || (wbuf == nullptr))
return false;
@ -203,6 +220,7 @@ bool Win32_IO_File::write(const void *wbuf, size_t buf_size)
size_t bytes_left_to_write = buf_size;
BOOL success = FALSE;
DWORD writeError = NO_ERROR; // use also a local var here to be 100% thread-safe
do
{
@ -219,6 +237,10 @@ bool Win32_IO_File::write(const void *wbuf, size_t buf_size)
bytes_left_to_write -= static_cast<size_t>(bytes_written);
total_bytes_written += static_cast<size_t>(bytes_written);
}
else
{
writeError = ::GetLastError();
}
} while (success && bytes_left_to_write);
NppParameters& nppParam = NppParameters::getInstance();
@ -234,11 +256,11 @@ bool Win32_IO_File::write(const void *wbuf, size_t buf_size)
std::string msg = _path;
msg += " written failed: ";
std::wstring lastErrorMsg = GetLastErrorAsString(::GetLastError());
std::wstring lastErrorMsg = GetLastErrorAsString(writeError);
msg += wstring2string(lastErrorMsg, CP_UTF8);
writeLog(nppIssueLog.c_str(), msg.c_str());
}
_dwErrorCode = writeError; // store
return false;
}
else

View File

@ -48,6 +48,10 @@ public:
return write(str.c_str(), str.length());
};
DWORD getLastErrorCode() {
return _dwErrorCode;
};
private:
HANDLE _hFile {INVALID_HANDLE_VALUE};
bool _written {false};
@ -56,4 +60,6 @@ private:
const DWORD _accessParam { GENERIC_READ | GENERIC_WRITE };
const DWORD _shareParam { FILE_SHARE_READ | FILE_SHARE_WRITE };
const DWORD _attribParam { FILE_ATTRIBUTE_NORMAL };
DWORD _dwErrorCode{ NO_ERROR };
};

View File

@ -683,8 +683,11 @@ bool Notepad_plus::doSave(BufferID id, const wchar_t * filename, bool isCopy)
}
else if (res == SavingStatus::SaveWritingFailed)
{
wstring errorMessage = GetLastErrorAsString(GetLastError());
::MessageBox(_pPublicInterface->getHSelf(), errorMessage.c_str(), L"Save failed", MB_OK | MB_ICONWARNING);
if (!(NppParameters::getInstance()).isEndSessionCritical()) // can we report to the user?
{
wstring errorMessage = GetLastErrorAsString(::GetLastError());
::MessageBox(_pPublicInterface->getHSelf(), errorMessage.c_str(), L"Save failed", MB_OK | MB_ICONWARNING);
}
}
else if (res == SavingStatus::SaveOpenFailed)
{

View File

@ -2649,13 +2649,15 @@ void NppParameters::feedColumnEditorParameters(TiXmlNode *node)
if (strVal)
{
if (lstrcmp(strVal, L"hex") == 0)
_columnEditParam._formatChoice = 1;
_columnEditParam._formatChoice = BASE_16;
else if (lstrcmp(strVal, L"hexuc") == 0)
_columnEditParam._formatChoice = BASE_16_UPPERCASE;
else if (lstrcmp(strVal, L"oct") == 0)
_columnEditParam._formatChoice = 2;
_columnEditParam._formatChoice = BASE_08;
else if (lstrcmp(strVal, L"bin") == 0)
_columnEditParam._formatChoice = 3;
_columnEditParam._formatChoice = BASE_02;
else // "dec"
_columnEditParam._formatChoice = 0;
_columnEditParam._formatChoice = BASE_10;
}
strVal = (childNode->ToElement())->Attribute(L"leadingChoice");
@ -4370,11 +4372,13 @@ bool NppParameters::writeColumnEditorSettings() const
(numberNode.ToElement())->SetAttribute(L"increase", _columnEditParam._increaseNum);
(numberNode.ToElement())->SetAttribute(L"repeat", _columnEditParam._repeatNum);
wstring format = L"dec";
if (_columnEditParam._formatChoice == 1)
if (_columnEditParam._formatChoice == BASE_16)
format = L"hex";
else if (_columnEditParam._formatChoice == 2)
else if (_columnEditParam._formatChoice == BASE_16_UPPERCASE)
format = L"hexuc";
else if (_columnEditParam._formatChoice == BASE_08)
format = L"oct";
else if (_columnEditParam._formatChoice == 3)
else if (_columnEditParam._formatChoice == BASE_02)
format = L"bin";
(numberNode.ToElement())->SetAttribute(L"formatChoice", format);
wstring leading = L"none";

View File

@ -1320,7 +1320,7 @@ struct ColumnEditorParam final
int _initialNum = -1;
int _increaseNum = -1;
int _repeatNum = -1;
int _formatChoice = 0; // 0:Dec 1:Hex 2:Oct 3:Bin
int _formatChoice = 0; // 0:Dec 1:Hex 2:Oct 3:Bin 4:HexUpperCase
leadingChoice _leadingChoice = noneLeading;
};

View File

@ -65,6 +65,15 @@ namespace // anonymous
return defvalue; // fallback unknown
}
// local helper to get the current system time in milliseconds since Unix epoch (January 1, 1970)
ULONGLONG GetUnixSysTimeInMilliseconds()
{
FILETIME ft;
::GetSystemTimeAsFileTime(&ft); // 100-nanosecond intervals since January 1, 1601 (UTC)
ULONGLONG ullTime = (((ULONGLONG)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
const ULONGLONG EPOCH_DIFF = 116444736000000000ULL; // difference between Jan 1, 1601 and Jan 1, 1970 in 100-ns intervals
return (ullTime - EPOCH_DIFF) / 10000; // subtract the diff and convert to milliseconds
}
} // anonymous namespace
using namespace std;
@ -1093,13 +1102,31 @@ bool FileManager::deleteFile(BufferID id)
}
bool FileManager::moveFile(BufferID id, const wchar_t * newFileName)
bool FileManager::moveFile(BufferID id, const wchar_t* newFileName)
{
Buffer* buf = getBufferByID(id);
const wchar_t *fileNamePath = buf->getFullPathName();
if (::MoveFileEx(fileNamePath, newFileName, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) == 0)
if (id == BUFFER_INVALID)
return false;
Buffer* buf = getBufferByID(id);
const wchar_t* fileNamePath = buf->getFullPathName();
if (!::MoveFileExW(fileNamePath, newFileName, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH))
{
if (::GetLastError() != ERROR_ACCESS_DENIED)
return false;
// ERROR_ACCESS_DENIED, try to move elevated
// (notepad++.exe #UAC-MOVEFILE# original_file_path new_file_path)
wstring strCmdLineParams = NPP_UAC_MOVEFILE_SIGN;
strCmdLineParams += L" \"";
strCmdLineParams += fileNamePath;
strCmdLineParams += L"\" \"";
strCmdLineParams += newFileName;
strCmdLineParams += L"\"";
DWORD dwNppUacOpError = invokeNppUacOp(strCmdLineParams);
if (dwNppUacOpError != NO_ERROR)
return false;
}
buf->setFileName(newFileName);
return true;
}
@ -1323,7 +1350,7 @@ SavingStatus FileManager::saveBuffer(BufferID id, const wchar_t* filename, bool
Buffer* buffer = getBufferByID(id);
bool isHiddenOrSys = false;
wchar_t fullpath[MAX_PATH] = { 0 };
wchar_t fullpath[MAX_PATH]{};
if (isWin32NamespacePrefixedFileName(filename))
{
// use directly the raw file name, skip the GetFullPathName WINAPI
@ -1338,7 +1365,7 @@ SavingStatus FileManager::saveBuffer(BufferID id, const wchar_t* filename, bool
}
}
wchar_t dirDest[MAX_PATH];
wchar_t dirDest[MAX_PATH]{};
wcscpy_s(dirDest, MAX_PATH, fullpath);
::PathRemoveFileSpecW(dirDest);
@ -1379,105 +1406,137 @@ SavingStatus FileManager::saveBuffer(BufferID id, const wchar_t* filename, bool
int encoding = buffer->getEncoding();
if (UnicodeConvertor.openFile(fullpath))
wstring strTempFile = L"";
if (!UnicodeConvertor.openFile(fullpath))
{
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, buffer->_doc); //generate new document
if (NppParameters::getInstance().isEndSessionCritical())
return SavingStatus::SaveOpenFailed; // cannot continue to the UAC-prompt at the Windows logoff/reboot/shutdown time
size_t lengthDoc = _pscratchTilla->getCurrentDocLen();
char* buf = (char*)_pscratchTilla->execute(SCI_GETCHARACTERPOINTER); //to get characters directly from Scintilla buffer
bool isWrittenSuccessful = false;
if (UnicodeConvertor.getLastFileErrorState() != ERROR_ACCESS_DENIED)
return SavingStatus::SaveOpenFailed; // cannot be solved by the UAC-prompt
if (encoding == -1) //no special encoding; can be handled directly by Utf8_16_Write
{
isWrittenSuccessful = UnicodeConvertor.writeFile(buf, lengthDoc);
if (lengthDoc == 0)
isWrittenSuccessful = true;
}
else
{
if (lengthDoc == 0)
{
isWrittenSuccessful = UnicodeConvertor.writeFile(buf, 0);
}
else
{
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
size_t grabSize = 0;
for (size_t i = 0; i < lengthDoc; i += grabSize)
{
grabSize = lengthDoc - i;
if (grabSize > blockSize)
grabSize = blockSize;
// ERROR_ACCESS_DENIED, swap to temporary file copy for the UAC elevation way
int newDataLen = 0;
int incompleteMultibyteChar = 0;
const char* newData = wmc.encode(SC_CP_UTF8, encoding, buf + i, static_cast<int>(grabSize), &newDataLen, &incompleteMultibyteChar);
grabSize -= incompleteMultibyteChar;
isWrittenSuccessful = UnicodeConvertor.writeFile(newData, newDataLen);
}
}
}
wchar_t wszBuf[MAX_PATH + 1]{};
if (::GetTempPath(MAX_PATH, wszBuf) == 0)
return SavingStatus::SaveOpenFailed; // cannot continue
UnicodeConvertor.closeFile();
strTempFile = wszBuf;
strTempFile += L"npp-" + std::to_wstring(GetUnixSysTimeInMilliseconds()) + L".tmp"; // make unique temporary filename
if (!UnicodeConvertor.openFile(strTempFile.c_str()))
return SavingStatus::SaveOpenFailed; // cannot continue, weird
}
// Error, we didn't write the entire document to disk.
if (!isWrittenSuccessful)
{
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
return SavingStatus::SaveWritingFailed;
}
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, buffer->_doc); //generate new document
if (isHiddenOrSys)
::SetFileAttributes(fullpath, attributes.dwFileAttributes);
size_t lengthDoc = _pscratchTilla->getCurrentDocLen();
char* buf = (char*)_pscratchTilla->execute(SCI_GETCHARACTERPOINTER); //to get characters directly from Scintilla buffer
bool isWrittenSuccessful = false;
if (isCopy) // "Save a Copy As..." command
{
unsigned long MODEVENTMASK_ON = NppParameters::getInstance().getScintillaModEventMask();
_pscratchTilla->execute(SCI_SETMODEVENTMASK, MODEVENTMASK_OFF);
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
_pscratchTilla->execute(SCI_SETMODEVENTMASK, MODEVENTMASK_ON);
return SavingStatus::SaveOK; //all done - we don't change the current buffer's path to "fullpath", since it's "Save a Copy As..." action.
}
buffer->setFileName(fullpath);
// if not a large file and language is normal text (not defined)
// we may try determine its language from its content
if (!buffer->isLargeFile() && buffer->_lang == L_TEXT)
{
LangType detectedLang = detectLanguageFromTextBeginning((unsigned char*)buf, lengthDoc);
// if a language is detected from the content
if (detectedLang != L_TEXT)
{
buffer->_lang = detectedLang;
buffer->doNotify(BufferChangeFilename | BufferChangeTimestamp | BufferChangeLanguage);
}
}
buffer->setDirty(false);
buffer->setUnsync(false);
buffer->setSavePointDirty(false);
buffer->setStatus(DOC_REGULAR);
buffer->checkFileState();
_pscratchTilla->execute(SCI_SETSAVEPOINT);
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
wstring backupFilePath = buffer->getBackupFileName();
if (!backupFilePath.empty())
{
// delete backup file
buffer->setBackupFileName(wstring());
::DeleteFile(backupFilePath.c_str());
}
return SavingStatus::SaveOK;
if (encoding == -1) //no special encoding; can be handled directly by Utf8_16_Write
{
isWrittenSuccessful = UnicodeConvertor.writeFile(buf, lengthDoc);
if (lengthDoc == 0)
isWrittenSuccessful = true;
}
else
{
return SavingStatus::SaveOpenFailed;
if (lengthDoc == 0)
{
isWrittenSuccessful = UnicodeConvertor.writeFile(buf, 0);
}
else
{
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
size_t grabSize = 0;
for (size_t i = 0; i < lengthDoc; i += grabSize)
{
grabSize = lengthDoc - i;
if (grabSize > blockSize)
grabSize = blockSize;
int newDataLen = 0;
int incompleteMultibyteChar = 0;
const char* newData = wmc.encode(SC_CP_UTF8, encoding, buf + i, static_cast<int>(grabSize), &newDataLen, &incompleteMultibyteChar);
grabSize -= incompleteMultibyteChar;
isWrittenSuccessful = UnicodeConvertor.writeFile(newData, newDataLen);
}
}
}
UnicodeConvertor.closeFile();
if (isHiddenOrSys && strTempFile.empty())
::SetFileAttributes(fullpath, attributes.dwFileAttributes);
// Error, we didn't write the entire document to disk.
if (!isWrittenSuccessful)
{
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
if (!strTempFile.empty())
::DeleteFileW(strTempFile.c_str());
return SavingStatus::SaveWritingFailed;
}
if (!strTempFile.empty())
{
// elevated saving/overwriting of the original file by the help of the tempfile
// (notepad++.exe #UAC-SAVE# temp_file_path dest_file_path)
wstring strCmdLineParams = NPP_UAC_SAVE_SIGN;
strCmdLineParams += L" \"" + strTempFile + L"\" \"";
strCmdLineParams += fullpath;
strCmdLineParams += L"\"";
DWORD dwNppUacOpError = invokeNppUacOp(strCmdLineParams);
if (dwNppUacOpError != NO_ERROR)
{
::DeleteFileW(strTempFile.c_str()); // ensure no failed op remnant
::SetLastError(dwNppUacOpError); // set that as our current thread one for reporting later
return SavingStatus::SaveWritingFailed;
}
}
if (isCopy) // "Save a Copy As..." command
{
unsigned long MODEVENTMASK_ON = NppParameters::getInstance().getScintillaModEventMask();
_pscratchTilla->execute(SCI_SETMODEVENTMASK, MODEVENTMASK_OFF);
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
_pscratchTilla->execute(SCI_SETMODEVENTMASK, MODEVENTMASK_ON);
return SavingStatus::SaveOK; //all done - we don't change the current buffer's path to "fullpath", since it's "Save a Copy As..." action.
}
buffer->setFileName(fullpath);
// if not a large file and language is normal text (not defined)
// we may try determine its language from its content
if (!buffer->isLargeFile() && buffer->_lang == L_TEXT)
{
LangType detectedLang = detectLanguageFromTextBeginning((unsigned char*)buf, lengthDoc);
// if a language is detected from the content
if (detectedLang != L_TEXT)
{
buffer->_lang = detectedLang;
buffer->doNotify(BufferChangeFilename | BufferChangeTimestamp | BufferChangeLanguage);
}
}
buffer->setDirty(false);
buffer->setUnsync(false);
buffer->setSavePointDirty(false);
buffer->setStatus(DOC_REGULAR);
buffer->checkFileState();
_pscratchTilla->execute(SCI_SETSAVEPOINT);
_pscratchTilla->execute(SCI_SETDOCPOINTER, 0, _scratchDocDefault);
wstring backupFilePath = buffer->getBackupFileName();
if (!backupFilePath.empty())
{
// delete backup file
buffer->setBackupFileName(wstring());
::DeleteFile(backupFilePath.c_str());
}
return SavingStatus::SaveOK;
}
size_t FileManager::nextUntitledNewNumber() const

View File

@ -248,6 +248,20 @@ void Searching::displaySectionCentered(size_t posStart, size_t posEnd, Scintilla
// Adjust so that we see the entire match; primarily horizontally
pEditView->execute(SCI_SCROLLRANGE, posStart, posEnd);
// make sure won't start/end the selection in the middle of a multibyte character,
// or in between a CR/LF pair for Windows files
// (needed for stale search-results where user has made doc edits after the search)
if (posStart > 0)
{
posStart = pEditView->execute(SCI_POSITIONBEFORE, posStart);
posStart = pEditView->execute(SCI_POSITIONAFTER, posStart);
}
if (posEnd > 0)
{
posEnd = pEditView->execute(SCI_POSITIONBEFORE, posEnd);
posEnd = pEditView->execute(SCI_POSITIONAFTER, posEnd);
}
// Move cursor to end of result and select result
pEditView->execute(SCI_GOTOPOS, posEnd);
pEditView->execute(SCI_SETANCHOR, posStart);

View File

@ -3919,15 +3919,19 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, size_t initial, siz
//Defined in ScintillaEditView.h :
//const UCHAR MASK_FORMAT = 0x03;
UCHAR f = format & MASK_FORMAT;
bool useUppercase = false;
int base = 10;
if (f == BASE_16)
if (format == BASE_16)
base = 16;
else if (f == BASE_08)
else if (format == BASE_08)
base = 8;
else if (f == BASE_02)
else if (format == BASE_02)
base = 2;
else if (format == BASE_16_UPPERCASE)
{
base = 16;
useUppercase = true;
}
const int stringSize = 512;
char str[stringSize];
@ -3966,7 +3970,7 @@ void ScintillaEditView::columnReplace(ColumnModeInfos & cmi, size_t initial, siz
cmi[i]._selLpos += totalDiff;
cmi[i]._selRpos += totalDiff;
variedFormatNumber2String<char>(str, stringSize, numbers.at(i), base, kib, lead);
variedFormatNumber2String<char>(str, stringSize, numbers.at(i), base, useUppercase, kib, lead);
const bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0;
if (hasVirtualSpc) // if virtual space is present, then insert space

View File

@ -109,12 +109,7 @@ enum TextCase : UCHAR
RANDOMCASE
};
const UCHAR MASK_FORMAT = 0x03;
const UCHAR BASE_10 = 0x00; // Dec
const UCHAR BASE_16 = 0x01; // Hex
const UCHAR BASE_08 = 0x02; // Oct
const UCHAR BASE_02 = 0x03; // Bin
enum : UCHAR { BASE_10 = 0, BASE_16 = 1, BASE_08 = 2, BASE_02 = 3, BASE_16_UPPERCASE = 4 };
const int MARK_BOOKMARK = 20;
const int MARK_HIDELINESBEGIN = 19;
@ -252,7 +247,7 @@ const std::vector<std::vector<const char*>> g_nonPrintingChars =
size_t getNbDigits(size_t aNum, size_t base);
template<typename T>
T* variedFormatNumber2String(T* str, size_t strLen, size_t number, size_t base, size_t nbDigits, ColumnEditorParam::leadingChoice lead)
T* variedFormatNumber2String(T* str, size_t strLen, size_t number, size_t base, bool useUpper, size_t nbDigits, ColumnEditorParam::leadingChoice lead)
{
if (nbDigits == 0 || nbDigits >= strLen) return NULL;
@ -293,6 +288,8 @@ T* variedFormatNumber2String(T* str, size_t strLen, size_t number, size_t base,
else if (base == 16)
{
std::stringstream stream;
if (useUpper)
stream << std::uppercase;
stream << std::hex << number;
numberStr = stream.str();
}

View File

@ -42,21 +42,23 @@ void ColumnEditorDlg::display(bool toShow) const
intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
{
static HBRUSH hRedBrush = nullptr;
static int whichFlashRed = 0;
constexpr COLORREF rgbRed = RGB(255, 0, 0);
static HWND hCurrentBalloonTip = nullptr;
switch (message)
{
case WM_INITDIALOG :
{
hRedBrush = CreateSolidBrush(rgbRed); // Create red brush once
ColumnEditorParam colEditParam = NppParameters::getInstance()._columnEditParam;
NppDarkMode::autoSubclassAndThemeChildControls(_hSelf);
::SetDlgItemText(_hSelf, IDC_COL_TEXT_EDIT, colEditParam._insertedTextContent.c_str());
if (colEditParam._initialNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, colEditParam._initialNum, FALSE);
if (colEditParam._increaseNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, colEditParam._increaseNum, FALSE);
if (colEditParam._repeatNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, colEditParam._repeatNum, FALSE);
setNumericFields(colEditParam);
::SendDlgItemMessage(_hSelf, IDC_COL_LEADING_COMBO, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"None"));
::SendDlgItemMessage(_hSelf, IDC_COL_LEADING_COMBO, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"Zeros"));
@ -72,15 +74,22 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
::SendMessage(::GetDlgItem(_hSelf, IDC_COL_LEADING_COMBO), CB_SETCURSEL, curSel, 0);
int format = IDC_COL_DEC_RADIO;
if (colEditParam._formatChoice == 1)
if ((colEditParam._formatChoice == BASE_16) || (colEditParam._formatChoice == BASE_16_UPPERCASE)) // either BASE_16 or BASE_16_UC
format = IDC_COL_HEX_RADIO;
else if (colEditParam._formatChoice == 2)
else if (colEditParam._formatChoice == BASE_08)
format = IDC_COL_OCT_RADIO;
else if (colEditParam._formatChoice == 3)
else if (colEditParam._formatChoice == BASE_02)
format = IDC_COL_BIN_RADIO;
::SendDlgItemMessage(_hSelf, format, BM_SETCHECK, TRUE, 0);
// populate the Hex-Case dropdown and activate correct case
::SendDlgItemMessage(_hSelf, IDC_COL_HEXUC_COMBO, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"a-f"));
::SendDlgItemMessage(_hSelf, IDC_COL_HEXUC_COMBO, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(L"A-F"));
UCHAR uc = (colEditParam._formatChoice == BASE_16_UPPERCASE) ? 1 : 0;
::SendDlgItemMessage(_hSelf, IDC_COL_HEXUC_COMBO, CB_SETCURSEL, uc, 0); // activate correct case
EnableWindow(GetDlgItem(_hSelf, IDC_COL_HEXUC_COMBO), format == IDC_COL_HEX_RADIO); // enable combobox only if hex is chosen
switchTo(colEditParam._mainChoice);
goToCenter(SWP_SHOWWINDOW | SWP_NOSIZE);
@ -89,6 +98,12 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
case WM_CTLCOLOREDIT:
{
int id = GetDlgCtrlID(reinterpret_cast<HWND>(lParam));
if (id == whichFlashRed)
{
SetBkColor((HDC)wParam, rgbRed);
return (LRESULT)hRedBrush;
}
return NppDarkMode::onCtlColorCtrl(reinterpret_cast<HDC>(wParam));
}
@ -152,25 +167,35 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
{
switch (LOWORD(wParam))
{
case IDCANCEL : // Close
display(false);
return TRUE;
case IDCANCEL: // in case of ESC keystroke
{
if (hCurrentBalloonTip && IsWindowVisible(hCurrentBalloonTip)) // if current baloon tip shown, just hide it
{
ShowWindow(hCurrentBalloonTip, SW_HIDE);
}
else // if current baloon tip doesn't show, we hide Column Editor dialog
{
display(false);
}
case IDOK :
{
return TRUE;
}
case IDOK:
{
(*_ppEditView)->execute(SCI_BEGINUNDOACTION);
constexpr int stringSize = 1024;
wchar_t str[stringSize]{};
bool isTextMode = (BST_CHECKED == ::SendDlgItemMessage(_hSelf, IDC_COL_TEXT_RADIO, BM_GETCHECK, 0, 0));
if (isTextMode)
{
::SendDlgItemMessage(_hSelf, IDC_COL_TEXT_EDIT, WM_GETTEXT, stringSize, reinterpret_cast<LPARAM>(str));
display(false);
if ((*_ppEditView)->execute(SCI_SELECTIONISRECTANGLE) || (*_ppEditView)->execute(SCI_GETSELECTIONS) > 1)
{
ColumnModeInfos colInfos = (*_ppEditView)->getColumnModeSelectInfo();
@ -188,9 +213,9 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
auto endLine = (*_ppEditView)->execute(SCI_LINEFROMPOSITION, endPos);
constexpr int lineAllocatedLen = 1024;
wchar_t *line = new wchar_t[lineAllocatedLen];
wchar_t* line = new wchar_t[lineAllocatedLen];
for (size_t i = cursorLine ; i <= static_cast<size_t>(endLine); ++i)
for (size_t i = cursorLine; i <= static_cast<size_t>(endLine); ++i)
{
auto lineBegin = (*_ppEditView)->execute(SCI_POSITIONFROMLINE, i);
auto lineEnd = (*_ppEditView)->execute(SCI_GETLINEENDPOSITION, i);
@ -200,7 +225,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
if (lineLen > lineAllocatedLen)
{
delete [] line;
delete[] line;
line = new wchar_t[lineLen];
}
(*_ppEditView)->getGenericText(line, lineLen, lineBegin, lineEnd);
@ -218,19 +243,43 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
auto posRelative2Start = posAbs2Start - lineBegin;
if (posRelative2Start > static_cast<long long>(s2r.length()))
posRelative2Start = s2r.length();
s2r.insert(posRelative2Start, str);
}
(*_ppEditView)->replaceTarget(s2r.c_str(), lineBegin, lineEnd);
}
delete [] line;
delete[] line;
}
}
else
{
size_t initialNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, NULL, TRUE);
size_t increaseNumber = ::GetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, NULL, TRUE);
size_t repeat = ::GetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, NULL, TRUE);
ColumnEditorParam colEditParam = NppParameters::getInstance()._columnEditParam;
::GetDlgItemText(_hSelf, IDC_COL_INITNUM_EDIT, str, stringSize);
int initialNumber = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (initialNumber == -1)
{
whichFlashRed = sendValidationErrorMessage(IDC_COL_INITNUM_EDIT, colEditParam._formatChoice, str);
return TRUE;
}
::GetDlgItemText(_hSelf, IDC_COL_INCREASENUM_EDIT, str, stringSize);
int increaseNumber = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (increaseNumber == -1)
{
whichFlashRed = sendValidationErrorMessage(IDC_COL_INCREASENUM_EDIT, colEditParam._formatChoice, str);
return TRUE;
}
::GetDlgItemText(_hSelf, IDC_COL_REPEATNUM_EDIT, str, stringSize);
int repeat = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (repeat == -1)
{
whichFlashRed = sendValidationErrorMessage(IDC_COL_REPEATNUM_EDIT, colEditParam._formatChoice, str);
return TRUE;
}
if (repeat == 0)
{
repeat = 1; // Without this we might get an infinite loop while calculating the set "numbers" below.
@ -268,7 +317,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
const size_t kiMaxSize = 1 + (size_t)endLine - (size_t)cursorLine;
while (numbers.size() < kiMaxSize)
{
for (size_t i = 0; i < repeat; i++)
for (int i = 0; i < repeat; i++)
{
numbers.push_back(curNumber);
@ -279,17 +328,21 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
}
constexpr int lineAllocatedLen = 1024;
wchar_t *line = new wchar_t[lineAllocatedLen];
UCHAR f = format & MASK_FORMAT;
wchar_t* line = new wchar_t[lineAllocatedLen];
size_t base = 10;
if (f == BASE_16)
bool useUppercase = false;
if (format == BASE_16)
base = 16;
else if (f == BASE_08)
else if (format == BASE_08)
base = 8;
else if (f == BASE_02)
else if (format == BASE_02)
base = 2;
else if (format == BASE_16_UPPERCASE)
{
base = 16;
useUppercase = true;
}
size_t endNumber = *numbers.rbegin();
size_t nbEnd = getNbDigits(endNumber, base);
@ -297,7 +350,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
size_t nb = std::max<size_t>(nbInit, nbEnd);
for (size_t i = cursorLine ; i <= size_t(endLine) ; ++i)
for (size_t i = cursorLine; i <= size_t(endLine); ++i)
{
auto lineBegin = (*_ppEditView)->execute(SCI_POSITIONFROMLINE, i);
auto lineEnd = (*_ppEditView)->execute(SCI_GETLINEENDPOSITION, i);
@ -307,7 +360,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
if (lineLen > lineAllocatedLen)
{
delete [] line;
delete[] line;
line = new wchar_t[lineLen];
}
(*_ppEditView)->getGenericText(line, lineLen, lineBegin, lineEnd);
@ -317,7 +370,7 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
//
// Calcule wstring
//
variedFormatNumber2String<wchar_t>(str, stringSize, numbers.at(i - cursorLine), base, nb, getLeading());
variedFormatNumber2String<wchar_t>(str, stringSize, numbers.at(i - cursorLine), base, useUppercase, nb, getLeading());
if (lineEndCol < cursorCol)
{
@ -331,21 +384,21 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
auto posRelative2Start = posAbs2Start - lineBegin;
if (posRelative2Start > static_cast<long long>(s2r.length()))
posRelative2Start = s2r.length();
s2r.insert(posRelative2Start, str);
}
(*_ppEditView)->replaceTarget(s2r.c_str(), int(lineBegin), int(lineEnd));
}
delete [] line;
delete[] line;
}
}
(*_ppEditView)->execute(SCI_ENDUNDOACTION);
(*_ppEditView)->grabFocus();
return TRUE;
}
case IDC_COL_TEXT_RADIO :
case IDC_COL_NUM_RADIO :
(*_ppEditView)->grabFocus();
return TRUE;
}
case IDC_COL_TEXT_RADIO:
case IDC_COL_NUM_RADIO:
{
ColumnEditorParam& colEditParam = NppParameters::getInstance()._columnEditParam;
colEditParam._mainChoice = (wParam == IDC_COL_TEXT_RADIO) ? activeText : activeNumeric;
@ -359,13 +412,16 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
case IDC_COL_BIN_RADIO:
{
ColumnEditorParam& colEditParam = NppParameters::getInstance()._columnEditParam;
colEditParam._formatChoice = 0; // dec
if (wParam == IDC_COL_HEX_RADIO)
colEditParam._formatChoice = 1;
else if (wParam == IDC_COL_OCT_RADIO)
colEditParam._formatChoice = 2;
else if (wParam == IDC_COL_BIN_RADIO)
colEditParam._formatChoice = 3;
colEditParam._formatChoice = BASE_10; // dec
if (LOWORD(wParam) == IDC_COL_HEX_RADIO)
colEditParam._formatChoice = getHexCase(); // will pick appropriate UC or LC version of hex
else if (LOWORD(wParam) == IDC_COL_OCT_RADIO)
colEditParam._formatChoice = BASE_08;
else if (LOWORD(wParam) == IDC_COL_BIN_RADIO)
colEditParam._formatChoice = BASE_02;
setNumericFields(colEditParam); // reformat the field text to be based on the new radix
EnableWindow(GetDlgItem(_hSelf, IDC_COL_HEXUC_COMBO), LOWORD(wParam) == IDC_COL_HEX_RADIO); // enable combobox only if hex is chosen
return TRUE;
}
@ -399,7 +455,14 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
return TRUE;
}
int num = ::GetDlgItemInt(_hSelf, LOWORD(wParam), NULL, TRUE);
int num = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (num == -1)
{
num = colEditParam._initialNum;
setNumericFields(colEditParam); // reformat the strings to eliminate error
whichFlashRed = sendValidationErrorMessage(LOWORD(wParam), colEditParam._formatChoice, str);
}
colEditParam._initialNum = num;
return TRUE;
}
@ -413,7 +476,14 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
return TRUE;
}
int num = ::GetDlgItemInt(_hSelf, LOWORD(wParam), NULL, TRUE);
int num = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (num == -1)
{
num = colEditParam._increaseNum;
setNumericFields(colEditParam); // reformat the strings to eliminate error
whichFlashRed = sendValidationErrorMessage(LOWORD(wParam), colEditParam._formatChoice, str);
}
colEditParam._increaseNum = num;
return TRUE;
}
@ -427,7 +497,14 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
return TRUE;
}
int num = ::GetDlgItemInt(_hSelf, LOWORD(wParam), NULL, TRUE);
int num = getNumericFieldValueFromText(colEditParam._formatChoice, str, stringSize);
if (num == -1)
{
num = colEditParam._repeatNum;
setNumericFields(colEditParam); // reformat the strings to eliminate error
whichFlashRed = sendValidationErrorMessage(LOWORD(wParam), colEditParam._formatChoice, str);
}
colEditParam._repeatNum = num;
return TRUE;
}
@ -443,6 +520,15 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
colEditParam._leadingChoice = getLeading();
return TRUE;
}
else if(LOWORD(wParam) == IDC_COL_HEXUC_COMBO)
{
ColumnEditorParam& colEditParam = NppParameters::getInstance()._columnEditParam;
if ((colEditParam._formatChoice & BASE_16) == BASE_16 )
colEditParam._formatChoice = getHexCase();
setNumericFields(colEditParam); // want the GUI fields to update case when combobox changes
return TRUE;
}
}
break;
}
@ -452,6 +538,51 @@ intptr_t CALLBACK ColumnEditorDlg::run_dlgProc(UINT message, WPARAM wParam, LPAR
break;
}
case WM_TIMER:
{
static int idRedraw = 0;
if (wParam == IDT_COL_FLASH_TIMER)
{
KillTimer(_hSelf, IDT_COL_FLASH_TIMER);
idRedraw = whichFlashRed; // keep the ID for the one whose flash is ending...
whichFlashRed = 0; // must be 0 before the redraw, otherwise it will maintain color
redrawDlgItem(idRedraw, true); // redraw the just the one that was flashed
// Remember the latest/current baloon tip handle
hCurrentBalloonTip = [](HWND hEditControl) -> HWND {
HWND hTooltip = FindWindowEx(NULL, NULL, L"tooltips_class32", NULL);
while (hTooltip)
{
HWND hParent = GetParent(hTooltip);
if (hParent == hEditControl || hParent == GetParent(hEditControl))
{
return hTooltip;
}
hTooltip = FindWindowEx(NULL, hTooltip, L"tooltips_class32", NULL);
}
return NULL;
}(GetDlgItem(_hSelf, idRedraw));
}
if (wParam == IDC_COL_BALLONTIP_TIMER)
{
KillTimer(_hSelf, IDC_COL_BALLONTIP_TIMER);
SendMessage(GetDlgItem(_hSelf, idRedraw), EM_HIDEBALLOONTIP, 0, 0);
}
break;
}
case WM_DESTROY:
{
DeleteObject(hRedBrush);
break;
}
default :
return FALSE;
}
@ -492,16 +623,23 @@ void ColumnEditorDlg::switchTo(bool toText)
UCHAR ColumnEditorDlg::getFormat()
{
UCHAR f = 0; // Dec by default
UCHAR f = BASE_10; // Dec by default
if (isCheckedOrNot(IDC_COL_HEX_RADIO))
f = 1;
f = getHexCase(); // will give BASE_16 or BASE_16_UC, depending on case selector
else if (isCheckedOrNot(IDC_COL_OCT_RADIO))
f = 2;
f = BASE_08;
else if (isCheckedOrNot(IDC_COL_BIN_RADIO))
f = 3;
f = BASE_02;
return f;
}
UCHAR ColumnEditorDlg::getHexCase(void)
{
int curSel = static_cast<int>(::SendDlgItemMessage(_hSelf, IDC_COL_HEXUC_COMBO, CB_GETCURSEL, 0, 0));
return (curSel == 1) ? BASE_16_UPPERCASE : BASE_16;
}
ColumnEditorParam::leadingChoice ColumnEditorDlg::getLeading()
{
ColumnEditorParam::leadingChoice leading = ColumnEditorParam::noneLeading;
@ -527,3 +665,147 @@ ColumnEditorParam::leadingChoice ColumnEditorDlg::getLeading()
}
return leading;
}
void ColumnEditorDlg::setNumericFields(const ColumnEditorParam& colEditParam)
{
if (colEditParam._formatChoice == BASE_10)
{
if (colEditParam._initialNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_INITNUM_EDIT, colEditParam._initialNum, FALSE);
else
::SetDlgItemText(_hSelf, IDC_COL_INITNUM_EDIT, L"");
if (colEditParam._increaseNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_INCREASENUM_EDIT, colEditParam._increaseNum, FALSE);
else
::SetDlgItemText(_hSelf, IDC_COL_INCREASENUM_EDIT, L"");
if (colEditParam._repeatNum != -1)
::SetDlgItemInt(_hSelf, IDC_COL_REPEATNUM_EDIT, colEditParam._repeatNum, FALSE);
else
::SetDlgItemText(_hSelf, IDC_COL_REPEATNUM_EDIT, L"");
}
else
{
size_t base = 10;
switch (colEditParam._formatChoice)
{
case BASE_16: // hex
case BASE_16_UPPERCASE: // or hex w/ uppercase A-F
base = 16;
break;
case BASE_08: // oct
base = 8;
break;
case BASE_02: // bin
base = 2;
break;
default:
base = 10;
break;
}
bool useUpper = (colEditParam._formatChoice == BASE_16_UPPERCASE);
constexpr int stringSize = 1024;
wchar_t str[stringSize]{};
if (colEditParam._initialNum != -1)
{
variedFormatNumber2String<wchar_t>(str, stringSize, colEditParam._initialNum, base, useUpper, getNbDigits(colEditParam._initialNum, base), getLeading());
::SetDlgItemText(_hSelf, IDC_COL_INITNUM_EDIT, str);
}
else
::SetDlgItemText(_hSelf, IDC_COL_INITNUM_EDIT, L"");
if (colEditParam._increaseNum != -1)
{
variedFormatNumber2String<wchar_t>(str, stringSize, colEditParam._increaseNum, base, useUpper, getNbDigits(colEditParam._increaseNum, base), getLeading());
::SetDlgItemText(_hSelf, IDC_COL_INCREASENUM_EDIT, str);
}
else
::SetDlgItemText(_hSelf, IDC_COL_INCREASENUM_EDIT, L"");
if (colEditParam._repeatNum != -1)
{
variedFormatNumber2String<wchar_t>(str, stringSize, colEditParam._repeatNum, base, useUpper, getNbDigits(colEditParam._repeatNum, base), getLeading());
::SetDlgItemText(_hSelf, IDC_COL_REPEATNUM_EDIT, str);
}
else
::SetDlgItemText(_hSelf, IDC_COL_REPEATNUM_EDIT, L"");
}
return;
}
// Convert the string to an integer, depending on base
int ColumnEditorDlg::getNumericFieldValueFromText(int formatChoice, wchar_t str[], size_t /*stringSize*/)
{
int num = 0;
int base = 0;
switch (formatChoice)
{
case BASE_16:
case BASE_16_UPPERCASE:
base = 16;
break;
case BASE_08:
base = 8;
break;
case BASE_02:
base = 2;
break;
default:
base = 10;
break;
}
// convert string in base to int value; on error, return -1
wchar_t* pEnd = nullptr;
num = static_cast<int>(std::wcstol(str, &pEnd, base));
if (pEnd == nullptr || *pEnd != L'\0')
{
return -1;
}
return num;
}
int ColumnEditorDlg::sendValidationErrorMessage(int whichFlashRed, int formatChoice, wchar_t str[])
{
wchar_t wcMsg[1024];
const wchar_t *wcRadixNote;
EDITBALLOONTIP ebt;
ebt.cbStruct = sizeof(EDITBALLOONTIP);
ebt.pszTitle = L"Invalid Numeric Entry";
switch (formatChoice)
{
case BASE_16:
case BASE_16_UPPERCASE:
wcRadixNote = L"Hex numbers use 0-9, A-F!";
break;
case BASE_08:
wcRadixNote = L"Oct numbers only use 0-7!";
break;
case BASE_02:
wcRadixNote = L"Bin numbers only use 0-1!";
break;
default:
wcRadixNote = L"Decimal numbers only use 0-9!";
break;
}
if (str[0])
{
swprintf_s(wcMsg, L"Entered string \"%s\":\r\n%s", str, wcRadixNote);
ebt.pszText = wcMsg;
}
ebt.ttiIcon = TTI_ERROR_LARGE; // tooltip icon
SendMessage(GetDlgItem(_hSelf, whichFlashRed), EM_SHOWBALLOONTIP, 0, (LPARAM)&ebt);
SetTimer(_hSelf, IDT_COL_FLASH_TIMER, 250, NULL);
SetTimer(_hSelf, IDC_COL_BALLONTIP_TIMER, 3500, NULL);
redrawDlgItem(whichFlashRed);
return whichFlashRed;
}

View File

@ -45,10 +45,14 @@ public :
void switchTo(bool toText);
UCHAR getFormat();
ColumnEditorParam::leadingChoice getLeading();
UCHAR getHexCase(void);
protected :
intptr_t CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) override;
private :
ScintillaEditView **_ppEditView = nullptr;
void setNumericFields(const ColumnEditorParam& colEditParam);
int getNumericFieldValueFromText(int formatChoice, wchar_t str[], size_t stringSize);
int sendValidationErrorMessage(int whichFlashRed, int formatChoice, wchar_t str[]);
};

View File

@ -25,27 +25,28 @@ EXSTYLE WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE
CAPTION "Column / Multi-Selection Editor"
FONT 8, L"MS Shell Dlg", 0, 0, 0x0
BEGIN
CONTROL "&Text to Insert",IDC_COL_TEXT_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP | WS_GROUP,13,6,124,10
CONTROL "&Number to Insert",IDC_COL_NUM_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP | WS_GROUP,13,68,204,10
CONTROL "&Text to Insert",IDC_COL_TEXT_RADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,6,124,10
CONTROL "&Number to Insert",IDC_COL_NUM_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,68,204,10
GROUPBOX "",IDC_COL_TEXT_GRP_STATIC,8,14,124,46
EDITTEXT IDC_COL_TEXT_EDIT,20,32,97,12,ES_AUTOHSCROLL
GROUPBOX "",IDC_COL_NUM_GRP_STATIC,8,77,204,130
RTEXT "&Initial number:",IDC_COL_INITNUM_STATIC,10,89,76,8
EDITTEXT IDC_COL_INITNUM_EDIT,90,87,38,12,ES_NUMBER
RTEXT "Increase b&y:",IDC_COL_INCRNUM_STATIC,10,106,75,8
EDITTEXT IDC_COL_INCREASENUM_EDIT,90,104,38,12,ES_NUMBER
RTEXT "&Repeat:",IDC_COL_REPEATNUM_STATIC,10,123,75,8
EDITTEXT IDC_COL_REPEATNUM_EDIT,90,121,38,12,ES_NUMBER
RTEXT "&Leading:",IDC_COL_LEADING_STATIC,10,140,75,8
COMBOBOX IDC_COL_LEADING_COMBO,90,138,100,30,CBS_DROPDOWNLIST | WS_TABSTOP
GROUPBOX "Format",IDC_COL_FORMAT_GRP_STATIC,16,86,188,44,BS_CENTER
CONTROL "&Dec",IDC_COL_DEC_RADIO,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,27,99,50,10
CONTROL "&Hex",IDC_COL_HEX_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,110,99,50,10
CONTROL "&Oct",IDC_COL_OCT_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,27,114,50,10
CONTROL "&Bin",IDC_COL_BIN_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,110,114,50,10
COMBOBOX IDC_COL_HEXUC_COMBO,150,97,40,10,CBS_DROPDOWNLIST | WS_TABSTOP
GROUPBOX "Format",IDC_COL_FORMAT_GRP_STATIC,16,155,188,44,BS_CENTER
CONTROL "&Dec",IDC_COL_DEC_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,27,168,70,10
CONTROL "&Hex",IDC_COL_HEX_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,122,168,70,10
CONTROL "&Oct",IDC_COL_OCT_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,27,183,70,10
CONTROL "&Bin",IDC_COL_BIN_RADIO,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,122,183,70,10
GROUPBOX "",IDC_COL_NUM_GRP_STATIC,8,77,204,130
RTEXT "&Initial number:",IDC_COL_INITNUM_STATIC,10,140,76,8
EDITTEXT IDC_COL_INITNUM_EDIT,90,138,38,12
RTEXT "Increase b&y:",IDC_COL_INCRNUM_STATIC,10,157,75,8
EDITTEXT IDC_COL_INCREASENUM_EDIT,90,155,38,12
RTEXT "&Repeat:",IDC_COL_REPEATNUM_STATIC,10,174,75,8
EDITTEXT IDC_COL_REPEATNUM_EDIT,90,172,38,12
RTEXT "&Leading:",IDC_COL_LEADING_STATIC,10,191,75,8
COMBOBOX IDC_COL_LEADING_COMBO,90,189,100,30,CBS_DROPDOWNLIST | WS_TABSTOP
DEFPUSHBUTTON "OK",IDOK,142,18,70,14
PUSHBUTTON "Cancel",IDCANCEL,142,36,70,14

View File

@ -37,4 +37,7 @@
#define IDC_COL_REPEATNUM_EDIT (IDD_COLUMNEDIT + 17)
#define IDC_COL_LEADING_STATIC (IDD_COLUMNEDIT + 18)
#define IDC_COL_LEADING_COMBO (IDD_COLUMNEDIT + 19)
#define IDC_COL_HEXUC_COMBO (IDD_COLUMNEDIT + 20)
#define IDT_COL_FLASH_TIMER (IDD_COLUMNEDIT + 21)
#define IDC_COL_BALLONTIP_TIMER (IDD_COLUMNEDIT + 22)
#endif// COLUMNEDITOR_RC_H

View File

@ -292,6 +292,7 @@ Utf8_16_Write::Utf8_16_Write()
m_pNewBuf = NULL;
m_bFirstWrite = true;
m_nBufSize = 0;
m_dwLastFileError = NO_ERROR;
}
Utf8_16_Write::~Utf8_16_Write()
@ -301,11 +302,14 @@ Utf8_16_Write::~Utf8_16_Write()
bool Utf8_16_Write::openFile(const wchar_t *name)
{
m_pFile = std::make_unique<Win32_IO_File>(name);
m_dwLastFileError = NO_ERROR;
m_pFile = std::make_unique<Win32_IO_File>(name);
if (!m_pFile)
return false;
m_dwLastFileError = m_pFile->getLastErrorCode();
if (!m_pFile->isOpened())
{
m_pFile = nullptr;
@ -319,78 +323,85 @@ bool Utf8_16_Write::openFile(const wchar_t *name)
bool Utf8_16_Write::writeFile(const void* p, size_t _size)
{
// no file open
m_dwLastFileError = NO_ERROR;
// no file open
if (!m_pFile)
{
return false;
}
if (m_bFirstWrite)
{
switch (m_eEncoding)
{
case uniUTF8:
{
switch (m_eEncoding)
{
case uniUTF8:
{
if (!m_pFile->write(k_Boms[m_eEncoding], 3))
return false;
}
break;
case uni16BE:
case uni16LE:
{
if (!m_pFile->write(k_Boms[m_eEncoding], 2))
if (!m_pFile->write(k_Boms[m_eEncoding], 3))
{
m_dwLastFileError = m_pFile->getLastErrorCode();
return false;
}
}
break;
default:
case uni16BE:
case uni16LE:
{
if (!m_pFile->write(k_Boms[m_eEncoding], 2))
{
m_dwLastFileError = m_pFile->getLastErrorCode();
return false;
}
}
break;
default:
{
// nothing to do
}
break;
}
}
m_bFirstWrite = false;
}
}
bool isOK = false;
bool isOK = false;
switch (m_eEncoding)
{
switch (m_eEncoding)
{
case uni7Bit:
case uni8Bit:
case uniCookie:
case uniUTF8:
case uni8Bit:
case uniCookie:
case uniUTF8:
{
// Normal write
// Normal write
if (m_pFile->write(p, _size))
isOK = true;
}
m_dwLastFileError = m_pFile->getLastErrorCode();
}
break;
case uni16BE_NoBOM:
case uni16LE_NoBOM:
case uni16BE:
case uni16LE:
case uni16BE_NoBOM:
case uni16LE_NoBOM:
case uni16BE:
case uni16LE:
{
static const unsigned int bufSize = 64*1024;
static const unsigned int bufSize = 64 * 1024;
utf16* buf = new utf16[bufSize];
Utf8_Iter iter8;
iter8.set(static_cast<const ubyte*>(p), _size, m_eEncoding);
Utf8_Iter iter8;
iter8.set(static_cast<const ubyte*>(p), _size, m_eEncoding);
unsigned int bufIndex = 0;
while (iter8)
{
++iter8;
while ((bufIndex < bufSize) && iter8.canGet())
iter8.get(&buf [bufIndex++]);
iter8.get(&buf[bufIndex++]);
if (bufIndex == bufSize || !iter8)
{
if (!m_pFile->write(buf, bufIndex * sizeof(utf16)))
{
m_dwLastFileError = m_pFile->getLastErrorCode();
delete[] buf;
return 0;
}
@ -399,15 +410,14 @@ bool Utf8_16_Write::writeFile(const void* p, size_t _size)
}
isOK = true;
delete[] buf;
}
}
break;
default:
break;
}
return isOK;
default:
break;
}
return isOK;
}
@ -506,7 +516,15 @@ void Utf8_16_Write::closeFile()
}
if (m_pFile)
{
m_pFile->close(); // explicit closing for getting the possible flushing/closing error code
m_dwLastFileError = m_pFile->getLastErrorCode();
m_pFile = nullptr;
}
else
{
m_dwLastFileError = NO_ERROR;
}
}

View File

@ -148,11 +148,14 @@ public:
size_t convert(char* p, size_t _size);
char* getNewBuf() { return reinterpret_cast<char*>(m_pNewBuf); }
DWORD getLastFileErrorState() { return m_dwLastFileError; }
protected:
UniMode m_eEncoding;
std::unique_ptr<Win32_IO_File> m_pFile;
ubyte* m_pNewBuf;
size_t m_nBufSize;
bool m_bFirstWrite;
DWORD m_dwLastFileError;
};

View File

@ -1077,7 +1077,7 @@ wstring CustomFileDialog::doSaveDlg()
CurrentDirBackup backup;
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM);
_impl->addFlags(FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_NOTESTFILECREATE);
bool bOk = _impl->show();
return bOk ? _impl->getResultFilename() : L"";
}

View File

@ -19,14 +19,14 @@
//************ Notepad++ version **************************
#define NOTEPAD_PLUS_VERSION L"Notepad++ v8.8.4"
#define NOTEPAD_PLUS_VERSION L"Notepad++ v8.8.5"
// should be X.Y : ie. if VERSION_DIGITALVALUE == 4, 7, 1, 0 , then X = 4, Y = 71
// ex : #define VERSION_VALUE L"5.63\0"
#define VERSION_INTERNAL_VALUE L"8.84\0"
#define VERSION_INTERNAL_VALUE L"8.85\0"
#define VERSION_PRODUCT_VALUE L"8.8.4\0"
#define VERSION_DIGITALVALUE 8, 8, 4, 0
#define VERSION_PRODUCT_VALUE L"8.8.5\0"
#define VERSION_DIGITALVALUE 8, 8, 5, 0
//**********************************************************

View File

@ -1774,7 +1774,7 @@
<!-- Attention : Don't modify the name of styleID="0" -->
<WidgetStyle name="Default Style" styleID="32" fgColor="000000" bgColor="FFFFFF" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Indent guideline style" styleID="37" fgColor="C0C0C0" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Brace highlight style" styleID="34" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="1" fontSize="10" />
<WidgetStyle name="Brace highlight style" styleID="34" fgColor="FF0000" bgColor="FFFFFF" fontName="" fontStyle="1" fontSize="" />
<WidgetStyle name="Bad brace colour" styleID="35" fgColor="800000" bgColor="FFFFFF" fontName="" fontStyle="0" fontSize="" />
<WidgetStyle name="Current line background colour" styleID="0" bgColor="E8E8FF" />
<!-- In below rule 'fgColor' attribute for 'Selected text colour' can be unlocked with a enableSelectFgColor.xml file -->
@ -1825,6 +1825,6 @@
<WidgetStyle name="Document map" styleID="0" fgColor="FF8000" bgColor="FFFFFF" />
<WidgetStyle name="EOL custom color" styleID="0" fgColor="DADADA" />
<WidgetStyle name="Non-printing characters custom color" styleID="0" fgColor="FFB56A" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="10" />
<WidgetStyle name="Global override" styleID="0" fgColor="FFFF80" bgColor="FF8000" fontName="Courier New" fontStyle="0" fontSize="" />
</GlobalStyles>
</NotepadPlus>

View File

@ -408,6 +408,87 @@ bool launchUpdater(const std::wstring& updaterFullPath, const std::wstring& upda
return true;
}
DWORD nppUacSave(const wchar_t* wszTempFilePath, const wchar_t* wszProtectedFilePath2Save)
{
if ((lstrlenW(wszTempFilePath) == 0) || (lstrlenW(wszProtectedFilePath2Save) == 0)) // safe check (lstrlen returns 0 for possible nullptr)
return ERROR_INVALID_PARAMETER;
if (!doesFileExist(wszTempFilePath))
return ERROR_FILE_NOT_FOUND;
DWORD dwRetCode = ERROR_SUCCESS;
bool isOutputReadOnly = false;
bool isOutputHidden = false;
bool isOutputSystem = false;
WIN32_FILE_ATTRIBUTE_DATA attributes{};
attributes.dwFileAttributes = INVALID_FILE_ATTRIBUTES;
if (getFileAttributesExWithTimeout(wszProtectedFilePath2Save, &attributes))
{
if (attributes.dwFileAttributes != INVALID_FILE_ATTRIBUTES && !(attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
isOutputReadOnly = (attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
isOutputHidden = (attributes.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0;
isOutputSystem = (attributes.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != 0;
if (isOutputReadOnly) attributes.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
if (isOutputHidden) attributes.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
if (isOutputSystem) attributes.dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
if (isOutputReadOnly || isOutputHidden || isOutputSystem)
::SetFileAttributes(wszProtectedFilePath2Save, attributes.dwFileAttributes); // temporarily remove the problematic ones
}
}
// cannot use simple MoveFile here as it retains the tempfile permissions when on the same volume...
if (!::CopyFileW(wszTempFilePath, wszProtectedFilePath2Save, FALSE))
{
// fails if the destination file exists and has the R/O and/or Hidden attribute set
dwRetCode = ::GetLastError();
}
else
{
// ok, now dispose of the tempfile used
::DeleteFileW(wszTempFilePath);
}
// set back the possible original file attributes
if (isOutputReadOnly || isOutputHidden || isOutputSystem)
{
if (isOutputReadOnly) attributes.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
if (isOutputHidden) attributes.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
if (isOutputSystem) attributes.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
::SetFileAttributes(wszProtectedFilePath2Save, attributes.dwFileAttributes);
}
return dwRetCode;
}
DWORD nppUacSetFileAttributes(const DWORD dwFileAttribs, const wchar_t* wszFilePath)
{
if (lstrlenW(wszFilePath) == 0) // safe check (lstrlen returns 0 for possible nullptr)
return ERROR_INVALID_PARAMETER;
if (!doesFileExist(wszFilePath))
return ERROR_FILE_NOT_FOUND;
if (dwFileAttribs == INVALID_FILE_ATTRIBUTES || (dwFileAttribs & FILE_ATTRIBUTE_DIRECTORY))
return ERROR_INVALID_PARAMETER;
if (!::SetFileAttributes(wszFilePath, dwFileAttribs))
return ::GetLastError();
return ERROR_SUCCESS;
}
DWORD nppUacMoveFile(const wchar_t* wszOriginalFilePath, const wchar_t* wszNewFilePath)
{
if ((lstrlenW(wszOriginalFilePath) == 0) || (lstrlenW(wszNewFilePath) == 0)) // safe check (lstrlen returns 0 for possible nullptr)
return ERROR_INVALID_PARAMETER;
if (!doesFileExist(wszOriginalFilePath))
return ERROR_FILE_NOT_FOUND;
if (!::MoveFileEx(wszOriginalFilePath, wszNewFilePath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH))
return ::GetLastError();
else
return ERROR_SUCCESS;
}
} // namespace
@ -417,6 +498,39 @@ std::chrono::steady_clock::time_point g_nppStartTimePoint{};
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ PWSTR pCmdLine, _In_ int /*nShowCmd*/)
{
g_nppStartTimePoint = std::chrono::steady_clock::now();
// Notepad++ UAC OPS /////////////////////////////////////////////////////////////////////////////////////////////
if ((lstrlenW(pCmdLine) > 0) && (__argc >= 2)) // safe (if pCmdLine is NULL, lstrlen returns 0)
{
const wchar_t* wszNppUacOpSign = __wargv[1];
if (lstrlenW(wszNppUacOpSign) > lstrlenW(L"#UAC-#"))
{
if ((__argc == 4) && (wcscmp(wszNppUacOpSign, NPP_UAC_SAVE_SIGN) == 0))
{
// __wargv[x]: 2 ... tempFilePath, 3 ... protectedFilePath2Save
return static_cast<int>(nppUacSave(__wargv[2], __wargv[3]));
}
if ((__argc == 4) && (wcscmp(wszNppUacOpSign, NPP_UAC_SETFILEATTRIBUTES_SIGN) == 0))
{
// __wargv[x]: 2 ... dwFileAttributes (string), 3 ... filePath
try
{
return static_cast<int>(nppUacSetFileAttributes(static_cast<DWORD>(std::stoul(std::wstring(__wargv[2]))), __wargv[3]));
}
catch ([[maybe_unused]] const std::exception& e)
{
return static_cast<int>(ERROR_INVALID_PARAMETER); // conversion error (check e.what() for details)
}
}
if ((__argc == 4) && (wcscmp(wszNppUacOpSign, NPP_UAC_MOVEFILE_SIGN) == 0))
{
// __wargv[x]: 2 ... originalFilePath, 3 ... newFilePath
return static_cast<int>(nppUacMoveFile(__wargv[2], __wargv[3]));
}
}
} // Notepad++ UAC OPS////////////////////////////////////////////////////////////////////////////////////////////
bool TheFirstOne = true;
::SetLastError(NO_ERROR);