1 #pragma once
2 #include <plog/Appenders/IAppender.h>
3 #include <plog/WinApi.h>
4 
5 namespace plog
6 {
7     template <class Formatter>
8     class EventLogAppender : public IAppender
9     {
10     public:
EventLogAppender(const wchar_t * sourceName)11         EventLogAppender(const wchar_t* sourceName) : m_eventSource(RegisterEventSourceW(NULL, sourceName))
12         {
13         }
14 
~EventLogAppender()15         ~EventLogAppender()
16         {
17             DeregisterEventSource(m_eventSource);
18         }
19 
write(const Record & record)20         virtual void write(const Record& record)
21         {
22             std::wstring str = Formatter::format(record);
23             const wchar_t* logMessagePtr[] = { str.c_str() };
24 
25             ReportEventW(m_eventSource, logSeverityToType(record.getSeverity()), static_cast<WORD>(record.getSeverity()), 0, NULL, 1, 0, logMessagePtr, NULL);
26         }
27 
28     private:
logSeverityToType(plog::Severity severity)29         static WORD logSeverityToType(plog::Severity severity)
30         {
31             switch (severity)
32             {
33             case plog::fatal:
34             case plog::error:
35                 return eventLog::kErrorType;
36 
37             case plog::warning:
38                 return eventLog::kWarningType;
39 
40             case plog::info:
41             case plog::debug:
42             case plog::verbose:
43             default:
44                 return eventLog::kInformationType;
45             }
46         }
47 
48     private:
49         HANDLE m_eventSource;
50     };
51 
52     class EventLogAppenderRegistry
53     {
54     public:
55         static bool add(const wchar_t* sourceName, const wchar_t* logName = L"Application")
56         {
57             std::wstring logKeyName;
58             std::wstring sourceKeyName;
59             getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
60 
61             HKEY sourceKey;
62             if (0 != RegCreateKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, NULL, 0, regSam::kSetValue, NULL, &sourceKey, NULL))
63             {
64                 return false;
65             }
66 
67             const DWORD kTypesSupported = eventLog::kErrorType | eventLog::kWarningType | eventLog::kInformationType;
68             RegSetValueExW(sourceKey, L"TypesSupported", 0, regType::kDword, reinterpret_cast<const BYTE*>(&kTypesSupported), sizeof(kTypesSupported));
69 
70             const wchar_t kEventMessageFile[] = L"%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\EventLogMessages.dll;%windir%\\Microsoft.NET\\Framework\\v2.0.50727\\EventLogMessages.dll";
71             RegSetValueExW(sourceKey, L"EventMessageFile", 0, regType::kExpandSz, reinterpret_cast<const BYTE*>(kEventMessageFile), sizeof(kEventMessageFile) - sizeof(*kEventMessageFile));
72 
73             RegCloseKey(sourceKey);
74             return true;
75         }
76 
77         static bool exists(const wchar_t* sourceName, const wchar_t* logName = L"Application")
78         {
79             std::wstring logKeyName;
80             std::wstring sourceKeyName;
81             getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
82 
83             HKEY sourceKey;
84             if (0 != RegOpenKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, regSam::kQueryValue, &sourceKey))
85             {
86                 return false;
87             }
88 
89             RegCloseKey(sourceKey);
90             return true;
91         }
92 
93         static void remove(const wchar_t* sourceName, const wchar_t* logName = L"Application")
94         {
95             std::wstring logKeyName;
96             std::wstring sourceKeyName;
97             getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
98 
99             RegDeleteKeyW(hkey::kLocalMachine, sourceKeyName.c_str());
100             RegDeleteKeyW(hkey::kLocalMachine, logKeyName.c_str());
101         }
102 
103     private:
getKeyNames(const wchar_t * sourceName,const wchar_t * logName,std::wstring & sourceKeyName,std::wstring & logKeyName)104         static void getKeyNames(const wchar_t* sourceName, const wchar_t* logName, std::wstring& sourceKeyName, std::wstring& logKeyName)
105         {
106             const std::wstring kPrefix = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
107             logKeyName = kPrefix + logName;
108             sourceKeyName = logKeyName + L"\\" + sourceName;
109         }
110     };
111 }
112