/**---------------------------------------------------------------------------- \brief \param \return \code \endcode -----------------------------------------------------------------------------*/ void DebugMessage( const char* Function, int Line, const char* LogPrefix, const char* fmt, ... ) { _ASSERTE(NULL != LogPrefix); if (NULL == LogPrefix) return; _ASSERTE(NULL != fmt); if (NULL == fmt) return; char log_buffer[4096] = { 0 }; size_t remain = sizeof(log_buffer); char* pos = log_buffer; va_list args; // 프로세스 정보 // char name_buffer[MAX_PATH + 1] = { 0 }; char *name = name_buffer; name_buffer[0] = '\0'; DWORD len = GetModuleFileNameA(NULL, name_buffer, sizeof(name_buffer)); if (len>0) name = get_filename_part(name_buffer, len); // format string 파라미터를 Multibyte / WideChar 가 잘 못 들어온 경우등 // 에러가 발생할 수 있어서 해당 함수를 찾기위한 디버그 코드 // e.g. %s => L"debug string...." or %S => "debug string" // size_t remain_b = remain; char* pos_b = pos; HRESULT hRes = StringCbPrintfExA( pos, remain, &pos, &remain, 0, "%-18s(%04u:%04u), %s %s() ", name, GetCurrentProcessId(), GetCurrentThreadId(), LogPrefix, Function ); if (S_OK != hRes) { OutputDebugStringA("StringCbPrintfExA() failed, more log buffer needed...?"); return; } remain_b = remain; pos_b = pos; va_start(args, fmt); hRes = StringCbVPrintfExA( pos, remain, &pos, &remain, 0, fmt, args ); if (S_OK != hRes) { // 한글 같은 unicode 문자열이 있는 경우 발생할 수 있음 // StringCbPrintfExA( pos_b, remain_b, &pos_b, &remain_b, 0, "invalid function call parameters, line=%d", Line ); remain = remain_b; pos = pos_b; } va_end(args); hRes = StringCbPrintfExA( pos, remain, &pos, &remain, 0, "%s", "\r\n" ); if (!SUCCEEDED(hRes)) { OutputDebugStringA("StringCbPrintfExA() failed, more log buffer needed...?"); return; } OutputDebugStringA(log_buffer); }
/** * @brief * @param * @see * @remarks * @code * @endcode * @return **/ void log_write_fmt( _In_ uint32_t log_level, _In_z_ const char* function, _In_z_ const char* fmt, _In_ ... ) { if (NULL == fmt) return; char log_buffer[2048]; size_t remain = sizeof(log_buffer); char* pos = log_buffer; va_list args; // log level switch (log_level) { case log_level_debug: StringCbPrintfExA(pos, remain, &pos, &remain, 0, "%s", "[DEBG] "); break; case log_level_info: StringCbPrintfExA(pos, remain, &pos, &remain, 0, "%s", "[INFO] "); break; case log_level_warn: StringCbPrintfExA(pos, remain, &pos, &remain, 0, "%s", "[WARN] "); break; case log_level_error: StringCbPrintfExA(pos, remain, &pos, &remain, 0, "%s", "[EROR] "); break; default: _ASSERTE(!"never reach here!"); return; } //> show process name if (true == _show_process_name) { StringCbPrintfExA( pos, remain, &pos, &remain, 0, "%ws", get_current_module_fileEx().c_str() ); } //> show pid, tid if (true == _show_pid_tid) { StringCbPrintfExA( pos, remain, &pos, &remain, 0, "(%+5u:%+5u) : ", GetCurrentProcessId(), GetCurrentThreadId() ); } //> show function name if (true == _show_function_name) { StringCbPrintfExA(pos, remain, &pos, &remain, 0, "%s : ", function); } va_start(args,fmt); HRESULT hRes = StringCbVPrintfExA( pos, remain, &pos, &remain, 0, fmt, args ); if (S_OK != hRes) { // invalid character 가 끼어있는 경우 발생 할 수 있음 StringCbPrintfExA( pos, remain, &pos, &remain, 0, "invalid function call parameters" ); } va_end(args); // line feed StringCbPrintfExA(pos, remain, &pos, &remain, 0, "\n"); // Let's write logs. switch (log_level) { case log_level_error: // same as log_level_critical write_to_console(wtc_red, log_buffer); break; case log_level_info: case log_level_warn: write_to_console(wtc_green, log_buffer); break; default: write_to_console(wtc_none, log_buffer); } OutputDebugStringA(log_buffer); }
VOID __fastcall HashSaveWorkerMain( PHASHSAVECONTEXT phsctx ) { // Note that ALL message communication to and from the main window MUST // be asynchronous, or else there may be a deadlock. // Prep: expand directories, max path, etc. (prefix was set by earlier call) PostMessage(phsctx->hWnd, HM_WORKERTHREAD_TOGGLEPREP, (WPARAM)phsctx, TRUE); if (! HashCalcPrepare(phsctx)) return; HashCalcSetSaveFormat(phsctx); PostMessage(phsctx->hWnd, HM_WORKERTHREAD_TOGGLEPREP, (WPARAM)phsctx, FALSE); // Extract the slist into a vector for parallel_for_each std::vector<PHASHSAVEITEM> vecpItems; vecpItems.resize(phsctx->cTotal + 1); SLBuildIndex(phsctx->hList, (PVOID*)vecpItems.data()); assert(vecpItems.back() == nullptr); vecpItems.pop_back(); assert(vecpItems.back() != nullptr); #ifdef USE_PPL const bool bMultithreaded = vecpItems.size() > 1 && IsSSD(vecpItems[0]->szPath); concurrency::concurrent_vector<void*> vecBuffers; // a vector of all allocated read buffers (one per thread) DWORD dwBufferTlsIndex = TlsAlloc(); // TLS index of the current thread's read buffer if (dwBufferTlsIndex == TLS_OUT_OF_INDEXES) return; #else constexpr bool bMultithreaded = false; #endif PBYTE pbTheBuffer; // file read buffer, used iff not multithreaded if (! bMultithreaded) { pbTheBuffer = (PBYTE)VirtualAlloc(NULL, READ_BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE); if (pbTheBuffer == NULL) return; } // Initialize the progress bar update synchronization vars CRITICAL_SECTION updateCritSec; volatile ULONGLONG cbCurrentMaxSize = 0; if (bMultithreaded) InitializeCriticalSection(&updateCritSec); #ifdef _TIMED DWORD dwStarted; dwStarted = GetTickCount(); #endif class CanceledException {}; // concurrency::parallel_for_each(vecpItems.cbegin(), vecpItems.cend(), ... auto per_file_worker = [&](PHASHSAVEITEM pItem) { WHCTXEX whctx; // Indicate which hash type we are after, see WHEX... values in WinHash.h whctx.dwFlags = 1 << (phsctx->ofn.nFilterIndex - 1); PBYTE pbBuffer; #ifdef USE_PPL if (bMultithreaded) { // Allocate or retrieve the already-allocated read buffer for the current thread pbBuffer = (PBYTE)TlsGetValue(dwBufferTlsIndex); if (pbBuffer == NULL) { pbBuffer = (PBYTE)VirtualAlloc(NULL, READ_BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE); if (pbBuffer == NULL) throw CanceledException(); // Cache the read buffer for the current thread vecBuffers.push_back(pbBuffer); TlsSetValue(dwBufferTlsIndex, pbBuffer); } } #endif #pragma warning(push) #pragma warning(disable: 4700 4703) // potentially uninitialized local pointer variable 'pbBuffer' used // Get the hash WorkerThreadHashFile( (PCOMMONCONTEXT)phsctx, pItem->szPath, &whctx, &pItem->results, bMultithreaded ? pbBuffer : pbTheBuffer, NULL, 0, bMultithreaded ? &updateCritSec : NULL, &cbCurrentMaxSize #ifdef _TIMED , &pItem->dwElapsed #endif ); if (phsctx->status == PAUSED) WaitForSingleObject(phsctx->hUnpauseEvent, INFINITE); if (phsctx->status == CANCEL_REQUESTED) throw CanceledException(); // Write the data HashCalcWriteResult(phsctx, pItem); // Update the UI InterlockedIncrement(&phsctx->cSentMsgs); PostMessage(phsctx->hWnd, HM_WORKERTHREAD_UPDATE, (WPARAM)phsctx, (LPARAM)pItem); }; #pragma warning(pop) try { #ifdef USE_PPL if (bMultithreaded) concurrency::parallel_for_each(vecpItems.cbegin(), vecpItems.cend(), per_file_worker); else #endif std::for_each(vecpItems.cbegin(), vecpItems.cend(), per_file_worker); } catch (CanceledException) {} // ignore cancellation requests #ifdef _TIMED if (phsctx->cTotal > 1 && phsctx->status != CANCEL_REQUESTED) { union { CHAR szA[MAX_STRINGMSG]; WCHAR szW[MAX_STRINGMSG]; } buffer; size_t cbBufferLeft; if (phsctx->opt.dwSaveEncoding == 1) // UTF-16 { StringCbPrintfExW(buffer.szW, sizeof(buffer), NULL, &cbBufferLeft, 0, L"; Total elapsed: %d ms\r\n", GetTickCount() - dwStarted); } else // UTF-8 or ANSI { StringCbPrintfExA(buffer.szA, sizeof(buffer), NULL, &cbBufferLeft, 0, "; Total elapsed: %d ms\r\n", GetTickCount() - dwStarted); } DWORD dwUnused; WriteFile(phsctx->hFileOut, buffer.szA, (DWORD) (sizeof(buffer) - cbBufferLeft), &dwUnused, NULL); } #endif #ifdef USE_PPL if (bMultithreaded) { for (void* pBuffer : vecBuffers) VirtualFree(pBuffer, 0, MEM_RELEASE); DeleteCriticalSection(&updateCritSec); } else #endif VirtualFree(pbTheBuffer, 0, MEM_RELEASE); }
int vsprintfex( char *buffer, int buffersize,const char *format, va_list argList ) { int ptr=0; const char* in=format; LPSTR end; int nNextArg=0,index,length; while (*in!='\0') { if (*in=='%') { in++; // Finding first non number for(index=0;in[index]>='0' && in[index]<='9';index++); // Now index points to nonnumberic character if (in[index]==':') { // ok number was argument place if (index==0) return 0; nNextArg=atoi(in); // finding next '%' in+=index+1; for (length=0;in[length]!='\0' && in[length]!='%';length++); char* pTemp=new char[length+2]; pTemp[0]='%'; CopyMemory(pTemp+1,in,length); pTemp[length+1]='\0'; HRESULT hRes=StringCbPrintfExA(buffer+ptr,buffersize-ptr,&end,NULL,STRSAFE_IGNORE_NULLS,pTemp,va_getarg(argList,nNextArg)); if (FAILED(hRes)) return 0; ptr=int(end-buffer); delete[] pTemp; if (in[length]=='\0') break; in+=length; } else { nNextArg++; for (;in[index]!='\0' && in[index]!='%';index++); char* pTemp=new char[index+2]; pTemp[0]='%'; CopyMemory(pTemp+1,in,index); pTemp[index+1]='\0'; HRESULT hRes=StringCbPrintfExA(buffer+ptr,buffersize-ptr,&end,NULL,STRSAFE_IGNORE_NULLS,pTemp,va_getarg(argList,nNextArg)); if (FAILED(hRes)) return 0; ptr=int(end-buffer); delete[] pTemp; if (in[index]=='\0') break; in+=index; } } else buffer[ptr++]=*(in++); } buffer[ptr]='\0'; return ptr; }
BOOL WINAPI LSLog(int nLevel, LPCSTR pszModule, LPCSTR pszMessage) { #if defined(LS_COMPAT_LOGGING) wchar_t wzLogFile[MAX_PATH] = { 0 }; int nLogLevel = GetRCIntW(L"LSLogLevel", 2); // Should this message be logged? if (!pszModule || !pszMessage || (nLevel > nLogLevel) || (nLevel < 1) || (nLevel > 4)) { return FALSE; } // Has a log file been assigned? if (!GetRCStringW(L"LSLogFile", wzLogFile, NULL, MAX_PATH)) { return FALSE; } // If so, open it HANDLE hLogFile = CreateFile(wzLogFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // Did open succeed? if (hLogFile == INVALID_HANDLE_VALUE) { return FALSE; } // Move to the end of the file SetFilePointer(hLogFile, 0, NULL, FILE_END); // Get timestamp SYSTEMTIME st = { 0 }; GetLocalTime(&st); // Add timestamp and module name to message LPCSTR rszLevel[4] = { "Error", "Warning", "Notice", "Debug" }; CHAR szLine[MAX_LINE_LENGTH] = { 0 }; size_t cbLine = sizeof(szLine); size_t cbRemaining = 0; if (SUCCEEDED(StringCbPrintfExA(szLine, cbLine, NULL, &cbRemaining, STRSAFE_IGNORE_NULLS, "%02d-%02d-%04d %02d:%02d:%02d - %s - %s: %s\r\n", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond, rszLevel[nLevel-1], pszModule, pszMessage))) { size_t cbToWrite = cbLine - cbRemaining; ASSERT(cbToWrite <= MAXDWORD); // Write it to the log file DWORD dwCount = 0; WriteFile(hLogFile, szLine, (DWORD)cbToWrite, &dwCount, NULL); } // Close the log CloseHandle(hLogFile); #endif // LS_COMPAT_LOGGING return TRUE; }