├── .github └── workflows │ └── msbuild.yml ├── .gitignore ├── GenerateVersionHeader.py ├── NppAdminAccess ├── NppAdminAccess.vcxproj ├── NppAdminAccess.vcxproj.filters └── main.cpp ├── NppAdminAccessLib ├── CloseHandleCommand.cpp ├── CloseHandleCommand.hpp ├── CommandManager.cpp ├── CommandManager.hpp ├── CommandProcessor.cpp ├── CommandProcessor.hpp ├── CreateFileWCommand.cpp ├── CreateFileWCommand.hpp ├── GetFileTypeCommand.cpp ├── GetFileTypeCommand.hpp ├── ICommand.cpp ├── ICommand.hpp ├── NppAdminAccessLib.vcxproj ├── NppAdminAccessLib.vcxproj.filters ├── WriteFileCommand.cpp └── WriteFileCommand.hpp ├── NppCommon ├── Common.hpp ├── IWinApiFunctions.hpp ├── NppCommon.vcxproj ├── NppCommon.vcxproj.filters ├── Pipe.hpp ├── UniqueHandle.hpp └── pipe.cpp ├── NppSaveAsAdmin ├── .gitignore ├── license.txt ├── readme.FIRST ├── src │ ├── DockingFeature │ │ ├── Docking.h │ │ ├── DockingDlgInterface.h │ │ ├── GoToLineDlg.cpp │ │ ├── GoToLineDlg.h │ │ ├── StaticDialog.cpp │ │ ├── StaticDialog.h │ │ ├── Window.h │ │ ├── dockingResource.h │ │ ├── goLine.rc │ │ └── resource.h │ ├── Notepad_plus_msgs.h │ ├── NppPluginDemo.rc │ ├── PluginDefinition.cpp │ ├── PluginDefinition.h │ ├── PluginInterface.h │ ├── Resource.h │ ├── Scintilla.h │ ├── menuCmdID.h │ └── plugin │ │ ├── NppSaveAsAdmin.cpp │ │ └── SaveAsAdminVersion.hpp └── vs.proj │ ├── NppPluginTemplate.sln │ ├── NppPluginTemplate.vcxproj │ └── NppPluginTemplate.vcxproj.filters ├── NppSaveAsAdminLib ├── NppSaveAsAdminLib.vcxproj ├── NppSaveAsAdminLib.vcxproj.filters └── plugin │ ├── AdminAccess.cpp │ ├── AdminAccess.hpp │ ├── FuncExecutor.cpp │ ├── FuncExecutor.hpp │ ├── Injection.hpp │ ├── SaveAsAdminImpl.cpp │ └── SaveAsAdminImpl.hpp ├── README.md ├── UnitTests ├── ExecutionThread.hpp ├── MockWinApiFunctions.hpp ├── TestFuncExecutor.cpp ├── TestInjection.cpp ├── TestPipe.cpp ├── TestSaveAsAdminImpl.cpp ├── TestUniqueHandle.cpp ├── TestUtilities.hpp ├── UnitTests.vcxproj └── UnitTests.vcxproj.filters └── appveyor.yml /.github/workflows/msbuild.yml: -------------------------------------------------------------------------------- 1 | name: MSBuild 2 | 3 | on: [push] 4 | 5 | env: 6 | # Path to the solution file relative to the root of the project. 7 | SOLUTION_FILE_PATH: UnitTests/UnitTests.vcxproj 8 | 9 | jobs: 10 | build: 11 | runs-on: windows-2016 12 | 13 | strategy: 14 | matrix: 15 | platform: [Win32, x64] 16 | build_configuration: [Release, Debug] 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Install CMake 22 | uses: jwlawson/actions-setup-cmake@v1.7 23 | with: 24 | cmake-version: '3.19.3' 25 | 26 | - name: Checkout GTest 27 | uses: actions/checkout@v2 28 | with: 29 | repository: 'google/googletest' 30 | ref: 'release-1.10.0' 31 | path: 'googletest' 32 | 33 | - name: Build GTest 34 | shell: cmd 35 | run: | 36 | cd googletest 37 | md build 38 | cd build 39 | IF "${{ matrix.platform }}"=="Win32" ( 40 | SET CMAKE_COMPILER="Visual Studio 15 2017" 41 | ) ELSE ( 42 | SET CMAKE_COMPILER="Visual Studio 15 2017 Win64" 43 | ) 44 | echo "PLATFORM_FOLDER=%PLATFORM_FOLDER%" 45 | echo "CMAKE_COMPILER=%CMAKE_COMPILER%" 46 | echo "GITHUB_WORKSPACE=%GITHUB_WORKSPACE%" 47 | cmake -Dgtest_force_shared_crt=OFF -DCMAKE_INSTALL_PREFIX=%GITHUB_WORKSPACE%\googletest_release -G %CMAKE_COMPILER% .. 48 | IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% 49 | 50 | cmake --build . --config ${{ matrix.build_configuration }} 51 | IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% 52 | 53 | dir /b 54 | 55 | cmake --build . --target install --config ${{ matrix.build_configuration }} 56 | IF %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% 57 | 58 | cd ../.. 59 | 60 | - name: Update version 61 | working-directory: ${{env.GITHUB_WORKSPACE}} 62 | shell: cmd 63 | run: | 64 | set NEW_VERSION="1.1.%GITHUB_RUN_NUMBER%" 65 | echo Version: %NEW_VERSION% 66 | python GenerateVersionHeader.py %NEW_VERSION% > NppSaveAsAdmin\src\plugin\SaveAsAdminVersion.hpp 67 | 68 | - name: Add MSBuild to PATH 69 | uses: microsoft/setup-msbuild@v1 70 | #with: 71 | # vs-version: '[15.1, 15.9.16]' 72 | 73 | - name: Restore NuGet packages 74 | working-directory: ${{env.GITHUB_WORKSPACE}} 75 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} 76 | 77 | - name: Build 78 | working-directory: ${{env.GITHUB_WORKSPACE}} 79 | run: msbuild /m /p:Configuration=${{ matrix.build_configuration }} /p:platform=${{ matrix.platform }} /p:GTestPath=%GITHUB_WORKSPACE%\googletest_release /p:AssemblySearchPaths=googletest_release\include ${{env.SOLUTION_FILE_PATH}} 80 | 81 | - name: Unit test x64 82 | working-directory: ${{env.GITHUB_WORKSPACE}} 83 | if: matrix.platform == 'x64' 84 | run: UnitTests\x64\${{ matrix.build_configuration }}\UnitTests.exe 85 | 86 | - name: Unit test Win32 87 | working-directory: ${{env.GITHUB_WORKSPACE}} 88 | if: matrix.platform == 'Win32' 89 | run: UnitTests\${{ matrix.build_configuration }}\UnitTests.exe 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/Debug/* 2 | **/Release/* 3 | *.user 4 | *.ipch 5 | *.db 6 | NppSaveAsAdminLib/plugin/generated/NppAdminAccess.cpp 7 | NppSaveAsAdminLib/plugin/generated/NppAdminAccess.h -------------------------------------------------------------------------------- /GenerateVersionHeader.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | version_str = sys.argv[1] 4 | version_array = version_str.split('.') 5 | if (len(version_array) < 4): 6 | for i in range(len(version_array), 4): 7 | version_array.append('0') 8 | 9 | del version_array[4:] 10 | 11 | printable_version = '#define SAVE_AS_ADMIN_VERSION "' + version_str + '"' 12 | printable_version_unicode = '#define SAVE_AS_ADMIN_VERSION_UNICODE L"' + version_str + '"' 13 | resource_version = '#define SAVE_AS_ADMIN_VERSION_DIGITAL ' + ', '.join(version_array) 14 | 15 | print(printable_version) 16 | print(printable_version_unicode) 17 | print(resource_version) 18 | print('') 19 | -------------------------------------------------------------------------------- /NppAdminAccess/NppAdminAccess.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {CAA47112-6D75-466C-BA89-F024B9BA3018} 24 | Win32Proj 25 | NppAdminAccess 26 | 7.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141_xp 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141_xp 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141_xp 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141_xp 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | ..\NppSaveAsAdmin\bin_debug 76 | 77 | 78 | true 79 | ..\NppSaveAsAdmin\bin64_debug 80 | 81 | 82 | false 83 | ..\NppSaveAsAdmin\bin\ 84 | 85 | 86 | false 87 | ..\NppSaveAsAdmin\bin64\ 88 | 89 | 90 | 91 | Level4 92 | Disabled 93 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 94 | false 95 | ../NppCommon;../NppAdminAccessLib 96 | false 97 | MultiThreadedDebug 98 | 99 | 100 | true 101 | Windows 102 | 103 | 104 | true 105 | false 106 | 107 | 108 | 109 | 110 | Level4 111 | Disabled 112 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 113 | false 114 | ../NppCommon;../NppAdminAccessLib 115 | false 116 | MultiThreadedDebug 117 | 118 | 119 | true 120 | Windows 121 | 122 | 123 | true 124 | false 125 | 126 | 127 | 128 | 129 | Level4 130 | MaxSpeed 131 | true 132 | true 133 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 134 | false 135 | ../NppCommon;../NppAdminAccessLib 136 | false 137 | MultiThreaded 138 | 139 | 140 | true 141 | true 142 | true 143 | Windows 144 | 145 | 146 | true 147 | false 148 | 149 | 150 | 151 | 152 | Level4 153 | MaxSpeed 154 | true 155 | true 156 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 157 | false 158 | ../NppCommon;../NppAdminAccessLib 159 | false 160 | MultiThreaded 161 | 162 | 163 | true 164 | true 165 | true 166 | Windows 167 | 168 | 169 | true 170 | false 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | {2394591e-0d3a-4444-8e04-4bfbd689c6a1} 179 | 180 | 181 | {02b425e1-804d-4f60-90cd-9d26f75623b0} 182 | 183 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /NppAdminAccess/NppAdminAccess.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /NppAdminAccess/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "CommandManager.hpp" 4 | #include "CommandProcessor.hpp" 5 | #include "Common.hpp" 6 | #include "IWinApiFunctions.hpp" 7 | 8 | int WINAPI CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { 9 | int arg_count = 0; 10 | LPWSTR* args = CommandLineToArgvW(GetCommandLineW(), &arg_count); 11 | 12 | if (arg_count < 2) { 13 | MessageBox(0, TEXT("Do not run this application directly"), TEXT("Error"), 14 | MB_OK); 15 | return WrongExecute; 16 | } 17 | DefaultWinApiFunctions winapi; 18 | CommandManager command_manager; 19 | register_default_commands(command_manager, winapi); 20 | return process_commands(command_manager, args[1], args[2]); 21 | } 22 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CloseHandleCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ICommand.hpp" 2 | #include "IWinApiFunctions.hpp" 3 | 4 | class CloseHandleCommand : public ICommand { 5 | public: 6 | using ICommand::ICommand; 7 | 8 | private: 9 | bool execute(const std::vector& data, 10 | std::vector& ret_data) override { 11 | const CloseHandleData* tchd = 12 | get_command_data_from_vector(data); 13 | if (!tchd) 14 | return false; 15 | CloseHandleResult* result = 16 | prepare_vector_to_store_data(ret_data); 17 | 18 | result->success = (TRUE == m_winapi.close_handle(tchd->handle)); 19 | result->last_error = GetLastError(); 20 | 21 | return true; 22 | } 23 | }; 24 | 25 | std::unique_ptr make_close_handle_command(IWinApiFunctions& winapi) { 26 | return std::make_unique(winapi); 27 | } 28 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CloseHandleCommand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ICommand.hpp" 4 | 5 | std::unique_ptr make_close_handle_command(IWinApiFunctions& winapi); 6 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CommandManager.cpp: -------------------------------------------------------------------------------- 1 | #include "CommandManager.hpp" 2 | 3 | #include "CloseHandleCommand.hpp" 4 | #include "CreateFileWCommand.hpp" 5 | #include "GetFileTypeCommand.hpp" 6 | #include "WriteFileCommand.hpp" 7 | 8 | #include 9 | 10 | CommandManager::CommandManager() = default; 11 | 12 | CommandManager::~CommandManager() = default; 13 | 14 | void CommandManager::register_command(Commands cmd_num, 15 | std::shared_ptr cmd) { 16 | m_commands_map[cmd_num] = std::move(cmd); 17 | } 18 | 19 | void CommandManager::erase_command(Commands cmd_num) { 20 | m_commands_map.erase(cmd_num); 21 | } 22 | 23 | ICommand* CommandManager::find_commad(Commands cmd_num) { 24 | auto it = m_commands_map.find(cmd_num); 25 | if (it != m_commands_map.end()) 26 | return it->second.get(); 27 | 28 | return nullptr; 29 | } 30 | 31 | void register_default_commands(CommandManager& manager, 32 | IWinApiFunctions& winapi) { 33 | manager.register_command(CloseHandleCmd, make_close_handle_command(winapi)); 34 | manager.register_command(CreateFileWCmd, make_create_filew_command(winapi)); 35 | manager.register_command(WriteFileCmd, make_write_file_command(winapi)); 36 | manager.register_command(GetFileTypeCmd, make_file_type_command(winapi)); 37 | } 38 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CommandManager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "common.hpp" 7 | 8 | class ICommand; 9 | class IWinApiFunctions; 10 | 11 | class CommandManager { 12 | std::unordered_map> m_commands_map; 13 | 14 | public: 15 | CommandManager(); 16 | ~CommandManager(); 17 | void register_command(Commands cmd_num, std::shared_ptr cmd); 18 | void erase_command(Commands cmd_num); 19 | ICommand* find_commad(Commands cmd_num); 20 | }; 21 | 22 | void register_default_commands(CommandManager& manager, 23 | IWinApiFunctions& original_functions); 24 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CommandProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "CommandProcessor.hpp" 2 | 3 | #include "CommandManager.hpp" 4 | #include "Common.hpp" 5 | #include "ICommand.hpp" 6 | #include "Pipe.hpp" 7 | 8 | #include 9 | #include 10 | 11 | Commands get_command(const std::vector& buffer) { 12 | if (buffer.size() < sizeof(Commands)) 13 | return UnknownCmd; 14 | 15 | const Commands* command = reinterpret_cast(buffer.data()); 16 | 17 | if (*command <= UnknownCmd || *command >= MaxCmd) 18 | return UnknownCmd; 19 | 20 | return *command; 21 | } 22 | 23 | int process_commands(CommandManager& cmd_manager, 24 | const std::wstring& pipe_name_to_read, 25 | const std::wstring& pipe_name_to_write) { 26 | auto pipe_read = Pipe::open(pipe_name_to_read); 27 | auto pipe_write = Pipe::open(pipe_name_to_write); 28 | 29 | if (!pipe_read || !pipe_write) 30 | return FailedToOpenPipe; 31 | 32 | // The read operation will block until there is data to read 33 | std::vector buffer; 34 | std::vector result_buffer; 35 | 36 | while (pipe_read->read(buffer)) { 37 | if (!buffer.empty()) { 38 | const Commands cmd_num = get_command(buffer); 39 | if (ExitCmd == cmd_num) 40 | break; 41 | 42 | ICommand* const command = cmd_manager.find_commad(cmd_num); 43 | if (!command) 44 | return UnknownCommand; 45 | 46 | if (!command->execute(buffer, result_buffer)) 47 | return BadDataInBuffer; 48 | 49 | if (result_buffer.empty()) 50 | return ReturnBufferHasNoData; 51 | 52 | if (!pipe_write->write(result_buffer)) 53 | return FailedToWritePipe; 54 | } 55 | } 56 | 57 | return NoError; 58 | } 59 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CommandProcessor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class CommandManager; 6 | 7 | int process_commands(CommandManager& cmd_manager, 8 | const std::wstring& pipe_name_to_read, 9 | const std::wstring& pipe_name_to_write); 10 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CreateFileWCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ICommand.hpp" 2 | #include "IWinApiFunctions.hpp" 3 | 4 | class CreateFileWCommand : public ICommand { 5 | public: 6 | using ICommand::ICommand; 7 | 8 | private: 9 | bool execute(const std::vector& data, 10 | std::vector& ret_data) override { 11 | const CreateFileDataW* tofs = 12 | get_command_data_from_vector(data); 13 | if (!tofs) 14 | return false; 15 | CreateFileResult* result = 16 | prepare_vector_to_store_data(ret_data); 17 | 18 | SECURITY_ATTRIBUTES security_attributes = {0}; 19 | security_attributes.nLength = sizeof(security_attributes); 20 | security_attributes.bInheritHandle = TRUE; 21 | 22 | const HANDLE handle = m_winapi.create_file_w( 23 | tofs->filename, tofs->desired_access, tofs->share_mode, 24 | &security_attributes, tofs->creation_disposition, 25 | tofs->flags_and_attributes, 0); 26 | 27 | result->success = (handle != INVALID_HANDLE_VALUE); 28 | result->last_error = GetLastError(); 29 | if (result->success) { 30 | result->handle = handle; 31 | } 32 | 33 | return true; 34 | } 35 | }; 36 | 37 | std::unique_ptr make_create_filew_command( 38 | IWinApiFunctions& original_functions) { 39 | return std::make_unique(original_functions); 40 | } 41 | -------------------------------------------------------------------------------- /NppAdminAccessLib/CreateFileWCommand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ICommand.hpp" 4 | 5 | std::unique_ptr make_create_filew_command(IWinApiFunctions& winapi); 6 | -------------------------------------------------------------------------------- /NppAdminAccessLib/GetFileTypeCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ICommand.hpp" 2 | #include "IWinApiFunctions.hpp" 3 | 4 | class GetFileTypeCommand : public ICommand { 5 | public: 6 | using ICommand::ICommand; 7 | 8 | private: 9 | bool execute(const std::vector& data, 10 | std::vector& ret_data) override { 11 | const GetFileTypeData* tgft = 12 | get_command_data_from_vector(data); 13 | if (!tgft) 14 | return false; 15 | GetFileTypeResult* result = 16 | prepare_vector_to_store_data(ret_data); 17 | 18 | result->type = m_winapi.get_file_type(tgft->handle); 19 | result->last_error = GetLastError(); 20 | 21 | return true; 22 | } 23 | }; 24 | 25 | std::unique_ptr make_file_type_command( 26 | IWinApiFunctions& original_functions) { 27 | return std::make_unique(original_functions); 28 | } 29 | -------------------------------------------------------------------------------- /NppAdminAccessLib/GetFileTypeCommand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ICommand.hpp" 4 | 5 | std::unique_ptr make_file_type_command(IWinApiFunctions& winapi); 6 | -------------------------------------------------------------------------------- /NppAdminAccessLib/ICommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ICommand.hpp" 2 | 3 | #include "CommandManager.hpp" 4 | 5 | ICommand::ICommand(IWinApiFunctions& original_functions) 6 | : m_winapi(original_functions) {} 7 | 8 | ICommand::~ICommand() = default; 9 | -------------------------------------------------------------------------------- /NppAdminAccessLib/ICommand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Common.hpp" 6 | 7 | class IWinApiFunctions; 8 | 9 | class ICommand { 10 | public: 11 | virtual bool execute(const std::vector& data, 12 | std::vector& ret_data) = 0; 13 | ICommand(IWinApiFunctions& original_functions); 14 | virtual ~ICommand(); 15 | 16 | protected: 17 | IWinApiFunctions& m_winapi; 18 | }; 19 | 20 | template 21 | const T* get_command_data_from_vector(const std::vector& data) { 22 | if (data.size() != sizeof(PacketWithCommand)) 23 | return nullptr; 24 | const auto* packet_with_command = 25 | reinterpret_cast*>(data.data()); 26 | return &packet_with_command->commandData; 27 | } 28 | -------------------------------------------------------------------------------- /NppAdminAccessLib/NppAdminAccessLib.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 15.0 41 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1} 42 | Win32Proj 43 | NppAdminAccessLib 44 | 10.0.17134.0 45 | 46 | 47 | 48 | StaticLibrary 49 | true 50 | v141_xp 51 | Unicode 52 | 53 | 54 | StaticLibrary 55 | false 56 | v141_xp 57 | true 58 | Unicode 59 | 60 | 61 | StaticLibrary 62 | true 63 | v141_xp 64 | Unicode 65 | 66 | 67 | StaticLibrary 68 | false 69 | v141_xp 70 | true 71 | Unicode 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | true 93 | 94 | 95 | true 96 | 97 | 98 | false 99 | 100 | 101 | false 102 | 103 | 104 | 105 | NotUsing 106 | Level3 107 | Disabled 108 | true 109 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 110 | false 111 | 112 | ../NppCommon 113 | MultiThreadedDebug 114 | 115 | 116 | Windows 117 | true 118 | 119 | 120 | 121 | 122 | NotUsing 123 | Level3 124 | Disabled 125 | true 126 | _DEBUG;_LIB;%(PreprocessorDefinitions) 127 | false 128 | 129 | ../NppCommon 130 | MultiThreadedDebug 131 | 132 | 133 | Windows 134 | true 135 | 136 | 137 | 138 | 139 | NotUsing 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 146 | false 147 | 148 | ../NppCommon 149 | MultiThreaded 150 | 151 | 152 | Windows 153 | true 154 | true 155 | true 156 | 157 | 158 | 159 | 160 | NotUsing 161 | Level3 162 | MaxSpeed 163 | true 164 | true 165 | true 166 | NDEBUG;_LIB;%(PreprocessorDefinitions) 167 | false 168 | 169 | ../NppCommon 170 | MultiThreaded 171 | 172 | 173 | Windows 174 | true 175 | true 176 | true 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /NppAdminAccessLib/NppAdminAccessLib.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {e73c1987-9630-46b6-9c50-8cfde8fb0930} 18 | 19 | 20 | {84473fe6-d09c-4678-b7a9-3de2f9bb08a8} 21 | 22 | 23 | 24 | 25 | Source Files\commands 26 | 27 | 28 | Source Files\commands 29 | 30 | 31 | Source Files\commands 32 | 33 | 34 | Source Files\commands 35 | 36 | 37 | Source Files\commands 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files\commands 49 | 50 | 51 | Header Files\commands 52 | 53 | 54 | Header Files\commands 55 | 56 | 57 | Header Files\commands 58 | 59 | 60 | Header Files\commands 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | -------------------------------------------------------------------------------- /NppAdminAccessLib/WriteFileCommand.cpp: -------------------------------------------------------------------------------- 1 | #include "ICommand.hpp" 2 | #include "IWinApiFunctions.hpp" 3 | 4 | class WriteFileCommand : public ICommand { 5 | public: 6 | using ICommand::ICommand; 7 | 8 | private: 9 | bool execute(const std::vector& data, 10 | std::vector& ret_data) override { 11 | const WriteFileData* twfd = 12 | get_command_data_from_vector(data); 13 | if (!twfd) 14 | return false; 15 | WriteFileResult* result = 16 | prepare_vector_to_store_data(ret_data); 17 | 18 | DWORD written = 0; 19 | 20 | const BOOL write_result = m_winapi.write_file( 21 | twfd->handle, twfd->buffer_is_null ? nullptr : twfd->buffer, 22 | twfd->num_bytes_to_write, &written, NULL); 23 | 24 | result->success = (TRUE == write_result); 25 | result->last_error = GetLastError(); 26 | result->bytes_written = written; 27 | 28 | return true; 29 | } 30 | }; 31 | 32 | std::unique_ptr make_write_file_command( 33 | IWinApiFunctions& original_functions) { 34 | return std::make_unique(original_functions); 35 | } 36 | -------------------------------------------------------------------------------- /NppAdminAccessLib/WriteFileCommand.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ICommand.hpp" 4 | 5 | std::unique_ptr make_write_file_command(IWinApiFunctions& winapi); 6 | -------------------------------------------------------------------------------- /NppCommon/Common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | enum Errors { 7 | NoError = 0, 8 | WrongExecute, 9 | FailedToOpenPipe, 10 | ErrorCommandExecution, 11 | UnknownCommand, 12 | BadDataInBuffer, 13 | FailedToWritePipe, 14 | ReturnBufferHasNoData 15 | }; 16 | 17 | // commands 18 | enum Commands : std::uint8_t { 19 | UnknownCmd = 0, 20 | 21 | CreateFileACmd, 22 | CreateFileWCmd, 23 | WriteFileCmd, 24 | CloseHandleCmd, 25 | GetFileTypeCmd, 26 | ExitCmd, 27 | 28 | MaxCmd 29 | }; 30 | 31 | // CreateFile 32 | struct CreateFileDataA { 33 | char filename[1024]; 34 | DWORD desired_access; 35 | DWORD share_mode; 36 | DWORD creation_disposition; 37 | DWORD flags_and_attributes; 38 | }; 39 | 40 | struct CreateFileDataW { 41 | wchar_t filename[1024]; 42 | DWORD desired_access; 43 | DWORD share_mode; 44 | DWORD creation_disposition; 45 | DWORD flags_and_attributes; 46 | }; 47 | 48 | struct CreateFileResult { 49 | bool success; 50 | HANDLE handle; 51 | DWORD last_error; 52 | }; 53 | 54 | // WriteFile 55 | struct WriteFileData { 56 | HANDLE handle; 57 | DWORD num_bytes_to_write; 58 | enum { MaxBufferSize = 1024 * 3 }; 59 | bool buffer_is_null = false; 60 | char buffer[MaxBufferSize]; 61 | }; 62 | 63 | struct WriteFileResult { 64 | bool success; 65 | DWORD bytes_written; 66 | DWORD last_error; 67 | }; 68 | 69 | // CloseHandle 70 | struct CloseHandleData { 71 | HANDLE handle; 72 | }; 73 | 74 | struct CloseHandleResult { 75 | bool success; 76 | DWORD last_error; 77 | }; 78 | 79 | // GetFileType 80 | struct GetFileTypeData { 81 | HANDLE handle; 82 | }; 83 | 84 | struct GetFileTypeResult { 85 | DWORD type; 86 | int last_error; 87 | }; 88 | 89 | template 90 | struct PacketWithCommand { 91 | Commands command; 92 | T commandData; 93 | }; 94 | 95 | template 96 | T* prepare_vector_to_store_data(std::vector& data) { 97 | data.resize(sizeof(T), 0); 98 | return reinterpret_cast(data.data()); 99 | } 100 | 101 | template 102 | std::vector data_to_vector(const T& data) { 103 | std::vector result; 104 | T* tBufferPtr = prepare_vector_to_store_data(result); 105 | *tBufferPtr = data; 106 | return result; 107 | } 108 | 109 | template 110 | bool read_data_from_vector(T& out, const std::vector& data) { 111 | if (data.size() != sizeof(T)) 112 | return false; 113 | const T* data_ptr = reinterpret_cast(data.data()); 114 | out = *data_ptr; 115 | return true; 116 | } 117 | -------------------------------------------------------------------------------- /NppCommon/IWinApiFunctions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // clang-format off 4 | #include 5 | 6 | #pragma warning( push ) 7 | #pragma warning( disable : 4091) 8 | #include 9 | #pragma warning( pop ) 10 | 11 | #include 12 | // clang-format on 13 | 14 | class IWinApiFunctions { 15 | public: 16 | virtual BOOL write_file(HANDLE file_handle, 17 | LPCVOID buffer, 18 | DWORD number_of_bytes_to_write, 19 | LPDWORD number_of_bytes_written, 20 | LPOVERLAPPED overlapped) = 0; 21 | 22 | virtual HANDLE create_file_w(LPCWSTR file_name, 23 | DWORD desired_access, 24 | DWORD share_mode, 25 | LPSECURITY_ATTRIBUTES security_attributes, 26 | DWORD creation_disposition, 27 | DWORD flags_and_attributes, 28 | HANDLE template_file) = 0; 29 | 30 | virtual BOOL close_handle(HANDLE object) = 0; 31 | 32 | virtual DWORD get_file_type(HANDLE file) = 0; 33 | }; 34 | 35 | class DefaultWinApiFunctions : public IWinApiFunctions { 36 | public: 37 | BOOL write_file(HANDLE file_handle, 38 | LPCVOID buffer, 39 | DWORD number_of_bytes_to_write, 40 | LPDWORD number_of_bytes_written, 41 | LPOVERLAPPED overlapped) override { 42 | return WriteFile(file_handle, buffer, number_of_bytes_to_write, 43 | number_of_bytes_written, overlapped); 44 | } 45 | 46 | HANDLE create_file_w(LPCWSTR file_name, 47 | DWORD desired_access, 48 | DWORD share_mode, 49 | LPSECURITY_ATTRIBUTES security_attributes, 50 | DWORD creation_disposition, 51 | DWORD flags_and_attributes, 52 | HANDLE template_file) override { 53 | return CreateFileW(file_name, desired_access, share_mode, 54 | security_attributes, creation_disposition, 55 | flags_and_attributes, template_file); 56 | } 57 | 58 | BOOL close_handle(HANDLE object) override { 59 | return CloseHandle(object); 60 | } 61 | 62 | DWORD get_file_type(HANDLE file) override { return GetFileType(file); } 63 | }; 64 | -------------------------------------------------------------------------------- /NppCommon/NppCommon.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 15.0 32 | {02B425E1-804D-4F60-90CD-9D26F75623B0} 33 | Win32Proj 34 | NppCommon 35 | 10.0.17134.0 36 | 37 | 38 | 39 | StaticLibrary 40 | true 41 | v141_xp 42 | Unicode 43 | 44 | 45 | StaticLibrary 46 | false 47 | v141_xp 48 | true 49 | Unicode 50 | 51 | 52 | StaticLibrary 53 | true 54 | v141_xp 55 | Unicode 56 | 57 | 58 | StaticLibrary 59 | false 60 | v141_xp 61 | true 62 | Unicode 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | true 84 | 85 | 86 | true 87 | 88 | 89 | false 90 | 91 | 92 | false 93 | 94 | 95 | 96 | NotUsing 97 | Level4 98 | Disabled 99 | true 100 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 101 | false 102 | 103 | 104 | false 105 | MultiThreadedDebug 106 | 107 | 108 | Windows 109 | true 110 | 111 | 112 | 113 | 114 | NotUsing 115 | Level4 116 | Disabled 117 | true 118 | _DEBUG;_LIB;%(PreprocessorDefinitions) 119 | false 120 | 121 | 122 | false 123 | MultiThreadedDebug 124 | 125 | 126 | Windows 127 | true 128 | 129 | 130 | 131 | 132 | NotUsing 133 | Level4 134 | MaxSpeed 135 | true 136 | true 137 | true 138 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 139 | false 140 | 141 | 142 | false 143 | MultiThreaded 144 | 145 | 146 | Windows 147 | true 148 | true 149 | true 150 | 151 | 152 | 153 | 154 | NotUsing 155 | Level4 156 | MaxSpeed 157 | true 158 | true 159 | true 160 | NDEBUG;_LIB;%(PreprocessorDefinitions) 161 | false 162 | 163 | 164 | false 165 | MultiThreaded 166 | 167 | 168 | Windows 169 | true 170 | true 171 | true 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /NppCommon/NppCommon.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /NppCommon/Pipe.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "UniqueHandle.hpp" 9 | 10 | class Pipe final { 11 | const UniqueHandle<> m_pipe; 12 | const std::wstring m_name; 13 | 14 | Pipe(UniqueHandle<> pipe, std::wstring name); 15 | static std::unique_ptr create(UniqueHandle<> pipe, std::wstring name); 16 | 17 | public: 18 | static std::unique_ptr create(const std::wstring& name); 19 | static std::unique_ptr create_unique(); 20 | static std::unique_ptr open(const std::wstring& name); 21 | 22 | bool read(std::vector& data); 23 | bool write(const std::vector& data); 24 | const std::wstring& get_name() const; 25 | bool wait() const; 26 | }; 27 | -------------------------------------------------------------------------------- /NppCommon/UniqueHandle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class UniqueHandle final { 7 | public: 8 | UniqueHandle(const UniqueHandle&) = delete; 9 | UniqueHandle& operator=(const UniqueHandle&) = delete; 10 | 11 | UniqueHandle(UniqueHandle&& that) 12 | : m_handle(that.release()), m_handle_closer(that.m_handle_closer) { 13 | that.release(); 14 | } 15 | UniqueHandle& operator=(UniqueHandle&& that) { 16 | reset(); 17 | m_handle = that.release(); 18 | m_handle_closer = that.m_handle_closer; 19 | 20 | return *this; 21 | } 22 | 23 | UniqueHandle& operator=(HANDLE handle) { 24 | reset(); 25 | m_handle = handle; 26 | return *this; 27 | } 28 | 29 | UniqueHandle() : UniqueHandle(INVALID_HANDLE_VALUE) {} 30 | 31 | UniqueHandle(HANDLE handle, HandleCloser handle_closer = &CloseHandle) 32 | : m_handle(handle), m_handle_closer(handle_closer) {} 33 | 34 | ~UniqueHandle() { reset(); } 35 | 36 | void reset() { 37 | if (*this) { 38 | m_handle_closer(m_handle); 39 | release(); 40 | } 41 | } 42 | 43 | HANDLE release() { 44 | const HANDLE handle = m_handle; 45 | m_handle = INVALID_HANDLE_VALUE; 46 | return handle; 47 | } 48 | 49 | explicit operator bool() const { return m_handle != INVALID_HANDLE_VALUE; } 50 | 51 | HANDLE get() const { return m_handle; } 52 | 53 | HANDLE operator*() const { return get(); } 54 | 55 | private: 56 | HANDLE m_handle; 57 | HandleCloser m_handle_closer; 58 | }; 59 | 60 | template 61 | bool operator==(const UniqueHandle& lhs, const UniqueHandle& rhs) { 62 | return *lhs == *rhs; 63 | } 64 | 65 | template 66 | bool operator==(const UniqueHandle& lhs, const HANDLE rhs) { 67 | return *lhs == rhs; 68 | } 69 | 70 | template 71 | bool operator==(const HANDLE lhs, const UniqueHandle& rhs) { 72 | return lhs == *rhs; 73 | } 74 | 75 | template 76 | bool operator!=(const UniqueHandle& lhs, const UniqueHandle& rhs) { 77 | return !(lhs == rhs); 78 | } 79 | 80 | template 81 | bool operator!=(const UniqueHandle& lhs, const HANDLE rhs) { 82 | return !(lhs == rhs); 83 | } 84 | 85 | template 86 | bool operator!=(const HANDLE lhs, const UniqueHandle& rhs) { 87 | return !(lhs == rhs); 88 | } 89 | -------------------------------------------------------------------------------- /NppCommon/pipe.cpp: -------------------------------------------------------------------------------- 1 | #include "Pipe.hpp" 2 | 3 | #include 4 | ////////////////////////////////////////////////////////////////////////// 5 | 6 | namespace { 7 | std::wstring generate_random_string(int length) { 8 | static bool is_initialized = false; 9 | if (!is_initialized) 10 | srand(GetTickCount()); 11 | 12 | const wchar_t random_map[] = L"1234567890"; 13 | const size_t map_size = sizeof(random_map) / sizeof(random_map[0]); 14 | 15 | std::wstring result; 16 | result.reserve(length); 17 | 18 | for (int i = 0; i < length; ++i) 19 | result.append(1, random_map[rand() * (map_size - 1) / RAND_MAX]); 20 | 21 | return result; 22 | } 23 | 24 | const int MaxBufferSize = 1024 * 4; 25 | } // namespace 26 | 27 | ////////////////////////////////////////////////////////////////////////// 28 | 29 | Pipe::Pipe(UniqueHandle<> pipe, std::wstring name) 30 | : m_pipe(std::move(pipe)), m_name(std::move(name)) {} 31 | 32 | std::unique_ptr Pipe::create(UniqueHandle<> pipe, std::wstring name) { 33 | return std::unique_ptr(new Pipe(std::move(pipe), name)); 34 | } 35 | 36 | std::unique_ptr Pipe::create(const std::wstring& name) { 37 | UniqueHandle<> pipe(CreateNamedPipe( 38 | name.c_str(), // pipe's name 39 | PIPE_ACCESS_DUPLEX /*|FILE_FLAG_OVERLAPPED*/, // 40 | PIPE_TYPE_BYTE, 1, MaxBufferSize, MaxBufferSize, 10000, NULL)); 41 | 42 | if (!pipe) 43 | return nullptr; 44 | 45 | return create(std::move(pipe), name); 46 | } 47 | 48 | std::unique_ptr Pipe::create_unique() { 49 | std::unique_ptr result; 50 | do { 51 | std::wstring name = L"\\\\.\\pipe\\npp_"; 52 | name += generate_random_string(5); 53 | result = create(name); 54 | } while (!result); 55 | 56 | return result; 57 | } 58 | 59 | std::unique_ptr Pipe::open(const std::wstring& name) { 60 | UniqueHandle<> pipe( 61 | CreateFile(name.c_str(), // pipe's name 62 | GENERIC_READ | GENERIC_WRITE, // only need read access 63 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 64 | FILE_ATTRIBUTE_NORMAL, NULL)); 65 | 66 | if (!pipe) 67 | return nullptr; 68 | 69 | return create(std::move(pipe), name); 70 | } 71 | 72 | bool Pipe::read(std::vector& data) { 73 | DWORD read_size = 0; 74 | data.resize(MaxBufferSize); 75 | const DWORD buffer_size = static_cast(data.size()); 76 | const bool result = 77 | TRUE == ReadFile(*m_pipe, data.data(), buffer_size, &read_size, NULL); 78 | data.resize(result ? read_size : 0); 79 | return result; 80 | } 81 | 82 | bool Pipe::write(const std::vector& data) { 83 | DWORD written = 0; 84 | const DWORD buffer_size = static_cast(data.size()); 85 | const BOOL result = 86 | WriteFile(*m_pipe, data.data(), buffer_size, &written, NULL); 87 | return TRUE == result && written == data.size(); 88 | } 89 | 90 | const std::wstring& Pipe::get_name() const { 91 | return m_name; 92 | } 93 | 94 | bool Pipe::wait() const { 95 | return TRUE == ConnectNamedPipe(*m_pipe, NULL); 96 | } 97 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/.gitignore: -------------------------------------------------------------------------------- 1 | *.sdf 2 | *.sln 3 | *.suo 4 | bin/ 5 | bin64/ 6 | bin_debug/ 7 | bin64_debug/ 8 | vs.proj/.vs/* 9 | vs.proj/Debug 10 | vs.proj/Release 11 | vs.proj/x64 12 | src/NppPluginDemo.aps 13 | vs.proj/NppSaveAsAdmin.exp 14 | vs.proj/NppSaveAsAdmin.lib 15 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/readme.FIRST: -------------------------------------------------------------------------------- 1 | Even your grandmom can do it! 2 | 3 | This template is done for making plugin development as easy and simple as possible. 4 | 5 | A simple plugin can be done through 4 steps, by editing only 2 files (PluginDefinition.h and PluginDefinition.cpp) : 6 | 1. Define your plugin name in "PluginDefinition.h" 7 | 2. Define your plugin commands number in "PluginDefinition.h" 8 | 3. Customize plugin commands names and associated function name (and the other stuff, optional) in "PluginDefinition.cpp". 9 | 4. Define the associated functions 10 | 11 | Just follow the 4 steps (commented) in both PluginDefinition.h and PluginDefinition.cpp files : 12 | //-------------------------------------// 13 | //-- STEP 1. DEFINE YOUR PLUGIN NAME --// 14 | //-------------------------------------// 15 | 16 | //-----------------------------------------------// 17 | //-- STEP 2. DEFINE YOUR PLUGIN COMMAND NUMBER --// 18 | //-----------------------------------------------// 19 | 20 | //--------------------------------------------// 21 | //-- STEP 3. CUSTOMIZE YOUR PLUGIN COMMANDS --// 22 | //--------------------------------------------// 23 | 24 | //----------------------------------------------// 25 | //-- STEP 4. DEFINE YOUR ASSOCIATED FUNCTIONS --// 26 | //----------------------------------------------// 27 | 28 | Any questions and suggestions please post here : 29 | https://notepad-plus-plus.org/community/category/5/plugin-development 30 | 31 | For more information about plugin development, please check here: 32 | http://docs.notepad-plus-plus.org/index.php/Plugin_Resources 33 | 34 | 35 | Don HO 36 | don.h@free.fr 37 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/Docking.h: -------------------------------------------------------------------------------- 1 | /* 2 | this file is part of Function List Plugin for Notepad++ 3 | Copyright (C)2005 Jens Lorenz 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either 8 | version 2 of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | #ifndef DOCKING_H 21 | #define DOCKING_H 22 | 23 | // ATTENTION : It's a part of interface header, so don't include the others header here 24 | 25 | // styles for containers 26 | #define CAPTION_TOP TRUE 27 | #define CAPTION_BOTTOM FALSE 28 | 29 | // defines for docking manager 30 | #define CONT_LEFT 0 31 | #define CONT_RIGHT 1 32 | #define CONT_TOP 2 33 | #define CONT_BOTTOM 3 34 | #define DOCKCONT_MAX 4 35 | 36 | // mask params for plugins of internal dialogs 37 | #define DWS_ICONTAB 0x00000001 // Icon for tabs are available 38 | #define DWS_ICONBAR 0x00000002 // Icon for icon bar are available (currently not supported) 39 | #define DWS_ADDINFO 0x00000004 // Additional information are in use 40 | #define DWS_PARAMSALL (DWS_ICONTAB|DWS_ICONBAR|DWS_ADDINFO) 41 | 42 | // default docking values for first call of plugin 43 | #define DWS_DF_CONT_LEFT (CONT_LEFT << 28) // default docking on left 44 | #define DWS_DF_CONT_RIGHT (CONT_RIGHT << 28) // default docking on right 45 | #define DWS_DF_CONT_TOP (CONT_TOP << 28) // default docking on top 46 | #define DWS_DF_CONT_BOTTOM (CONT_BOTTOM << 28) // default docking on bottom 47 | #define DWS_DF_FLOATING 0x80000000 // default state is floating 48 | 49 | 50 | typedef struct { 51 | HWND hClient; // client Window Handle 52 | TCHAR *pszName; // name of plugin (shown in window) 53 | int dlgID; // a funcItem provides the function pointer to start a dialog. Please parse here these ID 54 | 55 | // user modifications 56 | UINT uMask; // mask params: look to above defines 57 | HICON hIconTab; // icon for tabs 58 | TCHAR *pszAddInfo; // for plugin to display additional informations 59 | 60 | // internal data, do not use !!! 61 | RECT rcFloat; // floating position 62 | int iPrevCont; // stores the privious container (toggling between float and dock) 63 | const TCHAR* pszModuleName; // it's the plugin file name. It's used to identify the plugin 64 | } tTbData; 65 | 66 | 67 | typedef struct { 68 | HWND hWnd; // the docking manager wnd 69 | RECT rcRegion[DOCKCONT_MAX]; // position of docked dialogs 70 | } tDockMgr; 71 | 72 | 73 | #define HIT_TEST_THICKNESS 20 74 | #define SPLITTER_WIDTH 4 75 | 76 | 77 | #endif // DOCKING_H 78 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/DockingDlgInterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | this file is part of Function List Plugin for Notepad++ 3 | Copyright (C)2005 Jens Lorenz 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either 8 | version 2 of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | #ifndef DOCKINGDLGINTERFACE_H 21 | #define DOCKINGDLGINTERFACE_H 22 | 23 | #include "StaticDialog.h" 24 | #include "dockingResource.h" 25 | #include "Docking.h" 26 | #include 27 | 28 | 29 | class DockingDlgInterface : public StaticDialog 30 | { 31 | public: 32 | DockingDlgInterface(): StaticDialog() {}; 33 | DockingDlgInterface(int dlgID): StaticDialog(), _dlgID(dlgID) {}; 34 | 35 | virtual void init(HINSTANCE hInst, HWND parent) 36 | { 37 | StaticDialog::init(hInst, parent); 38 | ::GetModuleFileName((HMODULE)hInst, _moduleName, MAX_PATH); 39 | lstrcpy(_moduleName, PathFindFileName(_moduleName)); 40 | } 41 | 42 | void create(tTbData * data, bool isRTL = false){ 43 | StaticDialog::create(_dlgID, isRTL); 44 | ::GetWindowText(_hSelf, _pluginName, sizeof(_pluginName)); 45 | 46 | // user information 47 | data->hClient = _hSelf; 48 | data->pszName = _pluginName; 49 | 50 | // supported features by plugin 51 | data->uMask = 0; 52 | 53 | // additional info 54 | data->pszAddInfo = NULL; 55 | _data = data; 56 | 57 | }; 58 | 59 | virtual void updateDockingDlg(void) { 60 | ::SendMessage(_hParent, NPPM_DMMUPDATEDISPINFO, 0, (LPARAM)_hSelf); 61 | } 62 | 63 | virtual void destroy() { 64 | }; 65 | 66 | virtual void display(bool toShow = true) const { 67 | ::SendMessage(_hParent, toShow?NPPM_DMMSHOW:NPPM_DMMHIDE, 0, (LPARAM)_hSelf); 68 | }; 69 | 70 | const TCHAR * getPluginFileName() const { 71 | return _moduleName; 72 | }; 73 | 74 | protected : 75 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM /*wParam*/, LPARAM lParam) 76 | { 77 | switch (message) 78 | { 79 | 80 | case WM_NOTIFY: 81 | { 82 | LPNMHDR pnmh = (LPNMHDR)lParam; 83 | 84 | if (pnmh->hwndFrom == _hParent) 85 | { 86 | switch (LOWORD(pnmh->code)) 87 | { 88 | case DMN_CLOSE: 89 | { 90 | break; 91 | } 92 | case DMN_FLOAT: 93 | { 94 | _isFloating = true; 95 | break; 96 | } 97 | case DMN_DOCK: 98 | { 99 | _isFloating = false; 100 | break; 101 | } 102 | default: 103 | break; 104 | } 105 | } 106 | break; 107 | } 108 | default: 109 | break; 110 | } 111 | return FALSE; 112 | }; 113 | 114 | // Handles 115 | HWND _HSource; 116 | tTbData* _data; 117 | int _dlgID; 118 | bool _isFloating; 119 | TCHAR _moduleName[MAX_PATH]; 120 | TCHAR _pluginName[MAX_PATH]; 121 | }; 122 | 123 | #endif // DOCKINGDLGINTERFACE_H 124 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/GoToLineDlg.cpp: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO ( donho@altern.org ) 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #include "GoToLineDlg.h" 19 | #include "../PluginDefinition.h" 20 | 21 | extern NppData nppData; 22 | 23 | INT_PTR CALLBACK DemoDlg::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) 24 | { 25 | switch (message) 26 | { 27 | case WM_COMMAND : 28 | { 29 | switch (wParam) 30 | { 31 | case IDOK : 32 | { 33 | int line = getLine(); 34 | if (line != -1) 35 | { 36 | // Get the current scintilla 37 | int which = -1; 38 | ::SendMessage(nppData._nppHandle, NPPM_GETCURRENTSCINTILLA, 0, (LPARAM)&which); 39 | if (which == -1) 40 | return FALSE; 41 | HWND curScintilla = (which == 0)?nppData._scintillaMainHandle:nppData._scintillaSecondHandle; 42 | 43 | ::SendMessage(curScintilla, SCI_ENSUREVISIBLE, line-1, 0); 44 | ::SendMessage(curScintilla, SCI_GOTOLINE, line-1, 0); 45 | } 46 | return TRUE; 47 | } 48 | } 49 | return FALSE; 50 | } 51 | 52 | default : 53 | return DockingDlgInterface::run_dlgProc(message, wParam, lParam); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/GoToLineDlg.h: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO ( donho@altern.org ) 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #ifndef GOTILINE_DLG_H 19 | #define GOTILINE_DLG_H 20 | 21 | #include "DockingDlgInterface.h" 22 | #include "resource.h" 23 | 24 | class DemoDlg : public DockingDlgInterface 25 | { 26 | public : 27 | DemoDlg() : DockingDlgInterface(IDD_PLUGINGOLINE_DEMO){}; 28 | 29 | virtual void display(bool toShow = true) const { 30 | DockingDlgInterface::display(toShow); 31 | if (toShow) 32 | ::SetFocus(::GetDlgItem(_hSelf, ID_GOLINE_EDIT)); 33 | }; 34 | 35 | void setParent(HWND parent2set){ 36 | _hParent = parent2set; 37 | }; 38 | 39 | protected : 40 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam); 41 | 42 | private : 43 | 44 | int getLine() const { 45 | BOOL isSuccessful; 46 | int line = ::GetDlgItemInt(_hSelf, ID_GOLINE_EDIT, &isSuccessful, FALSE); 47 | return (isSuccessful?line:-1); 48 | }; 49 | 50 | }; 51 | 52 | #endif //GOTILINE_DLG_H 53 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/StaticDialog.cpp: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO ( donho@altern.org ) 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #include 19 | #include "StaticDialog.h" 20 | 21 | void StaticDialog::goToCenter() 22 | { 23 | RECT rc; 24 | ::GetClientRect(_hParent, &rc); 25 | POINT center; 26 | center.x = rc.left + (rc.right - rc.left)/2; 27 | center.y = rc.top + (rc.bottom - rc.top)/2; 28 | ::ClientToScreen(_hParent, ¢er); 29 | 30 | int x = center.x - (_rc.right - _rc.left)/2; 31 | int y = center.y - (_rc.bottom - _rc.top)/2; 32 | 33 | ::SetWindowPos(_hSelf, HWND_TOP, x, y, _rc.right - _rc.left, _rc.bottom - _rc.top, SWP_SHOWWINDOW); 34 | } 35 | 36 | HGLOBAL StaticDialog::makeRTLResource(int dialogID, DLGTEMPLATE **ppMyDlgTemplate) 37 | { 38 | // Get Dlg Template resource 39 | HRSRC hDialogRC = ::FindResource(_hInst, MAKEINTRESOURCE(dialogID), RT_DIALOG); 40 | if (!hDialogRC) 41 | return NULL; 42 | 43 | HGLOBAL hDlgTemplate = ::LoadResource(_hInst, hDialogRC); 44 | if (!hDlgTemplate) 45 | return NULL; 46 | 47 | DLGTEMPLATE *pDlgTemplate = reinterpret_cast(::LockResource(hDlgTemplate)); 48 | if (!pDlgTemplate) 49 | return NULL; 50 | 51 | // Duplicate Dlg Template resource 52 | unsigned long sizeDlg = ::SizeofResource(_hInst, hDialogRC); 53 | HGLOBAL hMyDlgTemplate = ::GlobalAlloc(GPTR, sizeDlg); 54 | *ppMyDlgTemplate = reinterpret_cast(::GlobalLock(hMyDlgTemplate)); 55 | 56 | ::memcpy(*ppMyDlgTemplate, pDlgTemplate, sizeDlg); 57 | 58 | DLGTEMPLATEEX *pMyDlgTemplateEx = reinterpret_cast(*ppMyDlgTemplate); 59 | if (pMyDlgTemplateEx->signature == 0xFFFF) 60 | pMyDlgTemplateEx->exStyle |= WS_EX_LAYOUTRTL; 61 | else 62 | (*ppMyDlgTemplate)->dwExtendedStyle |= WS_EX_LAYOUTRTL; 63 | 64 | return hMyDlgTemplate; 65 | } 66 | 67 | void StaticDialog::create(int dialogID, bool isRTL) 68 | { 69 | if (isRTL) 70 | { 71 | DLGTEMPLATE *pMyDlgTemplate = NULL; 72 | HGLOBAL hMyDlgTemplate = makeRTLResource(dialogID, &pMyDlgTemplate); 73 | _hSelf = ::CreateDialogIndirectParam(_hInst, pMyDlgTemplate, _hParent, dlgProc, reinterpret_cast(this)); 74 | ::GlobalFree(hMyDlgTemplate); 75 | } 76 | else 77 | _hSelf = ::CreateDialogParam(_hInst, MAKEINTRESOURCE(dialogID), _hParent, dlgProc, reinterpret_cast(this)); 78 | 79 | if (!_hSelf) 80 | { 81 | DWORD err = ::GetLastError(); 82 | char errMsg[256]; 83 | sprintf(errMsg, "CreateDialogParam() return NULL.\rGetLastError() == %u", err); 84 | ::MessageBoxA(NULL, errMsg, "In StaticDialog::create()", MB_OK); 85 | return; 86 | } 87 | 88 | // if the destination of message NPPM_MODELESSDIALOG is not its parent, then it's the grand-parent 89 | ::SendMessage(_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast(_hSelf)); 90 | } 91 | 92 | INT_PTR CALLBACK StaticDialog::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 93 | { 94 | switch (message) 95 | { 96 | case WM_INITDIALOG: 97 | { 98 | StaticDialog *pStaticDlg = reinterpret_cast(lParam); 99 | pStaticDlg->_hSelf = hwnd; 100 | ::SetWindowLongPtr(hwnd, GWLP_USERDATA, static_cast(lParam)); 101 | ::GetWindowRect(hwnd, &(pStaticDlg->_rc)); 102 | pStaticDlg->run_dlgProc(message, wParam, lParam); 103 | 104 | return TRUE; 105 | } 106 | 107 | default: 108 | { 109 | StaticDialog *pStaticDlg = reinterpret_cast(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); 110 | if (!pStaticDlg) 111 | return FALSE; 112 | return pStaticDlg->run_dlgProc(message, wParam, lParam); 113 | } 114 | } 115 | } 116 | 117 | void StaticDialog::alignWith(HWND handle, HWND handle2Align, PosAlign pos, POINT & point) 118 | { 119 | RECT rc, rc2; 120 | ::GetWindowRect(handle, &rc); 121 | 122 | point.x = rc.left; 123 | point.y = rc.top; 124 | 125 | switch (pos) 126 | { 127 | case PosAlign::left: 128 | { 129 | ::GetWindowRect(handle2Align, &rc2); 130 | point.x -= rc2.right - rc2.left; 131 | break; 132 | } 133 | case PosAlign::right: 134 | { 135 | ::GetWindowRect(handle, &rc2); 136 | point.x += rc2.right - rc2.left; 137 | break; 138 | } 139 | case PosAlign::top: 140 | { 141 | ::GetWindowRect(handle2Align, &rc2); 142 | point.y -= rc2.bottom - rc2.top; 143 | break; 144 | } 145 | case PosAlign::bottom: 146 | { 147 | ::GetWindowRect(handle, &rc2); 148 | point.y += rc2.bottom - rc2.top; 149 | break; 150 | } 151 | } 152 | 153 | ::ScreenToClient(_hSelf, &point); 154 | } 155 | 156 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/StaticDialog.h: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO ( donho@altern.org ) 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #pragma once 19 | 20 | #include "Window.h" 21 | #include "..\Notepad_plus_msgs.h" 22 | 23 | enum class PosAlign { left, right, top, bottom }; 24 | 25 | struct DLGTEMPLATEEX { 26 | WORD dlgVer; 27 | WORD signature; 28 | DWORD helpID; 29 | DWORD exStyle; 30 | DWORD style; 31 | WORD cDlgItems; 32 | short x; 33 | short y; 34 | short cx; 35 | short cy; 36 | // The structure has more fields but are variable length 37 | } ; 38 | 39 | class StaticDialog : public Window 40 | { 41 | public : 42 | StaticDialog() : Window() {}; 43 | ~StaticDialog(){ 44 | if (isCreated()) { 45 | ::SetWindowLongPtr(_hSelf, GWLP_USERDATA, (long)NULL); //Prevent run_dlgProc from doing anything, since its virtual 46 | destroy(); 47 | } 48 | }; 49 | virtual void create(int dialogID, bool isRTL = false); 50 | 51 | virtual bool isCreated() const { 52 | return (_hSelf != NULL); 53 | }; 54 | 55 | void goToCenter(); 56 | void destroy() { 57 | ::SendMessage(_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGREMOVE, (WPARAM)_hSelf); 58 | ::DestroyWindow(_hSelf); 59 | }; 60 | 61 | protected : 62 | RECT _rc; 63 | static INT_PTR CALLBACK dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 64 | virtual INT_PTR CALLBACK run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam) = 0; 65 | 66 | void alignWith(HWND handle, HWND handle2Align, PosAlign pos, POINT & point); 67 | HGLOBAL makeRTLResource(int dialogID, DLGTEMPLATE **ppMyDlgTemplate); 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/Window.h: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #ifndef WINDOW_CONTROL_H 19 | #define WINDOW_CONTROL_H 20 | 21 | #include 22 | 23 | class Window 24 | { 25 | public: 26 | Window(): _hInst(NULL), _hParent(NULL), _hSelf(NULL){}; 27 | virtual ~Window() {}; 28 | 29 | virtual void init(HINSTANCE hInst, HWND parent) 30 | { 31 | _hInst = hInst; 32 | _hParent = parent; 33 | } 34 | 35 | virtual void destroy() = 0; 36 | 37 | virtual void display(bool toShow = true) const { 38 | ::ShowWindow(_hSelf, toShow?SW_SHOW:SW_HIDE); 39 | }; 40 | 41 | virtual void reSizeTo(RECT & rc) // should NEVER be const !!! 42 | { 43 | ::MoveWindow(_hSelf, rc.left, rc.top, rc.right, rc.bottom, TRUE); 44 | redraw(); 45 | }; 46 | 47 | virtual void reSizeToWH(RECT & rc) // should NEVER be const !!! 48 | { 49 | ::MoveWindow(_hSelf, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); 50 | redraw(); 51 | }; 52 | 53 | virtual void redraw(bool forceUpdate = false) const { 54 | ::InvalidateRect(_hSelf, NULL, TRUE); 55 | if (forceUpdate) 56 | ::UpdateWindow(_hSelf); 57 | }; 58 | 59 | virtual void getClientRect(RECT & rc) const { 60 | ::GetClientRect(_hSelf, &rc); 61 | }; 62 | 63 | virtual void getWindowRect(RECT & rc) const { 64 | ::GetWindowRect(_hSelf, &rc); 65 | }; 66 | 67 | virtual int getWidth() const { 68 | RECT rc; 69 | ::GetClientRect(_hSelf, &rc); 70 | return (rc.right - rc.left); 71 | }; 72 | 73 | virtual int getHeight() const { 74 | RECT rc; 75 | ::GetClientRect(_hSelf, &rc); 76 | if (::IsWindowVisible(_hSelf) == TRUE) 77 | return (rc.bottom - rc.top); 78 | return 0; 79 | }; 80 | 81 | virtual bool isVisible() const { 82 | return (::IsWindowVisible(_hSelf)?true:false); 83 | }; 84 | 85 | HWND getHSelf() const { 86 | //assert(_hSelf); 87 | return _hSelf; 88 | }; 89 | 90 | HWND getHParent() const { 91 | return _hParent; 92 | }; 93 | 94 | void getFocus() const { 95 | ::SetFocus(_hSelf); 96 | }; 97 | 98 | HINSTANCE getHinst() const { 99 | if (!_hInst) 100 | { 101 | ::MessageBox(NULL, TEXT("_hInst == NULL"), TEXT("class Window"), MB_OK); 102 | throw int(1999); 103 | } 104 | return _hInst; 105 | }; 106 | protected: 107 | HINSTANCE _hInst; 108 | HWND _hParent; 109 | HWND _hSelf; 110 | }; 111 | 112 | #endif //WINDOW_CONTROL_H 113 | 114 | 115 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/dockingResource.h: -------------------------------------------------------------------------------- 1 | //this file is part of docking functionality for Notepad++ 2 | //Copyright (C)2006 Jens Lorenz 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #ifndef DOCKING_RESOURCE_H 19 | #define DOCKING_RESOURCE_H 20 | 21 | #define IDD_PLUGIN_DLG 103 22 | #define IDC_EDIT1 1000 23 | 24 | 25 | #define IDB_CLOSE_DOWN 137 26 | #define IDB_CLOSE_UP 138 27 | #define IDD_CONTAINER_DLG 139 28 | 29 | #define IDC_TAB_CONT 1027 30 | #define IDC_CLIENT_TAB 1028 31 | #define IDC_BTN_CAPTION 1050 32 | 33 | #define DMM_MSG 0x5000 34 | #define DMM_CLOSE (DMM_MSG + 1) 35 | #define DMM_DOCK (DMM_MSG + 2) 36 | #define DMM_FLOAT (DMM_MSG + 3) 37 | #define DMM_DOCKALL (DMM_MSG + 4) 38 | #define DMM_FLOATALL (DMM_MSG + 5) 39 | #define DMM_MOVE (DMM_MSG + 6) 40 | #define DMM_UPDATEDISPINFO (DMM_MSG + 7) 41 | #define DMM_GETIMAGELIST (DMM_MSG + 8) 42 | #define DMM_GETICONPOS (DMM_MSG + 9) 43 | #define DMM_DROPDATA (DMM_MSG + 10) 44 | #define DMM_MOVE_SPLITTER (DMM_MSG + 11) 45 | #define DMM_CANCEL_MOVE (DMM_MSG + 12) 46 | #define DMM_LBUTTONUP (DMM_MSG + 13) 47 | 48 | #define DMN_FIRST 1050 49 | #define DMN_CLOSE (DMN_FIRST + 1) 50 | //nmhdr.code = DWORD(DMN_CLOSE, 0)); 51 | //nmhdr.hwndFrom = hwndNpp; 52 | //nmhdr.idFrom = ctrlIdNpp; 53 | 54 | #define DMN_DOCK (DMN_FIRST + 2) 55 | #define DMN_FLOAT (DMN_FIRST + 3) 56 | //nmhdr.code = DWORD(DMN_XXX, int newContainer); 57 | //nmhdr.hwndFrom = hwndNpp; 58 | //nmhdr.idFrom = ctrlIdNpp; 59 | 60 | 61 | 62 | #endif //DOCKING_RESOURCE_H 63 | 64 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/goLine.rc: -------------------------------------------------------------------------------- 1 | /* 2 | this file is part of notepad++ 3 | Copyright (C)2003 Don HO ( donho@altern.org ) 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either 8 | version 2 of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | #include 21 | #include "resource.h" 22 | 23 | IDD_PLUGINGOLINE_DEMO DIALOGEX 26, 41, 223, 67 24 | STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 25 | EXSTYLE WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE 26 | CAPTION "Go To Line #" 27 | FONT 8, "MS Sans Serif", 0, 0, 0x0 28 | BEGIN 29 | LTEXT "Go to line :", ID_UGO_STATIC,5,21,95,8 30 | EDITTEXT ID_GOLINE_EDIT, 55,20,30,12,ES_NUMBER 31 | DEFPUSHBUTTON "&Go",IDOK,100,21,70,14,BS_NOTIFY 32 | END 33 | 34 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/DockingFeature/resource.h: -------------------------------------------------------------------------------- 1 | //this file is part of notepad++ 2 | //Copyright (C)2003 Don HO 3 | // 4 | //This program is free software; you can redistribute it and/or 5 | //modify it under the terms of the GNU General Public License 6 | //as published by the Free Software Foundation; either 7 | //version 2 of the License, or (at your option) any later version. 8 | // 9 | //This program is distributed in the hope that it will be useful, 10 | //but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | //GNU General Public License for more details. 13 | // 14 | //You should have received a copy of the GNU General Public License 15 | //along with this program; if not, write to the Free Software 16 | //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #ifndef RESOURCE_H 19 | #define RESOURCE_H 20 | 21 | 22 | #ifndef IDC_STATIC 23 | #define IDC_STATIC -1 24 | #endif 25 | 26 | #define IDD_PLUGINGOLINE_DEMO 2500 27 | #define ID_GOLINE_EDIT (IDD_PLUGINGOLINE_DEMO + 1) 28 | #define ID_UGO_STATIC (IDD_PLUGINGOLINE_DEMO + 5) 29 | 30 | #endif // RESOURCE_H 31 | 32 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/NppPluginDemo.rc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Don HO 3 | 4 | This file is part of Notepad++ demo plugin. 5 | 6 | Notepad++ demo plugin is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Lesser General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | GUP is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public License 17 | along with GUP. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "plugin/SaveAsAdminVersion.hpp" 23 | 24 | #include "Resource.h" 25 | 26 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 27 | 28 | VS_VERSION_INFO VERSIONINFO 29 | FILEVERSION SAVE_AS_ADMIN_VERSION_DIGITAL 30 | PRODUCTVERSION SAVE_AS_ADMIN_VERSION_DIGITAL 31 | FILEFLAGSMASK 0x3fL 32 | FILEFLAGS 0 33 | FILEOS VOS_NT_WINDOWS32 34 | FILETYPE VFT_APP 35 | FILESUBTYPE VFT2_UNKNOWN 36 | BEGIN 37 | BLOCK "VarFileInfo" 38 | BEGIN 39 | VALUE "Translation", 0x409, 1200 40 | END 41 | BLOCK "StringFileInfo" 42 | BEGIN 43 | BLOCK "040904b0" 44 | BEGIN 45 | VALUE "CompanyName", "yauheni.khnykin@gmail.com\0" 46 | VALUE "FileDescription", "Plugin NppSaveAsAdmin for Notepad++\0" 47 | VALUE "FileVersion", SAVE_AS_ADMIN_VERSION 48 | VALUE "InternalName", "NppSaveAsAdmin.dll\0" 49 | VALUE "LegalCopyright", "Copyright 2018 by Yauheni Khnykin\0" 50 | VALUE "OriginalFilename", "NppSaveAsAdmin.dll\0" 51 | VALUE "ProductName", "NppSaveAsAdmin\0" 52 | VALUE "ProductVersion", SAVE_AS_ADMIN_VERSION 53 | END 54 | END 55 | END 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Dialog 61 | // 62 | 63 | IDD_ABOUT_SAVE_AS_ADMIN DIALOGEX 0, 0, 303, 185 64 | STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU 65 | CAPTION "Save as Admin plugin" 66 | FONT 8, "MS Shell Dlg", 0, 0, 0x1 67 | BEGIN 68 | DEFPUSHBUTTON "Close",IDCLOSE,126,164,50,14,WS_GROUP 69 | CONTROL "Custom1",IDC_SCINTILLA,"Scintilla",WS_TABSTOP,0,7,291,153 70 | END 71 | 72 | 73 | ///////////////////////////////////////////////////////////////////////////// 74 | // 75 | // DESIGNINFO 76 | // 77 | 78 | #ifdef APSTUDIO_INVOKED 79 | GUIDELINES DESIGNINFO 80 | BEGIN 81 | IDD_ABOUT_SAVE_AS_ADMIN, DIALOG 82 | BEGIN 83 | LEFTMARGIN, 7 84 | RIGHTMARGIN, 296 85 | TOPMARGIN, 7 86 | BOTTOMMARGIN, 178 87 | END 88 | END 89 | #endif // APSTUDIO_INVOKED 90 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/PluginDefinition.cpp: -------------------------------------------------------------------------------- 1 | // this file is part of notepad++ 2 | // Copyright (C)2003 Don HO 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either 7 | // version 2 of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #include "PluginDefinition.h" 19 | #include "Resource.h" 20 | #include "menuCmdID.h" 21 | #include "plugin/SaveAsAdminVersion.hpp" 22 | 23 | #include 24 | #include 25 | 26 | // 27 | // The plugin data that Notepad++ needs 28 | // 29 | FuncItem funcItem[nbFunc]; 30 | 31 | // 32 | // The data of Notepad++ that you can use in your plugin commands 33 | // 34 | NppData nppData; 35 | HINSTANCE module_handle; 36 | 37 | // 38 | // Initialize your plugin data here 39 | // It will be called while plugin loading 40 | void pluginInit(HINSTANCE hModule) { 41 | module_handle = hModule; 42 | } 43 | 44 | // 45 | // Here you can do the clean up, save the parameters (if any) for the next 46 | // session 47 | // 48 | void pluginCleanUp() {} 49 | 50 | void do_injection(); 51 | void un_do_injection(); 52 | bool is_admin_app_exists(); 53 | 54 | // 55 | // Initialization of your plugin commands 56 | // You should fill your plugins commands here 57 | void commandMenuInit() { 58 | setCommand(0, TEXT("About"), about, NULL, false); 59 | 60 | if (is_debugging()) { 61 | setCommand(1, TEXT("Hook"), do_injection, NULL, false); 62 | setCommand(2, TEXT("Unhook"), un_do_injection, NULL, false); 63 | } 64 | } 65 | 66 | // 67 | // Here you can do the clean up (especially for the shortcut) 68 | // 69 | void commandMenuCleanUp() { 70 | // Don't forget to deallocate your shortcut here 71 | } 72 | 73 | // 74 | // This function help you to initialize your plugin commands 75 | // 76 | bool setCommand(size_t index, 77 | TCHAR* cmdName, 78 | PFUNCPLUGINCMD pFunc, 79 | ShortcutKey* sk, 80 | bool check0nInit) { 81 | if (index >= nbFunc) 82 | return false; 83 | 84 | if (!pFunc) 85 | return false; 86 | 87 | lstrcpy(funcItem[index]._itemName, cmdName); 88 | funcItem[index]._pFunc = pFunc; 89 | funcItem[index]._init2Check = check0nInit; 90 | funcItem[index]._pShKey = sk; 91 | 92 | return true; 93 | } 94 | 95 | //----------------------------------------------// 96 | //-- STEP 4. DEFINE YOUR ASSOCIATED FUNCTIONS --// 97 | //----------------------------------------------// 98 | 99 | std::string make_about_text() { 100 | std::stringstream info; 101 | info << "Notepad++ SaveAsAdmin plugin" << std::endl; 102 | info << "Version: " << SAVE_AS_ADMIN_VERSION << std::endl; 103 | info << "Author: Khnykin Yauheni" << std::endl; 104 | 105 | if (is_admin_app_exists()) { 106 | info << std::endl 107 | << "Allows to save file as administrator with UAC prompt." 108 | << std::endl; 109 | info << "Just save file as you usually do with menu, hotkey, etc." 110 | << std::endl; 111 | } else { 112 | info << std::endl 113 | << "Something went wrong! Importand files are missed, please try to " 114 | "reinstall." 115 | << std::endl; 116 | } 117 | 118 | info << std::endl 119 | << "Plugin sources: https://github.com/Hsilgos/nppsaveasadmin" 120 | << std::endl; 121 | info << "Issue reports: https://github.com/Hsilgos/nppsaveasadmin/issues" 122 | << std::endl; 123 | return info.str(); 124 | } 125 | 126 | constexpr WPARAM SCINTILLA_STYLE_LINK = 2; 127 | 128 | struct LinkInfo { 129 | size_t position; 130 | std::string link; 131 | }; 132 | 133 | std::vector find_links( 134 | const std::string& text, 135 | const std::vector& link_prefixes) { 136 | std::vector result; 137 | for (const std::string& prefix : link_prefixes) { 138 | auto position = text.find(prefix); 139 | while (position != std::string::npos) { 140 | auto end_position = text.find_first_of(" \n", position); 141 | if (end_position == std::string::npos) { 142 | end_position = text.size(); 143 | } 144 | 145 | LinkInfo link_info; 146 | link_info.position = position; 147 | link_info.link = text.substr(position, end_position - position); 148 | 149 | result.push_back(link_info); 150 | 151 | position = text.find(prefix, end_position); 152 | } 153 | } 154 | return result; 155 | } 156 | 157 | void apply_links(HWND hDlg, 158 | int scintilla_id, 159 | const std::string& text, 160 | const std::vector& link_prefixes) { 161 | for (const LinkInfo& link_info : find_links(text, link_prefixes)) { 162 | SendDlgItemMessage(hDlg, scintilla_id, SCI_STARTSTYLING, link_info.position, 163 | 0); 164 | SendDlgItemMessage(hDlg, scintilla_id, SCI_SETSTYLING, 165 | link_info.link.size(), SCINTILLA_STYLE_LINK); 166 | } 167 | } 168 | 169 | std::string find_link_at_position( 170 | const std::string& text, 171 | std::uint32_t position, 172 | const std::vector& link_prefixes) { 173 | for (const LinkInfo& link_info : find_links(text, link_prefixes)) { 174 | if (position >= link_info.position && 175 | position < link_info.position + link_info.link.size()) { 176 | return link_info.link; 177 | } 178 | } 179 | 180 | return std::string(); 181 | } 182 | 183 | const std::vector link_prefixes = {"https://", "mailto:"}; 184 | 185 | void init_scintilla(HWND hDlg) { 186 | const std::string about_text = make_about_text(); 187 | SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETTEXT, 0, 188 | reinterpret_cast(about_text.c_str())); 189 | SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETREADONLY, TRUE, 0); 190 | SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETHSCROLLBAR, FALSE, 0); 191 | 192 | SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_SETHOTSPOTACTIVEFORE, TRUE, 193 | 0xFF0000); 194 | SendDlgItemMessage(hDlg, IDC_SCINTILLA, SCI_STYLESETHOTSPOT, 195 | SCINTILLA_STYLE_LINK, TRUE); 196 | 197 | apply_links(hDlg, IDC_SCINTILLA, about_text, link_prefixes); 198 | } 199 | 200 | void center_dialog(HWND hDlg) { 201 | const HWND hwndOwner = GetParent(hDlg); 202 | 203 | RECT rect_owner; 204 | GetWindowRect(hwndOwner, &rect_owner); 205 | 206 | RECT rect_dlg; 207 | GetWindowRect(hDlg, &rect_dlg); 208 | 209 | RECT result_rect; 210 | CopyRect(&result_rect, &rect_owner); 211 | 212 | OffsetRect(&rect_dlg, -rect_dlg.left, -rect_dlg.top); 213 | OffsetRect(&result_rect, -result_rect.left, -result_rect.top); 214 | OffsetRect(&result_rect, -rect_dlg.right, -rect_dlg.bottom); 215 | 216 | SetWindowPos(hDlg, HWND_TOP, rect_owner.left + (result_rect.right / 2), 217 | rect_owner.top + (result_rect.bottom / 2), 0, 0, SWP_NOSIZE); 218 | } 219 | 220 | // Message handler for about box. 221 | INT_PTR CALLBACK about_dlg_proc(HWND hDlg, 222 | UINT message, 223 | WPARAM wParam, 224 | LPARAM lParam) { 225 | switch (message) { 226 | case WM_INITDIALOG: { 227 | center_dialog(hDlg); 228 | init_scintilla(hDlg); 229 | 230 | return (INT_PTR)TRUE; 231 | } 232 | 233 | case WM_NOTIFY: { 234 | if (wParam == IDC_SCINTILLA) { 235 | const SCNotification* notification = 236 | reinterpret_cast(lParam); 237 | switch (notification->nmhdr.code) { 238 | case SCN_HOTSPOTCLICK: 239 | case SCN_HOTSPOTDOUBLECLICK: { 240 | const std::string link = find_link_at_position( 241 | make_about_text(), notification->position, link_prefixes); 242 | ShellExecuteA(NULL, "open", link.c_str(), NULL, NULL, 243 | SW_SHOWNORMAL); 244 | break; 245 | } 246 | } 247 | } 248 | 249 | break; 250 | } 251 | 252 | case WM_COMMAND: 253 | if (LOWORD(wParam) == IDCLOSE || LOWORD(wParam) == IDCANCEL) { 254 | EndDialog(hDlg, LOWORD(wParam)); 255 | return (INT_PTR)TRUE; 256 | } 257 | break; 258 | } 259 | return (INT_PTR)FALSE; 260 | } 261 | 262 | void about() { 263 | DialogBox(module_handle, MAKEINTRESOURCE(IDD_ABOUT_SAVE_AS_ADMIN), 264 | nppData._nppHandle, about_dlg_proc); 265 | } 266 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/PluginDefinition.h: -------------------------------------------------------------------------------- 1 | // this file is part of notepad++ 2 | // Copyright (C)2003 Don HO 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either 7 | // version 2 of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program; if not, write to the Free Software 16 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | 18 | #ifndef PLUGINDEFINITION_H 19 | #define PLUGINDEFINITION_H 20 | 21 | // 22 | // All difinitions of plugin interface 23 | // 24 | #include "PluginInterface.h" 25 | 26 | //-------------------------------------// 27 | //-- STEP 1. DEFINE YOUR PLUGIN NAME --// 28 | //-------------------------------------// 29 | // Here define your plugin name 30 | // 31 | const TCHAR NPP_PLUGIN_NAME[] = TEXT("NppSaveAsAdmin"); 32 | 33 | //-----------------------------------------------// 34 | //-- STEP 2. DEFINE YOUR PLUGIN COMMAND NUMBER --// 35 | //-----------------------------------------------// 36 | // 37 | // Here define the number of your plugin commands 38 | // 39 | 40 | inline bool is_debugging() { 41 | #ifdef _DEBUG 42 | return true; 43 | #else 44 | return false; 45 | #endif 46 | } 47 | 48 | #ifdef _DEBUG 49 | const int nbFunc = 3; 50 | #else 51 | const int nbFunc = 1; 52 | #endif 53 | 54 | // 55 | // Initialization of your plugin data 56 | // It will be called while plugin loading 57 | // 58 | void pluginInit(HINSTANCE hModule); 59 | 60 | // 61 | // Cleaning of your plugin 62 | // It will be called while plugin unloading 63 | // 64 | void pluginCleanUp(); 65 | 66 | // 67 | // Initialization of your plugin commands 68 | // 69 | void commandMenuInit(); 70 | 71 | // 72 | // Clean up your plugin commands allocation (if any) 73 | // 74 | void commandMenuCleanUp(); 75 | 76 | // 77 | // Function which sets your command 78 | // 79 | bool setCommand(size_t index, 80 | TCHAR* cmdName, 81 | PFUNCPLUGINCMD pFunc, 82 | ShortcutKey* sk = NULL, 83 | bool check0nInit = false); 84 | 85 | // 86 | // Your plugin command functions 87 | // 88 | void about(); 89 | 90 | #endif // PLUGINDEFINITION_H 91 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/PluginInterface.h: -------------------------------------------------------------------------------- 1 | // This file is part of Notepad++ project 2 | // Copyright (C)2003 Don HO 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either 7 | // version 2 of the License, or (at your option) any later version. 8 | // 9 | // Note that the GPL places important restrictions on "derived works", yet 10 | // it does not provide a detailed definition of that term. To avoid 11 | // misunderstandings, we consider an application to constitute a 12 | // "derivative work" for the purpose of this license if it does any of the 13 | // following: 14 | // 1. Integrates source code from Notepad++. 15 | // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable 16 | // installer, such as those produced by InstallShield. 17 | // 3. Links to a library or executes a program that does any of the above. 18 | // 19 | // This program is distributed in the hope that it will be useful, 20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | // GNU General Public License for more details. 23 | // 24 | // You should have received a copy of the GNU General Public License 25 | // along with this program; if not, write to the Free Software 26 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 | 28 | 29 | #ifndef PLUGININTERFACE_H 30 | #define PLUGININTERFACE_H 31 | 32 | #ifndef SCINTILLA_H 33 | #include "Scintilla.h" 34 | #endif //SCINTILLA_H 35 | 36 | #ifndef NOTEPAD_PLUS_MSGS_H 37 | #include "Notepad_plus_msgs.h" 38 | #endif //NOTEPAD_PLUS_MSGS_H 39 | 40 | const int nbChar = 64; 41 | 42 | typedef const TCHAR * (__cdecl * PFUNCGETNAME)(); 43 | 44 | struct NppData 45 | { 46 | HWND _nppHandle; 47 | HWND _scintillaMainHandle; 48 | HWND _scintillaSecondHandle; 49 | }; 50 | 51 | typedef void (__cdecl * PFUNCSETINFO)(NppData); 52 | typedef void (__cdecl * PFUNCPLUGINCMD)(); 53 | typedef void (__cdecl * PBENOTIFIED)(SCNotification *); 54 | typedef LRESULT (__cdecl * PMESSAGEPROC)(UINT Message, WPARAM wParam, LPARAM lParam); 55 | 56 | 57 | struct ShortcutKey 58 | { 59 | bool _isCtrl; 60 | bool _isAlt; 61 | bool _isShift; 62 | UCHAR _key; 63 | }; 64 | 65 | struct FuncItem 66 | { 67 | TCHAR _itemName[nbChar]; 68 | PFUNCPLUGINCMD _pFunc; 69 | int _cmdID; 70 | bool _init2Check; 71 | ShortcutKey *_pShKey; 72 | }; 73 | 74 | typedef FuncItem * (__cdecl * PFUNCGETFUNCSARRAY)(int *); 75 | 76 | // You should implement (or define an empty function body) those functions which are called by Notepad++ plugin manager 77 | extern "C" __declspec(dllexport) void setInfo(NppData); 78 | extern "C" __declspec(dllexport) const TCHAR * getName(); 79 | extern "C" __declspec(dllexport) FuncItem * getFuncsArray(int *); 80 | extern "C" __declspec(dllexport) void beNotified(SCNotification *); 81 | extern "C" __declspec(dllexport) LRESULT messageProc(UINT Message, WPARAM wParam, LPARAM lParam); 82 | 83 | // This API return always true now, since Notepad++ isn't compiled in ANSI mode anymore 84 | extern "C" __declspec(dllexport) BOOL isUnicode(); 85 | 86 | 87 | #endif //PLUGININTERFACE_H 88 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by test_resources.rc 4 | // 5 | #define IDC_MYICON 2 6 | #define IDD_TESTRESOURCES_DIALOG 102 7 | #define IDD_ABOUTBOX 103 8 | #define IDD_ABOUT_SAVE_AS_ADMIN 103 9 | #define IDR_MAINFRAME 128 10 | #define IDC_SCINTILLA 1001 11 | #define IDC_STATIC -1 12 | 13 | // Next default values for new objects 14 | // 15 | #ifdef APSTUDIO_INVOKED 16 | #ifndef APSTUDIO_READONLY_SYMBOLS 17 | #define _APS_NO_MFC 1 18 | #define _APS_NEXT_RESOURCE_VALUE 129 19 | #define _APS_NEXT_COMMAND_VALUE 32771 20 | #define _APS_NEXT_CONTROL_VALUE 1000 21 | #define _APS_NEXT_SYMED_VALUE 110 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/plugin/NppSaveAsAdmin.cpp: -------------------------------------------------------------------------------- 1 | #include "../PluginDefinition.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "plugin/AdminAccess.hpp" 7 | #include "plugin/SaveAsAdminImpl.hpp" 8 | 9 | #include "IWinApiFunctions.hpp" 10 | 11 | extern FuncItem funcItem[nbFunc]; 12 | extern NppData nppData; 13 | 14 | namespace { 15 | std::wstring g_admin_app_path; 16 | std::unique_ptr g_admin_access_runner; 17 | std::unique_ptr g_save_as_admin_impl; 18 | std::string g_recorded_initialisation_error; 19 | } 20 | 21 | std::string make_initialisation_error(const std::string& reason) { 22 | std::string error_text = "Failed to initialise SaveAsAdmin plugin with "; 23 | if (!reason.empty()) { 24 | error_text.append("error: ").append(reason); 25 | } 26 | else { 27 | error_text.append("undefined error."); 28 | } 29 | error_text.append("\nFunctionality is disabled, please contact author to fix the problem"); 30 | return error_text; 31 | } 32 | 33 | void do_injection() { 34 | if (!g_save_as_admin_impl) { 35 | g_admin_access_runner = AdminAccessRunner::make_default(g_admin_app_path); 36 | try { 37 | g_save_as_admin_impl = std::make_unique(*g_admin_access_runner); 38 | } 39 | catch (const std::exception& exc) { 40 | g_recorded_initialisation_error = make_initialisation_error(exc.what()); 41 | } 42 | catch (...) { 43 | g_recorded_initialisation_error = make_initialisation_error(std::string{}); 44 | } 45 | } 46 | } 47 | 48 | void un_do_injection() { 49 | g_save_as_admin_impl.reset(); 50 | } 51 | 52 | bool is_admin_app_exists() { 53 | return file_exists(g_admin_app_path); 54 | } 55 | 56 | std::wstring get_module_path(HINSTANCE hModule) { 57 | using Buffer = std::array; 58 | Buffer module_file = { { 0 } }; 59 | const int result_size = 60 | GetModuleFileName(static_cast(hModule), module_file.data(), static_cast(module_file.size())); 61 | return std::wstring(module_file.data(), result_size); 62 | } 63 | 64 | std::wstring get_admin_app_path(HINSTANCE hModule) { 65 | std::wstring module_path = get_module_path(hModule); 66 | const auto sep_position = module_path.find_last_of(L"\\/"); 67 | if (sep_position != std::wstring::npos) { 68 | module_path.replace(sep_position + 1, std::wstring::npos, L"NppAdminAccess.exe"); 69 | return module_path; 70 | } 71 | return std::wstring(); 72 | } 73 | 74 | ////////////////////////////////////////////////////////////////////////// 75 | 76 | BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reasonForCall, LPVOID /*lpReserved*/) { 77 | switch (reasonForCall) { 78 | case DLL_PROCESS_ATTACH: 79 | pluginInit(hModule); 80 | 81 | g_admin_app_path = get_admin_app_path(hModule); 82 | do_injection(); 83 | 84 | break; 85 | 86 | case DLL_PROCESS_DETACH: 87 | commandMenuCleanUp(); 88 | pluginCleanUp(); 89 | un_do_injection(); 90 | break; 91 | 92 | case DLL_THREAD_ATTACH: 93 | break; 94 | 95 | case DLL_THREAD_DETACH: 96 | break; 97 | } 98 | 99 | return TRUE; 100 | } 101 | 102 | extern "C" __declspec(dllexport) void setInfo(NppData notpadPlusData) { 103 | nppData = notpadPlusData; 104 | commandMenuInit(); 105 | } 106 | 107 | extern "C" __declspec(dllexport) const TCHAR* getName() { 108 | return NPP_PLUGIN_NAME; 109 | } 110 | 111 | extern "C" __declspec(dllexport) FuncItem* getFuncsArray(int* nbF) { 112 | *nbF = nbFunc; 113 | return funcItem; 114 | } 115 | 116 | extern "C" __declspec(dllexport) void beNotified(SCNotification* notifyCode) { 117 | switch (notifyCode->nmhdr.code) { 118 | case NPPN_READY: 119 | if (!g_save_as_admin_impl && !g_recorded_initialisation_error.empty()) { 120 | const int warning_result = 121 | MessageBoxA(static_cast(notifyCode->nmhdr.hwndFrom), 122 | g_recorded_initialisation_error.c_str(), 123 | "SaveAsAdmin initialisation failed", 124 | MB_OKCANCEL | MB_ICONWARNING | MB_DEFBUTTON2); 125 | // Don't bother user with repeated errors. 126 | g_recorded_initialisation_error.clear(); 127 | if (warning_result == IDOK) { 128 | about(); 129 | } 130 | } 131 | break; 132 | case NPPN_FILEBEFORESAVE: 133 | if (g_save_as_admin_impl) { 134 | g_save_as_admin_impl->allow_process_file(); 135 | } 136 | break; 137 | case NPPN_FILESAVED: 138 | if (g_save_as_admin_impl) { 139 | g_save_as_admin_impl->cancel_process_file(); 140 | } 141 | break; 142 | default: 143 | break; 144 | } 145 | } 146 | 147 | // Here you can process the Npp Messages 148 | // I will make the messages accessible little by little, according to the need 149 | // of plugin development. Please let me know if you need to access to some 150 | // messages : http://sourceforge.net/forum/forum.php?forum_id=482781 151 | // 152 | extern "C" __declspec(dllexport) LRESULT 153 | messageProc(UINT /*Message*/, WPARAM /*wParam*/, LPARAM /*lParam*/) { 154 | return TRUE; 155 | } 156 | 157 | #ifdef UNICODE 158 | extern "C" __declspec(dllexport) BOOL isUnicode() { 159 | return TRUE; 160 | } 161 | #endif // UNICODE 162 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/src/plugin/SaveAsAdminVersion.hpp: -------------------------------------------------------------------------------- 1 | #define SAVE_AS_ADMIN_VERSION "0.0.1" 2 | #define SAVE_AS_ADMIN_VERSION_UNICODE L"0.0.1" 3 | #define SAVE_AS_ADMIN_VERSION_DIGITAL 0, 0, 1, 0 4 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/vs.proj/NppPluginTemplate.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppSaveAsAdmin", "NppPluginTemplate.vcxproj", "{9D04DBD5-E12E-44E0-A683-6F43F21D533B}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {02B425E1-804D-4F60-90CD-9D26F75623B0} = {02B425E1-804D-4F60-90CD-9D26F75623B0} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppCommon", "..\..\NppCommon\NppCommon.vcxproj", "{02B425E1-804D-4F60-90CD-9D26F75623B0}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppAdminAccess", "..\..\NppAdminAccess\NppAdminAccess.vcxproj", "{CAA47112-6D75-466C-BA89-F024B9BA3018}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {02B425E1-804D-4F60-90CD-9D26F75623B0} = {02B425E1-804D-4F60-90CD-9D26F75623B0} 16 | EndProjectSection 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "..\..\UnitTests\UnitTests.vcxproj", "{A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}" 19 | ProjectSection(ProjectDependencies) = postProject 20 | {CAA47112-6D75-466C-BA89-F024B9BA3018} = {CAA47112-6D75-466C-BA89-F024B9BA3018} 21 | EndProjectSection 22 | EndProject 23 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppSaveAsAdminLib", "..\..\NppSaveAsAdminLib\NppSaveAsAdminLib.vcxproj", "{F10E6E67-956F-4847-9110-8B4EB56A2857}" 24 | ProjectSection(ProjectDependencies) = postProject 25 | {CAA47112-6D75-466C-BA89-F024B9BA3018} = {CAA47112-6D75-466C-BA89-F024B9BA3018} 26 | EndProjectSection 27 | EndProject 28 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppAdminAccessLib", "..\..\NppAdminAccessLib\NppAdminAccessLib.vcxproj", "{2394591E-0D3A-4444-8E04-4BFBD689C6A1}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug|x64 = Debug|x64 33 | Debug|x86 = Debug|x86 34 | Release|x64 = Release|x64 35 | Release|x86 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 38 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Debug|x64.ActiveCfg = Debug|x64 39 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Debug|x64.Build.0 = Debug|x64 40 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Debug|x86.ActiveCfg = Debug|Win32 41 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Debug|x86.Build.0 = Debug|Win32 42 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Release|x64.ActiveCfg = Release|x64 43 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Release|x64.Build.0 = Release|x64 44 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Release|x86.ActiveCfg = Release|Win32 45 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B}.Release|x86.Build.0 = Release|Win32 46 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Debug|x64.ActiveCfg = Debug|x64 47 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Debug|x64.Build.0 = Debug|x64 48 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Debug|x86.ActiveCfg = Debug|Win32 49 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Debug|x86.Build.0 = Debug|Win32 50 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Release|x64.ActiveCfg = Release|x64 51 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Release|x64.Build.0 = Release|x64 52 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Release|x86.ActiveCfg = Release|Win32 53 | {02B425E1-804D-4F60-90CD-9D26F75623B0}.Release|x86.Build.0 = Release|Win32 54 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Debug|x64.ActiveCfg = Debug|x64 55 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Debug|x64.Build.0 = Debug|x64 56 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Debug|x86.ActiveCfg = Debug|Win32 57 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Debug|x86.Build.0 = Debug|Win32 58 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Release|x64.ActiveCfg = Release|x64 59 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Release|x64.Build.0 = Release|x64 60 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Release|x86.ActiveCfg = Release|Win32 61 | {CAA47112-6D75-466C-BA89-F024B9BA3018}.Release|x86.Build.0 = Release|Win32 62 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Debug|x64.ActiveCfg = Debug|x64 63 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Debug|x64.Build.0 = Debug|x64 64 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Debug|x86.ActiveCfg = Debug|Win32 65 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Debug|x86.Build.0 = Debug|Win32 66 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Release|x64.ActiveCfg = Release|x64 67 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Release|x64.Build.0 = Release|x64 68 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Release|x86.ActiveCfg = Release|Win32 69 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0}.Release|x86.Build.0 = Release|Win32 70 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Debug|x64.ActiveCfg = Debug|x64 71 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Debug|x64.Build.0 = Debug|x64 72 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Debug|x86.ActiveCfg = Debug|Win32 73 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Debug|x86.Build.0 = Debug|Win32 74 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Release|x64.ActiveCfg = Release|x64 75 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Release|x64.Build.0 = Release|x64 76 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Release|x86.ActiveCfg = Release|Win32 77 | {F10E6E67-956F-4847-9110-8B4EB56A2857}.Release|x86.Build.0 = Release|Win32 78 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Debug|x64.ActiveCfg = Debug|x64 79 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Debug|x64.Build.0 = Debug|x64 80 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Debug|x86.ActiveCfg = Debug|Win32 81 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Debug|x86.Build.0 = Debug|Win32 82 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Release|x64.ActiveCfg = Release|x64 83 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Release|x64.Build.0 = Release|x64 84 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Release|x86.ActiveCfg = Release|Win32 85 | {2394591E-0D3A-4444-8E04-4BFBD689C6A1}.Release|x86.Build.0 = Release|Win32 86 | EndGlobalSection 87 | GlobalSection(SolutionProperties) = preSolution 88 | HideSolutionNode = FALSE 89 | EndGlobalSection 90 | GlobalSection(ExtensibilityGlobals) = postSolution 91 | SolutionGuid = {6411F804-D9F6-4820-B686-B1074EAC3572} 92 | EndGlobalSection 93 | EndGlobal 94 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/vs.proj/NppPluginTemplate.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {02b425e1-804d-4f60-90cd-9d26f75623b0} 49 | 50 | 51 | {f10e6e67-956f-4847-9110-8b4eb56a2857} 52 | 53 | 54 | 55 | {9D04DBD5-E12E-44E0-A683-6F43F21D533B} 56 | Win32Proj 57 | NppPluginTemplate 58 | NppSaveAsAdmin 59 | 7.0 60 | 61 | 62 | 63 | DynamicLibrary 64 | true 65 | v141_xp 66 | Unicode 67 | 68 | 69 | DynamicLibrary 70 | true 71 | v141_xp 72 | Unicode 73 | 74 | 75 | DynamicLibrary 76 | false 77 | v141_xp 78 | true 79 | Unicode 80 | 81 | 82 | DynamicLibrary 83 | false 84 | v141_xp 85 | true 86 | Unicode 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | true 106 | ..\bin_debug\ 107 | 108 | 109 | true 110 | ..\bin64_debug\ 111 | 112 | 113 | false 114 | ..\bin\ 115 | 116 | 117 | false 118 | ..\bin64\ 119 | 120 | 121 | 122 | NotUsing 123 | Level4 124 | Disabled 125 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPPLUGINTEMPLATE_EXPORTS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS=1;%(PreprocessorDefinitions) 126 | ../../NppCommon;../../NppSaveAsAdminLib 127 | false 128 | MultiThreadedDebug 129 | 130 | 131 | Windows 132 | true 133 | Version.lib;Dbghelp.lib;shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level4 141 | Disabled 142 | WIN32;_DEBUG;_WINDOWS;_USRDLL;NPPPLUGINTEMPLATE_EXPORTS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS=1;%(PreprocessorDefinitions) 143 | false 144 | ../../NppCommon;../../NppSaveAsAdminLib 145 | MultiThreadedDebug 146 | 147 | 148 | Windows 149 | true 150 | Version.lib;Dbghelp.lib;shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 151 | 152 | 153 | 154 | 155 | Level4 156 | NotUsing 157 | MaxSpeed 158 | true 159 | true 160 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPPLUGINTEMPLATE_EXPORTS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS=1;%(PreprocessorDefinitions) 161 | ../../NppCommon;../../NppSaveAsAdminLib 162 | false 163 | MultiThreaded 164 | 165 | 166 | Windows 167 | false 168 | true 169 | true 170 | Version.lib;Dbghelp.lib;shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 171 | $(TargetName).lib 172 | 173 | 174 | copy ..\license.txt ..\bin\license.txt 175 | copy ..\readme.FIRST ..\bin\readme.FIRST 176 | 177 | 178 | 179 | 180 | Level4 181 | 182 | 183 | MaxSpeed 184 | true 185 | true 186 | WIN32;NDEBUG;_WINDOWS;_USRDLL;NPPPLUGINTEMPLATE_EXPORTS;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_SWPRINTFS=1;%(PreprocessorDefinitions) 187 | false 188 | ../../NppCommon;../../NppSaveAsAdminLib 189 | MultiThreaded 190 | 191 | 192 | Windows 193 | false 194 | true 195 | true 196 | Version.lib;Dbghelp.lib;shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 197 | $(TargetName).lib 198 | 199 | 200 | copy ..\license.txt ..\bin64\license.txt 201 | copy ..\readme.FIRST ..\bin64\readme.FIRST 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /NppSaveAsAdmin/vs.proj/NppPluginTemplate.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | plugin 8 | 9 | 10 | plugin 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | plugin 27 | 28 | 29 | plugin 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {d5f4d2cb-8f1d-481a-9496-585f0f1b3d77} 39 | 40 | 41 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/NppSaveAsAdminLib.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | {caa47112-6d75-466c-ba89-f024b9ba3018} 35 | 36 | 37 | 38 | 15.0 39 | {F10E6E67-956F-4847-9110-8B4EB56A2857} 40 | Win32Proj 41 | NppSaveAsAdminLib 42 | 10.0.17134.0 43 | 44 | 45 | 46 | StaticLibrary 47 | true 48 | v141_xp 49 | Unicode 50 | 51 | 52 | StaticLibrary 53 | false 54 | v141_xp 55 | true 56 | Unicode 57 | 58 | 59 | StaticLibrary 60 | true 61 | v141_xp 62 | Unicode 63 | 64 | 65 | StaticLibrary 66 | false 67 | v141_xp 68 | true 69 | Unicode 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | true 91 | 92 | 93 | true 94 | 95 | 96 | false 97 | 98 | 99 | false 100 | 101 | 102 | 103 | NotUsing 104 | Level4 105 | Disabled 106 | true 107 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 108 | false 109 | 110 | ../NppCommon 111 | MultiThreadedDebug 112 | 113 | 114 | Windows 115 | true 116 | 117 | 118 | 119 | 120 | NotUsing 121 | Level4 122 | Disabled 123 | true 124 | _DEBUG;_LIB;%(PreprocessorDefinitions) 125 | false 126 | 127 | ../NppCommon 128 | MultiThreadedDebug 129 | 130 | 131 | Windows 132 | true 133 | 134 | 135 | 136 | 137 | NotUsing 138 | Level4 139 | MaxSpeed 140 | true 141 | true 142 | true 143 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 144 | false 145 | 146 | ../NppCommon 147 | MultiThreaded 148 | 149 | 150 | Windows 151 | true 152 | true 153 | true 154 | 155 | 156 | 157 | 158 | NotUsing 159 | Level4 160 | MaxSpeed 161 | true 162 | true 163 | true 164 | NDEBUG;_LIB;%(PreprocessorDefinitions) 165 | false 166 | 167 | ../NppCommon 168 | MultiThreaded 169 | 170 | 171 | Windows 172 | true 173 | true 174 | true 175 | 176 | 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/NppSaveAsAdminLib.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | 29 | 30 | Header Files 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/AdminAccess.cpp: -------------------------------------------------------------------------------- 1 | #include "AdminAccess.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "IWinApiFunctions.hpp" 7 | #include "UniqueHandle.hpp" 8 | 9 | HANDLE run_admin_access(const std::wstring& exe_path, 10 | const std::wstring& pipe_sender_name, 11 | const std::wstring& pipe_receiver_name) { 12 | SHELLEXECUTEINFOW sinfo = {0}; 13 | 14 | std::wstring params; 15 | params.append(L"\"") 16 | .append(pipe_sender_name) 17 | .append(L"\" ") 18 | .append(L"\"") 19 | .append(pipe_receiver_name) 20 | .append(L"\""); 21 | 22 | sinfo.cbSize = sizeof(SHELLEXECUTEINFOW); 23 | sinfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS; 24 | sinfo.hwnd = NULL; 25 | sinfo.lpFile = exe_path.c_str(); 26 | sinfo.lpParameters = params.c_str(); // L"\\\\.\\pipe\\my_pipe"; 27 | sinfo.lpVerb = L"runas"; // <<-- this is what makes a UAC prompt show up 28 | sinfo.nShow = SW_SHOWMAXIMIZED; // 29 | 30 | if (TRUE != ShellExecuteExW(&sinfo)) 31 | return INVALID_HANDLE_VALUE; 32 | 33 | return sinfo.hProcess; 34 | } 35 | 36 | bool file_exists(const std::wstring& file) { 37 | const DWORD attributes = GetFileAttributes(file.c_str()); 38 | 39 | return (attributes != INVALID_FILE_ATTRIBUTES && 40 | !(attributes & FILE_ATTRIBUTE_DIRECTORY)); 41 | } 42 | 43 | HANDLE run_admin_access_app(const std::wstring& exe_path, 44 | const std::wstring& pipe_sender_name, 45 | const std::wstring& pipe_receiver_name) { 46 | if (!file_exists(exe_path)) 47 | return INVALID_HANDLE_VALUE; 48 | 49 | return run_admin_access(exe_path, pipe_sender_name, pipe_receiver_name); 50 | } 51 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/AdminAccess.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class IWinApiFunctions; 7 | 8 | HANDLE run_admin_access_app(const std::wstring& exe_path, 9 | const std::wstring& pipe_sender_name, 10 | const std::wstring& pipe_receiver_name); 11 | 12 | bool file_exists(const std::wstring& file); 13 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/FuncExecutor.cpp: -------------------------------------------------------------------------------- 1 | #include "FuncExecutor.hpp" 2 | 3 | #include "Common.hpp" 4 | 5 | #include "Pipe.hpp" 6 | 7 | template 8 | bool execute_function(Pipe& pipe_sender, 9 | Pipe& pipe_receiver, 10 | const InData& in_data, 11 | Commands cmd_num, 12 | OutData& out_data) { 13 | std::vector in_buffer; 14 | std::vector read_buffer; 15 | 16 | PacketWithCommand* in_ptr = 17 | prepare_vector_to_store_data>(in_buffer); 18 | in_ptr->command = cmd_num; 19 | in_ptr->commandData = in_data; 20 | 21 | if (!pipe_sender.write(in_buffer)) 22 | return false; 23 | 24 | const bool read_result = pipe_receiver.read(read_buffer); 25 | return read_result && read_data_from_vector(out_data, read_buffer); 26 | } 27 | 28 | HANDLE execute_create_file_w(Pipe& pipe_sender, 29 | Pipe& pipe_receiver, 30 | LPCWSTR file_name, 31 | DWORD desired_access, 32 | DWORD share_mode, 33 | DWORD creation_disposition, 34 | DWORD flags_and_attributes) { 35 | CreateFileDataW tcfdw = {0}; 36 | wcscpy_s(tcfdw.filename, file_name); 37 | tcfdw.desired_access = desired_access; 38 | tcfdw.share_mode = share_mode; 39 | tcfdw.flags_and_attributes = flags_and_attributes; 40 | tcfdw.creation_disposition = creation_disposition; 41 | CreateFileResult result = {0}; 42 | if (!execute_function(pipe_sender, pipe_receiver, tcfdw, CreateFileWCmd, 43 | result)) 44 | return INVALID_HANDLE_VALUE; 45 | 46 | SetLastError(result.last_error); 47 | 48 | return result.handle; 49 | } 50 | 51 | inline void set_number_of_bytes_written(LPDWORD result, DWORD written) { 52 | if (result) { 53 | *result = written; 54 | } 55 | } 56 | 57 | BOOL execute_write_file(Pipe& pipe_sender, 58 | Pipe& pipe_receiver, 59 | HANDLE original_handle, 60 | LPCVOID buffer_ptr, 61 | DWORD number_of_bytes_to_write, 62 | LPDWORD number_of_bytes_written) { 63 | const char* ptr = static_cast(buffer_ptr); 64 | 65 | DWORD written = 0; 66 | 67 | do { 68 | WriteFileData twfd = {0}; 69 | twfd.handle = original_handle; 70 | twfd.num_bytes_to_write = 71 | min(WriteFileData::MaxBufferSize, number_of_bytes_to_write); 72 | if (ptr) 73 | memcpy(twfd.buffer, ptr, twfd.num_bytes_to_write); 74 | else 75 | twfd.buffer_is_null = true; 76 | 77 | WriteFileResult result = {0}; 78 | if (!execute_function(pipe_sender, pipe_receiver, twfd, WriteFileCmd, 79 | result)) { 80 | set_number_of_bytes_written(number_of_bytes_written, written); 81 | return FALSE; 82 | } 83 | 84 | written += result.bytes_written; 85 | 86 | if (!result.success || twfd.num_bytes_to_write != result.bytes_written) { 87 | SetLastError(result.last_error); 88 | set_number_of_bytes_written(number_of_bytes_written, written); 89 | return FALSE; 90 | } 91 | 92 | if (ptr) 93 | ptr += result.bytes_written; 94 | number_of_bytes_to_write -= result.bytes_written; 95 | } while (number_of_bytes_to_write > 0); 96 | 97 | set_number_of_bytes_written(number_of_bytes_written, written); 98 | 99 | return TRUE; 100 | } 101 | 102 | DWORD execute_get_file_type(Pipe& pipe_sender, 103 | Pipe& pipe_receiver, 104 | HANDLE handle) { 105 | GetFileTypeData tgft = {0}; 106 | tgft.handle = handle; 107 | GetFileTypeResult result = {0}; 108 | if (!execute_function(pipe_sender, pipe_receiver, tgft, GetFileTypeCmd, 109 | result)) 110 | return FALSE; 111 | 112 | SetLastError(result.last_error); 113 | 114 | return result.type; 115 | } 116 | 117 | BOOL execute_close_handle(Pipe& pipe_sender, 118 | Pipe& pipe_receiver, 119 | HANDLE handle) { 120 | CloseHandleData tchd = {0}; 121 | tchd.handle = handle; 122 | CloseHandleResult result = {0}; 123 | if (!execute_function(pipe_sender, pipe_receiver, tchd, CloseHandleCmd, 124 | result)) 125 | return FALSE; 126 | 127 | SetLastError(result.last_error); 128 | 129 | return result.success; 130 | } 131 | 132 | void execute_exit(Pipe& pipe_sender) { 133 | char code = ExitCmd; 134 | pipe_sender.write(data_to_vector(code)); 135 | } 136 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/FuncExecutor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Pipe; 6 | 7 | HANDLE execute_create_file_w(Pipe& pipe_sender, 8 | Pipe& pipe_receiver, 9 | LPCWSTR file_name, 10 | DWORD desired_access, 11 | DWORD share_mode, 12 | DWORD creation_disposition, 13 | DWORD flags_and_attributes); 14 | 15 | BOOL execute_write_file(Pipe& pipe_sender, 16 | Pipe& pipe_receiver, 17 | HANDLE orig_handle, 18 | LPCVOID buffer, 19 | DWORD number_of_bytes_to_write, 20 | LPDWORD number_of_bytes_written); 21 | DWORD execute_get_file_type(Pipe& pipe_sender, 22 | Pipe& pipe_receiver, 23 | HANDLE handle); 24 | 25 | BOOL execute_close_handle(Pipe& pipe_sender, 26 | Pipe& pipe_receiver, 27 | HANDLE handle); 28 | void execute_exit(Pipe& pipe_sender); 29 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/Injection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | const std::uint32_t MaxModuleNameLen = 128; 12 | const std::uint32_t MaxFunctionNameLen = 64; 13 | 14 | inline void append_new_ptr_impl(PROC* ptr_to_fun_memory, PROC ptr_to_new_fun) { 15 | MEMORY_BASIC_INFORMATION mbi = {0}; 16 | VirtualQuery(ptr_to_fun_memory, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); 17 | VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, 18 | &mbi.Protect); 19 | 20 | // Replace the original address of API with the address of corresponding 21 | // wrapper function 22 | *ptr_to_fun_memory = *ptr_to_new_fun; 23 | 24 | DWORD old_protect = 0; 25 | VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &old_protect); 26 | } 27 | 28 | template 29 | void append_new_ptr(PROC* ptr_to_fun_memory, Proc ptr_to_new_fun) { 30 | append_new_ptr_impl(ptr_to_fun_memory, 31 | reinterpret_cast(ptr_to_new_fun)); 32 | }; 33 | 34 | inline bool name_is_suitable(const char* desired_module_name, 35 | HMODULE module_handle, 36 | PIMAGE_IMPORT_DESCRIPTOR import_description) { 37 | return !desired_module_name || 38 | 0 == StrCmpIA((char*)((PBYTE)module_handle + import_description->Name), 39 | desired_module_name); 40 | } 41 | 42 | template 43 | struct InjectionResult { 44 | PROC* old_function_position = nullptr; 45 | Proc old_function = nullptr; 46 | }; 47 | 48 | template 49 | InjectionResult process_injection(const char* module_name, 50 | const char* function_name, 51 | Proc ptr_to_new_fun) { 52 | const size_t name_length = strnlen(function_name, MaxFunctionNameLen); 53 | HMODULE module_handle = GetModuleHandle(NULL); 54 | 55 | if (!module_handle) 56 | throw std::logic_error("Failed to retrieve module handle"); 57 | 58 | ULONG description_size = 0; 59 | 60 | PIMAGE_IMPORT_DESCRIPTOR import_description = 61 | (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData( 62 | module_handle, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &description_size); 63 | 64 | for (; import_description && import_description->Name; ++import_description) { 65 | if (name_is_suitable(module_name, module_handle, import_description)) 66 | break; 67 | } 68 | 69 | for (; import_description && import_description->Name; ++import_description) { 70 | if (!name_is_suitable(module_name, module_handle, import_description)) 71 | break; 72 | PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)( 73 | (PBYTE)module_handle + import_description->FirstThunk); 74 | PIMAGE_THUNK_DATA thunk_orig = (PIMAGE_THUNK_DATA)( 75 | (PBYTE)module_handle + import_description->OriginalFirstThunk); 76 | 77 | while (thunk->u1.AddressOfData) { 78 | PROC* ppfn = (PROC*)&thunk->u1.AddressOfData; 79 | 80 | PIMAGE_IMPORT_BY_NAME image_name = (PIMAGE_IMPORT_BY_NAME)( 81 | (PBYTE)module_handle + thunk_orig->u1.AddressOfData); 82 | 83 | if (0 == 84 | strncmp(function_name, (const char*)image_name->Name, name_length)) { 85 | InjectionResult result; 86 | result.old_function_position = ppfn; 87 | result.old_function = (Proc)(PROC)*ppfn; 88 | append_new_ptr(ppfn, ptr_to_new_fun); 89 | 90 | return result; 91 | } 92 | 93 | thunk++; 94 | thunk_orig++; 95 | } 96 | } 97 | std::stringstream error_info; 98 | error_info << "Injected function '" << function_name << "' "; 99 | if (module_name) { 100 | error_info << "in module '" << module_name << "' "; 101 | } 102 | error_info << "was not found"; 103 | throw std::logic_error(error_info.str()); 104 | } 105 | 106 | template 107 | class ScopedInjector { 108 | typedef Ret(WINAPI* WinapiFunctionPointer)(Args...); 109 | 110 | struct Data { 111 | InjectionResult injection_result; 112 | std::function callback; 113 | }; 114 | 115 | Data* m_data = nullptr; 116 | 117 | template 118 | struct StaticFunctionWrapper { 119 | static Data data; 120 | static Ret WINAPI injected_function(Args... args) { 121 | if (data.callback) { 122 | return data.callback(args...); 123 | } 124 | return data.injection_result.old_function(args...); 125 | } 126 | }; 127 | 128 | public: 129 | template 130 | ScopedInjector(Unique, 131 | const char* module, 132 | const char* function, 133 | std::function callback) { 134 | static StaticFunctionWrapper static_function; 135 | if (static_function.data.callback) { 136 | std::stringstream descr; 137 | descr << "You can't use same injection macro to "; 138 | descr << " inject same function more than once."; 139 | if (function) 140 | descr << " Function:" << function; 141 | if (module) 142 | descr << " in module: " << module; 143 | throw std::logic_error(descr.str()); 144 | } 145 | static_function.data.callback = callback; 146 | m_data = &static_function.data; 147 | try { 148 | static_function.data.injection_result = process_injection( 149 | module, function, static_function.injected_function); 150 | } catch (...) { 151 | static_function.data.callback = nullptr; 152 | throw; 153 | } 154 | } 155 | 156 | ~ScopedInjector() { 157 | m_data->callback = nullptr; 158 | append_new_ptr(m_data->injection_result.old_function_position, 159 | m_data->injection_result.old_function); 160 | } 161 | 162 | Ret call_original(Args... args) { 163 | return m_data->injection_result.old_function(args...); 164 | } 165 | 166 | using Pointer = std::unique_ptr>; 167 | }; 168 | 169 | template 170 | template 171 | typename ScopedInjector::Data 172 | ScopedInjector::StaticFunctionWrapper::data; 173 | 174 | template 175 | auto make_inject(const char* module, 176 | const char* function, 177 | Ret(WINAPI* ptr_to_original_fun)(Args...), 178 | std::function new_function) { 179 | Unique unique; 180 | (void)ptr_to_original_fun; 181 | return std::make_unique>(unique, module, 182 | function, new_function); 183 | } 184 | 185 | template 186 | auto make_inject(const char* module, 187 | const char* function, 188 | Ret(WINAPI* ptr_to_original_fun)(Args...), 189 | CallbackType new_function) { 190 | std::function function_wrapper = [=](Args... args) { 191 | return new_function(args...); 192 | }; 193 | return make_inject(module, function, ptr_to_original_fun, 194 | function_wrapper); 195 | } 196 | 197 | template 198 | auto injection_type_helper(Ret(WINAPI*)(Args...)) { 199 | return ScopedInjector::Pointer(nullptr); 200 | } 201 | 202 | #define injection_stringize_helper(s) #s 203 | #define injection_stringize(s) injection_stringize_helper(s) 204 | 205 | #define injection_ptr_type(win_api_function) \ 206 | decltype(injection_type_helper(win_api_function)) 207 | 208 | #define inject(win_api_function, new_function) \ 209 | inject_in_module(nullptr, win_api_function, new_function) 210 | 211 | #define inject_in_module(module_name, win_api_function, new_function) \ 212 | [](auto module_name_var, auto&& new_function_var) { \ 213 | struct Unique {}; \ 214 | return make_inject(module_name_var, \ 215 | injection_stringize(win_api_function), \ 216 | win_api_function, new_function_var); \ 217 | }(module_name, new_function); 218 | 219 | template 220 | auto make_injection_callback(ClassObj& object, 221 | Rest (ClassWithMemeber::*member)(Args...)) { 222 | ClassObj* object_ptr = &object; 223 | return [=](Args... args) { return (object_ptr->*member)(args...); }; 224 | } 225 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/SaveAsAdminImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "SaveAsAdminImpl.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "AdminAccess.hpp" 7 | #include "FuncExecutor.hpp" 8 | #include "IWinApiFunctions.hpp" 9 | #include "Injection.hpp" 10 | 11 | #include "Pipe.hpp" 12 | 13 | class SaveAsAdminImpl::Impl { 14 | public: 15 | Impl(AdminAccessRunner& admin_access_runner) 16 | : m_admin_access_runner(admin_access_runner) { 17 | m_write_file = inject_in_module( 18 | "Kernel32.dll", WriteFile, 19 | make_injection_callback(*this, &Impl::write_file_hook)); 20 | 21 | m_create_filew = inject_in_module( 22 | "Kernel32.dll", CreateFileW, 23 | make_injection_callback(*this, &Impl::create_file_w_hook)); 24 | m_get_file_type = inject_in_module( 25 | "Kernel32.dll", GetFileType, 26 | make_injection_callback(*this, &Impl::get_file_type_hook)); 27 | m_close_handle = inject_in_module( 28 | "Kernel32.dll", CloseHandle, 29 | make_injection_callback(*this, &Impl::close_handle_hook)); 30 | } 31 | 32 | void allow_process_file() { m_is_process_allowed = true; } 33 | 34 | void cancel_process_file() { m_is_process_allowed = false; } 35 | 36 | private: 37 | BOOL write_file_hook(HANDLE file_handle, 38 | LPCVOID buffer, 39 | DWORD number_of_bytes_to_write, 40 | LPDWORD number_of_bytes_written, 41 | LPOVERLAPPED overlapped) { 42 | HandleMap::iterator it = m_file_handles.find(file_handle); 43 | if (it != m_file_handles.end()) { 44 | return execute_write_file( 45 | *it->second->pipe_sender, *it->second->pipe_receiver, 46 | it->second->origin_handle, buffer, number_of_bytes_to_write, 47 | number_of_bytes_written); 48 | } else { 49 | return m_write_file->call_original(file_handle, buffer, 50 | number_of_bytes_to_write, 51 | number_of_bytes_written, overlapped); 52 | } 53 | } 54 | 55 | HANDLE create_file_w_hook(LPCWSTR file_name, 56 | DWORD desired_access, 57 | DWORD share_mode, 58 | LPSECURITY_ATTRIBUTES security_attributes, 59 | DWORD creation_disposition, 60 | DWORD flags_and_attributes, 61 | HANDLE template_file) { 62 | HANDLE result = m_create_filew->call_original( 63 | file_name, desired_access, share_mode, security_attributes, 64 | creation_disposition, flags_and_attributes, template_file); 65 | 66 | if (INVALID_HANDLE_VALUE == result && (desired_access & GENERIC_WRITE)) { 67 | const int error_code = GetLastError(); 68 | if (ERROR_ACCESS_DENIED == error_code && m_is_process_allowed) { 69 | std::unique_ptr new_handle = std::make_unique(); 70 | new_handle->pipe_sender = Pipe::create_unique(); 71 | new_handle->pipe_receiver = Pipe::create_unique(); 72 | if (!new_handle->pipe_sender || !new_handle->pipe_receiver) { 73 | return INVALID_HANDLE_VALUE; 74 | } 75 | 76 | new_handle->proc_handle = m_admin_access_runner.run_admin_access( 77 | new_handle->pipe_sender->get_name(), 78 | new_handle->pipe_receiver->get_name()); 79 | if (INVALID_HANDLE_VALUE == new_handle->proc_handle) { 80 | return INVALID_HANDLE_VALUE; 81 | } 82 | 83 | new_handle->pipe_sender->wait(); 84 | new_handle->pipe_receiver->wait(); 85 | 86 | new_handle->origin_handle = execute_create_file_w( 87 | *new_handle->pipe_sender, *new_handle->pipe_receiver, file_name, 88 | desired_access, share_mode, creation_disposition, 89 | flags_and_attributes); 90 | if (INVALID_HANDLE_VALUE == new_handle->origin_handle) { 91 | return INVALID_HANDLE_VALUE; 92 | } 93 | 94 | result = new_handle->proc_handle; 95 | m_file_handles[new_handle->proc_handle] = std::move(new_handle); 96 | } 97 | } 98 | 99 | return result; 100 | } 101 | 102 | BOOL close_handle_hook(HANDLE handle) { 103 | HandleMap::iterator it = m_file_handles.find(handle); 104 | if (it != m_file_handles.end()) { 105 | BOOL result = execute_close_handle(*it->second->pipe_sender, 106 | *it->second->pipe_receiver, 107 | it->second->origin_handle); 108 | execute_exit(*it->second->pipe_sender); 109 | m_file_handles.erase(it); 110 | return result; 111 | } else { 112 | return m_close_handle->call_original(handle); 113 | } 114 | } 115 | 116 | DWORD get_file_type_hook(HANDLE handle) { 117 | HandleMap::iterator it = m_file_handles.find(handle); 118 | if (it != m_file_handles.end()) 119 | return execute_get_file_type(*it->second->pipe_sender, 120 | *it->second->pipe_receiver, 121 | it->second->origin_handle); 122 | else 123 | return m_get_file_type->call_original(handle); 124 | } 125 | 126 | private: 127 | AdminAccessRunner& m_admin_access_runner; 128 | bool m_is_process_allowed = false; 129 | 130 | struct FileHandle { 131 | std::unique_ptr pipe_sender; 132 | std::unique_ptr pipe_receiver; 133 | HANDLE proc_handle; 134 | HANDLE origin_handle; 135 | }; 136 | 137 | using HandleMap = std::map>; 138 | HandleMap m_file_handles; 139 | 140 | injection_ptr_type(WriteFile) m_write_file; 141 | injection_ptr_type(CreateFileW) m_create_filew; 142 | injection_ptr_type(GetFileType) m_get_file_type; 143 | injection_ptr_type(CloseHandle) m_close_handle; 144 | }; 145 | 146 | namespace { 147 | class DefaultAdminAccessRunner : public AdminAccessRunner { 148 | public: 149 | DefaultAdminAccessRunner(std::wstring exe_path) 150 | : m_exe_path(std::move(exe_path)) {} 151 | 152 | private: 153 | HANDLE run_admin_access(const std::wstring& pipe_sender_name, 154 | const std::wstring& pipe_receiver_name) override { 155 | return run_admin_access_app(m_exe_path, pipe_sender_name, 156 | pipe_receiver_name); 157 | } 158 | 159 | private: 160 | std::wstring m_exe_path; 161 | }; 162 | } // namespace 163 | 164 | AdminAccessRunner::~AdminAccessRunner() = default; 165 | 166 | std::unique_ptr AdminAccessRunner::make_default( 167 | std::wstring admin_runner_exe_path) { 168 | return std::unique_ptr( 169 | new DefaultAdminAccessRunner(std::move(admin_runner_exe_path))); 170 | } 171 | 172 | SaveAsAdminImpl::SaveAsAdminImpl(AdminAccessRunner& admin_access_runner) 173 | : m_impl(std::make_unique(admin_access_runner)) {} 174 | 175 | SaveAsAdminImpl::~SaveAsAdminImpl() = default; 176 | 177 | void SaveAsAdminImpl::allow_process_file() { 178 | m_impl->allow_process_file(); 179 | } 180 | 181 | void SaveAsAdminImpl::cancel_process_file() { 182 | m_impl->allow_process_file(); 183 | } 184 | -------------------------------------------------------------------------------- /NppSaveAsAdminLib/plugin/SaveAsAdminImpl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | class IWinApiFunctions; 9 | 10 | class AdminAccessRunner { 11 | public: 12 | virtual HANDLE run_admin_access(const std::wstring& pipe_sender_name, 13 | const std::wstring& pipe_receiver_name) = 0; 14 | 15 | static std::unique_ptr make_default( 16 | std::wstring admin_runner_exe_path); 17 | virtual ~AdminAccessRunner(); 18 | }; 19 | 20 | class SaveAsAdminImpl { 21 | public: 22 | SaveAsAdminImpl(AdminAccessRunner& admin_access_runner); 23 | ~SaveAsAdminImpl(); 24 | 25 | void allow_process_file(); 26 | void cancel_process_file(); 27 | 28 | private: 29 | class Impl; 30 | std::unique_ptr m_impl; 31 | }; 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NppSaveAsAdmin 2 | Notepad++ Plugin nppSaveAsAdmin 3 | 4 | Allows to save file as administrator with UAC prompt. 5 | 6 | ## Installation 7 | Unpack to "%APPDATA%/Notepad++/plugins" to install 8 | 9 | 10 | ## Build Status 11 | AppVeyor `VS2017` [![Build status](https://ci.appveyor.com/api/projects/status/5886r5k7vu75qkdj?svg=true)](https://ci.appveyor.com/project/Hsilgos/nppsaveasadmin) -------------------------------------------------------------------------------- /UnitTests/ExecutionThread.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "CommandManager.hpp" 6 | #include "CommandProcessor.hpp" 7 | #include "Pipe.hpp" 8 | #include "plugin/FuncExecutor.hpp" 9 | #include "plugin/SaveAsAdminImpl.hpp" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | struct ExecutionThread { 16 | std::unique_ptr pipe_sender; 17 | std::unique_ptr pipe_receiver; 18 | std::thread thread; 19 | int execution_result = 0; 20 | CommandManager command_manager; 21 | 22 | ExecutionThread(bool auto_start = true) { 23 | if (auto_start) 24 | start(); 25 | } 26 | 27 | ~ExecutionThread() { stop(true); } 28 | 29 | void start() { 30 | pipe_sender = Pipe::create_unique(); 31 | pipe_receiver = Pipe::create_unique(); 32 | start(pipe_sender->get_name(), pipe_receiver->get_name()); 33 | pipe_sender->wait(); 34 | pipe_receiver->wait(); 35 | SetLastError(ERROR_SUCCESS); 36 | } 37 | 38 | void start(const std::wstring& pipe_sender_name, 39 | const std::wstring& pipe_receiver_name) { 40 | thread = std::thread([this, pipe_sender_name = pipe_sender_name, 41 | pipe_receiver_name = pipe_receiver_name]() { 42 | execution_result = process_commands(command_manager, pipe_sender_name, 43 | pipe_receiver_name); 44 | EXPECT_NE(FailedToOpenPipe, execution_result); 45 | if (FailedToOpenPipe == execution_result) { 46 | std::terminate(); 47 | } 48 | }); 49 | } 50 | 51 | void stop(bool call_execute_exit) { 52 | if (thread.joinable()) { 53 | auto future = std::async(std::launch::async, &std::thread::join, &thread); 54 | if (call_execute_exit) { 55 | EXPECT_NE(pipe_sender, nullptr); 56 | execute_exit(*pipe_sender); 57 | } 58 | EXPECT_NE(future.wait_for(std::chrono::seconds(5)), 59 | std::future_status::timeout); 60 | if (thread.joinable()) { 61 | std::terminate(); 62 | } 63 | } 64 | } 65 | int wait() { 66 | stop(false); 67 | return execution_result; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /UnitTests/MockWinApiFunctions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "IWinApiFunctions.hpp" 6 | 7 | class MockWinApiFunctions : public IWinApiFunctions { 8 | public: 9 | MOCK_METHOD5(write_file, BOOL(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED)); 10 | MOCK_METHOD7(create_file_a, 11 | HANDLE(LPCSTR, 12 | DWORD, 13 | DWORD, 14 | LPSECURITY_ATTRIBUTES, 15 | DWORD, 16 | DWORD, 17 | HANDLE)); 18 | MOCK_METHOD7(create_file_w, 19 | HANDLE(LPCWSTR, 20 | DWORD, 21 | DWORD, 22 | LPSECURITY_ATTRIBUTES, 23 | DWORD, 24 | DWORD, 25 | HANDLE)); 26 | MOCK_METHOD1(close_handle, BOOL(HANDLE)); 27 | MOCK_METHOD1(get_file_type, DWORD(HANDLE)); 28 | }; 29 | -------------------------------------------------------------------------------- /UnitTests/TestInjection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "plugin/AdminAccess.hpp" 4 | #include "plugin/Injection.hpp" 5 | #include "plugin/SaveAsAdminImpl.hpp" 6 | 7 | #include "CommandManager.hpp" 8 | #include "CommandProcessor.hpp" 9 | #include "TestUtilities.hpp" 10 | 11 | #include "IWinApiFunctions.hpp" 12 | #include "MockWinApiFunctions.hpp" 13 | #include "Pipe.hpp" 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace { 21 | const char* TestFileName1 = "test_file1.txt"; 22 | const std::string TestBuffer = "test_text"; 23 | const HANDLE ValidHandle = reinterpret_cast(1); 24 | 25 | const HANDLE ValidHandle1 = reinterpret_cast(1); 26 | const HANDLE ValidHandle2 = reinterpret_cast(2); 27 | 28 | using ::testing::_; 29 | using ::testing::Return; 30 | 31 | class InjectionFixture : public ::testing::Test { 32 | public: 33 | FileAutoremover file_auto_remove = FileAutoremover(TestFileName1); 34 | ::testing::StrictMock mock_winapi; 35 | 36 | void configure_mock_default() { 37 | ON_CALL(mock_winapi, create_file_a(_, _, _, _, _, _, _)) 38 | .WillByDefault(Return(ValidHandle)); 39 | ON_CALL(mock_winapi, write_file(_, _, _, _, _)) 40 | .WillByDefault(Return(TRUE)); 41 | ON_CALL(mock_winapi, close_handle(_)) 42 | .WillByDefault(Return(TRUE)); 43 | } 44 | 45 | template 46 | auto test_callback(Rest (MockWinApiFunctions::*member)(Args...)) { 47 | return make_injection_callback(mock_winapi, member); 48 | } 49 | 50 | HANDLE create_file_default() { 51 | return CreateFileA(TestFileName1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 52 | FILE_ATTRIBUTE_NORMAL, NULL); 53 | } 54 | void write_file_with_win_api() { 55 | HANDLE file = create_file_default(); 56 | ASSERT_NE(INVALID_HANDLE_VALUE, file); 57 | EXPECT_TRUE( 58 | WriteFile(file, TestBuffer.c_str(), get_size_as_ulong(TestBuffer), NULL, NULL)); 59 | CloseHandle(file); 60 | } 61 | 62 | void check_file_exists() { 63 | std::ifstream read_file(TestFileName1); 64 | ASSERT_TRUE(read_file); 65 | std::string file_content; 66 | read_file >> file_content; 67 | EXPECT_EQ(TestBuffer, file_content); 68 | } 69 | 70 | void check_file_not_exists() { 71 | std::ifstream read_file(TestFileName1); 72 | EXPECT_FALSE(read_file); 73 | } 74 | }; 75 | 76 | TEST_F(InjectionFixture, WriteFileWithoutInjection) { 77 | write_file_with_win_api(); 78 | check_file_exists(); 79 | } 80 | 81 | TEST_F(InjectionFixture, CreateFileIsHookedAndReleased) { 82 | EXPECT_CALL(mock_winapi, create_file_a(_, _, _, _, _, _, _)) 83 | .WillOnce(Return(ValidHandle)); 84 | auto create_file = 85 | inject_in_module("Kernel32.dll", CreateFileA, 86 | test_callback(&MockWinApiFunctions::create_file_a)); 87 | HANDLE file_handle = create_file_default(); 88 | ASSERT_EQ(ValidHandle, file_handle); 89 | 90 | create_file.reset(); 91 | file_handle = create_file_default(); 92 | ASSERT_NE(INVALID_HANDLE_VALUE, file_handle); 93 | EXPECT_TRUE(WriteFile(file_handle, TestBuffer.c_str(), get_size_as_ulong(TestBuffer), 94 | NULL, NULL)); 95 | CloseHandle(file_handle); 96 | 97 | check_file_exists(); 98 | } 99 | 100 | TEST_F(InjectionFixture, CreateFileIsHookedAndReleased_NoModule) { 101 | EXPECT_CALL(mock_winapi, create_file_a(_, _, _, _, _, _, _)) 102 | .WillOnce(Return(ValidHandle)); 103 | auto create_file = inject( 104 | CreateFileA, test_callback(&MockWinApiFunctions::create_file_a)); 105 | HANDLE file_handle = create_file_default(); 106 | ASSERT_EQ(ValidHandle, file_handle); 107 | 108 | create_file.reset(); 109 | file_handle = create_file_default(); 110 | ASSERT_NE(INVALID_HANDLE_VALUE, file_handle); 111 | EXPECT_TRUE(WriteFile(file_handle, TestBuffer.c_str(), get_size_as_ulong(TestBuffer), 112 | NULL, NULL)); 113 | CloseHandle(file_handle); 114 | 115 | check_file_exists(); 116 | } 117 | 118 | TEST_F(InjectionFixture, TryToInjectInWrongModule) { 119 | EXPECT_THROW( 120 | inject_in_module("WrongModule.dll", CreateFileA, 121 | test_callback(&MockWinApiFunctions::create_file_a)), 122 | std::logic_error); 123 | } 124 | 125 | TEST_F(InjectionFixture, TryToInjectTwice_WithSameMacro) { 126 | auto inject_same_function = [this]() { 127 | return inject(CreateFileA, 128 | test_callback(&MockWinApiFunctions::create_file_a)); 129 | }; 130 | auto injection = inject_same_function(); 131 | EXPECT_THROW(inject_same_function(), std::logic_error); 132 | } 133 | 134 | TEST_F(InjectionFixture, InjectTwice_LastAliveReceivesOperations) { 135 | ::testing::StrictMock file_operations1; 136 | ::testing::StrictMock file_operations2; 137 | 138 | EXPECT_CALL(file_operations1, create_file_a(_, _, _, _, _, _, _)) 139 | .WillOnce(Return(ValidHandle1)); 140 | EXPECT_CALL(file_operations2, create_file_a(_, _, _, _, _, _, _)) 141 | .WillOnce(Return(ValidHandle2)); 142 | 143 | auto create_file1 = 144 | inject(CreateFileA, 145 | make_injection_callback(file_operations1, 146 | &MockWinApiFunctions::create_file_a)); 147 | auto create_file2 = 148 | inject(CreateFileA, 149 | make_injection_callback(file_operations2, 150 | &MockWinApiFunctions::create_file_a)); 151 | 152 | ASSERT_EQ(ValidHandle2, create_file_default()); 153 | 154 | create_file2.reset(); 155 | 156 | ASSERT_EQ(ValidHandle1, create_file_default()); 157 | 158 | create_file1.reset(); 159 | 160 | write_file_with_win_api(); 161 | check_file_exists(); 162 | } 163 | 164 | TEST_F(InjectionFixture, InjectTwice_CallOriginalCallsPrevious) { 165 | ::testing::StrictMock file_operations1; 166 | ::testing::StrictMock file_operations2; 167 | 168 | EXPECT_CALL(file_operations1, create_file_a(_, _, _, _, _, _, _)) 169 | .WillOnce(Return(ValidHandle1)); 170 | 171 | auto create_file1 = 172 | inject(CreateFileA, 173 | make_injection_callback(file_operations1, 174 | &MockWinApiFunctions::create_file_a)); 175 | auto create_file2 = 176 | inject(CreateFileA, 177 | make_injection_callback(file_operations2, 178 | &MockWinApiFunctions::create_file_a)); 179 | 180 | ASSERT_EQ(ValidHandle1, create_file2->call_original( 181 | TestFileName1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 182 | FILE_ATTRIBUTE_NORMAL, NULL)); 183 | } 184 | 185 | TEST_F(InjectionFixture, InjectThreeTimes_ResetMiddle) { 186 | ::testing::StrictMock file_operations1; 187 | ::testing::StrictMock file_operations2; 188 | ::testing::StrictMock file_operations3; 189 | 190 | EXPECT_CALL(file_operations1, create_file_a(_, _, _, _, _, _, _)) 191 | .WillOnce(Return(ValidHandle1)); 192 | 193 | auto create_file1 = 194 | inject(CreateFileA, 195 | make_injection_callback(file_operations1, 196 | &MockWinApiFunctions::create_file_a)); 197 | auto create_file2 = 198 | inject(CreateFileA, 199 | make_injection_callback(file_operations2, 200 | &MockWinApiFunctions::create_file_a)); 201 | auto create_file3 = 202 | inject(CreateFileA, 203 | make_injection_callback(file_operations3, 204 | &MockWinApiFunctions::create_file_a)); 205 | 206 | create_file2.reset(); 207 | 208 | ASSERT_EQ(ValidHandle1, create_file3->call_original( 209 | TestFileName1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 210 | FILE_ATTRIBUTE_NORMAL, NULL)); 211 | } 212 | 213 | TEST_F(InjectionFixture, CallOriginalFunctionAfterHook) { 214 | auto create_file = 215 | inject_in_module("Kernel32.dll", CreateFileA, 216 | test_callback(&MockWinApiFunctions::create_file_a)); 217 | HANDLE file_handle = 218 | create_file->call_original(TestFileName1, GENERIC_WRITE, 0, NULL, 219 | CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 220 | ASSERT_NE(INVALID_HANDLE_VALUE, file_handle); 221 | EXPECT_TRUE(WriteFile(file_handle, TestBuffer.c_str(), get_size_as_ulong(TestBuffer), 222 | NULL, NULL)); 223 | CloseHandle(file_handle); 224 | 225 | check_file_exists(); 226 | } 227 | 228 | TEST_F(InjectionFixture, WriteFileWithInjection) { 229 | EXPECT_CALL(mock_winapi, create_file_a(_, _, _, _, _, _, _)) 230 | .WillOnce(Return(ValidHandle)); 231 | EXPECT_CALL(mock_winapi, write_file(_, _, _, _, _)) 232 | .WillOnce(Return(TRUE)); 233 | EXPECT_CALL(mock_winapi, close_handle(_)).WillOnce(Return(TRUE)); 234 | 235 | auto create_file = 236 | inject_in_module("Kernel32.dll", CreateFileA, 237 | test_callback(&MockWinApiFunctions::create_file_a)); 238 | auto write_file = 239 | inject_in_module("Kernel32.dll", WriteFile, 240 | test_callback(&MockWinApiFunctions::write_file)); 241 | auto close_handle = 242 | inject_in_module("Kernel32.dll", CloseHandle, 243 | test_callback(&MockWinApiFunctions::close_handle)); 244 | 245 | write_file_with_win_api(); 246 | check_file_not_exists(); 247 | 248 | create_file.reset(); 249 | write_file.reset(); 250 | close_handle.reset(); 251 | 252 | write_file_with_win_api(); 253 | check_file_exists(); 254 | } 255 | } // namespace 256 | -------------------------------------------------------------------------------- /UnitTests/TestPipe.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Pipe.hpp" 8 | 9 | namespace { 10 | std::vector string_as_vector(const std::string& str) { 11 | return std::vector(str.begin(), str.end()); 12 | } 13 | 14 | TEST(Pipe, ShouldBeUbique) { 15 | auto pipe1 = Pipe::create_unique(); 16 | auto pipe2 = Pipe::create_unique(); 17 | ASSERT_NE(nullptr, pipe1.get()); 18 | ASSERT_NE(nullptr, pipe2.get()); 19 | EXPECT_FALSE(pipe1->get_name().empty()); 20 | EXPECT_FALSE(pipe2->get_name().empty()); 21 | EXPECT_NE(pipe1->get_name(), pipe2->get_name()); 22 | } 23 | 24 | TEST(Pipe, WriteRead) { 25 | auto pipe1 = Pipe::create_unique(); 26 | ASSERT_NE(nullptr, pipe1); 27 | auto pipe2 = Pipe::open(pipe1->get_name()); 28 | ASSERT_NE(nullptr, pipe2); 29 | 30 | const std::vector expected_buffer = string_as_vector("test buffer"); 31 | EXPECT_TRUE(pipe2->write(expected_buffer)); 32 | 33 | std::vector buffer; 34 | EXPECT_TRUE(pipe1->read(buffer)); 35 | 36 | EXPECT_THAT(buffer, ::testing::ElementsAreArray(expected_buffer)); 37 | } 38 | 39 | TEST(Pipe, WaitToConnect) { 40 | auto pipe1 = Pipe::create_unique(); 41 | ASSERT_NE(nullptr, pipe1); 42 | 43 | const std::wstring name = pipe1->get_name(); 44 | 45 | const auto start = std::chrono::system_clock::now(); 46 | 47 | std::thread thread([name]() { 48 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 49 | auto pipe2 = Pipe::open(name); 50 | }); 51 | EXPECT_TRUE(pipe1->wait()); 52 | 53 | const auto duration = std::chrono::system_clock::now() - start; 54 | 55 | EXPECT_GE( 56 | std::chrono::duration_cast(duration).count(), 57 | std::chrono::milliseconds(100).count()); 58 | thread.join(); 59 | } 60 | 61 | TEST(Pipe, OpenNotExisting) { 62 | auto pipe = Pipe::open(L"\\\\.\\pipe\\npp_not_existing"); 63 | ASSERT_EQ(nullptr, pipe); 64 | } 65 | 66 | TEST(Pipe, CreatePipeWithSameName) { 67 | auto pipe1 = Pipe::create(L"\\\\.\\pipe\\npp_existing_name"); 68 | ASSERT_NE(nullptr, pipe1); 69 | auto pipe2 = Pipe::create(L"\\\\.\\pipe\\npp_existing_name"); 70 | ASSERT_EQ(nullptr, pipe2); 71 | } 72 | } // namespace 73 | -------------------------------------------------------------------------------- /UnitTests/TestSaveAsAdminImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "ExecutionThread.hpp" 6 | #include "IWinApiFunctions.hpp" 7 | #include "MockWinApiFunctions.hpp" 8 | #include "TestUtilities.hpp" 9 | #include "plugin/Injection.hpp" 10 | #include "plugin/SaveAsAdminImpl.hpp" 11 | 12 | namespace { 13 | using namespace ::testing; 14 | 15 | const HANDLE ValidHandle1 = reinterpret_cast(1); 16 | const HANDLE ValidHandle2 = reinterpret_cast(2); 17 | const std::string TestFileNameA1 = "test_wfile1.txt"; 18 | const std::wstring TestFileNameW1 = L"test_wfile1.txt"; 19 | const std::string TestFileNameA1_Hooked = "test_wfile1.txt-hooked"; 20 | const std::wstring TestFileNameW1_Hooked = L"test_wfile1.txt-hooked"; 21 | 22 | class MockAdminAccessRunner : public AdminAccessRunner { 23 | public: 24 | MOCK_METHOD2(run_admin_access, 25 | HANDLE( 26 | const std::wstring&, 27 | const std::wstring&)); 28 | }; 29 | 30 | class TestWinApiFunctions { 31 | public: 32 | TestWinApiFunctions() { 33 | m_write_file = inject( 34 | WriteFile, 35 | make_injection_callback(*this, &TestWinApiFunctions::write_file)); 36 | m_create_filea = inject( 37 | CreateFileA, 38 | make_injection_callback(*this, &TestWinApiFunctions::create_file_a)); 39 | m_create_filew = 40 | inject(CreateFileW, 41 | make_injection_callback( 42 | *this, &TestWinApiFunctions::create_file_w_denied_access)); 43 | m_get_file_type = inject( 44 | GetFileType, 45 | make_injection_callback(*this, &TestWinApiFunctions::get_file_type)); 46 | m_close_handle = inject( 47 | CloseHandle, 48 | make_injection_callback(*this, &TestWinApiFunctions::close_handle)); 49 | } 50 | 51 | void allow_create() { 52 | m_create_is_denied = false; 53 | } 54 | 55 | HANDLE create_file_w_denied_access(LPCWSTR file_name, 56 | DWORD desired_access, 57 | DWORD share_mode, 58 | LPSECURITY_ATTRIBUTES security_attributes, 59 | DWORD creation_disposition, 60 | DWORD flags_and_attributes, 61 | HANDLE template_file) { 62 | if (m_create_is_denied) { 63 | std::wstring file_name_str = file_name; 64 | if (file_name_str.find(L"\\\\.\\pipe") == std::wstring::npos) { 65 | SetLastError(ERROR_ACCESS_DENIED); 66 | return INVALID_HANDLE_VALUE; 67 | } 68 | } 69 | return create_file_w(file_name, desired_access, share_mode, 70 | security_attributes, creation_disposition, 71 | flags_and_attributes, template_file); 72 | } 73 | 74 | BOOL write_file(HANDLE file_handle, 75 | LPCVOID buffer, 76 | DWORD number_of_bytes_to_write, 77 | LPDWORD number_of_bytes_written, 78 | LPOVERLAPPED overlapped) { 79 | return m_write_file->call_original(file_handle, buffer, 80 | number_of_bytes_to_write, 81 | number_of_bytes_written, overlapped); 82 | } 83 | 84 | HANDLE create_file_a(LPCSTR file_name, 85 | DWORD desired_access, 86 | DWORD share_mode, 87 | LPSECURITY_ATTRIBUTES security_attributes, 88 | DWORD creation_disposition, 89 | DWORD flags_and_attributes, 90 | HANDLE template_file) { 91 | return m_create_filea->call_original( 92 | file_name, desired_access, share_mode, security_attributes, 93 | creation_disposition, flags_and_attributes, template_file); 94 | } 95 | 96 | HANDLE create_file_w(LPCWSTR file_name, 97 | DWORD desired_access, 98 | DWORD share_mode, 99 | LPSECURITY_ATTRIBUTES security_attributes, 100 | DWORD creation_disposition, 101 | DWORD flags_and_attributes, 102 | HANDLE template_file) { 103 | return m_create_filew->call_original( 104 | file_name, desired_access, share_mode, security_attributes, 105 | creation_disposition, flags_and_attributes, template_file); 106 | } 107 | 108 | BOOL close_handle(HANDLE object) { 109 | return m_close_handle->call_original(object); 110 | } 111 | 112 | DWORD get_file_type(HANDLE file) { 113 | return m_get_file_type->call_original(file); 114 | } 115 | 116 | private: 117 | bool m_create_is_denied = true; 118 | injection_ptr_type(WriteFile) m_write_file; 119 | injection_ptr_type(CreateFileA) m_create_filea; 120 | injection_ptr_type(CreateFileW) m_create_filew; 121 | injection_ptr_type(GetFileType) m_get_file_type; 122 | injection_ptr_type(CloseHandle) m_close_handle; 123 | }; 124 | 125 | struct SaveAsAdminImplFixture : public ::testing::Test { 126 | TestWinApiFunctions original_functions; 127 | ::testing::NiceMock mock_winapi_rename; 128 | ExecutionThread execution_thread; 129 | 130 | MockAdminAccessRunner mock_admin_access_runner; 131 | SaveAsAdminImpl save_as_admin_impl; 132 | 133 | SaveAsAdminImplFixture() 134 | : execution_thread(false), save_as_admin_impl(mock_admin_access_runner) { 135 | ON_CALL(mock_winapi_rename, create_file_a(_, _, _, _, _, _, _)) 136 | .WillByDefault( 137 | Invoke(this, &SaveAsAdminImplFixture::create_file_a_rename)); 138 | ON_CALL(mock_winapi_rename, create_file_w(_, _, _, _, _, _, _)) 139 | .WillByDefault( 140 | Invoke(this, &SaveAsAdminImplFixture::create_file_w_rename)); 141 | ON_CALL(mock_winapi_rename, write_file(_, _, _, _, _)) 142 | .WillByDefault( 143 | Invoke(&original_functions, &TestWinApiFunctions::write_file)); 144 | ON_CALL(mock_winapi_rename, close_handle(_)) 145 | .WillByDefault( 146 | Invoke(&original_functions, &TestWinApiFunctions::close_handle)); 147 | ON_CALL(mock_winapi_rename, get_file_type(_)) 148 | .WillByDefault( 149 | Invoke(&original_functions, &TestWinApiFunctions::get_file_type)); 150 | 151 | register_default_commands(execution_thread.command_manager, 152 | mock_winapi_rename); 153 | } 154 | 155 | HANDLE create_file_w_rename(LPCWSTR file_name, 156 | DWORD desired_access, 157 | DWORD share_mode, 158 | LPSECURITY_ATTRIBUTES security_attributes, 159 | DWORD creation_disposition, 160 | DWORD flags_and_attributes, 161 | HANDLE template_file) { 162 | std::wstring new_name = file_name; 163 | new_name.append(L"-hooked"); 164 | return original_functions.create_file_w( 165 | new_name.c_str(), desired_access, share_mode, security_attributes, 166 | creation_disposition, flags_and_attributes, template_file); 167 | } 168 | 169 | HANDLE create_file_a_rename(LPCSTR file_name, 170 | DWORD desired_access, 171 | DWORD share_mode, 172 | LPSECURITY_ATTRIBUTES security_attributes, 173 | DWORD creation_disposition, 174 | DWORD flags_and_attributes, 175 | HANDLE template_file) { 176 | std::string new_name = file_name; 177 | new_name.append("-hooked"); 178 | return original_functions.create_file_a( 179 | new_name.c_str(), desired_access, share_mode, security_attributes, 180 | creation_disposition, flags_and_attributes, template_file); 181 | } 182 | 183 | ~SaveAsAdminImplFixture() { execution_thread.wait(); } 184 | 185 | HANDLE start_execute_thread1(const std::wstring& pipe_sender_name, 186 | const std::wstring& pipe_receiver_name) { 187 | execution_thread.start(pipe_sender_name, pipe_receiver_name); 188 | return ValidHandle1; 189 | } 190 | 191 | void check_file_exists(const std::wstring& file_name, 192 | const std::string& expected_content) { 193 | std::wifstream read_file(file_name); 194 | ASSERT_TRUE(read_file); 195 | std::wstring file_content; 196 | read_file >> file_content; 197 | std::wstring expected_wcontent(expected_content.begin(), 198 | expected_content.end()); 199 | EXPECT_EQ(expected_wcontent, file_content); 200 | } 201 | 202 | void check_file_not_exists(const std::wstring& file_name) { 203 | std::wifstream read_file(file_name); 204 | ASSERT_FALSE(read_file); 205 | } 206 | 207 | void ProcessWriteFile(const std::wstring& file_name, 208 | const std::string& data) { 209 | HANDLE handle = CreateFileW(file_name.c_str(), GENERIC_WRITE, 0, NULL, 210 | CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 211 | ASSERT_NE(INVALID_HANDLE_VALUE, handle); 212 | EXPECT_TRUE(WriteFile(handle, data.c_str(), get_size_as_ulong(data), NULL, NULL)); 213 | CloseHandle(handle); 214 | } 215 | }; 216 | 217 | TEST_F(SaveAsAdminImplFixture, WriteFileIsHooked) { 218 | const auto remove_files = 219 | FileAutoremover({TestFileNameA1, TestFileNameA1_Hooked}); 220 | EXPECT_CALL(mock_admin_access_runner, run_admin_access(_, _)) 221 | .WillOnce(Invoke(this, &SaveAsAdminImplFixture::start_execute_thread1)); 222 | 223 | const char* TestData = "Test_data"; 224 | 225 | save_as_admin_impl.allow_process_file(); 226 | ProcessWriteFile(TestFileNameW1, TestData); 227 | save_as_admin_impl.cancel_process_file(); 228 | 229 | check_file_not_exists(TestFileNameW1); 230 | original_functions.allow_create(); 231 | check_file_exists(TestFileNameW1_Hooked, TestData); 232 | } 233 | 234 | TEST_F(SaveAsAdminImplFixture, WriteFileIsHookedButNotProcessedBecauseNotAllowed) { 235 | const auto remove_files = 236 | FileAutoremover({ TestFileNameA1, TestFileNameA1_Hooked }); 237 | EXPECT_CALL(mock_admin_access_runner, run_admin_access(_, _)).Times(0); 238 | 239 | HANDLE handle = CreateFileW(TestFileNameW1.c_str(), GENERIC_WRITE, 0, NULL, 240 | CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 241 | ASSERT_EQ(INVALID_HANDLE_VALUE, handle); 242 | 243 | check_file_not_exists(TestFileNameW1); 244 | check_file_not_exists(TestFileNameW1_Hooked); 245 | } 246 | 247 | TEST_F(SaveAsAdminImplFixture, WriteFileIsHookedButNotProcessedBecauseNotNeeded) { 248 | original_functions.allow_create(); 249 | const auto remove_files = 250 | FileAutoremover({ TestFileNameA1, TestFileNameA1_Hooked }); 251 | EXPECT_CALL(mock_admin_access_runner, run_admin_access(_, _)).Times(0); 252 | 253 | const char* TestData = "Test_data"; 254 | 255 | save_as_admin_impl.allow_process_file(); 256 | ProcessWriteFile(TestFileNameW1, TestData); 257 | save_as_admin_impl.cancel_process_file(); 258 | 259 | check_file_exists(TestFileNameW1, TestData); 260 | check_file_not_exists(TestFileNameW1_Hooked); 261 | } 262 | 263 | } // namespace 264 | -------------------------------------------------------------------------------- /UnitTests/TestUniqueHandle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "UniqueHandle.hpp" 6 | 7 | namespace { 8 | using namespace testing; 9 | 10 | const HANDLE ValidHandle = reinterpret_cast(1); 11 | const HANDLE ValidHandle2 = reinterpret_cast(2); 12 | 13 | class TestUniqueHandle : public Test { 14 | public: 15 | TestUniqueHandle() { SetLastError(0); } 16 | 17 | ~TestUniqueHandle() { EXPECT_EQ(0, GetLastError()); } 18 | }; 19 | 20 | TEST_F(TestUniqueHandle, DefaultCtor) { 21 | UniqueHandle<> unique_handle; 22 | EXPECT_FALSE(unique_handle); 23 | EXPECT_EQ(INVALID_HANDLE_VALUE, unique_handle.get()); 24 | EXPECT_EQ(INVALID_HANDLE_VALUE, *unique_handle); 25 | 26 | EXPECT_EQ(INVALID_HANDLE_VALUE, unique_handle); 27 | } 28 | 29 | TEST_F(TestUniqueHandle, CtorWithParamAndInvalidValue) { 30 | const UniqueHandle<> unique_handle; 31 | 32 | UniqueHandle<> unique_handle2(INVALID_HANDLE_VALUE); 33 | EXPECT_FALSE(unique_handle2); 34 | EXPECT_EQ(INVALID_HANDLE_VALUE, unique_handle2.get()); 35 | EXPECT_EQ(INVALID_HANDLE_VALUE, *unique_handle2); 36 | 37 | EXPECT_TRUE(unique_handle == unique_handle2); 38 | EXPECT_FALSE(unique_handle != unique_handle2); 39 | } 40 | 41 | TEST_F(TestUniqueHandle, CustomDeleterAndValidHandle) { 42 | MockFunction deleter; 43 | EXPECT_CALL(deleter, Call(ValidHandle)); 44 | UniqueHandle> unique_handle( 45 | ValidHandle, deleter.AsStdFunction()); 46 | EXPECT_TRUE(unique_handle); 47 | EXPECT_NE(INVALID_HANDLE_VALUE, unique_handle.get()); 48 | EXPECT_NE(INVALID_HANDLE_VALUE, *unique_handle); 49 | 50 | EXPECT_TRUE(INVALID_HANDLE_VALUE != unique_handle); 51 | EXPECT_TRUE(unique_handle != INVALID_HANDLE_VALUE); 52 | EXPECT_FALSE(INVALID_HANDLE_VALUE == unique_handle); 53 | EXPECT_FALSE(unique_handle == INVALID_HANDLE_VALUE); 54 | } 55 | 56 | TEST_F(TestUniqueHandle, CustomDeleterAndInvalidHandle) { 57 | MockFunction deleter; 58 | EXPECT_CALL(deleter, Call(_)).Times(0); 59 | UniqueHandle> unique_handle( 60 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 61 | EXPECT_FALSE(unique_handle); 62 | EXPECT_EQ(INVALID_HANDLE_VALUE, unique_handle.get()); 63 | EXPECT_EQ(INVALID_HANDLE_VALUE, *unique_handle); 64 | 65 | EXPECT_FALSE(INVALID_HANDLE_VALUE != unique_handle); 66 | EXPECT_FALSE(unique_handle != INVALID_HANDLE_VALUE); 67 | EXPECT_TRUE(INVALID_HANDLE_VALUE == unique_handle); 68 | EXPECT_TRUE(unique_handle == INVALID_HANDLE_VALUE); 69 | } 70 | 71 | TEST_F(TestUniqueHandle, ReleaseWithValidHandle) { 72 | MockFunction deleter; 73 | EXPECT_CALL(deleter, Call(_)).Times(0); 74 | UniqueHandle> unique_handle( 75 | ValidHandle, deleter.AsStdFunction()); 76 | EXPECT_EQ(ValidHandle, unique_handle.release()); 77 | 78 | EXPECT_FALSE(unique_handle); 79 | } 80 | 81 | TEST_F(TestUniqueHandle, ReleaseWithInvalidHandle) { 82 | MockFunction deleter; 83 | EXPECT_CALL(deleter, Call(_)).Times(0); 84 | UniqueHandle> unique_handle( 85 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 86 | EXPECT_EQ(INVALID_HANDLE_VALUE, unique_handle.release()); 87 | 88 | EXPECT_FALSE(unique_handle); 89 | } 90 | 91 | TEST_F(TestUniqueHandle, ResetWithValidHandle) { 92 | MockFunction deleter; 93 | EXPECT_CALL(deleter, Call(ValidHandle)).RetiresOnSaturation(); 94 | UniqueHandle> unique_handle( 95 | ValidHandle, deleter.AsStdFunction()); 96 | unique_handle.reset(); 97 | EXPECT_CALL(deleter, Call(_)).Times(0); 98 | 99 | EXPECT_FALSE(unique_handle); 100 | } 101 | 102 | TEST_F(TestUniqueHandle, ResetWithInvalidHandle) { 103 | MockFunction deleter; 104 | EXPECT_CALL(deleter, Call(_)).Times(0); 105 | UniqueHandle> unique_handle( 106 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 107 | unique_handle.reset(); 108 | 109 | EXPECT_FALSE(unique_handle); 110 | } 111 | 112 | TEST_F(TestUniqueHandle, MoveCtorFromValid) { 113 | MockFunction deleter; 114 | EXPECT_CALL(deleter, Call(_)).Times(0).RetiresOnSaturation(); 115 | UniqueHandle> unique_handle1( 116 | ValidHandle, deleter.AsStdFunction()); 117 | 118 | UniqueHandle> unique_handle2( 119 | std::move(unique_handle1)); 120 | 121 | EXPECT_FALSE(unique_handle1); 122 | EXPECT_TRUE(unique_handle2); 123 | 124 | EXPECT_CALL(deleter, Call(ValidHandle)); 125 | } 126 | 127 | TEST_F(TestUniqueHandle, MoveCtorFromInvalid) { 128 | MockFunction deleter; 129 | EXPECT_CALL(deleter, Call(_)).Times(0); 130 | UniqueHandle> unique_handle1( 131 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 132 | 133 | UniqueHandle> unique_handle2( 134 | std::move(unique_handle1)); 135 | 136 | EXPECT_FALSE(unique_handle1); 137 | EXPECT_FALSE(unique_handle2); 138 | } 139 | 140 | TEST_F(TestUniqueHandle, MoveEqFromValidToInvalid) { 141 | MockFunction deleter; 142 | EXPECT_CALL(deleter, Call(_)).Times(0).RetiresOnSaturation(); 143 | UniqueHandle> unique_handle1( 144 | ValidHandle, deleter.AsStdFunction()); 145 | 146 | UniqueHandle> unique_handle2; 147 | 148 | unique_handle2 = std::move(unique_handle1); 149 | 150 | EXPECT_FALSE(unique_handle1); 151 | EXPECT_TRUE(unique_handle2); 152 | 153 | EXPECT_CALL(deleter, Call(ValidHandle)); 154 | } 155 | 156 | TEST_F(TestUniqueHandle, MoveEqFromInvalidToInvalid) { 157 | MockFunction deleter; 158 | EXPECT_CALL(deleter, Call(_)).Times(0); 159 | UniqueHandle> unique_handle1( 160 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 161 | 162 | UniqueHandle> unique_handle2; 163 | 164 | unique_handle2 = std::move(unique_handle1); 165 | 166 | EXPECT_FALSE(unique_handle1); 167 | EXPECT_FALSE(unique_handle2); 168 | } 169 | 170 | TEST_F(TestUniqueHandle, MoveEqFromInvalidToValid) { 171 | MockFunction deleter1; 172 | EXPECT_CALL(deleter1, Call(_)).Times(0); 173 | UniqueHandle> unique_handle1( 174 | INVALID_HANDLE_VALUE, deleter1.AsStdFunction()); 175 | 176 | MockFunction deleter2; 177 | EXPECT_CALL(deleter2, Call(ValidHandle)).RetiresOnSaturation(); 178 | UniqueHandle> unique_handle2( 179 | ValidHandle, deleter2.AsStdFunction()); 180 | 181 | unique_handle2 = std::move(unique_handle1); 182 | 183 | EXPECT_CALL(deleter2, Call(_)).Times(0); 184 | 185 | EXPECT_FALSE(unique_handle1); 186 | EXPECT_FALSE(unique_handle2); 187 | } 188 | 189 | TEST_F(TestUniqueHandle, OperatorEqHandleToInvalid) { 190 | MockFunction deleter; 191 | EXPECT_CALL(deleter, Call(_)).Times(0).RetiresOnSaturation(); 192 | UniqueHandle> unique_handle( 193 | INVALID_HANDLE_VALUE, deleter.AsStdFunction()); 194 | 195 | unique_handle = ValidHandle; 196 | 197 | EXPECT_CALL(deleter, Call(ValidHandle)).RetiresOnSaturation(); 198 | 199 | unique_handle = ValidHandle2; 200 | 201 | EXPECT_CALL(deleter, Call(ValidHandle2)); 202 | } 203 | } // namespace 204 | -------------------------------------------------------------------------------- /UnitTests/TestUtilities.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class FileAutoremover { 8 | public: 9 | FileAutoremover(std::string filename) : FileAutoremover({filename}) {} 10 | 11 | FileAutoremover(std::initializer_list filenames) 12 | : m_filenames(filenames) { 13 | remove(); 14 | } 15 | 16 | ~FileAutoremover() { remove(); } 17 | 18 | private: 19 | void remove() const { 20 | for (const std::string& filename : m_filenames) { 21 | std::remove(filename.c_str()); 22 | } 23 | } 24 | const std::vector m_filenames; 25 | }; 26 | 27 | template 28 | inline DWORD get_size_as_ulong(const Container& container) { 29 | return static_cast(container.size()); 30 | } 31 | -------------------------------------------------------------------------------- /UnitTests/UnitTests.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {A25BA222-6DD6-46B2-9701-F0CE6C2B3BB0} 24 | Win32Proj 25 | UnitTests 26 | 10.0.17134.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141_xp 33 | Unicode 34 | C:\projects\googletest_release\x86 35 | 36 | 37 | Application 38 | false 39 | v141_xp 40 | true 41 | Unicode 42 | C:\projects\googletest_release\x86 43 | 44 | 45 | Application 46 | true 47 | v141_xp 48 | Unicode 49 | C:\projects\googletest_release\x64 50 | 51 | 52 | Application 53 | false 54 | v141_xp 55 | true 56 | Unicode 57 | C:\projects\googletest_release\x64 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | true 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | false 88 | 89 | 90 | 91 | NotUsing 92 | Level3 93 | Disabled 94 | true 95 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 96 | false 97 | 98 | ../NppAdminAccessLib;../NppSaveAsAdminLib;../NppCommon;$(GTestPath)/include 99 | MultiThreadedDebug 100 | 101 | 102 | Console 103 | DebugFull 104 | $(GTestPath)/lib 105 | gmock_maind.lib;Dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 106 | 107 | 108 | 109 | 110 | NotUsing 111 | Level3 112 | Disabled 113 | true 114 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 115 | false 116 | 117 | ../NppAdminAccessLib;../NppSaveAsAdminLib;../NppCommon;$(GTestPath)/include 118 | MultiThreadedDebug 119 | 120 | 121 | Console 122 | DebugFull 123 | $(GTestPath)/lib 124 | gmock_maind.lib;Dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 125 | 126 | 127 | 128 | 129 | NotUsing 130 | Level3 131 | MaxSpeed 132 | true 133 | true 134 | true 135 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | false 137 | 138 | ../NppAdminAccessLib;../NppSaveAsAdminLib;../NppCommon;$(GTestPath)/include 139 | MultiThreaded 140 | 141 | 142 | Console 143 | true 144 | true 145 | true 146 | $(GTestPath)/lib 147 | gmock_main.lib;Dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 148 | 149 | 150 | 151 | 152 | NotUsing 153 | Level3 154 | MaxSpeed 155 | true 156 | true 157 | true 158 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 159 | false 160 | 161 | ../NppAdminAccessLib;../NppSaveAsAdminLib;../NppCommon;$(GTestPath)/include 162 | MultiThreaded 163 | 164 | 165 | Console 166 | true 167 | true 168 | true 169 | $(GTestPath)/lib 170 | gmock_main.lib;Dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | {2394591e-0d3a-4444-8e04-4bfbd689c6a1} 183 | 184 | 185 | {02b425e1-804d-4f60-90cd-9d26f75623b0} 186 | 187 | 188 | {f10e6e67-956f-4847-9110-8b4eb56a2857} 189 | 190 | 191 | {9d04dbd5-e12e-44e0-a683-6f43f21d533b} 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /UnitTests/UnitTests.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | branches: 3 | only: 4 | - x64_support 5 | - master 6 | image: Visual Studio 2017 7 | 8 | environment: 9 | matrix: 10 | - PlatformToolset: v141_xp 11 | 12 | configuration: 13 | - Release 14 | - Debug 15 | 16 | platform: 17 | - x86 18 | - x64 19 | 20 | install: 21 | - if "%platform%"=="x64" set archi=amd64 22 | - if "%platform%"=="x64" set platform_input=x64 23 | 24 | - if "%platform%"=="x86" set archi=x86 25 | - if "%platform%"=="x86" set platform_input=Win32 26 | 27 | - if "%PlatformToolset%"=="v141_xp" call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" %archi% 28 | 29 | before_build: 30 | - cmd: >- 31 | git clone https://github.com/google/googletest 32 | 33 | cd googletest && mkdir build && cd build 34 | 35 | echo "PLATFORM=%PLATFORM%" 36 | 37 | echo "CONFIGURATION=%CONFIGURATION%" 38 | 39 | IF "%PLATFORM%"=="x86" (SET CMAKE_COMPILER="Visual Studio 15 2017") ELSE (SET CMAKE_COMPILER="Visual Studio 15 2017 Win64") 40 | 41 | echo "CMAKE_COMPILER=%CMAKE_COMPILER%" 42 | 43 | cmake -Dgtest_force_shared_crt=OFF -DCMAKE_INSTALL_PREFIX=c:\projects\googletest_release\%PLATFORM% -G %CMAKE_COMPILER% .. 44 | 45 | cmake --build . --target install --config %CONFIGURATION% 46 | 47 | cd ..\.. 48 | 49 | python GenerateVersionHeader.py %APPVEYOR_BUILD_VERSION% > NppSaveAsAdmin\src\plugin\SaveAsAdminVersion.hpp 50 | 51 | build_script: 52 | - cmd: cd "%APPVEYOR_BUILD_FOLDER%" 53 | - cmd: msbuild UnitTests/UnitTests.vcxproj /m /p:configuration="%configuration%" /p:platform="%platform_input%" /p:PlatformToolset="%PlatformToolset%" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 54 | 55 | after_build: 56 | - cmd: cd "%APPVEYOR_BUILD_FOLDER%" 57 | - ps: >- 58 | 59 | if ($env:CONFIGURATION -eq "Release") { 60 | if($env:PLATFORM -eq "x64") { 61 | $ZipFileName = "NppSaveAsAdmin_$($env:APPVEYOR_BUILD_VERSION)_x64.zip" 62 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\NppSaveAsAdmin\bin64\NppSaveAsAdmin.dll" 63 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\NppSaveAsAdmin\bin64\NppAdminAccess.exe" 64 | } 65 | if($env:PLATFORM -eq "x86") { 66 | $ZipFileName = "NppSaveAsAdmin_$($env:APPVEYOR_BUILD_VERSION)_x86.zip" 67 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\NppSaveAsAdmin\bin\NppSaveAsAdmin.dll" 68 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\NppSaveAsAdmin\bin\NppAdminAccess.exe" 69 | } 70 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\README.md" 71 | 7z a $ZipFileName "$($env:APPVEYOR_BUILD_FOLDER)\NppSaveAsAdmin\license.txt" 72 | } 73 | 74 | test_script: 75 | - ps: >- 76 | $BASE_EXE_PATH = "C:\projects\nppsaveasadmin\UnitTests\" 77 | 78 | if ("$env:PLATFORM" -eq "x64") {$BASE_EXE_PATH = $BASE_EXE_PATH + "x64\"} 79 | 80 | $TEST_EXE_PATH = $BASE_EXE_PATH + $env:CONFIGURATION + "\UnitTests.exe" 81 | 82 | echo "test exe = $TEST_EXE_PATH" 83 | 84 | & $TEST_EXE_PATH --gtest_output="xml:C:\projects\test_results.xml" 85 | 86 | $TestResult=$LastExitCode 87 | 88 | echo "Tests finished with code $TestResult" 89 | 90 | echo "Uploading test results" 91 | 92 | $wc = New-Object 'System.Net.WebClient' 93 | 94 | $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path C:\projects\test_results.xml)) 95 | 96 | if ($TestResult -ne 0) {exit $TestResult} 97 | 98 | artifacts: 99 | - path: NppSaveAsAdmin_*.zip 100 | name: release_package 101 | - path: UnitTests/%CONFIGURATION%/UnitTests.exe 102 | name: Unit test x86 binary 103 | - path: UnitTests/x64/%CONFIGURATION%/UnitTests.exe 104 | name: Unit test x64 binary 105 | 106 | deploy: 107 | provider: GitHub 108 | auth_token: 109 | secure: 6TQ/ECbh22HvTfxCyQQCE8j+Mlcu4qEapi5xOKto9YEYEf0Pf6daE3bmJ8DFFp2h 110 | artifact: release_package 111 | draft: false 112 | prerelease: false 113 | force_update: true 114 | on: 115 | appveyor_repo_tag: true 116 | PlatformToolset: v141_xp 117 | configuration: Release 118 | --------------------------------------------------------------------------------