|
| 1 | +Process Info |
| 2 | +=== |
| 3 | + |
| 4 | +# Background |
| 5 | +Provide end developer a new API to get all browser and child process ID with its type. End developers can use this API to track performance more closely, instead of using the task manager API to gather this information which requires a lot of preset. The process list provides all processes under the same user data folder, processes from multiple WebView creations will also be collected. |
| 6 | +Note: Crashpad process is not captured. |
| 7 | + |
| 8 | +# Examples |
| 9 | +## WinRT and .NET |
| 10 | +```c# |
| 11 | +IReadOnlyList<CoreWebView2ProcessInfo> _processList = new List<CoreWebView2ProcessInfo>(); |
| 12 | + |
| 13 | +void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) |
| 14 | +{ |
| 15 | + if (e.IsSuccess) |
| 16 | + { |
| 17 | + // ... |
| 18 | + webView.CoreWebView2.Environment.ProcessInfosChanged += WebView_ProcessInfosChanged; |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +void WebView_ProcessInfosChanged(object sender, object e) |
| 23 | +{ |
| 24 | + _processList = webView.CoreWebView2.Environment.GetProcessInfos(); |
| 25 | +} |
| 26 | + |
| 27 | +void PerfInfoCmdExecuted(object target, ExecutedRoutedEventArgs e) |
| 28 | +{ |
| 29 | + string result; |
| 30 | + int processListCount = _processList.Count; |
| 31 | + if (processListCount == 0) |
| 32 | + { |
| 33 | + result = "No process found."; |
| 34 | + } |
| 35 | + else |
| 36 | + { |
| 37 | + result = $"{processListCount} child process(s) found\n\n"; |
| 38 | + for (int i = 0; i < processListCount; ++i) |
| 39 | + { |
| 40 | + uint processId = _processList[i].ProcessId; |
| 41 | + CoreWebView2ProcessKind kind = _processList[i].Kind; |
| 42 | + |
| 43 | + var proc = Process.GetProcessById((int)processId); |
| 44 | + var memoryInBytes = proc.PrivateMemorySize64; |
| 45 | + var b2kb = memoryInBytes / 1024; |
| 46 | + result = result + $"Process ID: {processId} | Process Kind: {kind} | Memory: {b2kb} KB\n"; |
| 47 | + } |
| 48 | + } |
| 49 | + |
| 50 | + MessageBox.Show(this, result, "Process List"); |
| 51 | +} |
| 52 | +``` |
| 53 | +## Win32 C++ |
| 54 | +```cpp |
| 55 | +ProcessComponent::ProcessComponent(AppWindow* appWindow) |
| 56 | + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) |
| 57 | +{ |
| 58 | + // Register a handler for the ProcessInfosChanged event. |
| 59 | + //! [ProcessInfosChanged] |
| 60 | + wil::com_ptr<ICoreWebView2Environment> environment = appWindow->GetWebViewEnvironment(); |
| 61 | + CHECK_FAILURE(environment->GetProcessInfos(&m_processCollection)); |
| 62 | + CHECK_FAILURE(environment->add_ProcessInfosChanged( |
| 63 | + Callback<ICoreWebView2ProcessInfosChangedEventHandler>( |
| 64 | + [this](ICoreWebView2Environment* sender, IUnknown* args) -> HRESULT { |
| 65 | + CHECK_FAILURE(sender->GetProcessInfos(&m_processCollection)); |
| 66 | + |
| 67 | + return S_OK; |
| 68 | + }) |
| 69 | + .Get(), |
| 70 | + &m_processInfosChangedToken)); |
| 71 | + //! [ProcessInfosChanged] |
| 72 | +} |
| 73 | + |
| 74 | +std::wstring ProcessComponent::ProcessKindToString(const COREWEBVIEW2_PROCESS_KIND kind) |
| 75 | +{ |
| 76 | + switch (kind) |
| 77 | + { |
| 78 | +#define KIND_ENTRY(kindValue) \ |
| 79 | + case kindValue: \ |
| 80 | + return L#kindValue; |
| 81 | + |
| 82 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_BROWSER); |
| 83 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_RENDERER); |
| 84 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_UTILITY); |
| 85 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_SANDBOX_HELPER); |
| 86 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_GPU); |
| 87 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_PPAPI_PLUGIN); |
| 88 | + KIND_ENTRY(COREWEBVIEW2_PROCESS_KIND_PPAPI_BROKER); |
| 89 | + |
| 90 | +#undef KIND_ENTRY |
| 91 | + } |
| 92 | + |
| 93 | + return L"PROCESS KIND: " + std::to_wstring(static_cast<uint32_t>(kind)); |
| 94 | +} |
| 95 | + |
| 96 | +// Get the process info |
| 97 | +//! [ProcessInfosChanged] |
| 98 | +void ProcessComponent::PerformanceInfo() |
| 99 | +{ |
| 100 | + std::wstring result; |
| 101 | + UINT processListCount; |
| 102 | + CHECK_FAILURE(m_processCollection->get_Count(&processListCount)); |
| 103 | + |
| 104 | + if (processListCount == 0) |
| 105 | + { |
| 106 | + result += L"No process found."; |
| 107 | + } |
| 108 | + else |
| 109 | + { |
| 110 | + result += std::to_wstring(processListCount) + L" process(s) found"; |
| 111 | + result += L"\n\n"; |
| 112 | + for (UINT i = 0; i < processListCount; ++i) |
| 113 | + { |
| 114 | + wil::com_ptr<ICoreWebView2StagingProcessInfo> processInfo; |
| 115 | + CHECK_FAILURE(m_processCollection->GetValueAtIndex(i, &processInfo)); |
| 116 | + |
| 117 | + INT32 processId = 0; |
| 118 | + COREWEBVIEW2_PROCESS_KIND kind; |
| 119 | + CHECK_FAILURE(processInfo->get_ProcessId(&processId)); |
| 120 | + CHECK_FAILURE(processInfo->get_Kind(&kind)); |
| 121 | + |
| 122 | + WCHAR id[4096] = L""; |
| 123 | + StringCchPrintf(id, ARRAYSIZE(id), L"Process ID: %u", processId); |
| 124 | + |
| 125 | + HANDLE processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); |
| 126 | + PROCESS_MEMORY_COUNTERS_EX pmc; |
| 127 | + GetProcessMemoryInfo( |
| 128 | + processHandle, reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), sizeof(pmc)); |
| 129 | + SIZE_T virtualMemUsed = pmc.PrivateUsage / 1024; |
| 130 | + WCHAR memory[4096] = L""; |
| 131 | + StringCchPrintf(memory, ARRAYSIZE(memory), L"Memory: %u", virtualMemUsed); |
| 132 | + CloseHandle(processHandle); |
| 133 | + |
| 134 | + result = result + id + L" | Process Kind: " + ProcessKindToString(kind) + L" | " + |
| 135 | + memory + L" KB\n"; |
| 136 | + } |
| 137 | + } |
| 138 | + MessageBox(nullptr, result.c_str(), L"Memory Usage", MB_OK); |
| 139 | +} |
| 140 | +//! [ProcessInfoChanged] |
| 141 | +``` |
| 142 | +
|
| 143 | +# API Details |
| 144 | +``` |
| 145 | +interface ICoreWebView2Environment6; |
| 146 | +interface ICoreWebView2ProcessInfo; |
| 147 | +interface ICoreWebView2ProcessInfoCollection; |
| 148 | +interface ICoreWebView2ProcessInfosChangedEventHandler; |
| 149 | + |
| 150 | +[v1_enum] |
| 151 | +typedef enum COREWEBVIEW2_PROCESS_KIND { |
| 152 | + /// Indicates the browser process kind. |
| 153 | + COREWEBVIEW2_PROCESS_KIND_BROWSER, |
| 154 | + |
| 155 | + /// Indicates the render process kind. |
| 156 | + COREWEBVIEW2_PROCESS_KIND_RENDERER, |
| 157 | + |
| 158 | + /// Indicates the utility process kind. |
| 159 | + COREWEBVIEW2_PROCESS_KIND_UTILITY, |
| 160 | + |
| 161 | + /// Indicates the sandbox helper process kind. |
| 162 | + COREWEBVIEW2_PROCESS_KIND_SANDBOX_HELPER, |
| 163 | + |
| 164 | + /// Indicates the GPU process kind. |
| 165 | + COREWEBVIEW2_PROCESS_KIND_GPU, |
| 166 | + |
| 167 | + /// Indicates the PPAPI plugin process kind. |
| 168 | + COREWEBVIEW2_PROCESS_KIND_PPAPI_PLUGIN, |
| 169 | + |
| 170 | + /// Indicates the PPAPI plugin broker process kind. |
| 171 | + COREWEBVIEW2_PROCESS_KIND_PPAPI_BROKER, |
| 172 | +} COREWEBVIEW2_PROCESS_KIND; |
| 173 | + |
| 174 | +[uuid(20856F87-256B-41BE-BD64-AB1C36E3D944), object, pointer_default(unique)] |
| 175 | +interface ICoreWebView2Environment6 : ICoreWebView2Environment5 |
| 176 | +{ |
| 177 | + /// Adds an event handler for the `ProcessInfosChanged` event. |
| 178 | + /// |
| 179 | + /// \snippet ProcessComponent.cpp ProcessInfosChanged |
| 180 | + HRESULT add_ProcessInfosChanged( |
| 181 | + [in] ICoreWebView2ProcessInfosChangedEventHandler* eventHandler, |
| 182 | + [out] EventRegistrationToken* token); |
| 183 | + |
| 184 | + /// Remove an event handler previously added with `add_ProcessInfosChanged`. |
| 185 | + HRESULT remove_ProcessInfosChanged( |
| 186 | + [in] EventRegistrationToken token); |
| 187 | + |
| 188 | + /// Returns the `ICoreWebView2ProcessInfoCollection` |
| 189 | + /// Provide a list of all process using same user data folder. |
| 190 | + HRESULT GetProcessInfos([out, retval]ICoreWebView2ProcessInfoCollection** value); |
| 191 | +} |
| 192 | + |
| 193 | +/// Provides a set of properties for a process in the `ICoreWebView2Environment`. |
| 194 | +[uuid(7798D399-52A1-4823-AD6A-1F3EDD74B0B6), object, pointer_default(unique)] |
| 195 | +interface ICoreWebView2ProcessInfo : IUnknown { |
| 196 | + |
| 197 | + /// The process id of the process. |
| 198 | + [propget] HRESULT ProcessId([out, retval] INT32* value); |
| 199 | + |
| 200 | + /// The kind of the process. |
| 201 | + [propget] HRESULT Kind([out, retval] COREWEBVIEW2_PROCESS_KIND* kind); |
| 202 | +} |
| 203 | + |
| 204 | +/// A list containing process id and corresponding process type. |
| 205 | +[uuid(5356F3B3-4859-4763-9C95-837CDEEE8912), object, pointer_default(unique)] |
| 206 | +interface ICoreWebView2ProcessInfoCollection : IUnknown { |
| 207 | + /// The number of process contained in the ICoreWebView2ProcessInfoCollection. |
| 208 | + [propget] HRESULT Count([out, retval] UINT* count); |
| 209 | + |
| 210 | + /// Gets the `ICoreWebView2ProcessInfo` located in the `ICoreWebView2ProcessInfoCollection` |
| 211 | + /// at the given index. |
| 212 | + HRESULT GetValueAtIndex([in] UINT32 index, |
| 213 | + [out, retval] ICoreWebView2ProcessInfo** processInfo); |
| 214 | +} |
| 215 | + |
| 216 | +/// An event handler for the `ProcessInfosChanged` event. |
| 217 | +[uuid(CFF13C72-2E3B-4812-96FB-DFDDE67FBE90), object, pointer_default(unique)] |
| 218 | +interface ICoreWebView2ProcessInfosChangedEventHandler : IUnknown { |
| 219 | + /// Provides the event args for the corresponding event. No event args exist |
| 220 | + /// and the `args` parameter is set to `null`. |
| 221 | + HRESULT Invoke([in] ICoreWebView2* sender, [in] IUnknown* args); |
| 222 | +} |
| 223 | +``` |
| 224 | +
|
| 225 | +```c# (but really MIDL3) |
| 226 | +namespace Microsoft.Web.WebView2.Core |
| 227 | +{ |
| 228 | + // ... |
| 229 | + runtimeclass CoreWebView2ProcessInfo; |
| 230 | +
|
| 231 | + /// Kind of process type used in the CoreWebView2ProcessInfoCollection. |
| 232 | + enum CoreWebView2ProcessKind |
| 233 | + { |
| 234 | + Browser = 0, |
| 235 | + Renderer = 1, |
| 236 | + Utility = 2, |
| 237 | + SandboxHelper = 3, |
| 238 | + Gpu = 4, |
| 239 | + PpapiPlugin = 5, |
| 240 | + PpapiBroker = 6, |
| 241 | + }; |
| 242 | +
|
| 243 | + runtimeclass CoreWebView2ProcessInfo |
| 244 | + { |
| 245 | + // ICoreWebView2ProcessInfo members |
| 246 | + Int32 ProcessId { get; }; |
| 247 | +
|
| 248 | + CoreWebView2ProcessKind Kind { get; }; |
| 249 | + } |
| 250 | +
|
| 251 | + runtimeclass CoreWebView2Environment |
| 252 | + { |
| 253 | + /// Gets a list of process. |
| 254 | + IVectorView<CoreWebView2ProcessInfo> GetProcessInfos(); |
| 255 | + event Windows.Foundation.TypedEventHandler<CoreWebView2Environment, Object> ProcessInfosChanged; |
| 256 | +
|
| 257 | + // ... |
| 258 | + } |
| 259 | +
|
| 260 | + // ... |
| 261 | +} |
| 262 | +``` |
| 263 | + |
0 commit comments