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