diff --git a/CrashReport.cpp b/CrashReport.cpp index ab9e236..2759a29 100644 --- a/CrashReport.cpp +++ b/CrashReport.cpp @@ -53,8 +53,10 @@ static LPTOP_LEVEL_EXCEPTION_FILTER lpPrevExceptionFilter = NULL; static BOOL GetParamValue(_Inout_ LPCWSTR &sW, _Out_ LPVOID *lplpValue, _In_ WCHAR chEndingW); static LONG WINAPI OnUnhandledExceptionFilter(_In_ PEXCEPTION_POINTERS ExceptionInfo); -static VOID CleanupDumpFolder(_In_z_ LPCWSTR szBaseFileNameW); -static HANDLE CreateDumpFile(_In_z_ LPCWSTR szBaseFileNameW); + +static VOID RemoveOldFiles(_In_z_ LPCWSTR szDumpFolderW); + +static HANDLE CreateDumpFile(_In_z_ LPCWSTR szDumpFolderW, _In_z_ LPCWSTR szBaseFileNameW); //----------------------------------------------------------- @@ -70,15 +72,16 @@ VOID Initialize() return; } -BOOL HandleCrashDump(_In_z_ LPCWSTR szModuleNameW) +BOOL HandleCrashDump(_In_z_ LPCWSTR szApplicationNameW, _In_z_ LPCWSTR szModuleNameW) { - CStringW cStrBaseFileNameW; + CStringW cStrDumpFolderW; LPCWSTR sW; HANDLE hProc; LPCRASHINFO lpCrashInfo; CRASHINFO sLocalCrashInfo; HINSTANCE hDbgHelpDll; + MX_ASSERT(szApplicationNameW != NULL && *szApplicationNameW != 0); MX_ASSERT(szModuleNameW != NULL && *szModuleNameW != 0); //parse command line @@ -123,15 +126,11 @@ BOOL HandleCrashDump(_In_z_ LPCWSTR szModuleNameW) if (GetParamValue(sW, (LPVOID*)&lpCrashInfo, 0) == FALSE) return TRUE; //invalid command line parameter (handled) - //copy base module name - if (cStrBaseFileNameW.Copy(szModuleNameW) == FALSE) + //setup dump folder + if (FAILED(FileRoutines::GetCommonAppDataFolderPath(cStrDumpFolderW))) return TRUE; //error (handled) - //setup log folder - if (FAILED(MX::FileRoutines::GetAppDataFolderPath(cStrBaseFileNameW))) + if (cStrDumpFolderW.AppendFormat(L"%s\\Dumps\\", szApplicationNameW) == FALSE) return TRUE; //error (handled) - if (cStrBaseFileNameW.AppendFormat(L"Dumps\\%s\\", szModuleNameW) == FALSE) - return TRUE; //error (handled) - MX::FileRoutines::NormalizePath(cStrBaseFileNameW); //read crash info data if (::ReadProcessMemory(hProc, lpCrashInfo, &sLocalCrashInfo, sizeof(sLocalCrashInfo), NULL) == FALSE) @@ -147,11 +146,11 @@ BOOL HandleCrashDump(_In_z_ LPCWSTR szModuleNameW) { MX::CWindowsHandle cFileH; - MX::FileRoutines::CreateDirectoryRecursive((LPCWSTR)cStrBaseFileNameW); + MX::FileRoutines::CreateDirectoryRecursive((LPCWSTR)cStrDumpFolderW); - CleanupDumpFolder((LPCWSTR)cStrBaseFileNameW); + RemoveOldFiles((LPCWSTR)cStrDumpFolderW); - cFileH.Attach(CreateDumpFile((LPCWSTR)cStrBaseFileNameW)); + cFileH.Attach(CreateDumpFile((LPCWSTR)cStrDumpFolderW, szModuleNameW)); if (cFileH) { MINIDUMP_EXCEPTION_INFORMATION sMiniDumpExceptionInfo; @@ -169,6 +168,7 @@ BOOL HandleCrashDump(_In_z_ LPCWSTR szModuleNameW) } ::CloseHandle(hProc); + //done return TRUE; //handled } @@ -259,9 +259,9 @@ static LONG WINAPI OnUnhandledExceptionFilter(_In_ PEXCEPTION_POINTERS Exception return EXCEPTION_EXECUTE_HANDLER; } -static VOID CleanupDumpFolder(_In_z_ LPCWSTR szBaseFileNameW) +static VOID RemoveOldFiles(_In_z_ LPCWSTR szDumpFolderW) { - MX::CStringW cStrFileNameW; + MX::CStringW cStrTempW; WIN32_FIND_DATAW sFindDataW; ULARGE_INTEGER uliLowerTime, uliTemp; WCHAR szLowerFileNameW[sizeof(sFindDataW.cFileName)]; @@ -270,9 +270,9 @@ static VOID CleanupDumpFolder(_In_z_ LPCWSTR szBaseFileNameW) loop: dwCount = 0; - if (cStrFileNameW.Copy(szBaseFileNameW) == FALSE || cStrFileNameW.ConcatN(L"*", 1) == FALSE) + if (cStrTempW.Copy(szDumpFolderW) == FALSE || cStrTempW.ConcatN(L"*", 1) == FALSE) return; - hFindFile = ::FindFirstFileW((LPCWSTR)cStrFileNameW, &sFindDataW); + hFindFile = ::FindFirstFileW((LPCWSTR)cStrTempW, &sFindDataW); if (hFindFile == NULL || hFindFile == INVALID_HANDLE_VALUE) return; uliLowerTime.QuadPart = (ULONGLONG)-1; @@ -292,9 +292,9 @@ static VOID CleanupDumpFolder(_In_z_ LPCWSTR szBaseFileNameW) if (dwCount > MAX_DUMPS_COUNT) { - if (cStrFileNameW.Copy(szBaseFileNameW) == FALSE || cStrFileNameW.Concat(szLowerFileNameW) == FALSE) + if (cStrTempW.Copy(szDumpFolderW) == FALSE || cStrTempW.Concat(szLowerFileNameW) == FALSE) return; - if (FAILED(MX::FileRoutines::_DeleteFile((LPCWSTR)cStrFileNameW))) + if (FAILED(MX::FileRoutines::_DeleteFile((LPCWSTR)cStrTempW))) return; dwCount--; } @@ -304,31 +304,39 @@ static VOID CleanupDumpFolder(_In_z_ LPCWSTR szBaseFileNameW) return; } -static HANDLE CreateDumpFile(_In_z_ LPCWSTR szBaseFileNameW) +static HANDLE CreateDumpFile(_In_z_ LPCWSTR szDumpFolderW, _In_z_ LPCWSTR szBaseFileNameW) { MX::CStringW cStrFileNameW; SYSTEMTIME stNow; HANDLE hFile; - ULONG i; + HRESULT hRes; ::GetLocalTime(&stNow); - if (cStrFileNameW.Format(L"%sdump_%04lu-%02lu-%02lu.dmp", szBaseFileNameW, stNow.wYear, stNow.wMonth, + + if (cStrFileNameW.Format(L"%s%s_%04lu-%02lu-%02lu.dmp", szDumpFolderW, szBaseFileNameW, stNow.wYear, stNow.wMonth, stNow.wDay) != FALSE) { hFile = ::CreateFileW((LPCWSTR)cStrFileNameW, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) return hFile; + hRes = MX_HRESULT_FROM_LASTERROR(); + if (hRes != HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)) + return INVALID_HANDLE_VALUE; } - for (i=2; i<=1000; i++) + + for (ULONG i = 2; i <= 1000; i++) { - if (cStrFileNameW.Format(L"%sdump_%04lu-%02lu-%02lu_%lu.dmp", szBaseFileNameW, stNow.wYear, stNow.wMonth, - stNow.wDay, i) != FALSE) + if (cStrFileNameW.Format(L"%s%s_%04lu-%02lu-%02lu_%lu.dmp", szDumpFolderW, szBaseFileNameW, stNow.wYear, + stNow.wMonth, stNow.wDay, i) != FALSE) { hFile = ::CreateFileW((LPCWSTR)cStrFileNameW, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) return hFile; + hRes = MX_HRESULT_FROM_LASTERROR(); + if (hRes != HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)) + break; } } return INVALID_HANDLE_VALUE; diff --git a/CrashReport.h b/CrashReport.h index 6cbd363..b66ef7d 100644 --- a/CrashReport.h +++ b/CrashReport.h @@ -29,7 +29,7 @@ namespace MX { namespace CrashReport { VOID Initialize(); -BOOL HandleCrashDump(_In_z_ LPCWSTR szModuleNameW); +BOOL HandleCrashDump(_In_z_ LPCWSTR szApplicationNameW, _In_z_ LPCWSTR szModuleNameW); }; //namespace CrashReport diff --git a/FileRoutines.cpp b/FileRoutines.cpp index f8a2305..717b8d5 100644 --- a/FileRoutines.cpp +++ b/FileRoutines.cpp @@ -71,10 +71,6 @@ typedef VOID (__stdcall *lpfnCoTaskMemFree)(_In_opt_ LPVOID pv); //----------------------------------------------------------- -static LPCWSTR szAppDataSubFolderW = NULL; - -//----------------------------------------------------------- - static HRESULT _GetKnownFolderFolderPath(_In_ int csIdl, _In_ const GUID &sGuid, _In_ BOOL bCreate, _Out_ MX::CStringW &cStrDestW); @@ -82,8 +78,7 @@ static HRESULT _GetKnownFolderFolderPath(_In_ int csIdl, _In_ const GUID &sGuid, namespace MX { -namespace FileRoutines -{ +namespace FileRoutines { HRESULT GetAppFileName(_Out_ CStringW &cStrDestW) { @@ -221,30 +216,6 @@ HRESULT GetProcessFileName(_In_ HANDLE hProc, _Out_ CStringW &cStrDestW) return S_OK; } -VOID SetAppDataFolder(_In_z_ LPCWSTR szSubFolderW) -{ - szAppDataSubFolderW = szSubFolderW; - return; -} - -HRESULT GetAppDataFolderPath(_Out_ CStringW &cStrDestW) -{ - HRESULT hRes; - - if (szAppDataSubFolderW == NULL || *szAppDataSubFolderW == 0) - return E_FAIL; - hRes = GetCommonAppDataFolderPath(cStrDestW); - if (SUCCEEDED(hRes)) - { - if (cStrDestW.Concat(szAppDataSubFolderW) == FALSE || - cStrDestW.ConcatN(L"\\", 1) == FALSE) - { - hRes = E_OUTOFMEMORY; - } - } - return hRes; -} - HRESULT GetCommonAppDataFolderPath(_Out_ CStringW &cStrDestW) { static const GUID __FOLDERID_ProgramData = { diff --git a/FileRoutines.h b/FileRoutines.h index 8f680ca..35e6804 100644 --- a/FileRoutines.h +++ b/FileRoutines.h @@ -52,10 +52,6 @@ HRESULT GetAppFolderPath(_Out_ CStringW &cStrDestW); HRESULT GetProcessFileName(_In_ DWORD dwPid, _Out_ CStringW &cStrDestW); HRESULT GetProcessFileName(_In_ HANDLE hProc, _Out_ CStringW &cStrDestW); -//IMPORTANT: Passed parameter should exists in entire app's life. -VOID SetAppDataFolder(_In_z_ LPCWSTR szSubFolderW); -HRESULT GetAppDataFolderPath(_Out_ CStringW &cStrDestW); - HRESULT GetCommonAppDataFolderPath(_Out_ CStringW &cStrDestW); HRESULT GetProgramFilesFolderPath(_Out_ CStringW &cStrDestW); #if defined(_M_X64) diff --git a/Logger.cpp b/Logger.cpp index ea30cde..bfd9629 100644 --- a/Logger.cpp +++ b/Logger.cpp @@ -55,12 +55,18 @@ static WORD wLastDate[3] = { 0 }; //----------------------------------------------------------- -static VOID EndLogger(); -static VOID RemoveOldFiles(); +static VOID ShutdownLogger(); + +static VOID RemoveOldFiles(_In_ DWORD dwKeepDays, _In_z_ LPCWSTR szLogFolderW, _In_z_ LPCWSTR szLogBaseFileNameW); + +static HRESULT GetLogKeepDays(_In_z_ LPCWSTR szRegistryKeyW, _In_z_ LPCWSTR szRegistryValueW, + _In_ DWORD dwDefaultKeepDays, _Out_ DWORD &dwKeepDays); + static HRESULT OpenLog(_In_ LPSYSTEMTIME lpSystemTime); static HRESULT InitLogCommon(_Out_ LPSYSTEMTIME lpSystemTime); static VOID WriteLogCommon(_In_ BOOL bAddError, _In_ HRESULT hResError, _In_ LPSYSTEMTIME lpSystemTime, _In_z_ LPCWSTR szFormatW, _In_ va_list argptr); + static BOOL GenerateLogFileName(_In_ LPSYSTEMTIME lpSystemTime, _Out_ MX::CStringW &cStrFileNameW); //----------------------------------------------------------- @@ -69,99 +75,52 @@ namespace MX { namespace EventLogger { -HRESULT Initialize(_In_z_ LPCWSTR szModuleNameW, _In_z_ LPCWSTR szRegistryKeyW, _In_z_ LPCWSTR szRegistryValueW, - _In_ DWORD dwDefaultKeepDays) +HRESULT Initialize(_In_z_ LPCWSTR szApplicationNameW, _In_z_ LPCWSTR szModuleNameW, _In_z_ LPCWSTR szRegistryKeyW, + _In_z_ LPCWSTR szRegistryValueW, _In_ DWORD dwDefaultKeepDays) { CFastLock cLock(&nMutex); - HKEY hKeyBase = HKEY_LOCAL_MACHINE; HRESULT hRes; if (szModuleNameW == NULL || szRegistryKeyW == NULL || szRegistryValueW == NULL) return E_POINTER; if (*szModuleNameW == 0 || *szRegistryKeyW == 0 || *szRegistryValueW == 0 || dwDefaultKeepDays < 1) return E_INVALIDARG; - if (StrNCompareW(szRegistryKeyW, L"HKLM\\", 5, TRUE) == 0) - { - szRegistryKeyW += 5; - } - else if (StrNCompareW(szRegistryKeyW, L"HKEY_LOCAL_MACHINE\\", 19, TRUE) == 0) - { - szRegistryKeyW += 19; - } - else if (StrNCompareW(szRegistryKeyW, L"HKCU\\", 5, TRUE) == 0) - { - szRegistryKeyW += 5; - hKeyBase = HKEY_CURRENT_USER; - } - else if (StrNCompareW(szRegistryKeyW, L"HKEY_CURRENT_USER\\", 18, TRUE) == 0) - { - szRegistryKeyW += 18; - hKeyBase = HKEY_CURRENT_USER; - } - else - { - return E_INVALIDARG; - } + + ShutdownLogger(); //copy base module name if (cStrLogFileNameBaseW.Copy(szModuleNameW) == FALSE) return E_OUTOFMEMORY; //setup log folder - hRes = FileRoutines::GetAppDataFolderPath(cStrLogFolderW); + hRes = FileRoutines::GetCommonAppDataFolderPath(cStrLogFolderW); if (SUCCEEDED(hRes)) { - if (cStrLogFolderW.ConcatN(L"Logs\\", 5) == FALSE) + if (cStrLogFolderW.AppendFormat(L"%s\\Logs\\", szApplicationNameW) == FALSE) hRes = E_OUTOFMEMORY; } //get settings from registry if (SUCCEEDED(hRes)) { - CWindowsRegistry cWinReg; - - hRes = cWinReg.Open(hKeyBase, szRegistryKeyW); - if (SUCCEEDED(hRes)) - { - //get log keep days - hRes = cWinReg.ReadDWord(szRegistryValueW, dwLogKeepDays); - if (SUCCEEDED(hRes)) - { - if (dwLogKeepDays < 1) - dwLogKeepDays = 1; - else if (dwLogKeepDays > 180) - dwLogKeepDays = 180; - } - else if (hRes == MX_E_FileNotFound || hRes == MX_E_PathNotFound) - { - dwLogKeepDays = dwDefaultKeepDays; - hRes = S_OK; - } - } - else if (hRes == MX_E_FileNotFound || hRes == MX_E_PathNotFound) - { - dwLogKeepDays = dwDefaultKeepDays; - hRes = S_OK; - } + hRes = GetLogKeepDays(szRegistryKeyW, szRegistryValueW, dwDefaultKeepDays, dwLogKeepDays); } //register finalizer if (SUCCEEDED(hRes)) { - hRes = RegisterFinalizer(&EndLogger, 1); + hRes = RegisterFinalizer(&ShutdownLogger, 1); } //failure? if (FAILED(hRes)) { - cStrLogFolderW.Empty(); - cStrLogFileNameBaseW.Empty(); - dwLogKeepDays = 0; + ShutdownLogger(); return hRes; } //delete old files - RemoveOldFiles(); + RemoveOldFiles(dwLogKeepDays, (LPCWSTR)cStrLogFolderW, (LPCWSTR)cStrLogFileNameBaseW); //done _InterlockedOr(&nInitializedFlags, LOGFLAG_Initialized); @@ -271,11 +230,35 @@ HRESULT LogRaw(_In_z_ LPCWSTR szTextW) return S_OK; } -HRESULT GetLogFolder(_Out_ CStringW &_cStrLogFolderW) +HRESULT GetLogFolder(_Out_ CStringW &_cStrLogFolderW, _In_opt_ BOOL bCreate) { + _cStrLogFolderW.Empty(); if ((__InterlockedRead(&nInitializedFlags) & LOGFLAG_Initialized) == 0) return MX_E_NotReady; - return (_cStrLogFolderW.CopyN((LPCWSTR)cStrLogFolderW, cStrLogFolderW.GetLength()) != FALSE) ? S_OK : E_OUTOFMEMORY; + if (bCreate != FALSE) + { + MX::FileRoutines::CreateDirectoryRecursive((LPCWSTR)cStrLogFolderW); + } + if (_cStrLogFolderW.CopyN((LPCWSTR)cStrLogFolderW, cStrLogFolderW.GetLength()) == FALSE) + return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT GetLogFileName(_Out_ CStringW &cStrFileNameW, _In_opt_ BOOL bCreateFolder) +{ + SYSTEMTIME sSystemTime; + + cStrFileNameW.Empty(); + if ((__InterlockedRead(&nInitializedFlags) & LOGFLAG_Initialized) == 0) + return MX_E_NotReady; + if (bCreateFolder != FALSE) + { + MX::FileRoutines::CreateDirectoryRecursive((LPCWSTR)cStrLogFolderW); + } + ::GetSystemTime(&sSystemTime); + if (GenerateLogFileName(&sSystemTime, cStrFileNameW) == FALSE) + return E_OUTOFMEMORY; + return S_OK; } }; //namespace EventLogger @@ -284,14 +267,17 @@ HRESULT GetLogFolder(_Out_ CStringW &_cStrLogFolderW) //----------------------------------------------------------- -static VOID EndLogger() +static VOID ShutdownLogger() { cLogH.Close(); + cStrLogFolderW.Empty(); + cStrLogFileNameBaseW.Empty(); + dwLogKeepDays = 0; _InterlockedAnd(&nInitializedFlags, ~LOGFLAG_Initialized); return; } -static VOID RemoveOldFiles() +static VOID RemoveOldFiles(_In_ DWORD dwKeepDays, _In_z_ LPCWSTR szLogFolderW, _In_z_ LPCWSTR szLogBaseFileNameW) { ULONGLONG nDueTime, nTimeToSub, nFileTime; WIN32_FIND_DATAW sFindDataW; @@ -300,30 +286,29 @@ static VOID RemoveOldFiles() FILETIME sFt; SIZE_T nBaseNameLen; - if (dwLogKeepDays == 0) + if (dwKeepDays == 0) return; //calculate due time ::GetSystemTimeAsFileTime(&sFt); nDueTime = ((ULONGLONG)(sFt.dwHighDateTime) << 32) | (ULONGLONG)(sFt.dwLowDateTime); - nTimeToSub = MX_MILLISECONDS_TO_100NS((ULONGLONG)dwLogKeepDays * 86400000ui64); + nTimeToSub = MX_MILLISECONDS_TO_100NS((ULONGLONG)dwKeepDays * 86400000ui64); nDueTime = (nDueTime > nTimeToSub) ? (nDueTime - nTimeToSub) : 0ui64; //scan folder - if (cStrTempW.Copy((LPCWSTR)cStrLogFolderW) == FALSE || - cStrTempW.ConcatN(L"*", 1) == FALSE) - { + if (cStrTempW.Copy(szLogFolderW) == FALSE || cStrTempW.ConcatN(L"*", 1) == FALSE) return; - } + hFindFile = ::FindFirstFileW((LPCWSTR)cStrTempW, &sFindDataW); if (hFindFile != INVALID_HANDLE_VALUE) { + nBaseNameLen = MX::StrLenW(szLogBaseFileNameW); + do { if ((sFindDataW.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - nBaseNameLen = cStrLogFileNameBaseW.GetLength(); - if (MX::StrNCompareW((LPCWSTR)cStrLogFileNameBaseW, sFindDataW.cFileName, nBaseNameLen, TRUE) == 0 && + if (MX::StrNCompareW(szLogBaseFileNameW, sFindDataW.cFileName, nBaseNameLen, TRUE) == 0 && sFindDataW.cFileName[nBaseNameLen] == L'-') { #ifdef USE_FILE_CREATION_TIMESTAMP @@ -382,11 +367,73 @@ static VOID RemoveOldFiles() } } while (::FindNextFileW(hFindFile, &sFindDataW) != FALSE); + + //cleanup ::FindClose(hFindFile); } return; } +static HRESULT GetLogKeepDays(_In_z_ LPCWSTR szRegistryKeyW, _In_z_ LPCWSTR szRegistryValueW, + _In_ DWORD dwDefaultKeepDays, _Out_ DWORD &dwKeepDays) +{ + MX::CWindowsRegistry cWinReg; + HKEY hKeyBase = HKEY_LOCAL_MACHINE; + HRESULT hRes; + + dwKeepDays = dwDefaultKeepDays; + + if (MX::StrNCompareW(szRegistryKeyW, L"HKLM\\", 5, TRUE) == 0) + { + szRegistryKeyW += 5; + } + else if (MX::StrNCompareW(szRegistryKeyW, L"HKEY_LOCAL_MACHINE\\", 19, TRUE) == 0) + { + szRegistryKeyW += 19; + } + else if (MX::StrNCompareW(szRegistryKeyW, L"HKCU\\", 5, TRUE) == 0) + { + szRegistryKeyW += 5; + hKeyBase = HKEY_CURRENT_USER; + } + else if (MX::StrNCompareW(szRegistryKeyW, L"HKEY_CURRENT_USER\\", 18, TRUE) == 0) + { + szRegistryKeyW += 18; + hKeyBase = HKEY_CURRENT_USER; + } + else + { + return E_INVALIDARG; + } + + hRes = cWinReg.Open(hKeyBase, szRegistryKeyW); + if (SUCCEEDED(hRes)) + { + //get log keep days + hRes = cWinReg.ReadDWord(szRegistryValueW, dwLogKeepDays); + if (SUCCEEDED(hRes)) + { + if (dwLogKeepDays < 1) + dwLogKeepDays = 1; + else if (dwLogKeepDays > 180) + dwLogKeepDays = 180; + } + else if (hRes == MX_E_FileNotFound || hRes == MX_E_PathNotFound) + { + dwLogKeepDays = dwDefaultKeepDays; + hRes = S_OK; + } + } + else if (hRes == MX_E_FileNotFound || hRes == MX_E_PathNotFound) + { + dwLogKeepDays = dwDefaultKeepDays; + hRes = S_OK; + } + + //done + return hRes; +} + static HRESULT OpenLog(_In_ LPSYSTEMTIME lpSystemTime) { MX::CStringW cStrTempW, cStrOpSystemW; @@ -539,7 +586,7 @@ static HRESULT InitLogCommon(_Out_ LPSYSTEMTIME lpSystemTime) if ((_InterlockedOr(&nInitializedFlags, LOGFLAG_LogFileOpenProcessed) & LOGFLAG_LogFileOpenProcessed) != 0) return E_FAIL; - RemoveOldFiles(); + RemoveOldFiles(dwLogKeepDays, (LPCWSTR)cStrLogFolderW, (LPCWSTR)cStrLogFileNameBaseW); hRes = OpenLog(lpSystemTime); if (FAILED(hRes)) return hRes; diff --git a/Logger.h b/Logger.h index cff77a6..ea4ff8d 100644 --- a/Logger.h +++ b/Logger.h @@ -31,15 +31,16 @@ namespace MX { namespace EventLogger { -HRESULT Initialize(_In_z_ LPCWSTR szModuleNameW, _In_z_ LPCWSTR szRegistryKeyW, _In_z_ LPCWSTR szRegistryValueW, - _In_ DWORD dwDefaultKeepDays); +HRESULT Initialize(_In_z_ LPCWSTR szApplicationNameW, _In_z_ LPCWSTR szModuleNameW, _In_z_ LPCWSTR szRegistryKeyW, + _In_z_ LPCWSTR szRegistryValueW, _In_ DWORD dwDefaultKeepDays); HRESULT Log(_Printf_format_string_ LPCWSTR szFormatW, ...); HRESULT LogIfError(_In_ HRESULT hResError, _Printf_format_string_ LPCWSTR szFormatW, ...); HRESULT LogAlways(_In_ HRESULT hResError, _Printf_format_string_ LPCWSTR szFormatW, ...); HRESULT LogRaw(_In_z_ LPCWSTR szTextW); -HRESULT GetLogFolder(_Out_ CStringW &cStrLogFolderW); +HRESULT GetLogFolder(_Out_ CStringW &cStrLogFolderW, _In_opt_ BOOL bCreate = FALSE); +HRESULT GetLogFileName(_Out_ CStringW &cStrFileNameW, _In_opt_ BOOL bCreateFolder = FALSE); }; //namespace EventLogger diff --git a/Miscellaneous.cpp b/Miscellaneous.cpp index 2e1f9e9..55ae7fb 100644 --- a/Miscellaneous.cpp +++ b/Miscellaneous.cpp @@ -19,6 +19,12 @@ */ #include "Miscellaneous.h" #include "FileRoutines.h" +#include +#include + +//----------------------------------------------------------- + +static BOOL AddRepeatedChar(_Inout_ MX::CStringW &cStrW, _In_ WCHAR chW, _In_ SIZE_T nCount); //----------------------------------------------------------- @@ -430,27 +436,190 @@ HRESULT ExecuteApp(_In_z_ LPCWSTR szCmdLineW, _In_ DWORD dwAfterSeconds) return hRes; } -HRESULT SelfDeleteApp(_In_ DWORD dwAfterSeconds) +HRESULT ExecuteApp(_In_ BOOL bWait, _In_ BOOL bHide, _In_z_ LPCWSTR szAppNameW, _In_ ULONG nParamsCount, ...) { - CStringW cStrCmdW; + MX::CStringW cStrCmdLineW; + STARTUPINFOW sSiW; + PROCESS_INFORMATION sPi; + DWORD dwCreationFlags; + va_list argptr; HRESULT hRes; - hRes = FileRoutines::GetAppFileName(cStrCmdW); - if (SUCCEEDED(hRes)) + if (szAppNameW == NULL) + return E_POINTER; + if (szAppNameW[0] == 0) + return E_INVALIDARG; + + //quote application name if needed + if (MX::StrChrW(szAppNameW, L' ') != NULL) { - if (cStrCmdW.InsertN(L"DEL \"", 0, 5) != FALSE && cStrCmdW.ConcatN("\"", 1) != FALSE) + if (cStrCmdLineW.Format(L"\"%s\"", szAppNameW) == FALSE) + return E_OUTOFMEMORY; + } + else + { + if (cStrCmdLineW.Copy(szAppNameW) == FALSE) + return E_OUTOFMEMORY; + } + + //process arguments + va_start(argptr, nParamsCount); + for (ULONG i = nParamsCount; i > 0; i--) + { + LPCWSTR szParamW = va_arg(argptr, LPCWSTR); + + if (szParamW == NULL || szParamW[0] == 0) + continue; + + //insert separator + if (cStrCmdLineW.ConcatN(L" ", 1) == FALSE) + return E_OUTOFMEMORY; + + //insert parameter + if (MX::StrChrW(szParamW, L' ') != FALSE || MX::StrChrW(szParamW, L'\t') != FALSE || + MX::StrChrW(szParamW, L'\n') != FALSE || MX::StrChrW(szParamW, L'\v') != FALSE || + MX::StrChrW(szParamW, L'\"') != FALSE) { - hRes = ExecuteApp((LPCWSTR)cStrCmdW, dwAfterSeconds); + //escape parameter + + //opening quotes + if (cStrCmdLineW.ConcatN(L"\"", 1) == FALSE) + { + va_end(argptr); + return E_OUTOFMEMORY; + } + + for (;;) + { + SIZE_T nBackSlashCounter = 0; + + while (*szParamW == L'\\') + { + szParamW += 1; + nBackSlashCounter += 1; + } + + if (*szParamW == 0) + { + //escape all backslashes, but let the terminating double quotation mark we add below be interpreted + //as a metacharacter + if (AddRepeatedChar(cStrCmdLineW, L'\\', nBackSlashCounter * 2) == FALSE) + { + va_end(argptr); + return E_OUTOFMEMORY; + } + break; + } + + if (*szParamW == L'"') + { + //escape all backslashes and the following double quotation mark + nBackSlashCounter = nBackSlashCounter * 2 + 1; + } + //else backslashes aren't special + + if (AddRepeatedChar(cStrCmdLineW, L'\\', nBackSlashCounter) == FALSE || + cStrCmdLineW.ConcatN(szParamW, 1) == FALSE) + { + va_end(argptr); + return E_OUTOFMEMORY; + } + + //advance char + szParamW += 1; + } + + //closing quotes + if (cStrCmdLineW.ConcatN(L"\"", 1) == FALSE) + return E_OUTOFMEMORY; } else { - hRes = E_OUTOFMEMORY; + if (cStrCmdLineW.Concat(szParamW) == FALSE) + return E_OUTOFMEMORY; } } + va_end(argptr); + + //prepare to execute process + ::MxMemSet(&sSiW, 0, sizeof(sSiW)); + sSiW.cb = (DWORD)sizeof(sSiW); + ::MxMemSet(&sPi, 0, sizeof(sPi)); + + dwCreationFlags = 0; + if (bHide != FALSE) + { + dwCreationFlags |= CREATE_NO_WINDOW; + sSiW.dwFlags |= STARTF_USESHOWWINDOW; + sSiW.wShowWindow = SW_HIDE; + } + + //run child process + if (::CreateProcessW(NULL, (LPWSTR)cStrCmdLineW, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &sSiW, + &sPi) == FALSE) + { + return MX_HRESULT_FROM_LASTERROR(); + } + + //wait for exit code if requested + if (bWait != FALSE) + { + DWORD dwExitCode; + + ::WaitForSingleObject(sPi.hProcess, INFINITE); + ::GetExitCodeProcess(sPi.hProcess, &dwExitCode); + + hRes = MX_HRESULT_FROM_WIN32(dwExitCode); + } + else + { + hRes = S_OK; + } + + //cleanup + ::CloseHandle(sPi.hThread); + ::CloseHandle(sPi.hProcess); + //done return hRes; } +HRESULT SelfDeleteApp(_In_ DWORD dwAfterSeconds) +{ + CStringW cStrAppNameW, cStrCmdExeW; + WCHAR szSecondsW[16]; + HRESULT hRes; + + hRes = FileRoutines::GetAppFileName(cStrAppNameW); + if (FAILED(hRes)) + return hRes; + + hRes = FileRoutines::GetWindowsSystemPath(cStrCmdExeW); + if (FAILED(hRes)) + return hRes; + if (cStrCmdExeW.ConcatN(L"CMD.EXE", 7) == FALSE) + return E_OUTOFMEMORY; + + _snwprintf_s(szSecondsW, _countof(szSecondsW), _TRUNCATE, L"%lu", dwAfterSeconds); + + //done + return ExecuteApp(FALSE, TRUE, (LPCWSTR)cStrCmdExeW, 8, L"/C", L"PING", L"127.0.0.1", L"-n", szSecondsW, L"&", + L"DEL", (LPCWSTR)cStrAppNameW); +} + }; //namespace Misc }; //namespace MX + +//----------------------------------------------------------- + +static BOOL AddRepeatedChar(_Inout_ MX::CStringW &cStrW, _In_ WCHAR chW, _In_ SIZE_T nCount) +{ + while (nCount > 0) + { + if (cStrW.ConcatN(&chW, 1) == FALSE) + return FALSE; + nCount -= 1; + } + return TRUE; +} diff --git a/Miscellaneous.h b/Miscellaneous.h index a8c1494..7187a3e 100644 --- a/Miscellaneous.h +++ b/Miscellaneous.h @@ -35,7 +35,8 @@ BOOL GitWildcardMatch(_In_ LPCWSTR szTextW, _In_ SIZE_T nTextLen, _In_ LPCWSTR s BOOL String2Guid(_Out_ GUID &sGuid, _In_ LPCSTR szGuidA, _In_ SIZE_T nGuidLength = (SIZE_T)-1); BOOL String2Guid(_Out_ GUID &sGuid, _In_ LPCWSTR szGuidW, _In_ SIZE_T nGuidLength = (SIZE_T)-1); -HRESULT ExecuteApp(_In_z_ LPCWSTR szCmdLineW, _In_ DWORD dwAfterSeconds = 5); +HRESULT ExecuteApp(_In_ BOOL bWait, _In_ BOOL bHide, _In_z_ LPCWSTR szAppNameW, _In_ ULONG nParamsCount, ...); + HRESULT SelfDeleteApp(_In_ DWORD dwAfterSeconds = 5); }; //namespace Misc