Bug 1036653 - Windows-specific support for app sharing, r=jesup,jimm
authorMatthew A. Miller <linuxwolf@outer-planes.net>
Thu, 21 Aug 2014 11:24:15 -0600
changeset 223591 2356923247d09f037e44e2d017677aa2cb6a08c3
parent 223590 8e4dda1253b066898630b0a6514faf2e0601f54a
child 223592 7818b389a25bf46c29ee474da29581d4eadee308
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup, jimm
bugs1036653
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1036653 - Windows-specific support for app sharing, r=jesup,jimm
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture.gypi
media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.h
media/webrtc/trunk/webrtc/modules/desktop_capture/win/win_shared.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/win/win_shared.h
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
@@ -2,102 +2,415 @@
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
+
 #include "webrtc/modules/desktop_capture/window_capturer.h"
 #include "webrtc/modules/desktop_capture/app_capturer.h"
+#include "webrtc/modules/desktop_capture/screen_capturer.h"
+#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
+#include "webrtc/modules/desktop_capture/win/win_shared.h"
 
-#include <assert.h>
 #include <windows.h>
+#include <vector>
+#include <cassert>
 
 #include "webrtc/modules/desktop_capture/desktop_frame_win.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
 
 namespace webrtc {
 
 namespace {
 
-std::string Utf16ToUtf8(const WCHAR* str) {
-  int len_utf8 = WideCharToMultiByte(CP_UTF8, 0, str, -1,
-                                     NULL, 0, NULL, NULL);
-  if (len_utf8 <= 0)
-    return std::string();
-  std::string result(len_utf8, '\0');
-  int rv = WideCharToMultiByte(CP_UTF8, 0, str, -1,
-                               &*(result.begin()), len_utf8, NULL, NULL);
-  if (rv != len_utf8)
-    assert(false);
+// Proxy over the WebRTC window capturer, to allow post-processing
+// of the frame to merge multiple window capture frames into a single frame
+class WindowsCapturerProxy : DesktopCapturer::Callback {
+public:
+  WindowsCapturerProxy() :
+      window_capturer_(WindowCapturer::Create()) {
+    window_capturer_->Start(this);
+  }
+  ~WindowsCapturerProxy(){}
+
+  void SelectWindow(HWND hwnd) { window_capturer_->SelectWindow(reinterpret_cast<WindowId>(hwnd)); }
+  scoped_ptr<DesktopFrame>& GetFrame() { return frame_; }
+  void Capture(const DesktopRegion& region) { window_capturer_->Capture(region); }
 
-  return result;
-}
+  // Callback interface
+  virtual SharedMemory *CreateSharedMemory(size_t) OVERRIDE { return NULL; }
+  virtual void OnCaptureCompleted(DesktopFrame *frame) OVERRIDE { frame_.reset(frame); }
+private:
+  scoped_ptr<WindowCapturer> window_capturer_;
+  scoped_ptr<DesktopFrame> frame_;
+};
 
+// Proxy over the WebRTC screen capturer, to allow post-processing
+// of the frame to mask out non-application windows
+class ScreenCapturerProxy : DesktopCapturer::Callback {
+public:
+  ScreenCapturerProxy(const DesktopCaptureOptions& options) :
+      screen_capturer_(ScreenCapturer::Create(options)) {
+    screen_capturer_->SelectScreen(kFullDesktopScreenId);
+    screen_capturer_->Start(this);
+  }
+  void Capture(const DesktopRegion& region) { screen_capturer_->Capture(region); }
+  scoped_ptr<DesktopFrame>& GetFrame() { return frame_; }
+
+  // Callback interface
+  virtual SharedMemory *CreateSharedMemory(size_t) OVERRIDE { return NULL; }
+  virtual void OnCaptureCompleted(DesktopFrame *frame) OVERRIDE { frame_.reset(frame); }
+protected:
+  scoped_ptr<ScreenCapturer> screen_capturer_;
+  scoped_ptr<DesktopFrame> frame_;
+};
 
 class AppCapturerWin : public AppCapturer {
 public:
-  AppCapturerWin();
+  AppCapturerWin(const DesktopCaptureOptions& options);
   virtual ~AppCapturerWin();
 
   // AppCapturer interface.
   virtual bool GetAppList(AppList* apps) OVERRIDE;
-  virtual bool SelectApp(ProcessId id) OVERRIDE;
+  virtual bool SelectApp(ProcessId processId) OVERRIDE;
   virtual bool BringAppToFront() OVERRIDE;
 
   // DesktopCapturer interface.
   virtual void Start(Callback* callback) OVERRIDE;
   virtual void Capture(const DesktopRegion& region) OVERRIDE;
 
+  struct WindowItem {
+    HWND handle;
+    RECT bounds;
+    bool owned;
+  };
+
+  struct EnumWindowsCtx {
+    ProcessId process_id;
+    std::vector<WindowItem> windows;
+    bool list_all;
+  };
+
+  static BOOL CALLBACK EnumWindowsProc(HWND handle, LPARAM lParam);
+protected:
+  void CaptureByWebRTC(const DesktopRegion& region);
+  void CaptureBySample(const DesktopRegion& region);
 private:
   Callback* callback_;
 
   ProcessId processId_;
 
+  // Sample Mode
+  ScreenCapturerProxy screen_capturer_proxy_;
+  // Mask of foreground (non-app windows in front of selected)
+  HRGN hrgn_foreground_;
+  // Mask of background (desktop, non-app windows behind selected)
+  HRGN hrgn_background_;
+  // Region of selected windows
+  HRGN hrgn_visual_;
+
+  void UpdateRegions();
+
+  // WebRTC Window mode
+  WindowsCapturerProxy window_capturer_proxy_;
+
   DISALLOW_COPY_AND_ASSIGN(AppCapturerWin);
 };
 
-AppCapturerWin::AppCapturerWin()
+AppCapturerWin::AppCapturerWin(const DesktopCaptureOptions& options)
   : callback_(NULL),
+    screen_capturer_proxy_(options),
     processId_(NULL) {
+  // Initialize regions to zero
+  hrgn_foreground_ = CreateRectRgn(0, 0, 0, 0);
+  hrgn_background_ = CreateRectRgn(0, 0, 0, 0);
+  hrgn_visual_ = CreateRectRgn(0, 0, 0, 0);
 }
 
 AppCapturerWin::~AppCapturerWin() {
+  if (hrgn_foreground_) {
+    DeleteObject(hrgn_foreground_);
+  }
+  if (hrgn_background_) {
+    DeleteObject(hrgn_background_);
+  }
+  if (hrgn_visual_) {
+    DeleteObject(hrgn_visual_);
+  }
 }
 
 // AppCapturer interface.
 bool AppCapturerWin::GetAppList(AppList* apps){
-  // Not implemented yet: See Bug 1036653
+  // Implemented via DesktopDeviceInfo
   return true;
 }
 
-bool AppCapturerWin::SelectApp(ProcessId id) {
-  // Not implemented yet: See Bug 1036653
+bool AppCapturerWin::SelectApp(ProcessId processId) {
+  processId_ = processId;
   return true;
 }
 
 bool AppCapturerWin::BringAppToFront() {
   // Not implemented yet: See Bug 1036653
   return true;
 }
 
 // DesktopCapturer interface.
 void AppCapturerWin::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 void AppCapturerWin::Capture(const DesktopRegion& region) {
-  // Not implemented yet: See Bug 1036653
+  CaptureBySample(region);
+}
+
+BOOL CALLBACK AppCapturerWin::EnumWindowsProc(HWND handle, LPARAM lParam) {
+  EnumWindowsCtx *pEnumWindowsCtx = reinterpret_cast<EnumWindowsCtx *>(lParam);
+  if (!pEnumWindowsCtx) {
+    return FALSE;
+  }
+
+  DWORD procId = -1;
+  GetWindowThreadProcessId(handle, &procId);
+  if (procId == pEnumWindowsCtx->process_id || pEnumWindowsCtx->list_all) {
+    WindowItem window_item;
+    window_item.handle = handle;
+
+    if (!IsWindowVisible(handle) || IsIconic(handle)) {
+      return TRUE;
+    }
+
+    GetWindowRect(handle, &window_item.bounds);
+    window_item.owned = (procId == pEnumWindowsCtx->process_id);
+    pEnumWindowsCtx->windows.push_back(window_item);
+  }
+
+  return TRUE;
+}
+
+void AppCapturerWin::CaptureByWebRTC(const DesktopRegion& region) {
+  // List Windows of selected application
+  EnumWindowsCtx lParamEnumWindows;
+  lParamEnumWindows.process_id = processId_;
+  lParamEnumWindows.list_all = false;
+  EnumWindows(EnumWindowsProc, (LPARAM)&lParamEnumWindows);
+
+  // Prepare capture dc context
+  // TODO: handle multi-monitor setups; see Bug 1037997
+  DesktopRect rcDesktop(DesktopRect::MakeXYWH(
+      GetSystemMetrics(SM_XVIRTUALSCREEN),
+      GetSystemMetrics(SM_YVIRTUALSCREEN),
+      GetSystemMetrics(SM_CXVIRTUALSCREEN),
+      GetSystemMetrics(SM_CYVIRTUALSCREEN)
+  ));
+
+  HDC dcScreen = GetDC(NULL);
+  HDC memDcCapture = CreateCompatibleDC(dcScreen);
+  if (dcScreen) {
+    ReleaseDC(NULL, dcScreen);
+  }
+
+  scoped_ptr<DesktopFrameWin> frameCapture(DesktopFrameWin::Create(
+      DesktopSize(rcDesktop.width(), rcDesktop.height()),
+      NULL, memDcCapture));
+  HBITMAP bmpOrigin = static_cast<HBITMAP>(SelectObject(memDcCapture, frameCapture->bitmap()));
+  BOOL bCaptureAppResult = false;
+  // Capture and Combine all windows into memDcCapture
+  std::vector<WindowItem>::reverse_iterator itItem;
+  for (itItem = lParamEnumWindows.windows.rbegin(); itItem != lParamEnumWindows.windows.rend(); itItem++) {
+    WindowItem window_item = *itItem;
+    HWND hWndCapturer = window_item.handle;
+    if (!IsWindow(hWndCapturer) || !IsWindowVisible(hWndCapturer) || IsIconic(hWndCapturer)) {
+      continue;
+    }
+
+    HDC memDcWin = NULL;
+    HBITMAP bmpOriginWin = NULL;
+    HBITMAP hBitmapFrame = NULL;
+    HDC dcWin = NULL;
+    RECT rcWin = window_item.bounds;
+    bool bCaptureResult = false;
+    scoped_ptr<DesktopFrameWin> frame;
+    do {
+      if (rcWin.left == rcWin.right || rcWin.top == rcWin.bottom) {
+        break;
+      }
+
+      dcWin = GetWindowDC(hWndCapturer);
+      if (!dcWin) {
+        break;
+      }
+      memDcWin = CreateCompatibleDC(dcWin);
+
+      // Capture
+      window_capturer_proxy_.SelectWindow(hWndCapturer);
+      window_capturer_proxy_.Capture(region);
+      if (window_capturer_proxy_.GetFrame() != NULL) {
+        DesktopFrameWin *pDesktopFrameWin = reinterpret_cast<DesktopFrameWin *>(
+            window_capturer_proxy_.GetFrame().get());
+        if (pDesktopFrameWin) {
+          hBitmapFrame = pDesktopFrameWin->bitmap();
+        }
+        if (GetObjectType(hBitmapFrame) != OBJ_BITMAP) {
+          hBitmapFrame = NULL;
+        }
+      }
+      if (!hBitmapFrame) {
+        break;
+      }
+      bmpOriginWin = static_cast<HBITMAP>(SelectObject(memDcWin, hBitmapFrame));
+    } while(0);
+
+    // bitblt to capture memDcCapture
+    if (bmpOriginWin) {
+      BitBlt(memDcCapture,
+          rcWin.left, rcWin.top, rcWin.right - rcWin.left, rcWin.bottom - rcWin.top,
+          memDcWin, 0, 0, SRCCOPY);
+      bCaptureAppResult = true;
+    }
+
+    // Clean resource
+    if (memDcWin) {
+      SelectObject(memDcWin, bmpOriginWin);
+      DeleteDC(memDcWin);
+    }
+    if (dcWin) {
+      ReleaseDC(hWndCapturer, dcWin);
+    }
+  }
+
+  // Clean resource
+  if (memDcCapture) {
+    SelectObject(memDcCapture, bmpOrigin);
+    DeleteDC(memDcCapture);
+  }
+
+  // trigger event
+  if (bCaptureAppResult) {
+    callback_->OnCaptureCompleted(frameCapture.release());
+  }
+}
+
+// Application Capturer by sample and region
+void AppCapturerWin::CaptureBySample(const DesktopRegion& region){
+  // capture entire screen
+  screen_capturer_proxy_.Capture(region);
+
+  HBITMAP hBitmapFrame = NULL;
+  if (screen_capturer_proxy_.GetFrame() != NULL) {
+    SharedDesktopFrame* pSharedDesktopFrame = reinterpret_cast<SharedDesktopFrame*>(
+        screen_capturer_proxy_.GetFrame().get());
+    if (pSharedDesktopFrame) {
+      DesktopFrameWin *pDesktopFrameWin =reinterpret_cast<DesktopFrameWin *>(
+          pSharedDesktopFrame->GetUnderlyingFrame());
+      if (pDesktopFrameWin) {
+        hBitmapFrame = pDesktopFrameWin->bitmap();
+      }
+      if (GetObjectType(hBitmapFrame) != OBJ_BITMAP) {
+        hBitmapFrame = NULL;
+      }
+    }
+  }
+  if (hBitmapFrame) {
+    // calculate app visual/foreground region
+    UpdateRegions();
+
+    HDC dcScreen = GetDC(NULL);
+    HDC memDcCapture = CreateCompatibleDC(dcScreen);
+
+    RECT rcScreen = {0, 0,
+        screen_capturer_proxy_.GetFrame()->size().width(),
+        screen_capturer_proxy_.GetFrame()->size().height()
+    };
+
+    HBITMAP bmpOriginCapture = (HBITMAP)SelectObject(memDcCapture, hBitmapFrame);
+
+    // TODO: background/foreground mask colors should be configurable; see Bug 1054503
+    // fill background
+    SelectClipRgn(memDcCapture, hrgn_background_);
+    SelectObject(memDcCapture, GetStockObject(DC_BRUSH));
+    SetDCBrushColor(memDcCapture, RGB(0, 0, 0));
+    FillRect(memDcCapture, &rcScreen, (HBRUSH)GetStockObject(DC_BRUSH));
+
+    // fill foreground
+    SelectClipRgn(memDcCapture, hrgn_foreground_);
+    SelectObject(memDcCapture, GetStockObject(DC_BRUSH));
+    SetDCBrushColor(memDcCapture, RGB(0xff, 0xff, 0));
+    FillRect(memDcCapture, &rcScreen, (HBRUSH)GetStockObject(DC_BRUSH));
+
+    if (dcScreen) {
+      ReleaseDC(NULL, dcScreen);
+    }
+    SelectObject(memDcCapture, bmpOriginCapture);
+    DeleteDC(memDcCapture);
+  }
+
+  // trigger event
+  if (callback_) {
+    callback_->OnCaptureCompleted(screen_capturer_proxy_.GetFrame().release());
+  }
+}
+
+void AppCapturerWin::UpdateRegions() {
+  // List Windows of selected application
+  EnumWindowsCtx lParamEnumWindows;
+  lParamEnumWindows.process_id = processId_;
+  lParamEnumWindows.list_all = true;
+  EnumWindows(EnumWindowsProc, (LPARAM)&lParamEnumWindows);
+
+  SetRectRgn(hrgn_foreground_, 0, 0, 0, 0);
+  SetRectRgn(hrgn_visual_, 0, 0, 0, 0);
+  SetRectRgn(hrgn_background_, 0, 0, 0, 0);
+
+  HRGN hrgn_screen_ = CreateRectRgn(0, 0,
+      GetSystemMetrics(SM_CXVIRTUALSCREEN),
+      GetSystemMetrics(SM_CYVIRTUALSCREEN));
+
+  HRGN hrgn_window = CreateRectRgn(0, 0, 0, 0);
+  HRGN hrgn_internsect = CreateRectRgn(0, 0, 0, 0);
+  std::vector<WindowItem>::reverse_iterator itItem;
+  for (itItem = lParamEnumWindows.windows.rbegin(); itItem != lParamEnumWindows.windows.rend(); itItem++) {
+    WindowItem window_item = *itItem;
+    SetRectRgn(hrgn_window, 0, 0, 0, 0);
+    if (GetWindowRgn(window_item.handle, hrgn_window) == ERROR) {
+      SetRectRgn(hrgn_window, window_item.bounds.left,
+                 window_item.bounds.top,
+                 window_item.bounds.right,
+                 window_item.bounds.bottom);
+    }
+
+    if (window_item.owned) {
+      CombineRgn(hrgn_visual_, hrgn_visual_, hrgn_window, RGN_OR);
+      CombineRgn(hrgn_foreground_, hrgn_foreground_, hrgn_window, RGN_DIFF);
+    } else {
+      SetRectRgn(hrgn_internsect, 0, 0, 0, 0);
+      CombineRgn(hrgn_internsect, hrgn_visual_, hrgn_window, RGN_AND);
+
+      CombineRgn(hrgn_visual_, hrgn_visual_, hrgn_internsect, RGN_DIFF);
+
+      CombineRgn(hrgn_foreground_, hrgn_foreground_, hrgn_internsect, RGN_OR);
+    }
+  }
+  CombineRgn(hrgn_background_, hrgn_screen_, hrgn_visual_, RGN_DIFF);
+
+  if (hrgn_window) {
+    DeleteObject(hrgn_window);
+  }
+  if (hrgn_internsect) {
+    DeleteObject(hrgn_internsect);
+  }
 }
 
 }  // namespace
 
 // static
 AppCapturer* AppCapturer::Create(const DesktopCaptureOptions& options) {
-  return new AppCapturerWin();
+  return new AppCapturerWin(options);
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture.gypi
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture.gypi
@@ -144,16 +144,18 @@
              "screen_capturer_win.cc",
              "win/cursor.cc",
              "win/cursor.h",
              "win/desktop.cc",
              "win/desktop.h",
              "win/scoped_gdi_object.h",
              "win/scoped_thread_desktop.cc",
              "win/scoped_thread_desktop.h",
+             "win/win_shared.h",
+             "win/win_shared.cc",
              "win/desktop_device_info_win.h",
              "win/desktop_device_info_win.cc",
              "window_capturer_win.cc",
              "app_capturer_win.cc",
            ],
           }],
       ],
     },
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.cc
@@ -1,15 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "webrtc/modules/desktop_capture/win/desktop_device_info_win.h"
+#include "webrtc/modules/desktop_capture/win/win_shared.h"
+#include <stdio.h>
 
