From 02c5675c41e318fbaed6a8d20205772c3728ff5e Mon Sep 17 00:00:00 2001 From: Martin Malik Date: Tue, 12 Dec 2023 13:17:17 +0100 Subject: [PATCH 1/4] Enhance UNICODE support Also to fix #191 --- PresentData/PresentMonTraceConsumer.cpp | 7 +- PresentData/PresentMonTraceConsumer.hpp | 2 +- PresentData/TraceSession.cpp | 20 +- PresentData/TraceSession.hpp | 6 +- PresentMon/CommandLine.cpp | 326 +++++++++++------------ PresentMon/Console.cpp | 2 +- PresentMon/CsvOutput.cpp | 38 +-- PresentMon/LateStageReprojectionData.cpp | 28 +- PresentMon/LateStageReprojectionData.hpp | 2 +- PresentMon/MainThread.cpp | 6 +- PresentMon/OutputThread.cpp | 26 +- PresentMon/PresentMon.hpp | 18 +- PresentMon/Privilege.cpp | 24 +- PresentMon/TraceSession.cpp | 4 +- 14 files changed, 253 insertions(+), 256 deletions(-) diff --git a/PresentData/PresentMonTraceConsumer.cpp b/PresentData/PresentMonTraceConsumer.cpp index b8ad6587..634cc3f8 100644 --- a/PresentData/PresentMonTraceConsumer.cpp +++ b/PresentData/PresentMonTraceConsumer.cpp @@ -2190,10 +2190,7 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord) // e.g.: \Device\HarddiskVolume...\...\Proces.exe. We prune off everything other than // the filename here to be consistent. size_t start = ImageName.find_last_of('\\') + 1; - size_t size = ImageName.size() - start; - event.ImageFileName.resize(size + 1); - wcstombs_s(&size, &event.ImageFileName[0], size + 1, ImageName.c_str() + start, size); - event.ImageFileName.resize(size - 1); + event.ImageFileName = ImageName.c_str() + start; break; } case Microsoft_Windows_Kernel_Process::ProcessStop_Stop::Id: { @@ -2218,7 +2215,7 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord) }; mMetadata.GetEventData(pEventRecord, desc, _countof(desc)); event.ProcessId = desc[0].GetData(); - event.ImageFileName = desc[1].GetData(); + event.ImageFileName = desc[1].GetData(); event.IsStartEvent = true; } else if (hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_END|| hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_DC_END) { diff --git a/PresentData/PresentMonTraceConsumer.hpp b/PresentData/PresentMonTraceConsumer.hpp index 68062c8a..717d17f7 100644 --- a/PresentData/PresentMonTraceConsumer.hpp +++ b/PresentData/PresentMonTraceConsumer.hpp @@ -124,7 +124,7 @@ struct InputEvent { // A ProcessEvent occurs whenever a Process starts or stops. struct ProcessEvent { - std::string ImageFileName; // The name of the process exe file. This is only available on process start events. + std::wstring ImageFileName; // The name of the process exe file. This is only available on process start events. uint64_t QpcTime; // The time of the start/stop event. uint32_t ProcessId; // The id of the process. bool IsStartEvent; // Whether this is a start event (true) or a stop event (false). diff --git a/PresentData/TraceSession.cpp b/PresentData/TraceSession.cpp index 1bcab8e8..f80706dd 100644 --- a/PresentData/TraceSession.cpp +++ b/PresentData/TraceSession.cpp @@ -469,7 +469,7 @@ PEVENT_RECORD_CALLBACK GetEventRecordCallback(bool t1, bool t2, bool t3, bool t4 : GetEventRecordCallback(t2, t3, t4); } -ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILEA* pLogFile) +ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILE* pLogFile) { auto session = (TraceSession*) pLogFile->Context; return session->mContinueProcessingBuffers; // TRUE = continue processing events, FALSE = return out of ProcessTrace() @@ -480,8 +480,8 @@ ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILEA* pLogFile) ULONG TraceSession::Start( PMTraceConsumer* pmConsumer, MRTraceConsumer* mrConsumer, - char const* etlPath, - char const* sessionName) + WCHAR const* etlPath, + WCHAR const* sessionName) { assert(mSessionHandle == 0); assert(mTraceHandle == INVALID_PROCESSTRACE_HANDLE); @@ -492,8 +492,8 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // Configure trace properties - EVENT_TRACE_LOGFILEA traceProps = {}; - traceProps.LogFileName = (char*) etlPath; + EVENT_TRACE_LOGFILE traceProps = {}; + traceProps.LogFileName = (WCHAR*) etlPath; traceProps.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP; traceProps.Context = this; /* Output members (passed also to BufferCallback): @@ -523,7 +523,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // For realtime collection, start the session with the required providers if (traceProps.LogFileName == nullptr) { - traceProps.LoggerName = (char*) sessionName; + traceProps.LoggerName = (WCHAR*) sessionName; traceProps.ProcessTraceMode |= PROCESS_TRACE_MODE_REAL_TIME; TraceProperties sessionProps = {}; @@ -556,7 +556,7 @@ ULONG TraceSession::Start( sessionProps.LoggerThreadId // tracing session identifier */ - auto status = StartTraceA(&mSessionHandle, sessionName, &sessionProps); + auto status = StartTrace(&mSessionHandle, sessionName, &sessionProps); if (status != ERROR_SUCCESS) { mSessionHandle = 0; return status; @@ -571,7 +571,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // Open the trace - mTraceHandle = OpenTraceA(&traceProps); + mTraceHandle = OpenTrace(&traceProps); if (mTraceHandle == INVALID_PROCESSTRACE_HANDLE) { auto lastError = GetLastError(); Stop(); @@ -646,12 +646,12 @@ void TraceSession::Stop() } } -ULONG TraceSession::StopNamedSession(char const* sessionName) +ULONG TraceSession::StopNamedSession(WCHAR const* sessionName) { TraceProperties sessionProps = {}; sessionProps.Wnode.BufferSize = (ULONG) sizeof(TraceProperties); sessionProps.LoggerNameOffset = offsetof(TraceProperties, mSessionName); - return ControlTraceA((TRACEHANDLE) 0, sessionName, &sessionProps, EVENT_TRACE_CONTROL_STOP); + return ControlTraceW((TRACEHANDLE) 0, sessionName, &sessionProps, EVENT_TRACE_CONTROL_STOP); } diff --git a/PresentData/TraceSession.hpp b/PresentData/TraceSession.hpp index 040fc3ca..8990552c 100644 --- a/PresentData/TraceSession.hpp +++ b/PresentData/TraceSession.hpp @@ -17,11 +17,11 @@ struct TraceSession { ULONG Start( PMTraceConsumer* pmConsumer, // Required PMTraceConsumer instance MRTraceConsumer* mrConsumer, // If nullptr, no WinMR tracing - char const* etlPath, // If nullptr, live/realtime tracing session - char const* sessionName); // Required session name + WCHAR const* etlPath, // If nullptr, live/realtime tracing session + WCHAR const* sessionName); // Required session name void Stop(); ULONG CheckLostReports(ULONG* eventsLost, ULONG* buffersLost) const; - static ULONG StopNamedSession(char const* sessionName); + static ULONG StopNamedSession(WCHAR const* sessionName); }; diff --git a/PresentMon/CommandLine.cpp b/PresentMon/CommandLine.cpp index ab231492..26fdc633 100644 --- a/PresentMon/CommandLine.cpp +++ b/PresentMon/CommandLine.cpp @@ -18,118 +18,118 @@ enum { struct KeyNameCode { - char const* mName; + WCHAR const* mName; UINT mCode; }; KeyNameCode const HOTKEY_MODS[] = { - { "ALT", MOD_ALT }, - { "CONTROL", MOD_CONTROL }, - { "CTRL", MOD_CONTROL }, - { "SHIFT", MOD_SHIFT }, - { "WINDOWS", MOD_WIN }, - { "WIN", MOD_WIN }, + { L"ALT", MOD_ALT }, + { L"CONTROL", MOD_CONTROL }, + { L"CTRL", MOD_CONTROL }, + { L"SHIFT", MOD_SHIFT }, + { L"WINDOWS", MOD_WIN }, + { L"WIN", MOD_WIN }, }; KeyNameCode const HOTKEY_KEYS[] = { - { "BACKSPACE", VK_BACK }, - { "TAB", VK_TAB }, - { "CLEAR", VK_CLEAR }, - { "ENTER", VK_RETURN }, - { "PAUSE", VK_PAUSE }, - { "CAPSLOCK", VK_CAPITAL }, - { "ESC", VK_ESCAPE }, - { "SPACE", VK_SPACE }, - { "PAGEUP", VK_PRIOR }, - { "PAGEDOWN", VK_NEXT }, - { "END", VK_END }, - { "HOME", VK_HOME }, - { "LEFT", VK_LEFT }, - { "UP", VK_UP }, - { "RIGHT", VK_RIGHT }, - { "DOWN", VK_DOWN }, - { "PRINTSCREEN", VK_SNAPSHOT }, - { "INS", VK_INSERT }, - { "DEL", VK_DELETE }, - { "HELP", VK_HELP }, - { "NUMLOCK", VK_NUMLOCK }, - { "SCROLLLOCK", VK_SCROLL }, - { "NUM0", VK_NUMPAD0 }, - { "NUM1", VK_NUMPAD1 }, - { "NUM2", VK_NUMPAD2 }, - { "NUM3", VK_NUMPAD3 }, - { "NUM4", VK_NUMPAD4 }, - { "NUM5", VK_NUMPAD5 }, - { "NUM6", VK_NUMPAD6 }, - { "NUM7", VK_NUMPAD7 }, - { "NUM8", VK_NUMPAD8 }, - { "NUM9", VK_NUMPAD9 }, - { "MULTIPLY", VK_MULTIPLY }, - { "ADD", VK_ADD }, - { "SEPARATOR", VK_SEPARATOR }, - { "SUBTRACT", VK_SUBTRACT }, - { "DECIMAL", VK_DECIMAL }, - { "DIVIDE", VK_DIVIDE }, - { "0", 0x30 }, - { "1", 0x31 }, - { "2", 0x32 }, - { "3", 0x33 }, - { "4", 0x34 }, - { "5", 0x35 }, - { "6", 0x36 }, - { "7", 0x37 }, - { "8", 0x38 }, - { "9", 0x39 }, - { "A", 0x41 }, - { "B", 0x42 }, - { "C", 0x43 }, - { "D", 0x44 }, - { "E", 0x45 }, - { "F", 0x46 }, - { "G", 0x47 }, - { "H", 0x48 }, - { "I", 0x49 }, - { "J", 0x4A }, - { "K", 0x4B }, - { "L", 0x4C }, - { "M", 0x4D }, - { "N", 0x4E }, - { "O", 0x4F }, - { "P", 0x50 }, - { "Q", 0x51 }, - { "R", 0x52 }, - { "S", 0x53 }, - { "T", 0x54 }, - { "U", 0x55 }, - { "V", 0x56 }, - { "W", 0x57 }, - { "X", 0x58 }, - { "Y", 0x59 }, - { "Z", 0x5A }, - { "F1", VK_F1 }, - { "F2", VK_F2 }, - { "F3", VK_F3 }, - { "F4", VK_F4 }, - { "F5", VK_F5 }, - { "F6", VK_F6 }, - { "F7", VK_F7 }, - { "F8", VK_F8 }, - { "F9", VK_F9 }, - { "F10", VK_F10 }, - { "F11", VK_F11 }, - { "F12", VK_F12 }, - { "F13", VK_F13 }, - { "F14", VK_F14 }, - { "F15", VK_F15 }, - { "F16", VK_F16 }, - { "F17", VK_F17 }, - { "F18", VK_F18 }, - { "F19", VK_F19 }, - { "F20", VK_F20 }, - { "F21", VK_F21 }, - { "F22", VK_F22 }, - { "F23", VK_F23 }, - { "F24", VK_F24 }, + { L"BACKSPACE", VK_BACK }, + { L"TAB", VK_TAB }, + { L"CLEAR", VK_CLEAR }, + { L"ENTER", VK_RETURN }, + { L"PAUSE", VK_PAUSE }, + { L"CAPSLOCK", VK_CAPITAL }, + { L"ESC", VK_ESCAPE }, + { L"SPACE", VK_SPACE }, + { L"PAGEUP", VK_PRIOR }, + { L"PAGEDOWN", VK_NEXT }, + { L"END", VK_END }, + { L"HOME", VK_HOME }, + { L"LEFT", VK_LEFT }, + { L"UP", VK_UP }, + { L"RIGHT", VK_RIGHT }, + { L"DOWN", VK_DOWN }, + { L"PRINTSCREEN", VK_SNAPSHOT }, + { L"INS", VK_INSERT }, + { L"DEL", VK_DELETE }, + { L"HELP", VK_HELP }, + { L"NUMLOCK", VK_NUMLOCK }, + { L"SCROLLLOCK", VK_SCROLL }, + { L"NUM0", VK_NUMPAD0 }, + { L"NUM1", VK_NUMPAD1 }, + { L"NUM2", VK_NUMPAD2 }, + { L"NUM3", VK_NUMPAD3 }, + { L"NUM4", VK_NUMPAD4 }, + { L"NUM5", VK_NUMPAD5 }, + { L"NUM6", VK_NUMPAD6 }, + { L"NUM7", VK_NUMPAD7 }, + { L"NUM8", VK_NUMPAD8 }, + { L"NUM9", VK_NUMPAD9 }, + { L"MULTIPLY", VK_MULTIPLY }, + { L"ADD", VK_ADD }, + { L"SEPARATOR", VK_SEPARATOR }, + { L"SUBTRACT", VK_SUBTRACT }, + { L"DECIMAL", VK_DECIMAL }, + { L"DIVIDE", VK_DIVIDE }, + { L"0", 0x30 }, + { L"1", 0x31 }, + { L"2", 0x32 }, + { L"3", 0x33 }, + { L"4", 0x34 }, + { L"5", 0x35 }, + { L"6", 0x36 }, + { L"7", 0x37 }, + { L"8", 0x38 }, + { L"9", 0x39 }, + { L"A", 0x41 }, + { L"B", 0x42 }, + { L"C", 0x43 }, + { L"D", 0x44 }, + { L"E", 0x45 }, + { L"F", 0x46 }, + { L"G", 0x47 }, + { L"H", 0x48 }, + { L"I", 0x49 }, + { L"J", 0x4A }, + { L"K", 0x4B }, + { L"L", 0x4C }, + { L"M", 0x4D }, + { L"N", 0x4E }, + { L"O", 0x4F }, + { L"P", 0x50 }, + { L"Q", 0x51 }, + { L"R", 0x52 }, + { L"S", 0x53 }, + { L"T", 0x54 }, + { L"U", 0x55 }, + { L"V", 0x56 }, + { L"W", 0x57 }, + { L"X", 0x58 }, + { L"Y", 0x59 }, + { L"Z", 0x5A }, + { L"F1", VK_F1 }, + { L"F2", VK_F2 }, + { L"F3", VK_F3 }, + { L"F4", VK_F4 }, + { L"F5", VK_F5 }, + { L"F6", VK_F6 }, + { L"F7", VK_F7 }, + { L"F8", VK_F8 }, + { L"F9", VK_F9 }, + { L"F10", VK_F10 }, + { L"F11", VK_F11 }, + { L"F12", VK_F12 }, + { L"F13", VK_F13 }, + { L"F14", VK_F14 }, + { L"F15", VK_F15 }, + { L"F16", VK_F16 }, + { L"F17", VK_F17 }, + { L"F18", VK_F18 }, + { L"F19", VK_F19 }, + { L"F20", VK_F20 }, + { L"F21", VK_F21 }, + { L"F22", VK_F22 }, + { L"F23", VK_F23 }, + { L"F24", VK_F24 }, }; CommandLineArgs gCommandLineArgs; @@ -142,38 +142,38 @@ size_t GetConsoleWidth() : std::max(DEFAULT_CONSOLE_WIDTH, info.srWindow.Right - info.srWindow.Left + 1); } -bool ParseKeyName(KeyNameCode const* valid, size_t validCount, char* name, char const* errorMessage, UINT* outKeyCode) +bool ParseKeyName(KeyNameCode const* valid, size_t validCount, WCHAR* name, char const* errorMessage, UINT* outKeyCode) { for (size_t i = 0; i < validCount; ++i) { - if (_stricmp(name, valid[i].mName) == 0) { + if (_wcsicmp(name, valid[i].mName) == 0) { *outKeyCode = valid[i].mCode; return true; } } - int col = PrintErrorNoNewLine("error: %s '%s'.\nValid options (case insensitive):", errorMessage, name); + int col = PrintErrorNoNewLine("error: %s '%ws'.\nValid options (case insensitive):", errorMessage, name); size_t consoleWidth = GetConsoleWidth(); for (size_t i = 0; i < validCount; ++i) { - auto len = strlen(valid[i].mName); + auto len = wcslen(valid[i].mName); if (col + len + 1 > consoleWidth) { col = PrintErrorNoNewLine("\n ") - 1; } - col += PrintErrorNoNewLine(" %s", valid[i].mName); + col += PrintErrorNoNewLine(" %ws", valid[i].mName); } fprintf(stderr, "\n"); return false; } -bool AssignHotkey(char* key, CommandLineArgs* args) +bool AssignHotkey(WCHAR* key, CommandLineArgs* args) { #pragma warning(suppress: 4996) - auto token = strtok(key, "+"); + auto token = wcstok(key, L"+"); for (;;) { auto prev = token; #pragma warning(suppress: 4996) - token = strtok(nullptr, "+"); + token = wcstok(nullptr, L"+"); if (token == nullptr) { if (!ParseKeyName(HOTKEY_KEYS, _countof(HOTKEY_KEYS), prev, "invalid -hotkey key", &args->mHotkeyVirtualKeyCode)) { return false; @@ -203,7 +203,7 @@ void SetCaptureAll(CommandLineArgs* args) } // Allow /ARG, -ARG, or --ARG -bool ParseArgPrefix(char** arg) +bool ParseArgPrefix(WCHAR** arg) { if (**arg == '/') { *arg += 1; @@ -221,43 +221,43 @@ bool ParseArgPrefix(char** arg) return false; } -bool ParseArg(char* arg, char const* option) +bool ParseArg(WCHAR* arg, WCHAR const* option) { return ParseArgPrefix(&arg) && - _stricmp(arg, option) == 0; + _wcsicmp(arg, option) == 0; } -bool ParseValue(char** argv, int argc, int* i) +bool ParseValue(WCHAR** argv, int argc, int* i) { if (*i + 1 < argc) { *i += 1; return true; } - PrintError("error: %s expecting argument.", argv[*i]); + PrintError("error: %ws expecting argument.", argv[*i]); return false; } -bool ParseValue(char** argv, int argc, int* i, char const** value) +bool ParseValue(WCHAR** argv, int argc, int* i, WCHAR const** value) { if (!ParseValue(argv, argc, i)) return false; *value = argv[*i]; return true; } -bool ParseValue(char** argv, int argc, int* i, std::vector* value) +bool ParseValue(WCHAR** argv, int argc, int* i, std::vector* value) { - char const* v = nullptr; + WCHAR const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; value->emplace_back(v); return true; } -bool ParseValue(char** argv, int argc, int* i, UINT* value) +bool ParseValue(WCHAR** argv, int argc, int* i, UINT* value) { - char const* v = nullptr; + WCHAR const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; - *value = strtoul(v, nullptr, 10); + *value = wcstoul(v, nullptr, 10); return true; } @@ -315,7 +315,7 @@ CommandLineArgs const& GetCommandLineArgs() return gCommandLineArgs; } -bool ParseCommandLine(int argc, char** argv) +bool ParseCommandLine(int argc, WCHAR** argv) { auto args = &gCommandLineArgs; @@ -323,7 +323,7 @@ bool ParseCommandLine(int argc, char** argv) args->mExcludeProcessNames.clear(); args->mOutputCsvFileName = nullptr; args->mEtlFileName = nullptr; - args->mSessionName = "PresentMon"; + args->mSessionName = L"PresentMon"; args->mTargetPid = 0; args->mDelay = 0; args->mTimer = 0; @@ -363,57 +363,57 @@ bool ParseCommandLine(int argc, char** argv) for (int i = 1; i < argc; ++i) { // Capture target options: - if (ParseArg(argv[i], "captureall")) { SetCaptureAll(args); continue; } - else if (ParseArg(argv[i], "process_name")) { if (ParseValue(argv, argc, &i, &args->mTargetProcessNames)) continue; } - else if (ParseArg(argv[i], "exclude")) { if (ParseValue(argv, argc, &i, &args->mExcludeProcessNames)) continue; } - else if (ParseArg(argv[i], "process_id")) { if (ParseValue(argv, argc, &i, &args->mTargetPid)) continue; } - else if (ParseArg(argv[i], "etl_file")) { if (ParseValue(argv, argc, &i, &args->mEtlFileName)) continue; } + if (ParseArg(argv[i], L"captureall")) { SetCaptureAll(args); continue; } + else if (ParseArg(argv[i], L"process_name")) { if (ParseValue(argv, argc, &i, &args->mTargetProcessNames)) continue; } + else if (ParseArg(argv[i], L"exclude")) { if (ParseValue(argv, argc, &i, &args->mExcludeProcessNames)) continue; } + else if (ParseArg(argv[i], L"process_id")) { if (ParseValue(argv, argc, &i, &args->mTargetPid)) continue; } + else if (ParseArg(argv[i], L"etl_file")) { if (ParseValue(argv, argc, &i, &args->mEtlFileName)) continue; } // Output options: - else if (ParseArg(argv[i], "output_file")) { if (ParseValue(argv, argc, &i, &args->mOutputCsvFileName)) continue; } - else if (ParseArg(argv[i], "output_stdout")) { args->mOutputCsvToStdout = true; continue; } - else if (ParseArg(argv[i], "multi_csv")) { args->mMultiCsv = true; continue; } - else if (ParseArg(argv[i], "no_csv")) { args->mOutputCsvToFile = false; continue; } - else if (ParseArg(argv[i], "no_top")) { args->mConsoleOutputType = ConsoleOutput::Simple; continue; } - else if (ParseArg(argv[i], "qpc_time")) { args->mOutputQpcTime = true; continue; } - else if (ParseArg(argv[i], "qpc_time_s")) { args->mOutputQpcTimeInSeconds = true; continue; } + else if (ParseArg(argv[i], L"output_file")) { if (ParseValue(argv, argc, &i, &args->mOutputCsvFileName)) continue; } + else if (ParseArg(argv[i], L"output_stdout")) { args->mOutputCsvToStdout = true; continue; } + else if (ParseArg(argv[i], L"multi_csv")) { args->mMultiCsv = true; continue; } + else if (ParseArg(argv[i], L"no_csv")) { args->mOutputCsvToFile = false; continue; } + else if (ParseArg(argv[i], L"no_top")) { args->mConsoleOutputType = ConsoleOutput::Simple; continue; } + else if (ParseArg(argv[i], L"qpc_time")) { args->mOutputQpcTime = true; continue; } + else if (ParseArg(argv[i], L"qpc_time_s")) { args->mOutputQpcTimeInSeconds = true; continue; } // Recording options: - else if (ParseArg(argv[i], "hotkey")) { if (ParseValue(argv, argc, &i) && AssignHotkey(argv[i], args)) continue; } - else if (ParseArg(argv[i], "delay")) { if (ParseValue(argv, argc, &i, &args->mDelay)) continue; } - else if (ParseArg(argv[i], "timed")) { if (ParseValue(argv, argc, &i, &args->mTimer)) { args->mStartTimer = true; continue; } } - else if (ParseArg(argv[i], "exclude_dropped")) { args->mExcludeDropped = true; continue; } - else if (ParseArg(argv[i], "scroll_indicator")) { args->mScrollLockIndicator = true; continue; } - else if (ParseArg(argv[i], "no_track_display")) { args->mTrackDisplay = false; continue; } - else if (ParseArg(argv[i], "track_debug")) { args->mTrackDebug = true; continue; } - else if (ParseArg(argv[i], "simple")) { DEPRECATED_simple = true; continue; } - else if (ParseArg(argv[i], "verbose")) { DEPRECATED_verbose = true; continue; } + else if (ParseArg(argv[i], L"hotkey")) { if (ParseValue(argv, argc, &i) && AssignHotkey(argv[i], args)) continue; } + else if (ParseArg(argv[i], L"delay")) { if (ParseValue(argv, argc, &i, &args->mDelay)) continue; } + else if (ParseArg(argv[i], L"timed")) { if (ParseValue(argv, argc, &i, &args->mTimer)) { args->mStartTimer = true; continue; } } + else if (ParseArg(argv[i], L"exclude_dropped")) { args->mExcludeDropped = true; continue; } + else if (ParseArg(argv[i], L"scroll_indicator")) { args->mScrollLockIndicator = true; continue; } + else if (ParseArg(argv[i], L"no_track_display")) { args->mTrackDisplay = false; continue; } + else if (ParseArg(argv[i], L"track_debug")) { args->mTrackDebug = true; continue; } + else if (ParseArg(argv[i], L"simple")) { DEPRECATED_simple = true; continue; } + else if (ParseArg(argv[i], L"verbose")) { DEPRECATED_verbose = true; continue; } // Execution options: - else if (ParseArg(argv[i], "session_name")) { if (ParseValue(argv, argc, &i, &args->mSessionName)) continue; } - else if (ParseArg(argv[i], "stop_existing_session")) { args->mStopExistingSession = true; continue; } - else if (ParseArg(argv[i], "terminate_existing")) { args->mTerminateExisting = true; continue; } - else if (ParseArg(argv[i], "dont_restart_as_admin")) { DEPRECATED_dontRestart = true; continue; } - else if (ParseArg(argv[i], "restart_as_admin")) { args->mTryToElevate = true; continue; } - else if (ParseArg(argv[i], "terminate_on_proc_exit")) { args->mTerminateOnProcExit = true; continue; } - else if (ParseArg(argv[i], "terminate_after_timed")) { args->mTerminateAfterTimer = true; continue; } + else if (ParseArg(argv[i], L"session_name")) { if (ParseValue(argv, argc, &i, &args->mSessionName)) continue; } + else if (ParseArg(argv[i], L"stop_existing_session")) { args->mStopExistingSession = true; continue; } + else if (ParseArg(argv[i], L"terminate_existing")) { args->mTerminateExisting = true; continue; } + else if (ParseArg(argv[i], L"dont_restart_as_admin")) { DEPRECATED_dontRestart = true; continue; } + else if (ParseArg(argv[i], L"restart_as_admin")) { args->mTryToElevate = true; continue; } + else if (ParseArg(argv[i], L"terminate_on_proc_exit")) { args->mTerminateOnProcExit = true; continue; } + else if (ParseArg(argv[i], L"terminate_after_timed")) { args->mTerminateAfterTimer = true; continue; } // Beta options: - else if (ParseArg(argv[i], "date_time")) { args->mOutputDateTime = true; continue; } - else if (ParseArg(argv[i], "track_gpu")) { args->mTrackGPU = true; continue; } - else if (ParseArg(argv[i], "track_gpu_video")) { args->mTrackGPUVideo = true; continue; } - else if (ParseArg(argv[i], "track_input")) { args->mTrackInput = true; continue; } - else if (ParseArg(argv[i], "track_mixed_reality")) { args->mTrackWMR = true; continue; } - else if (ParseArg(argv[i], "include_mixed_reality")) { DEPRECATED_wmr = true; continue; } + else if (ParseArg(argv[i], L"date_time")) { args->mOutputDateTime = true; continue; } + else if (ParseArg(argv[i], L"track_gpu")) { args->mTrackGPU = true; continue; } + else if (ParseArg(argv[i], L"track_gpu_video")) { args->mTrackGPUVideo = true; continue; } + else if (ParseArg(argv[i], L"track_input")) { args->mTrackInput = true; continue; } + else if (ParseArg(argv[i], L"track_mixed_reality")) { args->mTrackWMR = true; continue; } + else if (ParseArg(argv[i], L"include_mixed_reality")) { DEPRECATED_wmr = true; continue; } // Hidden options: #if PRESENTMON_ENABLE_DEBUG_TRACE - else if (ParseArg(argv[i], "debug_verbose_trace")) { verboseTrace = true; continue; } + else if (ParseArg(argv[i], L"debug_verbose_trace")) { verboseTrace = true; continue; } #endif // Provided argument wasn't recognized - else if (!(ParseArg(argv[i], "?") || ParseArg(argv[i], "h") || ParseArg(argv[i], "help"))) { - PrintError("error: unrecognized argument '%s'.", argv[i]); + else if (!(ParseArg(argv[i], L"?") || ParseArg(argv[i], L"h") || ParseArg(argv[i], L"help"))) { + PrintError("error: unrecognized argument '%ws'.", argv[i]); } PrintHelp(); diff --git a/PresentMon/Console.cpp b/PresentMon/Console.cpp index 2265ece1..f5c31cd0 100644 --- a/PresentMon/Console.cpp +++ b/PresentMon/Console.cpp @@ -191,7 +191,7 @@ void UpdateConsole(uint32_t processId, ProcessInfo const& processInfo) if (empty) { empty = false; - ConsolePrintLn("%s[%d]:", processInfo.mModuleName.c_str(), processId); + ConsolePrintLn("%ws[%d]:", processInfo.mModuleName.c_str(), processId); } ConsolePrint(" %016llX (%s): SyncInterval=%d Flags=%d CPU%s%s=%.2lf", diff --git a/PresentMon/CsvOutput.cpp b/PresentMon/CsvOutput.cpp index 68559f18..35b78e96 100644 --- a/PresentMon/CsvOutput.cpp +++ b/PresentMon/CsvOutput.cpp @@ -144,7 +144,7 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven } // Output in CSV format - fprintf(fp, "%s,%d,0x%016llX,%s,%d,%d,%s,", + fprintf(fp, "%ws,%d,0x%016llX,%s,%d,%d,%s,", processInfo->mModuleName.c_str(), p.ProcessId, p.SwapChainAddress, @@ -224,55 +224,55 @@ with `-INDEX` appended to the file name. If `-include_mixed_reality` is used, a second CSV file will be generated with `_WMR` appended to the filename containing the WMR data. */ -static void GenerateFilename(char* path, char const* processName, uint32_t processId) +static void GenerateFilename(WCHAR* path, WCHAR const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); - char ext[_MAX_EXT]; + WCHAR ext[_MAX_EXT]; int pathLength = MAX_PATH; #define ADD_TO_PATH(...) do { \ if (path != nullptr) { \ - auto result = _snprintf_s(path, pathLength, _TRUNCATE, __VA_ARGS__); \ + auto result = _snwprintf_s(path, pathLength, _TRUNCATE, __VA_ARGS__); \ if (result == -1) path = nullptr; else { path += result; pathLength -= result; } \ } \ } while (0) // Generate base filename. if (args.mOutputCsvFileName) { - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char name[_MAX_FNAME]; - _splitpath_s(args.mOutputCsvFileName, drive, dir, name, ext); - ADD_TO_PATH("%s%s%s", drive, dir, name); + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + WCHAR name[_MAX_FNAME]; + _wsplitpath_s(args.mOutputCsvFileName, drive, dir, name, ext); + ADD_TO_PATH(L"%s%s%s", drive, dir, name); } else { struct tm tm; time_t time_now = time(NULL); localtime_s(&tm, &time_now); - ADD_TO_PATH("PresentMon-%4d-%02d-%02dT%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - strcpy_s(ext, ".csv"); + ADD_TO_PATH(L"PresentMon-%4d-%02d-%02dT%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + wcscpy_s(ext, L".csv"); } // Append -PROCESSNAME if applicable. if (processName != nullptr) { - if (strcmp(processName, "")) { - ADD_TO_PATH("-%s", processName); + if (wcscmp(processName, L"")) { + ADD_TO_PATH(L"-%s", processName); } - ADD_TO_PATH("-%u", processId); + ADD_TO_PATH(L"-%u", processId); } // Append -INDEX if applicable. if (args.mHotkeySupport) { - ADD_TO_PATH("-%d", gRecordingCount); + ADD_TO_PATH(L"-%d", gRecordingCount); } // Append extension. - ADD_TO_PATH("%s", ext); + ADD_TO_PATH(L"%s", ext); #undef ADD_TO_PATH } -static OutputCsv CreateOutputCsv(char const* processName, uint32_t processId) +static OutputCsv CreateOutputCsv(WCHAR const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); @@ -282,10 +282,10 @@ static OutputCsv CreateOutputCsv(char const* processName, uint32_t processId) outputCsv.mFile = stdout; outputCsv.mWmrFile = nullptr; // WMR disallowed if -output_stdout } else { - char path[MAX_PATH]; + WCHAR path[MAX_PATH]; GenerateFilename(path, processName, processId); - fopen_s(&outputCsv.mFile, path, "w"); + _wfopen_s(&outputCsv.mFile, path, L"w"); if (args.mTrackWMR) { outputCsv.mWmrFile = CreateLsrCsvFile(path); diff --git a/PresentMon/LateStageReprojectionData.cpp b/PresentMon/LateStageReprojectionData.cpp index 761d2168..0cf5068c 100644 --- a/PresentMon/LateStageReprojectionData.cpp +++ b/PresentMon/LateStageReprojectionData.cpp @@ -182,23 +182,23 @@ LateStageReprojectionRuntimeStats LateStageReprojectionData::ComputeRuntimeStats return stats; } -FILE* CreateLsrCsvFile(char const* path) +FILE* CreateLsrCsvFile(WCHAR const* path) { auto const& args = GetCommandLineArgs(); // Add _WMR to the file name - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char name[_MAX_FNAME]; - char ext[_MAX_EXT]; - _splitpath_s(path, drive, dir, name, ext); + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + WCHAR name[_MAX_FNAME]; + WCHAR ext[_MAX_EXT]; + _wsplitpath_s(path, drive, dir, name, ext); - char outputPath[MAX_PATH] = {}; - _snprintf_s(outputPath, _TRUNCATE, "%s%s%s_WMR%s", drive, dir, name, ext); + WCHAR outputPath[MAX_PATH] = {}; + _snwprintf_s(outputPath, _TRUNCATE, L"%s%s%s_WMR%s", drive, dir, name, ext); // Open output file FILE* fp = nullptr; - if (fopen_s(&fp, outputPath, "w")) { + if (_wfopen_s(&fp, outputPath, L"w")) { return nullptr; } @@ -252,7 +252,7 @@ void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageRe const double deltaMilliseconds = 1000.0 * QpcDeltaToSeconds(curr.QpcTime - prev.QpcTime); const double timeInSeconds = QpcToSeconds(p.QpcTime); - fprintf(fp, "%s,%d,%d", proc->mModuleName.c_str(), curr.GetAppProcessId(), curr.ProcessId); + fprintf(fp, "%ws,%d,%d", proc->mModuleName.c_str(), curr.GetAppProcessId(), curr.ProcessId); if (args.mTrackDebug) { fprintf(fp, ",%d", curr.GetAppFrameId()); } @@ -321,8 +321,8 @@ void UpdateConsole(std::unordered_map const& activeProces if (args.mTrackDisplay) { auto processIter = activeProcesses.find(runtimeStats.mAppProcessId); - ConsolePrintLn(" App - %s[%d]:", - processIter == activeProcesses.end() ? "" : processIter->second.mModuleName.c_str(), + ConsolePrintLn(" App - %ws[%d]:", + processIter == activeProcesses.end() ? L"" : processIter->second.mModuleName.c_str(), runtimeStats.mAppProcessId); ConsolePrint(" %.2lf ms/frame (%.1lf fps, %.2lf ms CPU", 1000.0 / fps, fps, runtimeStats.mAppSourceCpuRenderTimeInMs); } else { @@ -346,8 +346,8 @@ void UpdateConsole(std::unordered_map const& activeProces const double fps = lsr.ComputeFps(); auto processIter = activeProcesses.find(runtimeStats.mLsrProcessId); - ConsolePrintLn(" Compositor - %s[%d]:", - processIter == activeProcesses.end() ? "" : processIter->second.mModuleName.c_str(), + ConsolePrintLn(" Compositor - %ws[%d]:", + processIter == activeProcesses.end() ? L"" : processIter->second.mModuleName.c_str(), runtimeStats.mLsrProcessId); ConsolePrintLn(" %.2lf ms/frame (%.1lf fps, %.1lf displayed fps, %.2lf ms CPU)", 1000.0 / fps, diff --git a/PresentMon/LateStageReprojectionData.hpp b/PresentMon/LateStageReprojectionData.hpp index ea0790e3..a26f7ea9 100644 --- a/PresentMon/LateStageReprojectionData.hpp +++ b/PresentMon/LateStageReprojectionData.hpp @@ -85,6 +85,6 @@ struct LateStageReprojectionData { double ComputeHistoryTime(const std::deque& lsrHistory) const; }; -FILE* CreateLsrCsvFile(char const* path); +FILE* CreateLsrCsvFile(WCHAR const* path); void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageReprojectionEvent& p); void UpdateConsole(std::unordered_map const& activeProcesses, LateStageReprojectionData& lsr); diff --git a/PresentMon/MainThread.cpp b/PresentMon/MainThread.cpp index e48549ad..707b9b2a 100644 --- a/PresentMon/MainThread.cpp +++ b/PresentMon/MainThread.cpp @@ -172,7 +172,7 @@ void ExitMainThread() PostMessage(gWnd, WM_QUIT, 0, 0); } -int main(int argc, char** argv) +int wmain(int argc, WCHAR** argv) { // Load system DLLs LoadLibraryExA("advapi32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -196,8 +196,8 @@ int main(int argc, char** argv) auto status = TraceSession::StopNamedSession(args.mSessionName); switch (status) { case ERROR_SUCCESS: return 0; - case ERROR_WMI_INSTANCE_NOT_FOUND: PrintError("error: no existing sessions found: %s", args.mSessionName); break; - default: PrintError("error: failed to terminate existing session (%s): %lu", args.mSessionName, status); break; + case ERROR_WMI_INSTANCE_NOT_FOUND: PrintError("error: no existing sessions found: %ws", args.mSessionName); break; + default: PrintError("error: failed to terminate existing session (%ws): %lu", args.mSessionName, status); break; } return 7; } diff --git a/PresentMon/OutputThread.cpp b/PresentMon/OutputThread.cpp index 66fce329..e6972da5 100644 --- a/PresentMon/OutputThread.cpp +++ b/PresentMon/OutputThread.cpp @@ -88,25 +88,25 @@ static uint32_t gTargetProcessCount = 0; // Removes any directory and extension, and converts the remaining name to // lower case. -void CanonicalizeProcessName(std::string* name) +void CanonicalizeProcessName(std::wstring* name) { - size_t i = name->find_last_of("./\\"); - if (i != std::string::npos && (*name)[i] == '.') { + size_t i = name->find_last_of(L"./\\"); + if (i != std::wstring::npos && (*name)[i] == L'.') { name->resize(i); - i = name->find_last_of("/\\"); + i = name->find_last_of(L"/\\"); } *name = name->substr(i + 1); std::transform(name->begin(), name->end(), name->begin(), - [](unsigned char c) { return (unsigned char) ::tolower((int) c); }); + [](WCHAR c) { return (WCHAR) ::towlower(c); }); } -static bool IsTargetProcess(uint32_t processId, std::string const& processName) +static bool IsTargetProcess(uint32_t processId, std::wstring const& processName) { auto const& args = GetCommandLineArgs(); - std::string compareName; + std::wstring compareName; if (args.mExcludeProcessNames.size() + args.mTargetProcessNames.size() > 0) { compareName = processName; CanonicalizeProcessName(&compareName); @@ -139,7 +139,7 @@ static bool IsTargetProcess(uint32_t processId, std::string const& processName) return false; } -static ProcessInfo CreateProcessInfo(uint32_t processId, HANDLE handle, std::string const& processName) +static ProcessInfo CreateProcessInfo(uint32_t processId, HANDLE handle, std::wstring const& processName) { auto isTarget = IsTargetProcess(processId, processName); if (isTarget) { @@ -168,13 +168,13 @@ static ProcessInfo* GetProcessInfo(uint32_t processId) // another account, unless we're running with SeDebugPrivilege. auto const& args = GetCommandLineArgs(); HANDLE handle = NULL; - char const* processName = ""; + WCHAR const* processName = L""; if (args.mEtlFileName == nullptr) { - char path[MAX_PATH]; - DWORD numChars = sizeof(path); + WCHAR path[MAX_PATH]; + DWORD numChars = _countof(path); handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); - if (QueryFullProcessImageNameA(handle, 0, path, &numChars)) { - processName = PathFindFileNameA(path); + if (QueryFullProcessImageName(handle, 0, path, &numChars)) { + processName = PathFindFileName(path); } } diff --git a/PresentMon/PresentMon.hpp b/PresentMon/PresentMon.hpp index 93aa0398..33c34d03 100644 --- a/PresentMon/PresentMon.hpp +++ b/PresentMon/PresentMon.hpp @@ -42,11 +42,11 @@ enum class ConsoleOutput { }; struct CommandLineArgs { - std::vector mTargetProcessNames; - std::vector mExcludeProcessNames; - const char *mOutputCsvFileName; - const char *mEtlFileName; - const char *mSessionName; + std::vector mTargetProcessNames; + std::vector mExcludeProcessNames; + const WCHAR *mOutputCsvFileName; + const WCHAR *mEtlFileName; + const WCHAR *mSessionName; UINT mTargetPid; UINT mDelay; UINT mTimer; @@ -94,7 +94,7 @@ struct OutputCsv { }; struct ProcessInfo { - std::string mModuleName; + std::wstring mModuleName; std::unordered_map mSwapChain; HANDLE mHandle; OutputCsv mOutputCsv; @@ -104,7 +104,7 @@ struct ProcessInfo { #include "LateStageReprojectionData.hpp" // CommandLine.cpp: -bool ParseCommandLine(int argc, char** argv); +bool ParseCommandLine(int argc, WCHAR** argv); CommandLineArgs const& GetCommandLineArgs(); // Console.cpp: @@ -139,12 +139,12 @@ void ExitMainThread(); void StartOutputThread(); void StopOutputThread(); void SetOutputRecordingState(bool record); -void CanonicalizeProcessName(std::string* path); +void CanonicalizeProcessName(std::wstring* path); // Privilege.cpp: bool InPerfLogUsersGroup(); bool EnableDebugPrivilege(); -int RestartAsAdministrator(int argc, char** argv); +int RestartAsAdministrator(int argc, WCHAR** argv); // TraceSession.cpp: bool StartTraceSession(); diff --git a/PresentMon/Privilege.cpp b/PresentMon/Privilege.cpp index d04986ad..60b0a7a7 100644 --- a/PresentMon/Privilege.cpp +++ b/PresentMon/Privilege.cpp @@ -69,43 +69,43 @@ bool EnableDebugPrivilege() int RestartAsAdministrator( int argc, - char** argv) + WCHAR** argv) { // Get the exe path - char exe_path[MAX_PATH] = {}; - GetModuleFileNameA(NULL, exe_path, sizeof(exe_path)); + WCHAR exe_path[MAX_PATH] = {}; + GetModuleFileName(NULL, exe_path, _countof(exe_path)); // Combine arguments into single string and remove -restart_as_admin to // prevent an endless loop if the escalation fails. - std::string args; + std::wstring args; for (int i = 1; i < argc; ++i) { - if (_stricmp(argv[i], "-restart_as_admin") == 0) continue; + if (_wcsicmp(argv[i], L"-restart_as_admin") == 0) continue; - auto addQuotes = argv[i][0] != '\"' && strchr(argv[i], ' ') != nullptr; + auto addQuotes = argv[i][0] != L'\"' && wcschr(argv[i], L' ') != nullptr; if (addQuotes) { - args += '\"'; + args += L'\"'; } args += argv[i]; if (addQuotes) { - args += '\"'; + args += L'\"'; } - args += ' '; + args += L' '; } // Re-run the process with the runas verb DWORD code = 2; - SHELLEXECUTEINFOA info = {}; + SHELLEXECUTEINFO info = {}; info.cbSize = sizeof(info); info.fMask = SEE_MASK_NOCLOSEPROCESS; // return info.hProcess for explicit wait - info.lpVerb = "runas"; + info.lpVerb = L"runas"; info.lpFile = exe_path; info.lpParameters = args.c_str(); info.nShow = SW_SHOWDEFAULT; - auto ok = ShellExecuteExA(&info); + auto ok = ShellExecuteEx(&info); if (ok) { WaitForSingleObject(info.hProcess, INFINITE); GetExitCodeProcess(info.hProcess, &code); diff --git a/PresentMon/TraceSession.cpp b/PresentMon/TraceSession.cpp index 7bdf494a..89c95833 100644 --- a/PresentMon/TraceSession.cpp +++ b/PresentMon/TraceSession.cpp @@ -43,12 +43,12 @@ bool StartTraceSession() if (status == ERROR_ALREADY_EXISTS) { if (args.mStopExistingSession) { PrintWarning( - "warning: a trace session named \"%s\" is already running and it will be stopped.\n" + "warning: a trace session named \"%ws\" is already running and it will be stopped.\n" " Use -session_name with a different name to start a new session.", args.mSessionName); } else { PrintError( - "error: a trace session named \"%s\" is already running. Use -stop_existing_session\n" + "error: a trace session named \"%ws\" is already running. Use -stop_existing_session\n" " to stop the existing session, or use -session_name with a different name to\n" " start a new session.", args.mSessionName); From b7ed19bddd49ce4c059ec0713789b899b5fa1969 Mon Sep 17 00:00:00 2001 From: Martin Malik Date: Tue, 12 Dec 2023 13:17:17 +0100 Subject: [PATCH 2/4] Enhance UNICODE support Also to fix #191 Signed-off-by: Martin Malik --- PresentData/PresentMonTraceConsumer.cpp | 7 +- PresentData/PresentMonTraceConsumer.hpp | 2 +- PresentData/TraceSession.cpp | 20 +- PresentData/TraceSession.hpp | 6 +- PresentMon/CommandLine.cpp | 326 +++++++++++------------ PresentMon/Console.cpp | 2 +- PresentMon/CsvOutput.cpp | 38 +-- PresentMon/LateStageReprojectionData.cpp | 28 +- PresentMon/LateStageReprojectionData.hpp | 2 +- PresentMon/MainThread.cpp | 6 +- PresentMon/OutputThread.cpp | 26 +- PresentMon/PresentMon.hpp | 18 +- PresentMon/Privilege.cpp | 24 +- PresentMon/TraceSession.cpp | 4 +- 14 files changed, 253 insertions(+), 256 deletions(-) diff --git a/PresentData/PresentMonTraceConsumer.cpp b/PresentData/PresentMonTraceConsumer.cpp index b8ad6587..634cc3f8 100644 --- a/PresentData/PresentMonTraceConsumer.cpp +++ b/PresentData/PresentMonTraceConsumer.cpp @@ -2190,10 +2190,7 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord) // e.g.: \Device\HarddiskVolume...\...\Proces.exe. We prune off everything other than // the filename here to be consistent. size_t start = ImageName.find_last_of('\\') + 1; - size_t size = ImageName.size() - start; - event.ImageFileName.resize(size + 1); - wcstombs_s(&size, &event.ImageFileName[0], size + 1, ImageName.c_str() + start, size); - event.ImageFileName.resize(size - 1); + event.ImageFileName = ImageName.c_str() + start; break; } case Microsoft_Windows_Kernel_Process::ProcessStop_Stop::Id: { @@ -2218,7 +2215,7 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord) }; mMetadata.GetEventData(pEventRecord, desc, _countof(desc)); event.ProcessId = desc[0].GetData(); - event.ImageFileName = desc[1].GetData(); + event.ImageFileName = desc[1].GetData(); event.IsStartEvent = true; } else if (hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_END|| hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_DC_END) { diff --git a/PresentData/PresentMonTraceConsumer.hpp b/PresentData/PresentMonTraceConsumer.hpp index 68062c8a..717d17f7 100644 --- a/PresentData/PresentMonTraceConsumer.hpp +++ b/PresentData/PresentMonTraceConsumer.hpp @@ -124,7 +124,7 @@ struct InputEvent { // A ProcessEvent occurs whenever a Process starts or stops. struct ProcessEvent { - std::string ImageFileName; // The name of the process exe file. This is only available on process start events. + std::wstring ImageFileName; // The name of the process exe file. This is only available on process start events. uint64_t QpcTime; // The time of the start/stop event. uint32_t ProcessId; // The id of the process. bool IsStartEvent; // Whether this is a start event (true) or a stop event (false). diff --git a/PresentData/TraceSession.cpp b/PresentData/TraceSession.cpp index 1bcab8e8..f80706dd 100644 --- a/PresentData/TraceSession.cpp +++ b/PresentData/TraceSession.cpp @@ -469,7 +469,7 @@ PEVENT_RECORD_CALLBACK GetEventRecordCallback(bool t1, bool t2, bool t3, bool t4 : GetEventRecordCallback(t2, t3, t4); } -ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILEA* pLogFile) +ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILE* pLogFile) { auto session = (TraceSession*) pLogFile->Context; return session->mContinueProcessingBuffers; // TRUE = continue processing events, FALSE = return out of ProcessTrace() @@ -480,8 +480,8 @@ ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILEA* pLogFile) ULONG TraceSession::Start( PMTraceConsumer* pmConsumer, MRTraceConsumer* mrConsumer, - char const* etlPath, - char const* sessionName) + WCHAR const* etlPath, + WCHAR const* sessionName) { assert(mSessionHandle == 0); assert(mTraceHandle == INVALID_PROCESSTRACE_HANDLE); @@ -492,8 +492,8 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // Configure trace properties - EVENT_TRACE_LOGFILEA traceProps = {}; - traceProps.LogFileName = (char*) etlPath; + EVENT_TRACE_LOGFILE traceProps = {}; + traceProps.LogFileName = (WCHAR*) etlPath; traceProps.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP; traceProps.Context = this; /* Output members (passed also to BufferCallback): @@ -523,7 +523,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // For realtime collection, start the session with the required providers if (traceProps.LogFileName == nullptr) { - traceProps.LoggerName = (char*) sessionName; + traceProps.LoggerName = (WCHAR*) sessionName; traceProps.ProcessTraceMode |= PROCESS_TRACE_MODE_REAL_TIME; TraceProperties sessionProps = {}; @@ -556,7 +556,7 @@ ULONG TraceSession::Start( sessionProps.LoggerThreadId // tracing session identifier */ - auto status = StartTraceA(&mSessionHandle, sessionName, &sessionProps); + auto status = StartTrace(&mSessionHandle, sessionName, &sessionProps); if (status != ERROR_SUCCESS) { mSessionHandle = 0; return status; @@ -571,7 +571,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // Open the trace - mTraceHandle = OpenTraceA(&traceProps); + mTraceHandle = OpenTrace(&traceProps); if (mTraceHandle == INVALID_PROCESSTRACE_HANDLE) { auto lastError = GetLastError(); Stop(); @@ -646,12 +646,12 @@ void TraceSession::Stop() } } -ULONG TraceSession::StopNamedSession(char const* sessionName) +ULONG TraceSession::StopNamedSession(WCHAR const* sessionName) { TraceProperties sessionProps = {}; sessionProps.Wnode.BufferSize = (ULONG) sizeof(TraceProperties); sessionProps.LoggerNameOffset = offsetof(TraceProperties, mSessionName); - return ControlTraceA((TRACEHANDLE) 0, sessionName, &sessionProps, EVENT_TRACE_CONTROL_STOP); + return ControlTraceW((TRACEHANDLE) 0, sessionName, &sessionProps, EVENT_TRACE_CONTROL_STOP); } diff --git a/PresentData/TraceSession.hpp b/PresentData/TraceSession.hpp index 040fc3ca..8990552c 100644 --- a/PresentData/TraceSession.hpp +++ b/PresentData/TraceSession.hpp @@ -17,11 +17,11 @@ struct TraceSession { ULONG Start( PMTraceConsumer* pmConsumer, // Required PMTraceConsumer instance MRTraceConsumer* mrConsumer, // If nullptr, no WinMR tracing - char const* etlPath, // If nullptr, live/realtime tracing session - char const* sessionName); // Required session name + WCHAR const* etlPath, // If nullptr, live/realtime tracing session + WCHAR const* sessionName); // Required session name void Stop(); ULONG CheckLostReports(ULONG* eventsLost, ULONG* buffersLost) const; - static ULONG StopNamedSession(char const* sessionName); + static ULONG StopNamedSession(WCHAR const* sessionName); }; diff --git a/PresentMon/CommandLine.cpp b/PresentMon/CommandLine.cpp index ab231492..26fdc633 100644 --- a/PresentMon/CommandLine.cpp +++ b/PresentMon/CommandLine.cpp @@ -18,118 +18,118 @@ enum { struct KeyNameCode { - char const* mName; + WCHAR const* mName; UINT mCode; }; KeyNameCode const HOTKEY_MODS[] = { - { "ALT", MOD_ALT }, - { "CONTROL", MOD_CONTROL }, - { "CTRL", MOD_CONTROL }, - { "SHIFT", MOD_SHIFT }, - { "WINDOWS", MOD_WIN }, - { "WIN", MOD_WIN }, + { L"ALT", MOD_ALT }, + { L"CONTROL", MOD_CONTROL }, + { L"CTRL", MOD_CONTROL }, + { L"SHIFT", MOD_SHIFT }, + { L"WINDOWS", MOD_WIN }, + { L"WIN", MOD_WIN }, }; KeyNameCode const HOTKEY_KEYS[] = { - { "BACKSPACE", VK_BACK }, - { "TAB", VK_TAB }, - { "CLEAR", VK_CLEAR }, - { "ENTER", VK_RETURN }, - { "PAUSE", VK_PAUSE }, - { "CAPSLOCK", VK_CAPITAL }, - { "ESC", VK_ESCAPE }, - { "SPACE", VK_SPACE }, - { "PAGEUP", VK_PRIOR }, - { "PAGEDOWN", VK_NEXT }, - { "END", VK_END }, - { "HOME", VK_HOME }, - { "LEFT", VK_LEFT }, - { "UP", VK_UP }, - { "RIGHT", VK_RIGHT }, - { "DOWN", VK_DOWN }, - { "PRINTSCREEN", VK_SNAPSHOT }, - { "INS", VK_INSERT }, - { "DEL", VK_DELETE }, - { "HELP", VK_HELP }, - { "NUMLOCK", VK_NUMLOCK }, - { "SCROLLLOCK", VK_SCROLL }, - { "NUM0", VK_NUMPAD0 }, - { "NUM1", VK_NUMPAD1 }, - { "NUM2", VK_NUMPAD2 }, - { "NUM3", VK_NUMPAD3 }, - { "NUM4", VK_NUMPAD4 }, - { "NUM5", VK_NUMPAD5 }, - { "NUM6", VK_NUMPAD6 }, - { "NUM7", VK_NUMPAD7 }, - { "NUM8", VK_NUMPAD8 }, - { "NUM9", VK_NUMPAD9 }, - { "MULTIPLY", VK_MULTIPLY }, - { "ADD", VK_ADD }, - { "SEPARATOR", VK_SEPARATOR }, - { "SUBTRACT", VK_SUBTRACT }, - { "DECIMAL", VK_DECIMAL }, - { "DIVIDE", VK_DIVIDE }, - { "0", 0x30 }, - { "1", 0x31 }, - { "2", 0x32 }, - { "3", 0x33 }, - { "4", 0x34 }, - { "5", 0x35 }, - { "6", 0x36 }, - { "7", 0x37 }, - { "8", 0x38 }, - { "9", 0x39 }, - { "A", 0x41 }, - { "B", 0x42 }, - { "C", 0x43 }, - { "D", 0x44 }, - { "E", 0x45 }, - { "F", 0x46 }, - { "G", 0x47 }, - { "H", 0x48 }, - { "I", 0x49 }, - { "J", 0x4A }, - { "K", 0x4B }, - { "L", 0x4C }, - { "M", 0x4D }, - { "N", 0x4E }, - { "O", 0x4F }, - { "P", 0x50 }, - { "Q", 0x51 }, - { "R", 0x52 }, - { "S", 0x53 }, - { "T", 0x54 }, - { "U", 0x55 }, - { "V", 0x56 }, - { "W", 0x57 }, - { "X", 0x58 }, - { "Y", 0x59 }, - { "Z", 0x5A }, - { "F1", VK_F1 }, - { "F2", VK_F2 }, - { "F3", VK_F3 }, - { "F4", VK_F4 }, - { "F5", VK_F5 }, - { "F6", VK_F6 }, - { "F7", VK_F7 }, - { "F8", VK_F8 }, - { "F9", VK_F9 }, - { "F10", VK_F10 }, - { "F11", VK_F11 }, - { "F12", VK_F12 }, - { "F13", VK_F13 }, - { "F14", VK_F14 }, - { "F15", VK_F15 }, - { "F16", VK_F16 }, - { "F17", VK_F17 }, - { "F18", VK_F18 }, - { "F19", VK_F19 }, - { "F20", VK_F20 }, - { "F21", VK_F21 }, - { "F22", VK_F22 }, - { "F23", VK_F23 }, - { "F24", VK_F24 }, + { L"BACKSPACE", VK_BACK }, + { L"TAB", VK_TAB }, + { L"CLEAR", VK_CLEAR }, + { L"ENTER", VK_RETURN }, + { L"PAUSE", VK_PAUSE }, + { L"CAPSLOCK", VK_CAPITAL }, + { L"ESC", VK_ESCAPE }, + { L"SPACE", VK_SPACE }, + { L"PAGEUP", VK_PRIOR }, + { L"PAGEDOWN", VK_NEXT }, + { L"END", VK_END }, + { L"HOME", VK_HOME }, + { L"LEFT", VK_LEFT }, + { L"UP", VK_UP }, + { L"RIGHT", VK_RIGHT }, + { L"DOWN", VK_DOWN }, + { L"PRINTSCREEN", VK_SNAPSHOT }, + { L"INS", VK_INSERT }, + { L"DEL", VK_DELETE }, + { L"HELP", VK_HELP }, + { L"NUMLOCK", VK_NUMLOCK }, + { L"SCROLLLOCK", VK_SCROLL }, + { L"NUM0", VK_NUMPAD0 }, + { L"NUM1", VK_NUMPAD1 }, + { L"NUM2", VK_NUMPAD2 }, + { L"NUM3", VK_NUMPAD3 }, + { L"NUM4", VK_NUMPAD4 }, + { L"NUM5", VK_NUMPAD5 }, + { L"NUM6", VK_NUMPAD6 }, + { L"NUM7", VK_NUMPAD7 }, + { L"NUM8", VK_NUMPAD8 }, + { L"NUM9", VK_NUMPAD9 }, + { L"MULTIPLY", VK_MULTIPLY }, + { L"ADD", VK_ADD }, + { L"SEPARATOR", VK_SEPARATOR }, + { L"SUBTRACT", VK_SUBTRACT }, + { L"DECIMAL", VK_DECIMAL }, + { L"DIVIDE", VK_DIVIDE }, + { L"0", 0x30 }, + { L"1", 0x31 }, + { L"2", 0x32 }, + { L"3", 0x33 }, + { L"4", 0x34 }, + { L"5", 0x35 }, + { L"6", 0x36 }, + { L"7", 0x37 }, + { L"8", 0x38 }, + { L"9", 0x39 }, + { L"A", 0x41 }, + { L"B", 0x42 }, + { L"C", 0x43 }, + { L"D", 0x44 }, + { L"E", 0x45 }, + { L"F", 0x46 }, + { L"G", 0x47 }, + { L"H", 0x48 }, + { L"I", 0x49 }, + { L"J", 0x4A }, + { L"K", 0x4B }, + { L"L", 0x4C }, + { L"M", 0x4D }, + { L"N", 0x4E }, + { L"O", 0x4F }, + { L"P", 0x50 }, + { L"Q", 0x51 }, + { L"R", 0x52 }, + { L"S", 0x53 }, + { L"T", 0x54 }, + { L"U", 0x55 }, + { L"V", 0x56 }, + { L"W", 0x57 }, + { L"X", 0x58 }, + { L"Y", 0x59 }, + { L"Z", 0x5A }, + { L"F1", VK_F1 }, + { L"F2", VK_F2 }, + { L"F3", VK_F3 }, + { L"F4", VK_F4 }, + { L"F5", VK_F5 }, + { L"F6", VK_F6 }, + { L"F7", VK_F7 }, + { L"F8", VK_F8 }, + { L"F9", VK_F9 }, + { L"F10", VK_F10 }, + { L"F11", VK_F11 }, + { L"F12", VK_F12 }, + { L"F13", VK_F13 }, + { L"F14", VK_F14 }, + { L"F15", VK_F15 }, + { L"F16", VK_F16 }, + { L"F17", VK_F17 }, + { L"F18", VK_F18 }, + { L"F19", VK_F19 }, + { L"F20", VK_F20 }, + { L"F21", VK_F21 }, + { L"F22", VK_F22 }, + { L"F23", VK_F23 }, + { L"F24", VK_F24 }, }; CommandLineArgs gCommandLineArgs; @@ -142,38 +142,38 @@ size_t GetConsoleWidth() : std::max(DEFAULT_CONSOLE_WIDTH, info.srWindow.Right - info.srWindow.Left + 1); } -bool ParseKeyName(KeyNameCode const* valid, size_t validCount, char* name, char const* errorMessage, UINT* outKeyCode) +bool ParseKeyName(KeyNameCode const* valid, size_t validCount, WCHAR* name, char const* errorMessage, UINT* outKeyCode) { for (size_t i = 0; i < validCount; ++i) { - if (_stricmp(name, valid[i].mName) == 0) { + if (_wcsicmp(name, valid[i].mName) == 0) { *outKeyCode = valid[i].mCode; return true; } } - int col = PrintErrorNoNewLine("error: %s '%s'.\nValid options (case insensitive):", errorMessage, name); + int col = PrintErrorNoNewLine("error: %s '%ws'.\nValid options (case insensitive):", errorMessage, name); size_t consoleWidth = GetConsoleWidth(); for (size_t i = 0; i < validCount; ++i) { - auto len = strlen(valid[i].mName); + auto len = wcslen(valid[i].mName); if (col + len + 1 > consoleWidth) { col = PrintErrorNoNewLine("\n ") - 1; } - col += PrintErrorNoNewLine(" %s", valid[i].mName); + col += PrintErrorNoNewLine(" %ws", valid[i].mName); } fprintf(stderr, "\n"); return false; } -bool AssignHotkey(char* key, CommandLineArgs* args) +bool AssignHotkey(WCHAR* key, CommandLineArgs* args) { #pragma warning(suppress: 4996) - auto token = strtok(key, "+"); + auto token = wcstok(key, L"+"); for (;;) { auto prev = token; #pragma warning(suppress: 4996) - token = strtok(nullptr, "+"); + token = wcstok(nullptr, L"+"); if (token == nullptr) { if (!ParseKeyName(HOTKEY_KEYS, _countof(HOTKEY_KEYS), prev, "invalid -hotkey key", &args->mHotkeyVirtualKeyCode)) { return false; @@ -203,7 +203,7 @@ void SetCaptureAll(CommandLineArgs* args) } // Allow /ARG, -ARG, or --ARG -bool ParseArgPrefix(char** arg) +bool ParseArgPrefix(WCHAR** arg) { if (**arg == '/') { *arg += 1; @@ -221,43 +221,43 @@ bool ParseArgPrefix(char** arg) return false; } -bool ParseArg(char* arg, char const* option) +bool ParseArg(WCHAR* arg, WCHAR const* option) { return ParseArgPrefix(&arg) && - _stricmp(arg, option) == 0; + _wcsicmp(arg, option) == 0; } -bool ParseValue(char** argv, int argc, int* i) +bool ParseValue(WCHAR** argv, int argc, int* i) { if (*i + 1 < argc) { *i += 1; return true; } - PrintError("error: %s expecting argument.", argv[*i]); + PrintError("error: %ws expecting argument.", argv[*i]); return false; } -bool ParseValue(char** argv, int argc, int* i, char const** value) +bool ParseValue(WCHAR** argv, int argc, int* i, WCHAR const** value) { if (!ParseValue(argv, argc, i)) return false; *value = argv[*i]; return true; } -bool ParseValue(char** argv, int argc, int* i, std::vector* value) +bool ParseValue(WCHAR** argv, int argc, int* i, std::vector* value) { - char const* v = nullptr; + WCHAR const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; value->emplace_back(v); return true; } -bool ParseValue(char** argv, int argc, int* i, UINT* value) +bool ParseValue(WCHAR** argv, int argc, int* i, UINT* value) { - char const* v = nullptr; + WCHAR const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; - *value = strtoul(v, nullptr, 10); + *value = wcstoul(v, nullptr, 10); return true; } @@ -315,7 +315,7 @@ CommandLineArgs const& GetCommandLineArgs() return gCommandLineArgs; } -bool ParseCommandLine(int argc, char** argv) +bool ParseCommandLine(int argc, WCHAR** argv) { auto args = &gCommandLineArgs; @@ -323,7 +323,7 @@ bool ParseCommandLine(int argc, char** argv) args->mExcludeProcessNames.clear(); args->mOutputCsvFileName = nullptr; args->mEtlFileName = nullptr; - args->mSessionName = "PresentMon"; + args->mSessionName = L"PresentMon"; args->mTargetPid = 0; args->mDelay = 0; args->mTimer = 0; @@ -363,57 +363,57 @@ bool ParseCommandLine(int argc, char** argv) for (int i = 1; i < argc; ++i) { // Capture target options: - if (ParseArg(argv[i], "captureall")) { SetCaptureAll(args); continue; } - else if (ParseArg(argv[i], "process_name")) { if (ParseValue(argv, argc, &i, &args->mTargetProcessNames)) continue; } - else if (ParseArg(argv[i], "exclude")) { if (ParseValue(argv, argc, &i, &args->mExcludeProcessNames)) continue; } - else if (ParseArg(argv[i], "process_id")) { if (ParseValue(argv, argc, &i, &args->mTargetPid)) continue; } - else if (ParseArg(argv[i], "etl_file")) { if (ParseValue(argv, argc, &i, &args->mEtlFileName)) continue; } + if (ParseArg(argv[i], L"captureall")) { SetCaptureAll(args); continue; } + else if (ParseArg(argv[i], L"process_name")) { if (ParseValue(argv, argc, &i, &args->mTargetProcessNames)) continue; } + else if (ParseArg(argv[i], L"exclude")) { if (ParseValue(argv, argc, &i, &args->mExcludeProcessNames)) continue; } + else if (ParseArg(argv[i], L"process_id")) { if (ParseValue(argv, argc, &i, &args->mTargetPid)) continue; } + else if (ParseArg(argv[i], L"etl_file")) { if (ParseValue(argv, argc, &i, &args->mEtlFileName)) continue; } // Output options: - else if (ParseArg(argv[i], "output_file")) { if (ParseValue(argv, argc, &i, &args->mOutputCsvFileName)) continue; } - else if (ParseArg(argv[i], "output_stdout")) { args->mOutputCsvToStdout = true; continue; } - else if (ParseArg(argv[i], "multi_csv")) { args->mMultiCsv = true; continue; } - else if (ParseArg(argv[i], "no_csv")) { args->mOutputCsvToFile = false; continue; } - else if (ParseArg(argv[i], "no_top")) { args->mConsoleOutputType = ConsoleOutput::Simple; continue; } - else if (ParseArg(argv[i], "qpc_time")) { args->mOutputQpcTime = true; continue; } - else if (ParseArg(argv[i], "qpc_time_s")) { args->mOutputQpcTimeInSeconds = true; continue; } + else if (ParseArg(argv[i], L"output_file")) { if (ParseValue(argv, argc, &i, &args->mOutputCsvFileName)) continue; } + else if (ParseArg(argv[i], L"output_stdout")) { args->mOutputCsvToStdout = true; continue; } + else if (ParseArg(argv[i], L"multi_csv")) { args->mMultiCsv = true; continue; } + else if (ParseArg(argv[i], L"no_csv")) { args->mOutputCsvToFile = false; continue; } + else if (ParseArg(argv[i], L"no_top")) { args->mConsoleOutputType = ConsoleOutput::Simple; continue; } + else if (ParseArg(argv[i], L"qpc_time")) { args->mOutputQpcTime = true; continue; } + else if (ParseArg(argv[i], L"qpc_time_s")) { args->mOutputQpcTimeInSeconds = true; continue; } // Recording options: - else if (ParseArg(argv[i], "hotkey")) { if (ParseValue(argv, argc, &i) && AssignHotkey(argv[i], args)) continue; } - else if (ParseArg(argv[i], "delay")) { if (ParseValue(argv, argc, &i, &args->mDelay)) continue; } - else if (ParseArg(argv[i], "timed")) { if (ParseValue(argv, argc, &i, &args->mTimer)) { args->mStartTimer = true; continue; } } - else if (ParseArg(argv[i], "exclude_dropped")) { args->mExcludeDropped = true; continue; } - else if (ParseArg(argv[i], "scroll_indicator")) { args->mScrollLockIndicator = true; continue; } - else if (ParseArg(argv[i], "no_track_display")) { args->mTrackDisplay = false; continue; } - else if (ParseArg(argv[i], "track_debug")) { args->mTrackDebug = true; continue; } - else if (ParseArg(argv[i], "simple")) { DEPRECATED_simple = true; continue; } - else if (ParseArg(argv[i], "verbose")) { DEPRECATED_verbose = true; continue; } + else if (ParseArg(argv[i], L"hotkey")) { if (ParseValue(argv, argc, &i) && AssignHotkey(argv[i], args)) continue; } + else if (ParseArg(argv[i], L"delay")) { if (ParseValue(argv, argc, &i, &args->mDelay)) continue; } + else if (ParseArg(argv[i], L"timed")) { if (ParseValue(argv, argc, &i, &args->mTimer)) { args->mStartTimer = true; continue; } } + else if (ParseArg(argv[i], L"exclude_dropped")) { args->mExcludeDropped = true; continue; } + else if (ParseArg(argv[i], L"scroll_indicator")) { args->mScrollLockIndicator = true; continue; } + else if (ParseArg(argv[i], L"no_track_display")) { args->mTrackDisplay = false; continue; } + else if (ParseArg(argv[i], L"track_debug")) { args->mTrackDebug = true; continue; } + else if (ParseArg(argv[i], L"simple")) { DEPRECATED_simple = true; continue; } + else if (ParseArg(argv[i], L"verbose")) { DEPRECATED_verbose = true; continue; } // Execution options: - else if (ParseArg(argv[i], "session_name")) { if (ParseValue(argv, argc, &i, &args->mSessionName)) continue; } - else if (ParseArg(argv[i], "stop_existing_session")) { args->mStopExistingSession = true; continue; } - else if (ParseArg(argv[i], "terminate_existing")) { args->mTerminateExisting = true; continue; } - else if (ParseArg(argv[i], "dont_restart_as_admin")) { DEPRECATED_dontRestart = true; continue; } - else if (ParseArg(argv[i], "restart_as_admin")) { args->mTryToElevate = true; continue; } - else if (ParseArg(argv[i], "terminate_on_proc_exit")) { args->mTerminateOnProcExit = true; continue; } - else if (ParseArg(argv[i], "terminate_after_timed")) { args->mTerminateAfterTimer = true; continue; } + else if (ParseArg(argv[i], L"session_name")) { if (ParseValue(argv, argc, &i, &args->mSessionName)) continue; } + else if (ParseArg(argv[i], L"stop_existing_session")) { args->mStopExistingSession = true; continue; } + else if (ParseArg(argv[i], L"terminate_existing")) { args->mTerminateExisting = true; continue; } + else if (ParseArg(argv[i], L"dont_restart_as_admin")) { DEPRECATED_dontRestart = true; continue; } + else if (ParseArg(argv[i], L"restart_as_admin")) { args->mTryToElevate = true; continue; } + else if (ParseArg(argv[i], L"terminate_on_proc_exit")) { args->mTerminateOnProcExit = true; continue; } + else if (ParseArg(argv[i], L"terminate_after_timed")) { args->mTerminateAfterTimer = true; continue; } // Beta options: - else if (ParseArg(argv[i], "date_time")) { args->mOutputDateTime = true; continue; } - else if (ParseArg(argv[i], "track_gpu")) { args->mTrackGPU = true; continue; } - else if (ParseArg(argv[i], "track_gpu_video")) { args->mTrackGPUVideo = true; continue; } - else if (ParseArg(argv[i], "track_input")) { args->mTrackInput = true; continue; } - else if (ParseArg(argv[i], "track_mixed_reality")) { args->mTrackWMR = true; continue; } - else if (ParseArg(argv[i], "include_mixed_reality")) { DEPRECATED_wmr = true; continue; } + else if (ParseArg(argv[i], L"date_time")) { args->mOutputDateTime = true; continue; } + else if (ParseArg(argv[i], L"track_gpu")) { args->mTrackGPU = true; continue; } + else if (ParseArg(argv[i], L"track_gpu_video")) { args->mTrackGPUVideo = true; continue; } + else if (ParseArg(argv[i], L"track_input")) { args->mTrackInput = true; continue; } + else if (ParseArg(argv[i], L"track_mixed_reality")) { args->mTrackWMR = true; continue; } + else if (ParseArg(argv[i], L"include_mixed_reality")) { DEPRECATED_wmr = true; continue; } // Hidden options: #if PRESENTMON_ENABLE_DEBUG_TRACE - else if (ParseArg(argv[i], "debug_verbose_trace")) { verboseTrace = true; continue; } + else if (ParseArg(argv[i], L"debug_verbose_trace")) { verboseTrace = true; continue; } #endif // Provided argument wasn't recognized - else if (!(ParseArg(argv[i], "?") || ParseArg(argv[i], "h") || ParseArg(argv[i], "help"))) { - PrintError("error: unrecognized argument '%s'.", argv[i]); + else if (!(ParseArg(argv[i], L"?") || ParseArg(argv[i], L"h") || ParseArg(argv[i], L"help"))) { + PrintError("error: unrecognized argument '%ws'.", argv[i]); } PrintHelp(); diff --git a/PresentMon/Console.cpp b/PresentMon/Console.cpp index 2265ece1..f5c31cd0 100644 --- a/PresentMon/Console.cpp +++ b/PresentMon/Console.cpp @@ -191,7 +191,7 @@ void UpdateConsole(uint32_t processId, ProcessInfo const& processInfo) if (empty) { empty = false; - ConsolePrintLn("%s[%d]:", processInfo.mModuleName.c_str(), processId); + ConsolePrintLn("%ws[%d]:", processInfo.mModuleName.c_str(), processId); } ConsolePrint(" %016llX (%s): SyncInterval=%d Flags=%d CPU%s%s=%.2lf", diff --git a/PresentMon/CsvOutput.cpp b/PresentMon/CsvOutput.cpp index 68559f18..35b78e96 100644 --- a/PresentMon/CsvOutput.cpp +++ b/PresentMon/CsvOutput.cpp @@ -144,7 +144,7 @@ void UpdateCsv(ProcessInfo* processInfo, SwapChainData const& chain, PresentEven } // Output in CSV format - fprintf(fp, "%s,%d,0x%016llX,%s,%d,%d,%s,", + fprintf(fp, "%ws,%d,0x%016llX,%s,%d,%d,%s,", processInfo->mModuleName.c_str(), p.ProcessId, p.SwapChainAddress, @@ -224,55 +224,55 @@ with `-INDEX` appended to the file name. If `-include_mixed_reality` is used, a second CSV file will be generated with `_WMR` appended to the filename containing the WMR data. */ -static void GenerateFilename(char* path, char const* processName, uint32_t processId) +static void GenerateFilename(WCHAR* path, WCHAR const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); - char ext[_MAX_EXT]; + WCHAR ext[_MAX_EXT]; int pathLength = MAX_PATH; #define ADD_TO_PATH(...) do { \ if (path != nullptr) { \ - auto result = _snprintf_s(path, pathLength, _TRUNCATE, __VA_ARGS__); \ + auto result = _snwprintf_s(path, pathLength, _TRUNCATE, __VA_ARGS__); \ if (result == -1) path = nullptr; else { path += result; pathLength -= result; } \ } \ } while (0) // Generate base filename. if (args.mOutputCsvFileName) { - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char name[_MAX_FNAME]; - _splitpath_s(args.mOutputCsvFileName, drive, dir, name, ext); - ADD_TO_PATH("%s%s%s", drive, dir, name); + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + WCHAR name[_MAX_FNAME]; + _wsplitpath_s(args.mOutputCsvFileName, drive, dir, name, ext); + ADD_TO_PATH(L"%s%s%s", drive, dir, name); } else { struct tm tm; time_t time_now = time(NULL); localtime_s(&tm, &time_now); - ADD_TO_PATH("PresentMon-%4d-%02d-%02dT%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - strcpy_s(ext, ".csv"); + ADD_TO_PATH(L"PresentMon-%4d-%02d-%02dT%02d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + wcscpy_s(ext, L".csv"); } // Append -PROCESSNAME if applicable. if (processName != nullptr) { - if (strcmp(processName, "")) { - ADD_TO_PATH("-%s", processName); + if (wcscmp(processName, L"")) { + ADD_TO_PATH(L"-%s", processName); } - ADD_TO_PATH("-%u", processId); + ADD_TO_PATH(L"-%u", processId); } // Append -INDEX if applicable. if (args.mHotkeySupport) { - ADD_TO_PATH("-%d", gRecordingCount); + ADD_TO_PATH(L"-%d", gRecordingCount); } // Append extension. - ADD_TO_PATH("%s", ext); + ADD_TO_PATH(L"%s", ext); #undef ADD_TO_PATH } -static OutputCsv CreateOutputCsv(char const* processName, uint32_t processId) +static OutputCsv CreateOutputCsv(WCHAR const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); @@ -282,10 +282,10 @@ static OutputCsv CreateOutputCsv(char const* processName, uint32_t processId) outputCsv.mFile = stdout; outputCsv.mWmrFile = nullptr; // WMR disallowed if -output_stdout } else { - char path[MAX_PATH]; + WCHAR path[MAX_PATH]; GenerateFilename(path, processName, processId); - fopen_s(&outputCsv.mFile, path, "w"); + _wfopen_s(&outputCsv.mFile, path, L"w"); if (args.mTrackWMR) { outputCsv.mWmrFile = CreateLsrCsvFile(path); diff --git a/PresentMon/LateStageReprojectionData.cpp b/PresentMon/LateStageReprojectionData.cpp index 761d2168..0cf5068c 100644 --- a/PresentMon/LateStageReprojectionData.cpp +++ b/PresentMon/LateStageReprojectionData.cpp @@ -182,23 +182,23 @@ LateStageReprojectionRuntimeStats LateStageReprojectionData::ComputeRuntimeStats return stats; } -FILE* CreateLsrCsvFile(char const* path) +FILE* CreateLsrCsvFile(WCHAR const* path) { auto const& args = GetCommandLineArgs(); // Add _WMR to the file name - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char name[_MAX_FNAME]; - char ext[_MAX_EXT]; - _splitpath_s(path, drive, dir, name, ext); + WCHAR drive[_MAX_DRIVE]; + WCHAR dir[_MAX_DIR]; + WCHAR name[_MAX_FNAME]; + WCHAR ext[_MAX_EXT]; + _wsplitpath_s(path, drive, dir, name, ext); - char outputPath[MAX_PATH] = {}; - _snprintf_s(outputPath, _TRUNCATE, "%s%s%s_WMR%s", drive, dir, name, ext); + WCHAR outputPath[MAX_PATH] = {}; + _snwprintf_s(outputPath, _TRUNCATE, L"%s%s%s_WMR%s", drive, dir, name, ext); // Open output file FILE* fp = nullptr; - if (fopen_s(&fp, outputPath, "w")) { + if (_wfopen_s(&fp, outputPath, L"w")) { return nullptr; } @@ -252,7 +252,7 @@ void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageRe const double deltaMilliseconds = 1000.0 * QpcDeltaToSeconds(curr.QpcTime - prev.QpcTime); const double timeInSeconds = QpcToSeconds(p.QpcTime); - fprintf(fp, "%s,%d,%d", proc->mModuleName.c_str(), curr.GetAppProcessId(), curr.ProcessId); + fprintf(fp, "%ws,%d,%d", proc->mModuleName.c_str(), curr.GetAppProcessId(), curr.ProcessId); if (args.mTrackDebug) { fprintf(fp, ",%d", curr.GetAppFrameId()); } @@ -321,8 +321,8 @@ void UpdateConsole(std::unordered_map const& activeProces if (args.mTrackDisplay) { auto processIter = activeProcesses.find(runtimeStats.mAppProcessId); - ConsolePrintLn(" App - %s[%d]:", - processIter == activeProcesses.end() ? "" : processIter->second.mModuleName.c_str(), + ConsolePrintLn(" App - %ws[%d]:", + processIter == activeProcesses.end() ? L"" : processIter->second.mModuleName.c_str(), runtimeStats.mAppProcessId); ConsolePrint(" %.2lf ms/frame (%.1lf fps, %.2lf ms CPU", 1000.0 / fps, fps, runtimeStats.mAppSourceCpuRenderTimeInMs); } else { @@ -346,8 +346,8 @@ void UpdateConsole(std::unordered_map const& activeProces const double fps = lsr.ComputeFps(); auto processIter = activeProcesses.find(runtimeStats.mLsrProcessId); - ConsolePrintLn(" Compositor - %s[%d]:", - processIter == activeProcesses.end() ? "" : processIter->second.mModuleName.c_str(), + ConsolePrintLn(" Compositor - %ws[%d]:", + processIter == activeProcesses.end() ? L"" : processIter->second.mModuleName.c_str(), runtimeStats.mLsrProcessId); ConsolePrintLn(" %.2lf ms/frame (%.1lf fps, %.1lf displayed fps, %.2lf ms CPU)", 1000.0 / fps, diff --git a/PresentMon/LateStageReprojectionData.hpp b/PresentMon/LateStageReprojectionData.hpp index ea0790e3..a26f7ea9 100644 --- a/PresentMon/LateStageReprojectionData.hpp +++ b/PresentMon/LateStageReprojectionData.hpp @@ -85,6 +85,6 @@ struct LateStageReprojectionData { double ComputeHistoryTime(const std::deque& lsrHistory) const; }; -FILE* CreateLsrCsvFile(char const* path); +FILE* CreateLsrCsvFile(WCHAR const* path); void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageReprojectionEvent& p); void UpdateConsole(std::unordered_map const& activeProcesses, LateStageReprojectionData& lsr); diff --git a/PresentMon/MainThread.cpp b/PresentMon/MainThread.cpp index e48549ad..707b9b2a 100644 --- a/PresentMon/MainThread.cpp +++ b/PresentMon/MainThread.cpp @@ -172,7 +172,7 @@ void ExitMainThread() PostMessage(gWnd, WM_QUIT, 0, 0); } -int main(int argc, char** argv) +int wmain(int argc, WCHAR** argv) { // Load system DLLs LoadLibraryExA("advapi32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -196,8 +196,8 @@ int main(int argc, char** argv) auto status = TraceSession::StopNamedSession(args.mSessionName); switch (status) { case ERROR_SUCCESS: return 0; - case ERROR_WMI_INSTANCE_NOT_FOUND: PrintError("error: no existing sessions found: %s", args.mSessionName); break; - default: PrintError("error: failed to terminate existing session (%s): %lu", args.mSessionName, status); break; + case ERROR_WMI_INSTANCE_NOT_FOUND: PrintError("error: no existing sessions found: %ws", args.mSessionName); break; + default: PrintError("error: failed to terminate existing session (%ws): %lu", args.mSessionName, status); break; } return 7; } diff --git a/PresentMon/OutputThread.cpp b/PresentMon/OutputThread.cpp index 66fce329..e6972da5 100644 --- a/PresentMon/OutputThread.cpp +++ b/PresentMon/OutputThread.cpp @@ -88,25 +88,25 @@ static uint32_t gTargetProcessCount = 0; // Removes any directory and extension, and converts the remaining name to // lower case. -void CanonicalizeProcessName(std::string* name) +void CanonicalizeProcessName(std::wstring* name) { - size_t i = name->find_last_of("./\\"); - if (i != std::string::npos && (*name)[i] == '.') { + size_t i = name->find_last_of(L"./\\"); + if (i != std::wstring::npos && (*name)[i] == L'.') { name->resize(i); - i = name->find_last_of("/\\"); + i = name->find_last_of(L"/\\"); } *name = name->substr(i + 1); std::transform(name->begin(), name->end(), name->begin(), - [](unsigned char c) { return (unsigned char) ::tolower((int) c); }); + [](WCHAR c) { return (WCHAR) ::towlower(c); }); } -static bool IsTargetProcess(uint32_t processId, std::string const& processName) +static bool IsTargetProcess(uint32_t processId, std::wstring const& processName) { auto const& args = GetCommandLineArgs(); - std::string compareName; + std::wstring compareName; if (args.mExcludeProcessNames.size() + args.mTargetProcessNames.size() > 0) { compareName = processName; CanonicalizeProcessName(&compareName); @@ -139,7 +139,7 @@ static bool IsTargetProcess(uint32_t processId, std::string const& processName) return false; } -static ProcessInfo CreateProcessInfo(uint32_t processId, HANDLE handle, std::string const& processName) +static ProcessInfo CreateProcessInfo(uint32_t processId, HANDLE handle, std::wstring const& processName) { auto isTarget = IsTargetProcess(processId, processName); if (isTarget) { @@ -168,13 +168,13 @@ static ProcessInfo* GetProcessInfo(uint32_t processId) // another account, unless we're running with SeDebugPrivilege. auto const& args = GetCommandLineArgs(); HANDLE handle = NULL; - char const* processName = ""; + WCHAR const* processName = L""; if (args.mEtlFileName == nullptr) { - char path[MAX_PATH]; - DWORD numChars = sizeof(path); + WCHAR path[MAX_PATH]; + DWORD numChars = _countof(path); handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); - if (QueryFullProcessImageNameA(handle, 0, path, &numChars)) { - processName = PathFindFileNameA(path); + if (QueryFullProcessImageName(handle, 0, path, &numChars)) { + processName = PathFindFileName(path); } } diff --git a/PresentMon/PresentMon.hpp b/PresentMon/PresentMon.hpp index 93aa0398..33c34d03 100644 --- a/PresentMon/PresentMon.hpp +++ b/PresentMon/PresentMon.hpp @@ -42,11 +42,11 @@ enum class ConsoleOutput { }; struct CommandLineArgs { - std::vector mTargetProcessNames; - std::vector mExcludeProcessNames; - const char *mOutputCsvFileName; - const char *mEtlFileName; - const char *mSessionName; + std::vector mTargetProcessNames; + std::vector mExcludeProcessNames; + const WCHAR *mOutputCsvFileName; + const WCHAR *mEtlFileName; + const WCHAR *mSessionName; UINT mTargetPid; UINT mDelay; UINT mTimer; @@ -94,7 +94,7 @@ struct OutputCsv { }; struct ProcessInfo { - std::string mModuleName; + std::wstring mModuleName; std::unordered_map mSwapChain; HANDLE mHandle; OutputCsv mOutputCsv; @@ -104,7 +104,7 @@ struct ProcessInfo { #include "LateStageReprojectionData.hpp" // CommandLine.cpp: -bool ParseCommandLine(int argc, char** argv); +bool ParseCommandLine(int argc, WCHAR** argv); CommandLineArgs const& GetCommandLineArgs(); // Console.cpp: @@ -139,12 +139,12 @@ void ExitMainThread(); void StartOutputThread(); void StopOutputThread(); void SetOutputRecordingState(bool record); -void CanonicalizeProcessName(std::string* path); +void CanonicalizeProcessName(std::wstring* path); // Privilege.cpp: bool InPerfLogUsersGroup(); bool EnableDebugPrivilege(); -int RestartAsAdministrator(int argc, char** argv); +int RestartAsAdministrator(int argc, WCHAR** argv); // TraceSession.cpp: bool StartTraceSession(); diff --git a/PresentMon/Privilege.cpp b/PresentMon/Privilege.cpp index d04986ad..60b0a7a7 100644 --- a/PresentMon/Privilege.cpp +++ b/PresentMon/Privilege.cpp @@ -69,43 +69,43 @@ bool EnableDebugPrivilege() int RestartAsAdministrator( int argc, - char** argv) + WCHAR** argv) { // Get the exe path - char exe_path[MAX_PATH] = {}; - GetModuleFileNameA(NULL, exe_path, sizeof(exe_path)); + WCHAR exe_path[MAX_PATH] = {}; + GetModuleFileName(NULL, exe_path, _countof(exe_path)); // Combine arguments into single string and remove -restart_as_admin to // prevent an endless loop if the escalation fails. - std::string args; + std::wstring args; for (int i = 1; i < argc; ++i) { - if (_stricmp(argv[i], "-restart_as_admin") == 0) continue; + if (_wcsicmp(argv[i], L"-restart_as_admin") == 0) continue; - auto addQuotes = argv[i][0] != '\"' && strchr(argv[i], ' ') != nullptr; + auto addQuotes = argv[i][0] != L'\"' && wcschr(argv[i], L' ') != nullptr; if (addQuotes) { - args += '\"'; + args += L'\"'; } args += argv[i]; if (addQuotes) { - args += '\"'; + args += L'\"'; } - args += ' '; + args += L' '; } // Re-run the process with the runas verb DWORD code = 2; - SHELLEXECUTEINFOA info = {}; + SHELLEXECUTEINFO info = {}; info.cbSize = sizeof(info); info.fMask = SEE_MASK_NOCLOSEPROCESS; // return info.hProcess for explicit wait - info.lpVerb = "runas"; + info.lpVerb = L"runas"; info.lpFile = exe_path; info.lpParameters = args.c_str(); info.nShow = SW_SHOWDEFAULT; - auto ok = ShellExecuteExA(&info); + auto ok = ShellExecuteEx(&info); if (ok) { WaitForSingleObject(info.hProcess, INFINITE); GetExitCodeProcess(info.hProcess, &code); diff --git a/PresentMon/TraceSession.cpp b/PresentMon/TraceSession.cpp index 7bdf494a..89c95833 100644 --- a/PresentMon/TraceSession.cpp +++ b/PresentMon/TraceSession.cpp @@ -43,12 +43,12 @@ bool StartTraceSession() if (status == ERROR_ALREADY_EXISTS) { if (args.mStopExistingSession) { PrintWarning( - "warning: a trace session named \"%s\" is already running and it will be stopped.\n" + "warning: a trace session named \"%ws\" is already running and it will be stopped.\n" " Use -session_name with a different name to start a new session.", args.mSessionName); } else { PrintError( - "error: a trace session named \"%s\" is already running. Use -stop_existing_session\n" + "error: a trace session named \"%ws\" is already running. Use -stop_existing_session\n" " to stop the existing session, or use -session_name with a different name to\n" " start a new session.", args.mSessionName); From ad59d2e0dac81f99f50aa2c5b23282be414200c6 Mon Sep 17 00:00:00 2001 From: Martin Malik Date: Tue, 12 Dec 2023 22:41:29 +0100 Subject: [PATCH 3/4] Changes requested --- PresentData/PresentMonTraceConsumer.cpp | 3 ++- PresentData/TraceSession.cpp | 10 +++++----- PresentData/TraceSession.hpp | 6 +++--- PresentMon/CommandLine.cpp | 24 ++++++++++++------------ PresentMon/CsvOutput.cpp | 14 +++++++------- PresentMon/LateStageReprojectionData.cpp | 12 ++++++------ PresentMon/LateStageReprojectionData.hpp | 2 +- PresentMon/MainThread.cpp | 2 +- PresentMon/OutputThread.cpp | 6 +++--- PresentMon/PresentMon.hpp | 10 +++++----- PresentMon/Privilege.cpp | 4 ++-- 11 files changed, 47 insertions(+), 46 deletions(-) diff --git a/PresentData/PresentMonTraceConsumer.cpp b/PresentData/PresentMonTraceConsumer.cpp index 634cc3f8..bdfaadda 100644 --- a/PresentData/PresentMonTraceConsumer.cpp +++ b/PresentData/PresentMonTraceConsumer.cpp @@ -2215,7 +2215,8 @@ void PMTraceConsumer::HandleProcessEvent(EVENT_RECORD* pEventRecord) }; mMetadata.GetEventData(pEventRecord, desc, _countof(desc)); event.ProcessId = desc[0].GetData(); - event.ImageFileName = desc[1].GetData(); + std::string str = desc[1].GetData(); + event.ImageFileName = std::wstring(str.begin(), str.end()); event.IsStartEvent = true; } else if (hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_END|| hdr.EventDescriptor.Opcode == EVENT_TRACE_TYPE_DC_END) { diff --git a/PresentData/TraceSession.cpp b/PresentData/TraceSession.cpp index f80706dd..3b98c92a 100644 --- a/PresentData/TraceSession.cpp +++ b/PresentData/TraceSession.cpp @@ -480,8 +480,8 @@ ULONG CALLBACK BufferCallback(EVENT_TRACE_LOGFILE* pLogFile) ULONG TraceSession::Start( PMTraceConsumer* pmConsumer, MRTraceConsumer* mrConsumer, - WCHAR const* etlPath, - WCHAR const* sessionName) + wchar_t const* etlPath, + wchar_t const* sessionName) { assert(mSessionHandle == 0); assert(mTraceHandle == INVALID_PROCESSTRACE_HANDLE); @@ -493,7 +493,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // Configure trace properties EVENT_TRACE_LOGFILE traceProps = {}; - traceProps.LogFileName = (WCHAR*) etlPath; + traceProps.LogFileName = (wchar_t*) etlPath; traceProps.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP; traceProps.Context = this; /* Output members (passed also to BufferCallback): @@ -523,7 +523,7 @@ ULONG TraceSession::Start( // ------------------------------------------------------------------------- // For realtime collection, start the session with the required providers if (traceProps.LogFileName == nullptr) { - traceProps.LoggerName = (WCHAR*) sessionName; + traceProps.LoggerName = (wchar_t*) sessionName; traceProps.ProcessTraceMode |= PROCESS_TRACE_MODE_REAL_TIME; TraceProperties sessionProps = {}; @@ -646,7 +646,7 @@ void TraceSession::Stop() } } -ULONG TraceSession::StopNamedSession(WCHAR const* sessionName) +ULONG TraceSession::StopNamedSession(wchar_t const* sessionName) { TraceProperties sessionProps = {}; sessionProps.Wnode.BufferSize = (ULONG) sizeof(TraceProperties); diff --git a/PresentData/TraceSession.hpp b/PresentData/TraceSession.hpp index 8990552c..4653606d 100644 --- a/PresentData/TraceSession.hpp +++ b/PresentData/TraceSession.hpp @@ -17,11 +17,11 @@ struct TraceSession { ULONG Start( PMTraceConsumer* pmConsumer, // Required PMTraceConsumer instance MRTraceConsumer* mrConsumer, // If nullptr, no WinMR tracing - WCHAR const* etlPath, // If nullptr, live/realtime tracing session - WCHAR const* sessionName); // Required session name + wchar_t const* etlPath, // If nullptr, live/realtime tracing session + wchar_t const* sessionName); // Required session name void Stop(); ULONG CheckLostReports(ULONG* eventsLost, ULONG* buffersLost) const; - static ULONG StopNamedSession(WCHAR const* sessionName); + static ULONG StopNamedSession(wchar_t const* sessionName); }; diff --git a/PresentMon/CommandLine.cpp b/PresentMon/CommandLine.cpp index 26fdc633..f7b5c459 100644 --- a/PresentMon/CommandLine.cpp +++ b/PresentMon/CommandLine.cpp @@ -18,7 +18,7 @@ enum { struct KeyNameCode { - WCHAR const* mName; + wchar_t const* mName; UINT mCode; }; @@ -142,7 +142,7 @@ size_t GetConsoleWidth() : std::max(DEFAULT_CONSOLE_WIDTH, info.srWindow.Right - info.srWindow.Left + 1); } -bool ParseKeyName(KeyNameCode const* valid, size_t validCount, WCHAR* name, char const* errorMessage, UINT* outKeyCode) +bool ParseKeyName(KeyNameCode const* valid, size_t validCount, wchar_t* name, char const* errorMessage, UINT* outKeyCode) { for (size_t i = 0; i < validCount; ++i) { if (_wcsicmp(name, valid[i].mName) == 0) { @@ -166,7 +166,7 @@ bool ParseKeyName(KeyNameCode const* valid, size_t validCount, WCHAR* name, char return false; } -bool AssignHotkey(WCHAR* key, CommandLineArgs* args) +bool AssignHotkey(wchar_t* key, CommandLineArgs* args) { #pragma warning(suppress: 4996) auto token = wcstok(key, L"+"); @@ -203,7 +203,7 @@ void SetCaptureAll(CommandLineArgs* args) } // Allow /ARG, -ARG, or --ARG -bool ParseArgPrefix(WCHAR** arg) +bool ParseArgPrefix(wchar_t** arg) { if (**arg == '/') { *arg += 1; @@ -221,14 +221,14 @@ bool ParseArgPrefix(WCHAR** arg) return false; } -bool ParseArg(WCHAR* arg, WCHAR const* option) +bool ParseArg(wchar_t* arg, wchar_t const* option) { return ParseArgPrefix(&arg) && _wcsicmp(arg, option) == 0; } -bool ParseValue(WCHAR** argv, int argc, int* i) +bool ParseValue(wchar_t** argv, int argc, int* i) { if (*i + 1 < argc) { *i += 1; @@ -238,24 +238,24 @@ bool ParseValue(WCHAR** argv, int argc, int* i) return false; } -bool ParseValue(WCHAR** argv, int argc, int* i, WCHAR const** value) +bool ParseValue(wchar_t** argv, int argc, int* i, wchar_t const** value) { if (!ParseValue(argv, argc, i)) return false; *value = argv[*i]; return true; } -bool ParseValue(WCHAR** argv, int argc, int* i, std::vector* value) +bool ParseValue(wchar_t** argv, int argc, int* i, std::vector* value) { - WCHAR const* v = nullptr; + wchar_t const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; value->emplace_back(v); return true; } -bool ParseValue(WCHAR** argv, int argc, int* i, UINT* value) +bool ParseValue(wchar_t** argv, int argc, int* i, UINT* value) { - WCHAR const* v = nullptr; + wchar_t const* v = nullptr; if (!ParseValue(argv, argc, i, &v)) return false; *value = wcstoul(v, nullptr, 10); return true; @@ -315,7 +315,7 @@ CommandLineArgs const& GetCommandLineArgs() return gCommandLineArgs; } -bool ParseCommandLine(int argc, WCHAR** argv) +bool ParseCommandLine(int argc, wchar_t** argv) { auto args = &gCommandLineArgs; diff --git a/PresentMon/CsvOutput.cpp b/PresentMon/CsvOutput.cpp index 35b78e96..bd969248 100644 --- a/PresentMon/CsvOutput.cpp +++ b/PresentMon/CsvOutput.cpp @@ -224,11 +224,11 @@ with `-INDEX` appended to the file name. If `-include_mixed_reality` is used, a second CSV file will be generated with `_WMR` appended to the filename containing the WMR data. */ -static void GenerateFilename(WCHAR* path, WCHAR const* processName, uint32_t processId) +static void GenerateFilename(wchar_t* path, wchar_t const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); - WCHAR ext[_MAX_EXT]; + wchar_t ext[_MAX_EXT]; int pathLength = MAX_PATH; #define ADD_TO_PATH(...) do { \ @@ -240,9 +240,9 @@ static void GenerateFilename(WCHAR* path, WCHAR const* processName, uint32_t pro // Generate base filename. if (args.mOutputCsvFileName) { - WCHAR drive[_MAX_DRIVE]; - WCHAR dir[_MAX_DIR]; - WCHAR name[_MAX_FNAME]; + wchar_t drive[_MAX_DRIVE]; + wchar_t dir[_MAX_DIR]; + wchar_t name[_MAX_FNAME]; _wsplitpath_s(args.mOutputCsvFileName, drive, dir, name, ext); ADD_TO_PATH(L"%s%s%s", drive, dir, name); } else { @@ -272,7 +272,7 @@ static void GenerateFilename(WCHAR* path, WCHAR const* processName, uint32_t pro #undef ADD_TO_PATH } -static OutputCsv CreateOutputCsv(WCHAR const* processName, uint32_t processId) +static OutputCsv CreateOutputCsv(wchar_t const* processName, uint32_t processId) { auto const& args = GetCommandLineArgs(); @@ -282,7 +282,7 @@ static OutputCsv CreateOutputCsv(WCHAR const* processName, uint32_t processId) outputCsv.mFile = stdout; outputCsv.mWmrFile = nullptr; // WMR disallowed if -output_stdout } else { - WCHAR path[MAX_PATH]; + wchar_t path[MAX_PATH]; GenerateFilename(path, processName, processId); _wfopen_s(&outputCsv.mFile, path, L"w"); diff --git a/PresentMon/LateStageReprojectionData.cpp b/PresentMon/LateStageReprojectionData.cpp index 0cf5068c..a0945514 100644 --- a/PresentMon/LateStageReprojectionData.cpp +++ b/PresentMon/LateStageReprojectionData.cpp @@ -182,18 +182,18 @@ LateStageReprojectionRuntimeStats LateStageReprojectionData::ComputeRuntimeStats return stats; } -FILE* CreateLsrCsvFile(WCHAR const* path) +FILE* CreateLsrCsvFile(wchar_t const* path) { auto const& args = GetCommandLineArgs(); // Add _WMR to the file name - WCHAR drive[_MAX_DRIVE]; - WCHAR dir[_MAX_DIR]; - WCHAR name[_MAX_FNAME]; - WCHAR ext[_MAX_EXT]; + wchar_t drive[_MAX_DRIVE]; + wchar_t dir[_MAX_DIR]; + wchar_t name[_MAX_FNAME]; + wchar_t ext[_MAX_EXT]; _wsplitpath_s(path, drive, dir, name, ext); - WCHAR outputPath[MAX_PATH] = {}; + wchar_t outputPath[MAX_PATH] = {}; _snwprintf_s(outputPath, _TRUNCATE, L"%s%s%s_WMR%s", drive, dir, name, ext); // Open output file diff --git a/PresentMon/LateStageReprojectionData.hpp b/PresentMon/LateStageReprojectionData.hpp index a26f7ea9..7bf6d871 100644 --- a/PresentMon/LateStageReprojectionData.hpp +++ b/PresentMon/LateStageReprojectionData.hpp @@ -85,6 +85,6 @@ struct LateStageReprojectionData { double ComputeHistoryTime(const std::deque& lsrHistory) const; }; -FILE* CreateLsrCsvFile(WCHAR const* path); +FILE* CreateLsrCsvFile(wchar_t const* path); void UpdateLsrCsv(LateStageReprojectionData& lsr, ProcessInfo* proc, LateStageReprojectionEvent& p); void UpdateConsole(std::unordered_map const& activeProcesses, LateStageReprojectionData& lsr); diff --git a/PresentMon/MainThread.cpp b/PresentMon/MainThread.cpp index 707b9b2a..d41ba05c 100644 --- a/PresentMon/MainThread.cpp +++ b/PresentMon/MainThread.cpp @@ -172,7 +172,7 @@ void ExitMainThread() PostMessage(gWnd, WM_QUIT, 0, 0); } -int wmain(int argc, WCHAR** argv) +int wmain(int argc, wchar_t** argv) { // Load system DLLs LoadLibraryExA("advapi32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); diff --git a/PresentMon/OutputThread.cpp b/PresentMon/OutputThread.cpp index e6972da5..fc5807e7 100644 --- a/PresentMon/OutputThread.cpp +++ b/PresentMon/OutputThread.cpp @@ -99,7 +99,7 @@ void CanonicalizeProcessName(std::wstring* name) *name = name->substr(i + 1); std::transform(name->begin(), name->end(), name->begin(), - [](WCHAR c) { return (WCHAR) ::towlower(c); }); + [](wchar_t c) { return (wchar_t) ::towlower(c); }); } static bool IsTargetProcess(uint32_t processId, std::wstring const& processName) @@ -168,9 +168,9 @@ static ProcessInfo* GetProcessInfo(uint32_t processId) // another account, unless we're running with SeDebugPrivilege. auto const& args = GetCommandLineArgs(); HANDLE handle = NULL; - WCHAR const* processName = L""; + wchar_t const* processName = L""; if (args.mEtlFileName == nullptr) { - WCHAR path[MAX_PATH]; + wchar_t path[MAX_PATH]; DWORD numChars = _countof(path); handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); if (QueryFullProcessImageName(handle, 0, path, &numChars)) { diff --git a/PresentMon/PresentMon.hpp b/PresentMon/PresentMon.hpp index 33c34d03..c39e57fc 100644 --- a/PresentMon/PresentMon.hpp +++ b/PresentMon/PresentMon.hpp @@ -44,9 +44,9 @@ enum class ConsoleOutput { struct CommandLineArgs { std::vector mTargetProcessNames; std::vector mExcludeProcessNames; - const WCHAR *mOutputCsvFileName; - const WCHAR *mEtlFileName; - const WCHAR *mSessionName; + const wchar_t *mOutputCsvFileName; + const wchar_t *mEtlFileName; + const wchar_t *mSessionName; UINT mTargetPid; UINT mDelay; UINT mTimer; @@ -104,7 +104,7 @@ struct ProcessInfo { #include "LateStageReprojectionData.hpp" // CommandLine.cpp: -bool ParseCommandLine(int argc, WCHAR** argv); +bool ParseCommandLine(int argc, wchar_t** argv); CommandLineArgs const& GetCommandLineArgs(); // Console.cpp: @@ -144,7 +144,7 @@ void CanonicalizeProcessName(std::wstring* path); // Privilege.cpp: bool InPerfLogUsersGroup(); bool EnableDebugPrivilege(); -int RestartAsAdministrator(int argc, WCHAR** argv); +int RestartAsAdministrator(int argc, wchar_t** argv); // TraceSession.cpp: bool StartTraceSession(); diff --git a/PresentMon/Privilege.cpp b/PresentMon/Privilege.cpp index 60b0a7a7..0472bed9 100644 --- a/PresentMon/Privilege.cpp +++ b/PresentMon/Privilege.cpp @@ -69,10 +69,10 @@ bool EnableDebugPrivilege() int RestartAsAdministrator( int argc, - WCHAR** argv) + wchar_t** argv) { // Get the exe path - WCHAR exe_path[MAX_PATH] = {}; + wchar_t exe_path[MAX_PATH] = {}; GetModuleFileName(NULL, exe_path, _countof(exe_path)); // Combine arguments into single string and remove -restart_as_admin to From afbdf35b13227fb186d402311dfa70301c6fced7 Mon Sep 17 00:00:00 2001 From: Martin Malik Date: Fri, 8 Mar 2024 19:37:04 +0100 Subject: [PATCH 4/4] Fix memory leak --- PresentData/GpuTrace.cpp | 10 ++++++++++ PresentData/GpuTrace.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/PresentData/GpuTrace.cpp b/PresentData/GpuTrace.cpp index 7076366f..d652f413 100644 --- a/PresentData/GpuTrace.cpp +++ b/PresentData/GpuTrace.cpp @@ -75,6 +75,16 @@ GpuTrace::GpuTrace(PMTraceConsumer* pmConsumer) { } +GpuTrace::~GpuTrace() +{ + for (auto& pair : mContexts) { + auto context = pair.second; + if(context.mIsHwQueue) { + delete context.mNode; + } + } +} + void GpuTrace::RegisterDevice(uint64_t hDevice, uint64_t pDxgAdapter) { // Sometimes there are duplicate start events diff --git a/PresentData/GpuTrace.hpp b/PresentData/GpuTrace.hpp index 5aed1bc2..f4c900d1 100644 --- a/PresentData/GpuTrace.hpp +++ b/PresentData/GpuTrace.hpp @@ -75,6 +75,7 @@ class GpuTrace { public: explicit GpuTrace(PMTraceConsumer* pmConsumer); + ~GpuTrace(); void RegisterDevice(uint64_t hDevice, uint64_t pDxgAdapter); void UnregisterDevice(uint64_t hDevice);