1b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org/*
2b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *
4b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  Use of this source code is governed by a BSD-style license
5b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  that can be found in the LICENSE file in the root of the source
6b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  tree. An additional intellectual property rights grant can be found
7b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  in the file PATENTS.  All contributing project authors may
8b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  be found in the AUTHORS file in the root of the source tree.
9b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org */
10b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
11b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/window_capturer.h"
12b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1312dc1a38ca54a000e4fecfbc6d41138b895c9ca5pbos@webrtc.org#include <assert.h>
14b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1500b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org#include "webrtc/base/scoped_ptr.h"
16371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou#include "webrtc/base/checks.h"
17047abc93a24134d59b8feb895bbd7597e1aef4cdjiayl@webrtc.org#include "webrtc/base/win32.h"
18b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
19c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
2098f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/logging.h"
21b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
22b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace webrtc {
23b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
24b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace {
25b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
26b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgBOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
27b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturer::WindowList* list =
28b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org      reinterpret_cast<WindowCapturer::WindowList*>(param);
29b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
30b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip windows that are invisible, minimized, have no title, or are owned,
31b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // unless they have the app window style set.
32b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  int len = GetWindowTextLength(hwnd);
33b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  HWND owner = GetWindow(hwnd, GW_OWNER);
34b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
35b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
36b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org      (owner && !(exstyle & WS_EX_APPWINDOW))) {
37b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
38b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
39b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
40b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip the Program Manager window and the Start button.
41b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  const size_t kClassLength = 256;
42b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WCHAR class_name[kClassLength];
43371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  const int class_name_length = GetClassName(hwnd, class_name, kClassLength);
44371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  RTC_DCHECK(class_name_length)
45371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou      << "Error retrieving the application's class name";
46371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou
47b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip Program Manager window and the Start button. This is the same logic
48b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // that's used in Win32WindowPicker in libjingle. Consider filtering other
49b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // windows as well (e.g. toolbars).
50b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0)
51b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
52b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
53371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  // Windows 8 introduced a "Modern App" identified by their class name being
54371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  // either ApplicationFrameWindow or windows.UI.Core.coreWindow. The
55371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  // associated windows cannot be captured, so we skip them.
56371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  // http://crbug.com/526883.
57371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  if (rtc::IsWindows8OrLater() &&
58371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou      (wcscmp(class_name, L"ApplicationFrameWindow") == 0 ||
59371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou       wcscmp(class_name, L"Windows.UI.Core.CoreWindow") == 0)) {
60371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou    return TRUE;
61371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou  }
62371dc7e5601f05015d4816ed2624cc8f5f01d19agyzhou
63b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturer::Window window;
64a590b41c9ae8a41391a0556ae7d2aedbae7d3c38sergeyu@chromium.org  window.id = reinterpret_cast<WindowCapturer::WindowId>(hwnd);
65b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
66b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  const size_t kTitleLength = 500;
67b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WCHAR window_title[kTitleLength];
68b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Truncate the title if it's longer than kTitleLength.
69b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  GetWindowText(hwnd, window_title, kTitleLength);
70047abc93a24134d59b8feb895bbd7597e1aef4cdjiayl@webrtc.org  window.title = rtc::ToUtf8(window_title);
71b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
72b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip windows when we failed to convert the title or it is empty.
73b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (window.title.empty())
74b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
75b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
76b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  list->push_back(window);
77b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
78b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return TRUE;
79b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
80b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
81b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgclass WindowCapturerWin : public WindowCapturer {
82b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org public:
83b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturerWin();
84b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual ~WindowCapturerWin();
85b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
86b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // WindowCapturer interface.
8714665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool GetWindowList(WindowList* windows) override;
8814665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool SelectWindow(WindowId id) override;
8914665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool BringSelectedWindowToFront() override;
90b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
91b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // DesktopCapturer interface.
9214665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void Start(Callback* callback) override;
9314665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void Capture(const DesktopRegion& region) override;
94b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
95b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org private:
96b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  Callback* callback_;
97b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
98b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // HWND and HDC for the currently selected window or NULL if window is not
99b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // selected.
100b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  HWND window_;
101b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
102becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  DesktopSize previous_size_;
103becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
104d848d5e74aee56f454311756dc2032fad26d79adJiayang Liu  AeroChecker aero_checker_;
105d848d5e74aee56f454311756dc2032fad26d79adJiayang Liu
1063c089d751ede283e21e186885eaf705c3257ccd2henrikg  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
107b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org};
108b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
109b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerWin::WindowCapturerWin()
110b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    : callback_(NULL),
1118d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org      window_(NULL) {
112b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
113b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
114b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerWin::~WindowCapturerWin() {
115b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
116b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
117b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerWin::GetWindowList(WindowList* windows) {
118b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowList result;
119b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  LPARAM param = reinterpret_cast<LPARAM>(&result);
120b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!EnumWindows(&WindowsEnumerationHandler, param))
121b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return false;
122b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  windows->swap(result);
123b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return true;
124b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
125b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
126b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerWin::SelectWindow(WindowId id) {
1278d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HWND window = reinterpret_cast<HWND>(id);
1288d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window))
129b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return false;
1308d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  window_ = window;
131becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  previous_size_.set(0, 0);
132b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return true;
133b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
134b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
135886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.orgbool WindowCapturerWin::BringSelectedWindowToFront() {
136886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (!window_)
137886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
138886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
139886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (!IsWindow(window_) || !IsWindowVisible(window_) || IsIconic(window_))
140886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
141886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
142886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  return SetForegroundWindow(window_) != 0;
143886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org}
144886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
145b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerWin::Start(Callback* callback) {
146b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(!callback_);
147b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(callback);
148b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
149b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  callback_ = callback;
150b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
151b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
152b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerWin::Capture(const DesktopRegion& region) {
1538d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!window_) {
154b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
155b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
156b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return;
157b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
158b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
159c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  // Stop capturing if the window has been closed.
160c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  if (!IsWindow(window_)) {
161958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
162958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org    return;
163958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org  }
164958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org
165c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  // Return a 1x1 black frame if the window is minimized or invisible, to match
166c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  // behavior on mace. Window can be temporarily invisible during the
167c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  // transition of full screen mode on/off.
168c94bd9bf86d39b2b17ffaad0775d28e875f24b08gyzhou  if (IsIconic(window_) || !IsWindowVisible(window_)) {
169d91608dd2ddace8c4c2ce849617228a19e9a082cjiayl@webrtc.org    BasicDesktopFrame* frame = new BasicDesktopFrame(DesktopSize(1, 1));
17089959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    memset(frame->data(), 0, frame->stride() * frame->size().height());
17189959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org
17289959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    previous_size_ = frame->size();
17389959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    callback_->OnCaptureCompleted(frame);
17489959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    return;
17589959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org  }
17689959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org
177c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  DesktopRect original_rect;
178c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  DesktopRect cropped_rect;
179c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
180c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org    LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
181b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
182b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return;
183b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
184b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1858d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HDC window_dc = GetWindowDC(window_);
1868d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!window_dc) {
1878d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
1888d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
1898d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    return;
1908d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  }
1918d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org
19200b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<DesktopFrameWin> frame(
19300b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org      DesktopFrameWin::Create(cropped_rect.size(), NULL, window_dc));
1946a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org  if (!frame.get()) {
1958d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    ReleaseDC(window_, window_dc);
1966a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
1976a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org    return;
1986a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org  }
199b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
2008d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HDC mem_dc = CreateCompatibleDC(window_dc);
201ad3035fc9e30770392d5f4d955eae08d84562cdesergeyu@chromium.org  HGDIOBJ previous_object = SelectObject(mem_dc, frame->bitmap());
202b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  BOOL result = FALSE;
203b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
204b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // When desktop composition (Aero) is enabled each window is rendered to a
205b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // private buffer allowing BitBlt() to get the window content even if the
206b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // window is occluded. PrintWindow() is slower but lets rendering the window
207b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // contents to an off-screen device context when Aero is not available.
208b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // PrintWindow() is not supported by some applications.
209becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  //
210b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // If Aero is enabled, we prefer BitBlt() because it's faster and avoids
211b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // window flickering. Otherwise, we prefer PrintWindow() because BitBlt() may
212b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // render occluding windows on top of the desired window.
213becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  //
214becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // When composition is enabled the DC returned by GetWindowDC() doesn't always
215becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // have window frame rendered correctly. Windows renders it only once and then
216becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // caches the result between captures. We hack it around by calling
217f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // PrintWindow() whenever window size changes, including the first time of
218f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // capturing - it somehow affects what we get from BitBlt() on the subsequent
219f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // captures.
220becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
221d848d5e74aee56f454311756dc2032fad26d79adJiayang Liu  if (!aero_checker_.IsAeroEnabled() || !previous_size_.equals(frame->size())) {
222b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    result = PrintWindow(window_, mem_dc, 0);
223becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  }
224b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
225b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Aero is enabled or PrintWindow() failed, use BitBlt.
226b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!result) {
227b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    result = BitBlt(mem_dc, 0, 0, frame->size().width(), frame->size().height(),
228c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    window_dc,
229c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    cropped_rect.left() - original_rect.left(),
230c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    cropped_rect.top() - original_rect.top(),
231c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    SRCCOPY);
232b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
233b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
234ad3035fc9e30770392d5f4d955eae08d84562cdesergeyu@chromium.org  SelectObject(mem_dc, previous_object);
235becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  DeleteDC(mem_dc);
236becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  ReleaseDC(window_, window_dc);
237becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
238becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  previous_size_ = frame->size();
239becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
240d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org  frame->mutable_updated_region()->SetRect(
241d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org      DesktopRect::MakeSize(frame->size()));
242d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org
243b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!result) {
244b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    LOG(LS_ERROR) << "Both PrintWindow() and BitBlt() failed.";
245b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    frame.reset();
246b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
247b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
248b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  callback_->OnCaptureCompleted(frame.release());
249b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
250b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
251b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace
252b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
253b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org// static
254894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
255b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return new WindowCapturerWin();
256b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
257b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
258b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace webrtc
259