| 1 | #pragma once
|
|---|
| 2 |
|
|---|
| 3 | #include <direct.h>
|
|---|
| 4 | #include <stdlib.h>
|
|---|
| 5 | #include <stdio.h>
|
|---|
| 6 | #include <string>
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 | namespace simple_file {
|
|---|
| 10 |
|
|---|
| 11 | #ifndef CSIDL_COMMON_APPDATA
|
|---|
| 12 | #define CSIDL_COMMON_APPDATA 0x0023
|
|---|
| 13 | #define CSIDL_LOCAL_APPDATA 0x001c
|
|---|
| 14 | #endif
|
|---|
| 15 | typedef BOOL (WINAPI *fnSHGetSpecialFolderPath)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate);
|
|---|
| 16 | static BOOL WINAPI _SHGetSpecialFolderPath(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate) {
|
|---|
| 17 | static fnSHGetSpecialFolderPath __SHGetSpecialFolderPath = NULL;
|
|---|
| 18 | if (!__SHGetSpecialFolderPath) {
|
|---|
| 19 | HMODULE hDLL = LoadLibrary(_T("shell32.dll"));
|
|---|
| 20 | if (hDLL != NULL) {
|
|---|
| 21 | __SHGetSpecialFolderPath = (fnSHGetSpecialFolderPath)GetProcAddress(hDLL,"SHGetSpecialFolderPathW");
|
|---|
| 22 | }
|
|---|
| 23 | }
|
|---|
| 24 | if(__SHGetSpecialFolderPath)
|
|---|
| 25 | return __SHGetSpecialFolderPath(hwndOwner, lpszPath, nFolder, fCreate);
|
|---|
| 26 | return FALSE;
|
|---|
| 27 | }
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 | class file_appender {
|
|---|
| 31 | std::wstring file_;
|
|---|
| 32 | std::wstring path_;
|
|---|
| 33 | std::wstring filename_;
|
|---|
| 34 | public:
|
|---|
| 35 | file_appender(std::wstring path, std::wstring filename) : path_(path), filename_(filename) {}
|
|---|
| 36 | file_appender() {}
|
|---|
| 37 |
|
|---|
| 38 | void set_file(std::wstring path, std::wstring filename) {
|
|---|
| 39 | path_ = path;
|
|---|
| 40 | filename_ = filename;
|
|---|
| 41 | }
|
|---|
| 42 |
|
|---|
| 43 | inline std::wstring getFileName() {
|
|---|
| 44 | if (file_.empty())
|
|---|
| 45 | return getFileName(path_, filename_);
|
|---|
| 46 | return file_;
|
|---|
| 47 | }
|
|---|
| 48 | std::wstring getFileName(std::wstring pathname, std::wstring filename) {
|
|---|
| 49 | if (file_.empty()) {
|
|---|
| 50 | std::wstring path = getFolder() + _T("\\") + pathname;
|
|---|
| 51 | if (!directoryExists(path)) {
|
|---|
| 52 | if (_wmkdir(path.c_str()) != 0)
|
|---|
| 53 | return _T("");
|
|---|
| 54 | }
|
|---|
| 55 | file_ = path + _T("\\") + filename;
|
|---|
| 56 | }
|
|---|
| 57 | return file_;
|
|---|
| 58 | }
|
|---|
| 59 | private:
|
|---|
| 60 | inline std::wstring getFolder() {
|
|---|
| 61 | TCHAR buf[MAX_PATH+1];
|
|---|
| 62 | if (!_SHGetSpecialFolderPath(NULL, buf, CSIDL_LOCAL_APPDATA, FALSE)) {
|
|---|
| 63 | return _T("") + error::lookup::last_error();
|
|---|
| 64 | }
|
|---|
| 65 | return buf;
|
|---|
| 66 | }
|
|---|
| 67 | bool directoryExists(std::wstring path) {
|
|---|
| 68 | DWORD dwAtt = ::GetFileAttributes(path.c_str());
|
|---|
| 69 | if (dwAtt == INVALID_FILE_ATTRIBUTES) {
|
|---|
| 70 | return false;
|
|---|
| 71 | } else if ((dwAtt&FILE_ATTRIBUTE_DIRECTORY)==FILE_ATTRIBUTE_DIRECTORY) {
|
|---|
| 72 | return true;
|
|---|
| 73 | }
|
|---|
| 74 | return false;
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | HANDLE openAppendOrNew(std::wstring file) {
|
|---|
| 78 | DWORD numberOfBytesWritten = 0;
|
|---|
| 79 | HANDLE hFile = ::CreateFile(file.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|---|
| 80 | if (hFile == INVALID_HANDLE_VALUE) {
|
|---|
| 81 | hFile = ::CreateFile(file.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|---|
| 82 | if (hFile != INVALID_HANDLE_VALUE) {
|
|---|
| 83 | WORD wBOM = 0xFEFF;
|
|---|
| 84 | ::WriteFile(hFile, &wBOM, sizeof(WORD), &numberOfBytesWritten, NULL);
|
|---|
| 85 | } else {
|
|---|
| 86 | int x = 5;
|
|---|
| 87 | }
|
|---|
| 88 | }
|
|---|
| 89 | return hFile;
|
|---|
| 90 | }
|
|---|
| 91 | public:
|
|---|
| 92 |
|
|---|
| 93 | bool writeEntry(std::wstring line) {
|
|---|
| 94 | DWORD numberOfBytesWritten;
|
|---|
| 95 | HANDLE hFile = openAppendOrNew(getFileName());
|
|---|
| 96 | if (hFile == INVALID_HANDLE_VALUE) {
|
|---|
| 97 | return false;
|
|---|
| 98 | }
|
|---|
| 99 | if (::SetFilePointer(hFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) {
|
|---|
| 100 | // Ingore this error!
|
|---|
| 101 | }
|
|---|
| 102 | ::WriteFile(hFile, line.c_str(), (static_cast<DWORD>(line.length()))*(sizeof(TCHAR)), &numberOfBytesWritten, NULL);
|
|---|
| 103 | ::CloseHandle(hFile);
|
|---|
| 104 | return true;
|
|---|
| 105 | }
|
|---|
| 106 | };
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | namespace logging {
|
|---|
| 110 | class file_logger : public simple_file::file_appender {
|
|---|
| 111 | std::wstring datemask_;
|
|---|
| 112 | public:
|
|---|
| 113 | file_logger(std::wstring path, std::wstring filename) : file_appender(path, filename), datemask_(_T("%Y-%m-%d %H:%M:%S")) {
|
|---|
| 114 | _tzset();
|
|---|
| 115 | }
|
|---|
| 116 | void log(const std::wstring category, const wchar_t* file, const int line, const wchar_t* message) {
|
|---|
| 117 | TCHAR buffer[65];
|
|---|
| 118 | __time64_t ltime;
|
|---|
| 119 | _time64( <ime );
|
|---|
| 120 | struct tm *today = _localtime64( <ime );
|
|---|
| 121 | if (today) {
|
|---|
| 122 | size_t len = wcsftime(buffer, 63, datemask_.c_str(), today);
|
|---|
| 123 | if ((len < 1)||(len > 64))
|
|---|
| 124 | wcsncpy_s(buffer, 64, _T("???"), 63);
|
|---|
| 125 | else
|
|---|
| 126 | buffer[len] = 0;
|
|---|
| 127 | } else {
|
|---|
| 128 | wcsncpy_s(buffer, 64, _T("<unknown time>"), 63);
|
|---|
| 129 | }
|
|---|
| 130 | std::wstring logline = std::wstring(buffer) + _T(": ") + category + _T(":") + std::wstring(file) + _T(":") + strEx::itos(line) +_T(": ") + message + _T("\r\n");
|
|---|
| 131 | if (!writeEntry(logline)) {
|
|---|
| 132 | std::wcerr << _T("Failed to write: ") << logline;
|
|---|
| 133 | }
|
|---|
| 134 | }
|
|---|
| 135 | };
|
|---|
| 136 | } |
|---|