diff options
| author | Odd Stranne <odd@mullvad.net> | 2018-08-29 12:13:31 +0200 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2018-09-04 13:06:33 +0200 |
| commit | 0379da796c4436f6800cd65e02219a0843270dc3 (patch) | |
| tree | 84af72486c8c0d6276dbee44cff32ab27f57415e | |
| parent | 1d5be836d3aea89ce3e75eabcae8a3e7d5df1c83 (diff) | |
| download | mullvadvpn-0379da796c4436f6800cd65e02219a0843270dc3.tar.xz mullvadvpn-0379da796c4436f6800cd65e02219a0843270dc3.zip | |
Add NSIS 'log' plugin
| -rw-r--r-- | windows/nsis-plugins/nsis-plugins.sln | 11 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/dllmain.cpp | 11 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.cpp | 220 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.def | 10 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.h | 22 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.vcxproj | 125 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/log.vcxproj.filters | 18 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/logger.cpp | 111 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/logger.h | 62 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/stdafx.cpp | 8 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/stdafx.h | 16 | ||||
| -rw-r--r-- | windows/nsis-plugins/src/log/targetver.h | 12 |
12 files changed, 625 insertions, 1 deletions
diff --git a/windows/nsis-plugins/nsis-plugins.sln b/windows/nsis-plugins/nsis-plugins.sln index 0f2f5533f2..8bc6dd360e 100644 --- a/windows/nsis-plugins/nsis-plugins.sln +++ b/windows/nsis-plugins/nsis-plugins.sln @@ -12,7 +12,12 @@ Project("{54BCC44A-7EAA-4BB3-8CF5-564137999875}") = "cleanup", "src\cleanup\clea {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" +Project("{714F8F19-E50B-4920-9BC3-479EC443B3F5}") = "log", "src\log\log.vcxproj", "{1344152F-2BAD-4198-8E51-31AAC32BFBB2}" + ProjectSection(ProjectDependencies) = postProject + {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} + EndProjectSection +EndProject +Project("{EC315746-5E73-42EB-B79B-CC019245EDBC}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -28,6 +33,10 @@ Global {47B5C1C1-67D7-4544-9037-8E7F44C1E5BD}.Debug|x86.Build.0 = Debug|Win32 {47B5C1C1-67D7-4544-9037-8E7F44C1E5BD}.Release|x86.ActiveCfg = Release|Win32 {47B5C1C1-67D7-4544-9037-8E7F44C1E5BD}.Release|x86.Build.0 = Release|Win32 + {1344152F-2BAD-4198-8E51-31AAC32BFBB2}.Debug|x86.ActiveCfg = Debug|Win32 + {1344152F-2BAD-4198-8E51-31AAC32BFBB2}.Debug|x86.Build.0 = Debug|Win32 + {1344152F-2BAD-4198-8E51-31AAC32BFBB2}.Release|x86.ActiveCfg = Release|Win32 + {1344152F-2BAD-4198-8E51-31AAC32BFBB2}.Release|x86.Build.0 = Release|Win32 {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.ActiveCfg = Debug|Win32 {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.Build.0 = Debug|Win32 {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.ActiveCfg = Release|Win32 diff --git a/windows/nsis-plugins/src/log/dllmain.cpp b/windows/nsis-plugins/src/log/dllmain.cpp new file mode 100644 index 0000000000..a5a44613dd --- /dev/null +++ b/windows/nsis-plugins/src/log/dllmain.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include <windows.h> + +BOOL APIENTRY DllMain(HMODULE, DWORD reason, LPVOID) +{ + // + // Avoid doing work in DllMain since the loader lock is held + // + + return TRUE; +} diff --git a/windows/nsis-plugins/src/log/log.cpp b/windows/nsis-plugins/src/log/log.cpp new file mode 100644 index 0000000000..f4d255b190 --- /dev/null +++ b/windows/nsis-plugins/src/log/log.cpp @@ -0,0 +1,220 @@ +#include "stdafx.h" +#include "logger.h" +#include <libcommon/string.h> +#include <libcommon/filesystem.h> +#include <windows.h> +#include <nsis/pluginapi.h> +#include <string> +#include <vector> +#include <memory> +#include <experimental/filesystem> + +Logger *g_logger = nullptr; + +namespace +{ + +std::wstring PopString() +{ + // + // NSIS functions popstring() and popstringn() require that you definitely size the buffer + // before popping the string. Let's do it ourselves instead. + // + + if (!g_stacktop || !*g_stacktop) + { + throw std::runtime_error("NSIS variable stack is corrupted"); + } + + stack_t *th = *g_stacktop; + + std::wstring copy(th->text); + + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + + return copy; +} + +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + +void PinDll() +{ + // + // Apparently NSIS loads and unloads the plugin module for EVERY call it makes to the plugin. + // This makes it kind of difficult to maintain state. + // + // We can work around this by incrementing the module reference count. + // When NSIS calls FreeLibrary() the reference count decrements and becomes one. + // + + wchar_t self[MAX_PATH]; + + if (0 == GetModuleFileNameW((HINSTANCE)&__ImageBase, self, _countof(self))) + { + throw std::runtime_error("Failed to pin plugin module"); + } + + // + // For some reason, NSIS frees this particular DLL more times than it loads it + // so we have to up the reference count significantly. + // + for (int i = 0; i < 100; ++i) + { + LoadLibraryW(self); + } +} + +std::vector<std::wstring> BlockToRows(const std::wstring &textBlock) +{ + // + // This is such a hack :-( + // + // It only works because the tokenizer is greedy and because we don't care about + // empty lines for this usage. + // + return common::string::Tokenize(textBlock, L"\r\n"); +} + +} // anonymous namespace + +// +// Initialize +// +// Opens and maintains an open handle to the log file. +// +void __declspec(dllexport) NSISCALL Initialize +( + HWND hwndParent, + int string_size, + LPTSTR variables, + stack_t **stacktop, + extra_parameters *extra, + ... +) +{ + EXDLL_INIT(); + + try + { + PinDll(); + + auto logfile = std::experimental::filesystem::path(common::fs::GetKnownFolderPath( + FOLDERID_ProgramData, 0, nullptr)); + + logfile.append(L"Mullvad VPN").append(L"install.log"); + + g_logger = new Logger(std::make_unique<AnsiFileLogSink>(logfile)); + } + catch (...) + { + } +} + +// +// Log +// +// Writes a message to the log file. +// +void __declspec(dllexport) NSISCALL Log +( + HWND hwndParent, + int string_size, + LPTSTR variables, + stack_t **stacktop, + extra_parameters *extra, + ... +) +{ + EXDLL_INIT(); + + try + { + const auto message = PopString(); + + if (g_logger != nullptr) + { + g_logger->log(message); + } + } + catch (...) + { + } +} + +// +// LogWithDetails +// +// Writes a message to the log file. +// +void __declspec(dllexport) NSISCALL LogWithDetails +( + HWND hwndParent, + int string_size, + LPTSTR variables, + stack_t **stacktop, + extra_parameters *extra, + ... +) +{ + EXDLL_INIT(); + + try + { + const auto message = PopString(); + const auto details = PopString(); + + if (g_logger != nullptr) + { + g_logger->log(message, BlockToRows(details)); + } + } + catch (...) + { + } +} + +// +// PluginLog +// +// Writes a message to the log file. +// Use from other plugins to avoid passing messages like this: +// other plugin -> NSIS -> log plugin +// +void __declspec(dllexport) NSISCALL PluginLog +( + const std::wstring &message +) +{ + try + { + if (g_logger != nullptr) + { + g_logger->log(message); + } + } + catch (...) + { + } +} + +// +// PluginLogWithDetails +// +void __declspec(dllexport) NSISCALL PluginLogWithDetails +( + const std::wstring &message, + const std::vector<std::wstring> &details +) +{ + try + { + if (g_logger != nullptr) + { + g_logger->log(message, details); + } + } + catch (...) + { + } +} diff --git a/windows/nsis-plugins/src/log/log.def b/windows/nsis-plugins/src/log/log.def new file mode 100644 index 0000000000..581efdab9d --- /dev/null +++ b/windows/nsis-plugins/src/log/log.def @@ -0,0 +1,10 @@ +LIBRARY log + +EXPORTS + +Initialize +Log +LogWithDetails + +PluginLog +PluginLogWithDetails diff --git a/windows/nsis-plugins/src/log/log.h b/windows/nsis-plugins/src/log/log.h new file mode 100644 index 0000000000..1e2c0e40f3 --- /dev/null +++ b/windows/nsis-plugins/src/log/log.h @@ -0,0 +1,22 @@ +#pragma once + +#include <string> +#include <vector> + +// +// Import-only header +// +// Note on interfaces: While it's safer to use plain types for arguments, this is OK +// since the plugins are all built at the same time, and have the same interpretation of used types. +// + +void __declspec(dllimport) __stdcall PluginLog +( + const std::wstring &message +); + +void __declspec(dllimport) __stdcall PluginLogWithDetails +( + const std::wstring &message, + const std::vector<std::wstring> &details +); diff --git a/windows/nsis-plugins/src/log/log.vcxproj b/windows/nsis-plugins/src/log/log.vcxproj new file mode 100644 index 0000000000..a8506699d8 --- /dev/null +++ b/windows/nsis-plugins/src/log/log.vcxproj @@ -0,0 +1,125 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{1344152F-2BAD-4198-8E51-31AAC32BFBB2}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>log</RootNamespace> + <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;LOG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/windows/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <LanguageStandard>stdcpplatest</LanguageStandard> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/windows/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;pluginapi-x86-unicode.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)</AdditionalDependencies> + <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> + <ModuleDefinitionFile>log.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;LOG_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/windows/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/windows/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;pluginapi-x86-unicode.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)</AdditionalDependencies> + <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> + <ModuleDefinitionFile>log.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClInclude Include="log.h" /> + <ClInclude Include="logger.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="log.cpp" /> + <ClCompile Include="logger.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="log.def" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/nsis-plugins/src/log/log.vcxproj.filters b/windows/nsis-plugins/src/log/log.vcxproj.filters new file mode 100644 index 0000000000..b1f09f54f0 --- /dev/null +++ b/windows/nsis-plugins/src/log/log.vcxproj.filters @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + <ClInclude Include="log.h" /> + <ClInclude Include="logger.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp" /> + <ClCompile Include="stdafx.cpp" /> + <ClCompile Include="log.cpp" /> + <ClCompile Include="logger.cpp" /> + </ItemGroup> + <ItemGroup> + <None Include="log.def" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/nsis-plugins/src/log/logger.cpp b/windows/nsis-plugins/src/log/logger.cpp new file mode 100644 index 0000000000..f22bf84bf1 --- /dev/null +++ b/windows/nsis-plugins/src/log/logger.cpp @@ -0,0 +1,111 @@ +#include "stdafx.h" +#include "logger.h" +#include <libcommon/error.h> +#include <libcommon/string.h> +#include <sstream> +#include <iomanip> + +AnsiFileLogSink::AnsiFileLogSink(const std::wstring &file, bool append, bool flush) + : m_flush(flush) +{ + const DWORD creationDisposition = (append ? OPEN_ALWAYS : CREATE_ALWAYS); + + m_logfile = CreateFileW(file.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, + creationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr); + + THROW_GLE_IF(INVALID_HANDLE_VALUE, m_logfile, "Open/create log file"); + + if (append && ERROR_ALREADY_EXISTS == GetLastError()) + { + LARGE_INTEGER offset = { 0 }; + + const auto seekStatus = SetFilePointerEx(m_logfile, offset, nullptr, FILE_END); + + THROW_GLE_IF(FALSE, seekStatus, "Seek to end offset in existing log file"); + } +} + +AnsiFileLogSink::~AnsiFileLogSink() +{ + CloseHandle(m_logfile); +} + +void AnsiFileLogSink::log(const std::wstring &message) +{ + auto ansi = common::string::ToAnsi(message); + + ansi.append("\xd\xa"); + + DWORD bytesWritten; + + WriteFile(m_logfile, ansi.c_str(), ansi.size(), &bytesWritten, nullptr); + + if (m_flush) + { + FlushFileBuffers(m_logfile); + } +} + +void Logger::log(const std::wstring &message) +{ + m_logsink->log(Compose(message, Timestamp(), ordinal())); +} + +void Logger::log(const std::wstring &message, const std::vector<std::wstring> &details) +{ + const auto timestamp = this->Timestamp(); + const auto ordinal = this->ordinal(); + + m_logsink->log(Compose(message, timestamp, ordinal)); + + // + // Write details with indentation. + // + for (const auto detail : details) + { + m_logsink->log(Compose(detail, timestamp, ordinal, 4)); + } +} + +// static +std::wstring Logger::Timestamp() +{ + SYSTEMTIME time; + + GetLocalTime(&time); + + std::wstringstream ss; + + ss << L'[' + << std::right << std::setw(2) << std::setfill(L'0') << time.wHour + << L':' + << std::right << std::setw(2) << std::setfill(L'0') << time.wMinute + << L':' + << std::right << std::setw(2) << std::setfill(L'0') << time.wSecond + << L']'; + + return ss.str(); +} + +std::wstring Logger::ordinal() +{ + std::wstringstream ss; + + ss << std::right << std::setw(4) << std::setfill(L' ') << m_ordinal++; + + return ss.str(); +} + +//static +std::wstring Logger::Compose(const std::wstring &message, const std::wstring ×tamp, + const std::wstring &ordinal, size_t indentation) +{ + std::wstringstream ss; + + ss << timestamp << L' ' + << ordinal << L' ' + << std::wstring(indentation, L' ') + << message; + + return ss.str(); +} diff --git a/windows/nsis-plugins/src/log/logger.h b/windows/nsis-plugins/src/log/logger.h new file mode 100644 index 0000000000..71054d0bdc --- /dev/null +++ b/windows/nsis-plugins/src/log/logger.h @@ -0,0 +1,62 @@ +#pragma once + +#include <string> +#include <vector> +#include <memory> +#include <windows.h> + +struct ILogSink +{ + virtual ~ILogSink() = 0 + { + } + + virtual void log(const std::wstring &message) = 0; +}; + +class AnsiFileLogSink : public ILogSink +{ +public: + + AnsiFileLogSink(const std::wstring &file, bool append = true, bool flush = false); + ~AnsiFileLogSink(); + + AnsiFileLogSink(const AnsiFileLogSink &) = delete; + AnsiFileLogSink &operator=(const AnsiFileLogSink &) = delete; + + void log(const std::wstring &message) override; + +private: + + HANDLE m_logfile = INVALID_HANDLE_VALUE; + bool m_flush; +}; + +class Logger +{ +public: + + Logger(std::unique_ptr<ILogSink> &&logsink) + : m_logsink(std::move(logsink)) + { + } + + Logger(const Logger &) = delete; + Logger &operator=(const Logger &) = delete; + + void log(const std::wstring &message); + void log(const std::wstring &message, const std::vector<std::wstring> &details); + +private: + + std::unique_ptr<ILogSink> m_logsink; + + size_t m_ordinal = 1; + + static std::wstring Timestamp(); + + std::wstring ordinal(); + + static std::wstring Compose(const std::wstring &message, const std::wstring ×tamp, + const std::wstring &ordinal, size_t indentation = 0); +}; diff --git a/windows/nsis-plugins/src/log/stdafx.cpp b/windows/nsis-plugins/src/log/stdafx.cpp new file mode 100644 index 0000000000..3b6341d106 --- /dev/null +++ b/windows/nsis-plugins/src/log/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// driverlogic.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/windows/nsis-plugins/src/log/stdafx.h b/windows/nsis-plugins/src/log/stdafx.h new file mode 100644 index 0000000000..f3a07375c7 --- /dev/null +++ b/windows/nsis-plugins/src/log/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include <windows.h> + + + +// TODO: reference additional headers your program requires here diff --git a/windows/nsis-plugins/src/log/targetver.h b/windows/nsis-plugins/src/log/targetver.h new file mode 100644 index 0000000000..ae4a5c032c --- /dev/null +++ b/windows/nsis-plugins/src/log/targetver.h @@ -0,0 +1,12 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <WinSDKVer.h> + +#define _WIN32_WINNT _WIN32_WINNT_WIN7 + +#include <SDKDDKVer.h> |
