File: desktop_capture_devices_util_win.cc

package info (click to toggle)
chromium 140.0.7339.127-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,192,880 kB
  • sloc: cpp: 35,093,808; ansic: 7,161,670; javascript: 4,199,694; python: 1,441,797; asm: 949,904; xml: 747,503; pascal: 187,748; perl: 88,691; sh: 88,248; objc: 79,953; sql: 52,714; cs: 44,599; fortran: 24,137; makefile: 22,114; tcl: 15,277; php: 13,980; yacc: 9,000; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (159 lines) | stat: -rw-r--r-- 6,003 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media/webrtc/desktop_capture_devices_util_win.h"

#include <windows.h>

#include <array>

#include "base/base_paths_win.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/process/process_handle.h"
#include "base/win/scoped_handle.h"
#include "base/win/window_enumerator.h"
#include "base/win/windows_types.h"

namespace {

bool IsUWPApp(const base::FilePath& app_path) {
  base::FilePath system_path;
  if (!base::PathService::Get(base::DIR_SYSTEM, &system_path)) {
    return false;
  }

  // The ApplicationFrameHost.exe is the host process for UWP apps. It is
  // located in the system directory (usually C:\Windows\System32).
  if (base::FilePath::CompareEqualIgnoreCase(system_path.value(),
                                             app_path.DirName().value()) &&
      base::FilePath::CompareEqualIgnoreCase(app_path.BaseName().value(),
                                             L"ApplicationFrameHost.exe")) {
    return true;
  }

  return false;
}

// Callback to be provided to `base::win::EnumerateChildWindows` to find the
// child window of the UWP app with the "Windows.UI.Core.CoreWindow" class name.
// When the target window is found, this function should return `true`,
// signaling to `base::win::EnumerateChildWindows` that it should stop
// enumerating and store the found window handle in `out_uwp_app_core_window`.
// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms633493(v=vs.85)
bool IsUWPAppCoreWindow(HWND& out_uwp_app_core_window, HWND hwnd) {
  std::wstring class_name = base::win::GetWindowClass(hwnd);
  // Check if the class name matches the UWP app's core window class name.
  if (class_name == L"Windows.UI.Core.CoreWindow") {
    out_uwp_app_core_window = hwnd;
    return true;
  }

  return false;
}

// Given a window handle `hwnd` for a UWP app, finds the pid of the app's main
// process.
base::ProcessId GetUWPAppCoreWindowProcessId(HWND hwnd) {
  HWND main_uwp_app_core_window = nullptr;

  // For UWP apps, we need to find the child window which has the class name
  // Windows.UI.Core.CoreWindow and get the process ID from it.
  base::win::EnumerateChildWindows(
      hwnd, base::BindRepeating(&IsUWPAppCoreWindow,
                                std::ref(main_uwp_app_core_window)));
  // There is no child window with the class name Windows.UI.Core.CoreWindow.
  if (!main_uwp_app_core_window) {
    return base::kNullProcessId;
  }

  DWORD main_process_id;
  DWORD thread_id =
      GetWindowThreadProcessId(main_uwp_app_core_window, &main_process_id);
  if (!thread_id || !main_process_id) {
    return base::kNullProcessId;
  }

  return main_process_id;
}

// Returns the executable's path for the given process handle.
base::FilePath GetProcessExecutablePath(HANDLE process_handle) {
  std::wstring image_path(MAX_PATH, L'\0');
  DWORD path_length = image_path.size();
  BOOL success = QueryFullProcessImageNameW(process_handle, 0,
                                            image_path.data(), &path_length);
  if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
    // Process name is potentially greater than MAX_PATH, try larger max size.
    // https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
    image_path.resize(UNICODE_STRING_MAX_CHARS);
    path_length = image_path.size();
    success = QueryFullProcessImageName(process_handle, 0, image_path.data(),
                                        &path_length);
    if (!success) {
      return base::FilePath();
    }
  }

  return base::FilePath(image_path);
}

}  // namespace

base::ProcessId GetAppMainProcessId(intptr_t window_id) {
  HWND hwnd = reinterpret_cast<HWND>(window_id);
  DWORD process_id;
  DWORD thread_id = GetWindowThreadProcessId(hwnd, &process_id);
  if (!thread_id || !process_id) {
    return base::kNullProcessId;
  }

  base::win::ScopedHandle process_handle(
      OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
                  /*bInheritHandle=*/FALSE, process_id));
  if (!process_handle.is_valid()) {
    return base::kNullProcessId;
  }

  // UWP apps' UI follow a hierarchy where the top-level window is created by
  // ApplicationFrameHost.exe and the actual app window is a child window of the
  // top-level window. Therefore, in this situation, we need to look down in the
  // window hierarchy to find the correct process id.
  base::FilePath app_path = GetProcessExecutablePath(process_handle.get());
  // Checks if process is a UWP app.
  if (IsUWPApp(app_path)) {
    return GetUWPAppCoreWindowProcessId(hwnd);
  }

  base::ProcessId main_process_id_candidate = process_id;
  base::ProcessId parent_id = base::GetParentProcessId(process_handle.get());
  if (parent_id <= 0) {
    // If there is no parent process, we return the current process id.
    return main_process_id_candidate;
  }

  base::win::ScopedHandle parent_process_handle(OpenProcess(
      PROCESS_QUERY_LIMITED_INFORMATION, /*bInheritHandle=*/FALSE, parent_id));
  while (parent_process_handle.is_valid()) {
    base::FilePath parent_path =
        GetProcessExecutablePath(parent_process_handle.get());
    if (parent_path.empty()) {
      return main_process_id_candidate;
    }

    // If the executables are different, we return the last PID whose executable
    // was the same as `app_path`
    if (!base::FilePath::CompareEqualIgnoreCase(parent_path.value(),
                                                app_path.value())) {
      return main_process_id_candidate;
    }

    main_process_id_candidate = parent_id;
    parent_id = base::GetParentProcessId(parent_process_handle.Get());
    parent_process_handle.Set(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
                                          /*bInheritHandle=*/FALSE, parent_id));
  }

  return main_process_id_candidate;
}