-namespace webrtc{
+// Duplicating declaration so that it always resolves in decltype use
+// typedef BOOL (WINAPI *QueryFullProcessImageNameProc)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize);
+BOOL WINAPI QueryFullProcessImageName(HANDLE hProcess, DWORD dwFlags, LPTSTR lpExeName, PDWORD lpdwSize);
+
+// Duplicating declaration so that it always resolves in decltype use
+// typedoef DWORD (WINAPI *GetProcessImageFileNameProc)(HANDLE hProcess, LPTSTR lpImageFileName, DWORD nSize);
+DWORD WINAPI GetProcessImageFileName(HANDLE hProcess, LPTSTR lpImageFileName, DWORD nSize);
+
+namespace webrtc {
 
 DesktopDeviceInfo * DesktopDeviceInfoImpl::Create() {
   DesktopDeviceInfoWin * pDesktopDeviceInfo = new DesktopDeviceInfoWin();
   if(pDesktopDeviceInfo && pDesktopDeviceInfo->Init() != 0){
     delete pDesktopDeviceInfo;
     pDesktopDeviceInfo = NULL;
   }
   return pDesktopDeviceInfo;
@@ -17,50 +27,101 @@ DesktopDeviceInfo * DesktopDeviceInfoImp
 
 DesktopDeviceInfoWin::DesktopDeviceInfoWin() {
 }
 
 DesktopDeviceInfoWin::~DesktopDeviceInfoWin() {
 }
 
 #if !defined(MULTI_MONITOR_SCREENSHARE)
-int32_t DesktopDeviceInfoWin::MultiMonitorScreenshare()
+void DesktopDeviceInfoWin::MultiMonitorScreenshare()
 {
   DesktopDisplayDevice *pDesktopDeviceInfo = new DesktopDisplayDevice;
   if (pDesktopDeviceInfo) {
     pDesktopDeviceInfo->setScreenId(0);
     pDesktopDeviceInfo->setDeviceName("Primary Monitor");
     pDesktopDeviceInfo->setUniqueIdName("\\screen\\monitor#1");
 
     desktop_display_list_[pDesktopDeviceInfo->getScreenId()] = pDesktopDeviceInfo;
   }
-  return 0;
 }
 #endif
 
-int32_t DesktopDeviceInfoWin::Init() {
+void DesktopDeviceInfoWin::InitializeScreenList() {
 #if !defined(MULTI_MONITOR_SCREENSHARE)
   MultiMonitorScreenshare();
 #endif
+}
+void DesktopDeviceInfoWin::InitializeApplicationList() {
+  // List all running applications exclude background process.
+  HWND hWnd;
+  for (hWnd = GetWindow(GetDesktopWindow(), GW_CHILD); hWnd; hWnd = GetWindow(hWnd, GW_HWNDNEXT)) {
+    if (!IsWindowVisible(hWnd))
+      continue;
 
-  initializeWindowList();
+    DWORD dwProcessId = 0;
+    GetWindowThreadProcessId(hWnd, &dwProcessId);
+
+    // filter out non-process, current process, or any already seen processes
+    if (dwProcessId == 0 || dwProcessId == GetCurrentProcessId() ||
+        desktop_application_list_.find(dwProcessId) != desktop_application_list_.end()) {
+      continue;
+    }
+
+    // Add one application
+    DesktopApplication *pDesktopApplication = new DesktopApplication;
+    if (!pDesktopApplication) {
+      continue;
+    }
+
+    // process id
+    pDesktopApplication->setProcessId(dwProcessId);
 
-  return 0;
+    // process path name
+    WCHAR szFilePathName[MAX_PATH]={0};
+    decltype(QueryFullProcessImageName) *lpfnQueryFullProcessImageNameProc =
+      reinterpret_cast<decltype(QueryFullProcessImageName) *>(GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "QueryFullProcessImageNameW"));
+    if (lpfnQueryFullProcessImageNameProc) {
+      // After Vista
+      DWORD dwMaxSize = _MAX_PATH;
+      HANDLE hWndPro = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);
+      if(hWndPro) {
+        lpfnQueryFullProcessImageNameProc(hWndPro, 0, szFilePathName, &dwMaxSize);
+        CloseHandle(hWndPro);
+      }
+    } else {
+      HMODULE hModPSAPI = LoadLibrary(TEXT("PSAPI.dll"));
+      if (hModPSAPI) {
+        decltype(GetProcessImageFileName) *pfnGetProcessImageFileName =
+          reinterpret_cast<decltype(GetProcessImageFileName) *>(GetProcAddress(hModPSAPI, "GetProcessImageFileNameW"));
+
+        if (pfnGetProcessImageFileName) {
+          HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwProcessId);
+          if (hProcess) {
+            DWORD dwMaxSize = _MAX_PATH;
+            pfnGetProcessImageFileName(hProcess, szFilePathName, dwMaxSize);
+            CloseHandle(hProcess);
+          }
+        }
+        FreeLibrary(hModPSAPI);
+      }
+    }
+    pDesktopApplication->setProcessPathName(Utf16ToUtf8(szFilePathName).c_str());
+
+    // application name
+    WCHAR szWndTitle[_MAX_PATH]={0};
+    GetWindowText(hWnd, szWndTitle, MAX_PATH);
+    if (lstrlen(szWndTitle) <= 0) {
+      pDesktopApplication->setProcessAppName(Utf16ToUtf8(szFilePathName).c_str());
+    } else {
+      pDesktopApplication->setProcessAppName(Utf16ToUtf8(szWndTitle).c_str());
+    }
+
+    // unique id name
+    char idStr[64];
+    _snprintf_s(idStr, sizeof(idStr), sizeof(idStr) - 1, "%ld", pDesktopApplication->getProcessId());
+    pDesktopApplication->setUniqueIdName(idStr);
+
+    desktop_application_list_[pDesktopApplication->getProcessId()] = pDesktopApplication;
+  }
 }
 
-int32_t DesktopDeviceInfoWin::Refresh() {
-#if !defined(MULTI_MONITOR_SCREENSHARE)
-  std::map<intptr_t,DesktopDisplayDevice*>::iterator iterDevice;
-  for (iterDevice=desktop_display_list_.begin(); iterDevice!=desktop_display_list_.end(); iterDevice++){
-    DesktopDisplayDevice * pDesktopDisplayDevice = iterDevice->second;
-    delete pDesktopDisplayDevice;
-    iterDevice->second = NULL;
-  }
-  desktop_display_list_.clear();
-  MultiMonitorScreenshare();
-#endif
-
-  RefreshWindowList();
-
-  return 0;
-}
-
-} //namespace webrtc
+} // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/desktop_device_info_win.h
@@ -10,21 +10,22 @@
 
 namespace webrtc {
 
 class DesktopDeviceInfoWin : public DesktopDeviceInfoImpl {
 public:
   DesktopDeviceInfoWin();
   ~DesktopDeviceInfoWin();
 
+protected:
   //DesktopDeviceInfo Interfaces
-  virtual int32_t Init();
-  virtual int32_t Refresh();
+  virtual void InitializeApplicationList() OVERRIDE;
+  virtual void InitializeScreenList() OVERRIDE;
 
 private:
 #if !defined(MULTI_MONITOR_SCREENSHARE)
-  int32_t MultiMonitorScreenshare();
+  void MultiMonitorScreenshare();
 #endif
 };
 
 }// namespace webrtc
 
 #endif //WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_DEVICE_INFO_H_
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/win_shared.cc
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <windows.h>
+#include <assert.h>
+#include "webrtc/modules/desktop_capture/win/win_shared.h"
+
+namespace webrtc {
+
+std::string Utf16ToUtf8(const WCHAR* str) {
+    int len_utf8 = WideCharToMultiByte(CP_UTF8, 0, str, -1,
+                                       NULL, 0, NULL, NULL);
+    if (len_utf8 <= 0) {
+        return std::string();
+    }
+    std::string result(len_utf8, '\0');
+    int rv = WideCharToMultiByte(CP_UTF8, 0, str, -1,
+                                 &*(result.begin()), len_utf8,
+                                 NULL, NULL);
+    if (rv != len_utf8) {
+        assert(false);
+    }
+
+    return result;
+}
+
+};
new file mode 100644
--- /dev/null
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/win_shared.h
@@ -0,0 +1,12 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <windows.h>
+#include <string>
+
+namespace webrtc {
+
+std::string Utf16ToUtf8(const WCHAR* str);
+
+};