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