window_capturer_win.cc revision 89959966a9c0eb680da49052e42e3b541da26483
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
15047abc93a24134d59b8feb895bbd7597e1aef4cdjiayl@webrtc.org#include "webrtc/base/win32.h"
16b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
17c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
18b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h"
19b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_ptr.h"
20b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
21b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace webrtc {
22b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
23b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace {
24b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
25b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgtypedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled);
26b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
27b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgBOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
28b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturer::WindowList* list =
29b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org      reinterpret_cast<WindowCapturer::WindowList*>(param);
30b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
31b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip windows that are invisible, minimized, have no title, or are owned,
32b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // unless they have the app window style set.
33b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  int len = GetWindowTextLength(hwnd);
34b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  HWND owner = GetWindow(hwnd, GW_OWNER);
35b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
36b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
37b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org      (owner && !(exstyle & WS_EX_APPWINDOW))) {
38b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
39b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
40b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
41b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip the Program Manager window and the Start button.
42b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  const size_t kClassLength = 256;
43b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WCHAR class_name[kClassLength];
44b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  GetClassName(hwnd, class_name, kClassLength);
45b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip Program Manager window and the Start button. This is the same logic
46b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // that's used in Win32WindowPicker in libjingle. Consider filtering other
47b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // windows as well (e.g. toolbars).
48b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0)
49b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
50b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
51b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturer::Window window;
52a590b41c9ae8a41391a0556ae7d2aedbae7d3c38sergeyu@chromium.org  window.id = reinterpret_cast<WindowCapturer::WindowId>(hwnd);
53b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
54b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  const size_t kTitleLength = 500;
55b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WCHAR window_title[kTitleLength];
56b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Truncate the title if it's longer than kTitleLength.
57b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  GetWindowText(hwnd, window_title, kTitleLength);
58047abc93a24134d59b8feb895bbd7597e1aef4cdjiayl@webrtc.org  window.title = rtc::ToUtf8(window_title);
59b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
60b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Skip windows when we failed to convert the title or it is empty.
61b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (window.title.empty())
62b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return TRUE;
63b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
64b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  list->push_back(window);
65b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
66b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return TRUE;
67b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
68b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
69b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgclass WindowCapturerWin : public WindowCapturer {
70b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org public:
71b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowCapturerWin();
72b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual ~WindowCapturerWin();
73b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
74b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // WindowCapturer interface.
75b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual bool GetWindowList(WindowList* windows) OVERRIDE;
76b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual bool SelectWindow(WindowId id) OVERRIDE;
77886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  virtual bool BringSelectedWindowToFront() OVERRIDE;
78b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
79b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // DesktopCapturer interface.
80b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual void Start(Callback* callback) OVERRIDE;
81b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual void Capture(const DesktopRegion& region) OVERRIDE;
82b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
83b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org private:
84b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  bool IsAeroEnabled();
85b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
86b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  Callback* callback_;
87b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
88b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // HWND and HDC for the currently selected window or NULL if window is not
89b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // selected.
90b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  HWND window_;
91b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
92b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // dwmapi.dll is used to determine if desktop compositing is enabled.
93b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  HMODULE dwmapi_library_;
94b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  DwmIsCompositionEnabledFunc is_composition_enabled_func_;
95b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
96becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  DesktopSize previous_size_;
97becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
98b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
99b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org};
100b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
101b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerWin::WindowCapturerWin()
102b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    : callback_(NULL),
1038d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org      window_(NULL) {
104b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Try to load dwmapi.dll dynamically since it is not available on XP.
105b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  dwmapi_library_ = LoadLibrary(L"dwmapi.dll");
106b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (dwmapi_library_) {
107b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    is_composition_enabled_func_ =
108b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org        reinterpret_cast<DwmIsCompositionEnabledFunc>(
109b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org            GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled"));
110b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    assert(is_composition_enabled_func_);
111b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  } else {
112b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    is_composition_enabled_func_ = NULL;
113b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
114b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
115b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
116b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerWin::~WindowCapturerWin() {
117b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (dwmapi_library_)
118b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    FreeLibrary(dwmapi_library_);
119b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
120b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
121b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerWin::IsAeroEnabled() {
122b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  BOOL result = FALSE;
123b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (is_composition_enabled_func_)
124b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    is_composition_enabled_func_(&result);
125b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return result != FALSE;
126b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
127b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
128b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerWin::GetWindowList(WindowList* windows) {
129b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  WindowList result;
130b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  LPARAM param = reinterpret_cast<LPARAM>(&result);
131b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!EnumWindows(&WindowsEnumerationHandler, param))
132b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return false;
133b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  windows->swap(result);
134b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return true;
135b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
136b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
137b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerWin::SelectWindow(WindowId id) {
1388d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HWND window = reinterpret_cast<HWND>(id);
1398d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window))
140b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return false;
1418d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  window_ = window;
142becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  previous_size_.set(0, 0);
143b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return true;
144b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
145b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
146886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.orgbool WindowCapturerWin::BringSelectedWindowToFront() {
147886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (!window_)
148886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
149886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
150886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (!IsWindow(window_) || !IsWindowVisible(window_) || IsIconic(window_))
151886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
152886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
153886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  return SetForegroundWindow(window_) != 0;
154886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org}
155886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
156b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerWin::Start(Callback* callback) {
157b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(!callback_);
158b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(callback);
159b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
160b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  callback_ = callback;
161b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
162b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
163b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerWin::Capture(const DesktopRegion& region) {
1648d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!window_) {
165b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
166b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
167b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return;
168b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
169b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
170cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  // Stop capturing if the window has been closed or hidden.
171cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  if (!IsWindow(window_) || !IsWindowVisible(window_)) {
172958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
173958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org    return;
174958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org  }
175958cdf68f308d5c6e3e10a58cdae40cc0044625bsergeyu@chromium.org
17689959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org  // Return a 2x2 black frame if the window is minimized. The size is 2x2 so it
17789959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org  // can be subsampled to I420 downstream.
17889959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org  if (IsIconic(window_)) {
17989959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    BasicDesktopFrame* frame = new BasicDesktopFrame(DesktopSize(2, 2));
18089959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    memset(frame->data(), 0, frame->stride() * frame->size().height());
18189959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org
18289959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    previous_size_ = frame->size();
18389959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    callback_->OnCaptureCompleted(frame);
18489959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org    return;
18589959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org  }
18689959966a9c0eb680da49052e42e3b541da26483jiayl@webrtc.org
187c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  DesktopRect original_rect;
188c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  DesktopRect cropped_rect;
189c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org  if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
190c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org    LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
191b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
192b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    return;
193b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
194b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1958d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HDC window_dc = GetWindowDC(window_);
1968d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  if (!window_dc) {
1978d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
1988d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
1998d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    return;
2008d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  }
2018d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org
202b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  scoped_ptr<DesktopFrameWin> frame(DesktopFrameWin::Create(
203c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org      cropped_rect.size(), NULL, window_dc));
2046a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org  if (!frame.get()) {
2058d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org    ReleaseDC(window_, window_dc);
2066a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
2076a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org    return;
2086a5cc9d8998ec979ea3be1b3378b7b47d6c765e9sergeyu@chromium.org  }
209b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
2108d757ac0a21567b177df231b802961b0a2981d07sergeyu@chromium.org  HDC mem_dc = CreateCompatibleDC(window_dc);
211ad3035fc9e30770392d5f4d955eae08d84562cdesergeyu@chromium.org  HGDIOBJ previous_object = SelectObject(mem_dc, frame->bitmap());
212b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  BOOL result = FALSE;
213b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
214b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // When desktop composition (Aero) is enabled each window is rendered to a
215b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // private buffer allowing BitBlt() to get the window content even if the
216b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // window is occluded. PrintWindow() is slower but lets rendering the window
217b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // contents to an off-screen device context when Aero is not available.
218b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // PrintWindow() is not supported by some applications.
219becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  //
220b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // If Aero is enabled, we prefer BitBlt() because it's faster and avoids
221b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // window flickering. Otherwise, we prefer PrintWindow() because BitBlt() may
222b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // render occluding windows on top of the desired window.
223becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  //
224becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // When composition is enabled the DC returned by GetWindowDC() doesn't always
225becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // have window frame rendered correctly. Windows renders it only once and then
226becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  // caches the result between captures. We hack it around by calling
227f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // PrintWindow() whenever window size changes, including the first time of
228f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // capturing - it somehow affects what we get from BitBlt() on the subsequent
229f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  // captures.
230becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
231f0fc72f70eb9a63565a528aed0c93f9a913cc029jiayl@webrtc.org  if (!IsAeroEnabled() || !previous_size_.equals(frame->size())) {
232b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    result = PrintWindow(window_, mem_dc, 0);
233becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  }
234b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
235b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // Aero is enabled or PrintWindow() failed, use BitBlt.
236b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!result) {
237b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    result = BitBlt(mem_dc, 0, 0, frame->size().width(), frame->size().height(),
238c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    window_dc,
239c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    cropped_rect.left() - original_rect.left(),
240c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    cropped_rect.top() - original_rect.top(),
241c8ac17ca04897f8f5fbb5d179e8b7573f66b148ajiayl@webrtc.org                    SRCCOPY);
242b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
243b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
244ad3035fc9e30770392d5f4d955eae08d84562cdesergeyu@chromium.org  SelectObject(mem_dc, previous_object);
245becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  DeleteDC(mem_dc);
246becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  ReleaseDC(window_, window_dc);
247becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
248becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org  previous_size_ = frame->size();
249becbefaee6e97f9ca6d478d146b55985fc7b9625sergeyu@chromium.org
250d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org  frame->mutable_updated_region()->SetRect(
251d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org      DesktopRect::MakeSize(frame->size()));
252d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org
253b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  if (!result) {
254b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    LOG(LS_ERROR) << "Both PrintWindow() and BitBlt() failed.";
255b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org    frame.reset();
256b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  }
257b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
258b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  callback_->OnCaptureCompleted(frame.release());
259b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
260b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
261b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace
262b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
263b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org// static
264894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
265b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  return new WindowCapturerWin();
266b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
267b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
268b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace webrtc
269