15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved.
25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be
35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file.
45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace {
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu////////////////////////////////////////////////////////////////////////////////
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Status Tray API
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// The folowing describes the interface to the undocumented Windows Exporer APIs
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// for manipulating with the status tray area.  This code should be used with
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// care as it can change with versions (even minor versions) of Windows.
155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// ITrayNotify is an interface describing the API for manipulating the state of
175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// the Windows notification area, as well as for registering for change
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// notifications.
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass __declspec(uuid("FB852B2C-6BAD-4605-9551-F15F87830935")) ITrayNotify
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : public IUnknown {
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      RegisterCallback(INotificationCB* callback) = 0;
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      SetPreference(const NOTIFYITEM* notify_item) = 0;
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL enabled) = 0;
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// ITrayNotifyWin8 is the interface that replaces ITrayNotify for newer versions
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// of Windows.
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass __declspec(uuid("D133CE13-3537-48BA-93A7-AFCD5D2053B4")) ITrayNotifyWin8
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : public IUnknown {
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE UnregisterCallback(unsigned long*) = 0;
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE SetPreference(NOTIFYITEM const*) = 0;
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL) = 0;
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual HRESULT STDMETHODCALLTYPE DoAction(BOOL) = 0;
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst CLSID CLSID_TrayNotify = {
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    0x25DEAD04,
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    0x1EAC,
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    0x4911,
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    {0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}  // namespace
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuStatusTrayStateChangerWin::StatusTrayStateChangerWin(UINT icon_id, HWND window)
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : interface_version_(INTERFACE_VERSION_UNKNOWN),
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      icon_id_(icon_id),
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      window_(window) {
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  wchar_t module_name[MAX_PATH];
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ::GetModuleFileName(NULL, module_name, MAX_PATH);
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  file_name_ = module_name;
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid StatusTrayStateChangerWin::EnsureTrayIconVisible() {
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!CreateTrayNotify()) {
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    VLOG(1) << "Unable to create COM object for ITrayNotify.";
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<NOTIFYITEM> notify_item = RegisterCallback();
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If the user has already hidden us explicitly, try to honor their choice by
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // not changing anything.
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (notify_item->preference == PREFERENCE_SHOW_NEVER)
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If we are already on the taskbar, return since nothing needs to be done.
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (notify_item->preference == PREFERENCE_SHOW_ALWAYS)
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  notify_item->preference = PREFERENCE_SHOW_ALWAYS;
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  SendNotifyItemUpdate(notify_item.Pass());
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSTDMETHODIMP_(ULONG) StatusTrayStateChangerWin::AddRef() {
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return base::win::IUnknownImpl::AddRef();
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSTDMETHODIMP_(ULONG) StatusTrayStateChangerWin::Release() {
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return base::win::IUnknownImpl::Release();
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSTDMETHODIMP StatusTrayStateChangerWin::QueryInterface(REFIID riid,
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                                       PVOID* ptr_void) {
965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (riid == __uuidof(INotificationCB)) {
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    *ptr_void = static_cast<INotificationCB*>(this);
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    AddRef();
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return S_OK;
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return base::win::IUnknownImpl::QueryInterface(riid, ptr_void);
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSTDMETHODIMP StatusTrayStateChangerWin::Notify(ULONG event,
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                               NOTIFYITEM* notify_item) {
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(notify_item);
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (notify_item->hwnd != window_ || notify_item->id != icon_id_ ||
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::string16(notify_item->exe_name) != file_name_) {
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return S_OK;
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  notify_item_.reset(new NOTIFYITEM(*notify_item));
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return S_OK;
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuStatusTrayStateChangerWin::~StatusTrayStateChangerWin() {
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool StatusTrayStateChangerWin::CreateTrayNotify() {
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(CalledOnValidThread());
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tray_notify_.Release();  // Release so this method can be called more than
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                           // once.
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HRESULT hr = tray_notify_.CreateInstance(CLSID_TrayNotify);
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (FAILED(hr))
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  hr = tray_notify_win8.QueryFrom(tray_notify_);
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (SUCCEEDED(hr)) {
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    interface_version_ = INTERFACE_VERSION_WIN8;
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return true;
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::win::ScopedComPtr<ITrayNotify> tray_notify_legacy;
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  hr = tray_notify_legacy.QueryFrom(tray_notify_);
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (SUCCEEDED(hr)) {
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    interface_version_ = INTERFACE_VERSION_LEGACY;
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return true;
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return false;
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuscoped_ptr<NOTIFYITEM> StatusTrayStateChangerWin::RegisterCallback() {
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // |notify_item_| is used to store the result of the callback from
1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Explorer.exe, which happens synchronously during
1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // RegisterCallbackWin8 or RegisterCallbackLegacy.
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(notify_item_.get() == NULL);
1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // TODO(dewittj): Add UMA logging here to report if either of our strategies
1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // has a tendency to fail on particular versions of Windows.
1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  switch (interface_version_) {
1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case INTERFACE_VERSION_WIN8:
1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (!RegisterCallbackWin8())
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        VLOG(1) << "Unable to successfully run RegisterCallbackWin8.";
1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      break;
1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    case INTERFACE_VERSION_LEGACY:
1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (!RegisterCallbackLegacy())
1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        VLOG(1) << "Unable to successfully run RegisterCallbackLegacy.";
1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      break;
1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    default:
1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NOTREACHED();
1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Adding an intermediate scoped pointer here so that |notify_item_| is reset
1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // to NULL.
1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<NOTIFYITEM> rv(notify_item_.release());
1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return rv.Pass();
1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool StatusTrayStateChangerWin::RegisterCallbackWin8() {
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HRESULT hr = tray_notify_win8.QueryFrom(tray_notify_);
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (FAILED(hr))
1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The following two lines cause Windows Explorer to call us back with all the
1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // existing tray icons and their preference.  It would also presumably notify
1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // us if changes were made in realtime while we registered as a callback, but
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // we just want to modify our own entry so we immediately unregister.
1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  unsigned long callback_id = 0;
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  hr = tray_notify_win8->RegisterCallback(this, &callback_id);
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tray_notify_win8->UnregisterCallback(&callback_id);
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (FAILED(hr)) {
1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return true;
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool StatusTrayStateChangerWin::RegisterCallbackLegacy() {
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::win::ScopedComPtr<ITrayNotify> tray_notify;
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HRESULT hr = tray_notify.QueryFrom(tray_notify_);
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (FAILED(hr)) {
2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // The following two lines cause Windows Explorer to call us back with all the
2055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // existing tray icons and their preference.  It would also presumably notify
2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // us if changes were made in realtime while we registered as a callback.  In
2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // this version of the API, there can be only one registered callback so it is
2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // better to unregister as soon as possible.
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // TODO(dewittj): Try to notice if the notification area icon customization
2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // window is open and postpone this call until the user closes it;
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // registering the callback while the window is open can cause stale data to
2125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // be displayed to the user.
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  hr = tray_notify->RegisterCallback(this);
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tray_notify->RegisterCallback(NULL);
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (FAILED(hr)) {
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return true;
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid StatusTrayStateChangerWin::SendNotifyItemUpdate(
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_ptr<NOTIFYITEM> notify_item) {
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (interface_version_ == INTERFACE_VERSION_LEGACY) {
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::win::ScopedComPtr<ITrayNotify> tray_notify;
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    HRESULT hr = tray_notify.QueryFrom(tray_notify_);
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (SUCCEEDED(hr))
2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      tray_notify->SetPreference(notify_item.get());
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  } else if (interface_version_ == INTERFACE_VERSION_WIN8) {
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify;
2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    HRESULT hr = tray_notify.QueryFrom(tray_notify_);
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (SUCCEEDED(hr))
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      tray_notify->SetPreference(notify_item.get());
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
236