Sync with trunk r63343.
[reactos.git] / base / shell / rshell / CMenuFocusManager.cpp
1 /*
2 * Shell Menu Band
3 *
4 * Copyright 2014 David Quintana
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20 #include "precomp.h"
21 #include <windowsx.h>
22 #include <commoncontrols.h>
23 #include <shlwapi_undoc.h>
24
25 #include "CMenuFocusManager.h"
26 #include "CMenuToolbars.h"
27 #include "CMenuBand.h"
28
29 #if DBG
30 # undef _ASSERT
31 # define _ASSERT(x) DbgAssert(!!(x), __FILE__, __LINE__, #x)
32
33 bool DbgAssert(bool x, const char * filename, int line, const char * expr)
34 {
35 if (!x)
36 {
37 char szMsg[512];
38 const char *fname;
39
40 fname = strrchr(filename, '\\');
41 if (fname == NULL)
42 {
43 fname = strrchr(filename, '/');
44 }
45
46 if (fname == NULL)
47 fname = filename;
48 else
49 fname++;
50
51 sprintf(szMsg, "%s:%d: Assertion failed: %s\n", fname, line, expr);
52
53 OutputDebugStringA(szMsg);
54
55 __debugbreak();
56 }
57 return x;
58 }
59 #else
60 # undef _ASSERT
61 # define _ASSERT(x) (!!(x))
62 #endif
63
64 WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus);
65
66 DWORD CMenuFocusManager::TlsIndex = 0;
67
68 CMenuFocusManager * CMenuFocusManager::GetManager()
69 {
70 return reinterpret_cast<CMenuFocusManager *>(TlsGetValue(TlsIndex));
71 }
72
73 CMenuFocusManager * CMenuFocusManager::AcquireManager()
74 {
75 CMenuFocusManager * obj = NULL;
76
77 if (!TlsIndex)
78 {
79 if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
80 return NULL;
81 }
82
83 obj = GetManager();
84
85 if (!obj)
86 {
87 obj = new CComObject<CMenuFocusManager>();
88 TlsSetValue(TlsIndex, obj);
89 }
90
91 obj->AddRef();
92
93 return obj;
94 }
95
96 void CMenuFocusManager::ReleaseManager(CMenuFocusManager * obj)
97 {
98 if (!obj->Release())
99 {
100 TlsSetValue(TlsIndex, NULL);
101 }
102 }
103
104 LRESULT CALLBACK CMenuFocusManager::s_MsgFilterHook(INT nCode, WPARAM wParam, LPARAM lParam)
105 {
106 return GetManager()->MsgFilterHook(nCode, wParam, lParam);
107 }
108
109 LRESULT CALLBACK CMenuFocusManager::s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam)
110 {
111 return GetManager()->GetMsgHook(nCode, wParam, lParam);
112 }
113
114 HRESULT CMenuFocusManager::PushToArray(StackEntryType type, CMenuBand * mb, HMENU hmenu)
115 {
116 if (m_bandCount >= MAX_RECURSE)
117 return E_OUTOFMEMORY;
118
119 m_bandStack[m_bandCount].type = type;
120 m_bandStack[m_bandCount].mb = mb;
121 m_bandStack[m_bandCount].hmenu = hmenu;
122 m_bandCount++;
123
124 return S_OK;
125 }
126
127 HRESULT CMenuFocusManager::PopFromArray(StackEntryType * pType, CMenuBand ** pMb, HMENU * pHmenu)
128 {
129 if (pType) *pType = NoEntry;
130 if (pMb) *pMb = NULL;
131 if (pHmenu) *pHmenu = NULL;
132
133 if (m_bandCount <= 0)
134 return S_FALSE;
135
136 m_bandCount--;
137
138 if (pType) *pType = m_bandStack[m_bandCount].type;
139 if (*pType == TrackedMenuEntry)
140 {
141 if (pHmenu) *pHmenu = m_bandStack[m_bandCount].hmenu;
142 }
143 else
144 {
145 if (pMb) *pMb = m_bandStack[m_bandCount].mb;
146 }
147
148 return S_OK;
149 }
150
151 CMenuFocusManager::CMenuFocusManager() :
152 m_current(NULL),
153 m_parent(NULL),
154 m_hMsgFilterHook(NULL),
155 m_hGetMsgHook(NULL),
156 m_mouseTrackDisabled(FALSE),
157 m_captureHwnd(0),
158 m_hwndUnderMouse(NULL),
159 m_entryUnderMouse(NULL),
160 m_selectedMenu(NULL),
161 m_selectedItem(0),
162 m_selectedItemFlags(0),
163 m_bandCount(0)
164 {
165 m_ptPrev.x = 0;
166 m_ptPrev.y = 0;
167 m_threadId = GetCurrentThreadId();
168 }
169
170 CMenuFocusManager::~CMenuFocusManager()
171 {
172 }
173
174 void CMenuFocusManager::DisableMouseTrack(HWND parent, BOOL disableThis)
175 {
176 BOOL bDisable = FALSE;
177 BOOL lastDisable = FALSE;
178
179 int i = m_bandCount;
180 while (--i >= 0)
181 {
182 StackEntry& entry = m_bandStack[i];
183
184 if (entry.type != TrackedMenuEntry)
185 {
186 HWND hwnd;
187 HRESULT hr = entry.mb->_GetTopLevelWindow(&hwnd);
188 if (FAILED_UNEXPECTEDLY(hr))
189 break;
190
191 if (hwnd == parent)
192 {
193 lastDisable = disableThis;
194 entry.mb->_DisableMouseTrack(disableThis);
195 bDisable = TRUE;
196 }
197 else
198 {
199 lastDisable = bDisable;
200 entry.mb->_DisableMouseTrack(bDisable);
201 }
202 }
203 }
204 m_mouseTrackDisabled = lastDisable;
205 }
206
207 void CMenuFocusManager::SetCapture(HWND child)
208 {
209 if (m_captureHwnd != child)
210 {
211 if (child)
212 {
213 ::SetCapture(child);
214 m_captureHwnd = child;
215 DbgPrint("MouseTrack is now capturing %p\n", child);
216 }
217 else
218 {
219 ::ReleaseCapture();
220 m_captureHwnd = NULL;
221 DbgPrint("MouseTrack is now off\n");
222 }
223
224 }
225 }
226
227 HRESULT CMenuFocusManager::IsTrackedWindow(HWND hWnd, StackEntry ** pentry)
228 {
229 if (pentry)
230 *pentry = NULL;
231
232 for (int i = m_bandCount; --i >= 0;)
233 {
234 StackEntry& entry = m_bandStack[i];
235
236 if (entry.type != TrackedMenuEntry)
237 {
238 HRESULT hr = entry.mb->IsWindowOwner(hWnd);
239 if (FAILED_UNEXPECTEDLY(hr))
240 return hr;
241 if (hr == S_OK)
242 {
243 if (pentry)
244 *pentry = &entry;
245 return S_OK;
246 }
247 }
248 }
249
250 return S_FALSE;
251 }
252
253 HRESULT CMenuFocusManager::IsTrackedWindowOrParent(HWND hWnd)
254 {
255 for (int i = m_bandCount; --i >= 0;)
256 {
257 StackEntry& entry = m_bandStack[i];
258
259 if (entry.type != TrackedMenuEntry)
260 {
261 HRESULT hr = entry.mb->IsWindowOwner(hWnd);
262 if (FAILED_UNEXPECTEDLY(hr))
263 return hr;
264 if (hr == S_OK)
265 return S_OK;
266 if (entry.mb->_IsPopup() == S_OK)
267 {
268 CComPtr<IUnknown> site;
269 CComPtr<IOleWindow> pw;
270 hr = entry.mb->GetSite(IID_PPV_ARG(IUnknown, &site));
271 if (FAILED_UNEXPECTEDLY(hr))
272 continue;
273 hr = IUnknown_QueryService(site, SID_SMenuBandParent, IID_PPV_ARG(IOleWindow, &pw));
274 if (FAILED_UNEXPECTEDLY(hr))
275 continue;
276
277 HWND hParent;
278 if (pw->GetWindow(&hParent) == S_OK && hParent == hWnd)
279 return S_OK;
280 }
281 }
282 }
283
284 return S_FALSE;
285 }
286
287 LRESULT CMenuFocusManager::ProcessMouseMove(MSG* msg)
288 {
289 HWND child;
290 int iHitTestResult = -1;
291
292 POINT pt2 = { GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam) };
293 ClientToScreen(msg->hwnd, &pt2);
294
295 // Don't do anything if the mouse has not been moved
296 POINT pt = msg->pt;
297 if (pt.x == m_ptPrev.x && pt.y == m_ptPrev.y)
298 return TRUE;
299
300 // Don't do anything if another window is capturing the mouse.
301 HWND cCapture = ::GetCapture();
302 if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry)
303 return TRUE;
304
305 m_ptPrev = pt;
306
307 child = WindowFromPoint(pt);
308
309 StackEntry * entry = NULL;
310 IsTrackedWindow(child, &entry);
311
312 BOOL isTracking = FALSE;
313 if (entry)
314 {
315 ScreenToClient(child, &pt);
316 iHitTestResult = SendMessageW(child, TB_HITTEST, 0, (LPARAM) &pt);
317 isTracking = entry->mb->_IsTracking();
318
319 if (SendMessage(child, WM_USER_ISTRACKEDITEM, iHitTestResult, 0) == S_FALSE)
320 {
321 DbgPrint("Hot item tracking detected a change (capture=%p / cCapture=%p)...\n", m_captureHwnd, cCapture);
322 DisableMouseTrack(NULL, FALSE);
323 if (isTracking && iHitTestResult>=0 && m_current->type == TrackedMenuEntry)
324 SendMessage(entry->hwnd, WM_CANCELMODE, 0, 0);
325 PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, MAKELPARAM(isTracking, TRUE));
326 if (m_current->type == TrackedMenuEntry)
327 return FALSE;
328 }
329 }
330
331 if (m_entryUnderMouse != entry)
332 {
333 // Mouse moved away from a tracked window
334 if (m_entryUnderMouse)
335 {
336 m_entryUnderMouse->mb->_ChangeHotItem(NULL, -1, HICF_MOUSE);
337 }
338 if (cCapture == m_captureHwnd)
339 SetCapture(NULL);
340 }
341
342 if (m_hwndUnderMouse != child)
343 {
344 if (entry)
345 {
346 // Mouse moved to a tracked window
347 if (m_current->type == MenuPopupEntry)
348 {
349 ScreenToClient(child, &pt2);
350 SendMessage(child, WM_MOUSEMOVE, msg->wParam, MAKELPARAM(pt2.x, pt2.y));
351 }
352 }
353
354 m_hwndUnderMouse = child;
355 m_entryUnderMouse = entry;
356 }
357
358 if (m_current->type == MenuPopupEntry)
359 {
360 HWND parent = GetAncestor(child, GA_ROOT);
361 DisableMouseTrack(parent, FALSE);
362 }
363
364 return TRUE;
365 }
366
367 LRESULT CMenuFocusManager::MsgFilterHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
368 {
369 if (nCode < 0)
370 return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
371
372 if (nCode == MSGF_MENU)
373 {
374 BOOL callNext = TRUE;
375 MSG* msg = reinterpret_cast<MSG*>(hookLParam);
376
377 switch (msg->message)
378 {
379 case WM_NCLBUTTONDOWN:
380 case WM_LBUTTONDOWN:
381 if (m_menuBar)
382 {
383 POINT pt = msg->pt;
384 HWND child = WindowFromPoint(pt);
385 BOOL hoveringMenuBar = m_menuBar->mb->IsWindowOwner(child) == S_OK;
386 if (hoveringMenuBar)
387 {
388 m_menuBar->mb->_DisableMouseTrack(TRUE);
389 }
390 }
391 break;
392 case WM_MOUSEMOVE:
393 callNext = ProcessMouseMove(msg);
394 break;
395 case WM_INITMENUPOPUP:
396 DbgPrint("WM_INITMENUPOPUP %p %p\n", msg->wParam, msg->lParam);
397 m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
398 m_selectedItem = -1;
399 m_selectedItemFlags = 0;
400 break;
401 case WM_MENUSELECT:
402 DbgPrint("WM_MENUSELECT %p %p\n", msg->wParam, msg->lParam);
403 m_selectedMenu = reinterpret_cast<HMENU>(msg->lParam);
404 m_selectedItem = GET_X_LPARAM(msg->wParam);
405 m_selectedItemFlags = HIWORD(msg->wParam);
406 break;
407 case WM_KEYDOWN:
408 switch (msg->wParam)
409 {
410 case VK_LEFT:
411 if (m_current->hmenu == m_selectedMenu)
412 {
413 m_parent->mb->_MenuItemHotTrack(VK_LEFT);
414 }
415 break;
416 case VK_RIGHT:
417 if (m_selectedItem < 0 || !(m_selectedItemFlags & MF_POPUP))
418 {
419 m_parent->mb->_MenuItemHotTrack(VK_RIGHT);
420 }
421 break;
422 }
423 break;
424 }
425
426 if (!callNext)
427 return 1;
428 }
429
430 return CallNextHookEx(m_hMsgFilterHook, nCode, hookWParam, hookLParam);
431 }
432
433 LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM hookWParam, LPARAM hookLParam)
434 {
435 if (nCode < 0)
436 return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
437
438 if (nCode == HC_ACTION)
439 {
440 BOOL callNext = TRUE;
441 MSG* msg = reinterpret_cast<MSG*>(hookLParam);
442 POINT pt = msg->pt;
443
444 switch (msg->message)
445 {
446 case WM_NCLBUTTONDOWN:
447 case WM_LBUTTONDOWN:
448 if (m_current->type == MenuPopupEntry)
449 {
450 HWND child = WindowFromPoint(pt);
451
452 if (IsTrackedWindowOrParent(child) != S_OK)
453 {
454 SetCapture(NULL);
455 m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
456 }
457 }
458 break;
459 case WM_MOUSEMOVE:
460 callNext = ProcessMouseMove(msg);
461 break;
462 case WM_MOUSELEAVE:
463 callNext = ProcessMouseMove(msg);
464 //callNext = ProcessMouseLeave(msg);
465 break;
466 case WM_SYSKEYDOWN:
467 case WM_KEYDOWN:
468 if (m_current->type == MenuPopupEntry)
469 {
470 DisableMouseTrack(m_current->hwnd, TRUE);
471 switch (msg->wParam)
472 {
473 case VK_ESCAPE:
474 case VK_MENU:
475 case VK_LMENU:
476 case VK_RMENU:
477 m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL);
478 break;
479 case VK_RETURN:
480 m_current->mb->_MenuItemHotTrack(MPOS_EXECUTE);
481 break;
482 case VK_LEFT:
483 m_current->mb->_MenuItemHotTrack(VK_LEFT);
484 break;
485 case VK_RIGHT:
486 m_current->mb->_MenuItemHotTrack(VK_RIGHT);
487 break;
488 case VK_UP:
489 m_current->mb->_MenuItemHotTrack(VK_UP);
490 break;
491 case VK_DOWN:
492 m_current->mb->_MenuItemHotTrack(VK_DOWN);
493 break;
494 }
495 msg->message = WM_NULL;
496 msg->lParam = 0;
497 msg->wParam = 0;
498 }
499 break;
500 }
501
502 if (!callNext)
503 return 1;
504 }
505
506 return CallNextHookEx(m_hGetMsgHook, nCode, hookWParam, hookLParam);
507 }
508
509 HRESULT CMenuFocusManager::PlaceHooks()
510 {
511 if (m_current->type == TrackedMenuEntry)
512 {
513 DbgPrint("Entering MSGFILTER hook...\n");
514 m_hMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, s_MsgFilterHook, NULL, m_threadId);
515 }
516 else
517 {
518 DbgPrint("Entering GETMESSAGE hook...\n");
519 m_hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId);
520 }
521 return S_OK;
522 }
523
524 HRESULT CMenuFocusManager::RemoveHooks()
525 {
526 DbgPrint("Removing all hooks...\n");
527 if (m_hMsgFilterHook)
528 UnhookWindowsHookEx(m_hMsgFilterHook);
529 if (m_hGetMsgHook)
530 UnhookWindowsHookEx(m_hGetMsgHook);
531 m_hMsgFilterHook = NULL;
532 m_hGetMsgHook = NULL;
533 return S_OK;
534 }
535
536 HRESULT CMenuFocusManager::UpdateFocus()
537 {
538 HRESULT hr;
539 StackEntry * old = m_current;
540
541 if (old)
542 SetCapture(NULL);
543
544 if (m_bandCount > 0)
545 m_current = &(m_bandStack[m_bandCount - 1]);
546 else
547 m_current = NULL;
548
549 if (m_current && m_current->type != TrackedMenuEntry)
550 {
551 hr = m_current->mb->_GetTopLevelWindow(&(m_current->hwnd));
552 if (FAILED_UNEXPECTEDLY(hr))
553 return hr;
554 }
555
556 if (m_bandCount >= 2)
557 {
558 m_parent = &(m_bandStack[m_bandCount - 2]);
559 _ASSERT(m_parent->type != TrackedMenuEntry);
560 }
561 else
562 {
563 m_parent = NULL;
564 }
565
566 if (m_bandCount >= 1 && m_bandStack[0].type == MenuBarEntry)
567 {
568 m_menuBar = &(m_bandStack[0]);
569 }
570 else
571 {
572 m_menuBar = NULL;
573 }
574
575 if (old && (!m_current || old->type != m_current->type))
576 {
577 if (m_current && m_current->type != TrackedMenuEntry)
578 {
579 DisableMouseTrack(m_current->hwnd, FALSE);
580 }
581
582 hr = RemoveHooks();
583 if (FAILED_UNEXPECTEDLY(hr))
584 return hr;
585 }
586
587 if (m_current && (!old || old->type != m_current->type))
588 {
589 hr = PlaceHooks();
590 if (FAILED_UNEXPECTEDLY(hr))
591 return hr;
592 }
593
594 if (m_parent)
595 {
596 DisableMouseTrack(m_parent->hwnd, TRUE);
597 }
598
599 if ((m_current && m_current->type == MenuPopupEntry) &&
600 (!m_parent || m_parent->type == MenuBarEntry))
601 {
602 // When the mouse moves, it should set itself to the proper band
603 SetCapture(m_current->hwnd);
604
605 if (old && old->type == TrackedMenuEntry)
606 {
607 // FIXME: Debugging code, probably not right
608 POINT pt2;
609 RECT rc2;
610 GetCursorPos(&pt2);
611 ScreenToClient(m_current->hwnd, &pt2);
612 GetClientRect(m_current->hwnd, &rc2);
613 if (PtInRect(&rc2, pt2))
614 SendMessage(m_current->hwnd, WM_MOUSEMOVE, 0, MAKELPARAM(pt2.x, pt2.y));
615 else
616 SendMessage(m_current->hwnd, WM_MOUSELEAVE, 0, 0);
617 }
618 }
619
620 _ASSERT(!m_parent || m_parent->type != TrackedMenuEntry);
621
622 return S_OK;
623 }
624
625 HRESULT CMenuFocusManager::PushMenuBar(CMenuBand * mb)
626 {
627 _ASSERT(m_bandCount == 0);
628
629 HRESULT hr = PushToArray(MenuBarEntry, mb, NULL);
630 if (FAILED_UNEXPECTEDLY(hr))
631 return hr;
632
633 return UpdateFocus();
634 }
635
636 HRESULT CMenuFocusManager::PushMenuPopup(CMenuBand * mb)
637 {
638 _ASSERT(!m_current || m_current->type != TrackedMenuEntry);
639
640 HRESULT hr = PushToArray(MenuPopupEntry, mb, NULL);
641 if (FAILED_UNEXPECTEDLY(hr))
642 return hr;
643
644 hr = UpdateFocus();
645
646 if (m_parent && m_parent->type != TrackedMenuEntry)
647 {
648 m_parent->mb->_SetChildBand(mb);
649 mb->_SetParentBand(m_parent->mb);
650 }
651
652 return hr;
653 }
654
655 HRESULT CMenuFocusManager::PushTrackedPopup(HMENU popup)
656 {
657 _ASSERT(m_bandCount > 0);
658 _ASSERT(!m_current || m_current->type != TrackedMenuEntry);
659
660 HRESULT hr = PushToArray(TrackedMenuEntry, NULL, popup);
661 if (FAILED_UNEXPECTEDLY(hr))
662 return hr;
663
664 DbgPrint("PushTrackedPopup %p\n", popup);
665 m_selectedMenu = popup;
666 m_selectedItem = -1;
667 m_selectedItemFlags = 0;
668
669 return UpdateFocus();
670 }
671
672 HRESULT CMenuFocusManager::PopMenuBar(CMenuBand * mb)
673 {
674 StackEntryType type;
675 CMenuBand * mbc;
676 HRESULT hr;
677
678 hr = PopFromArray(&type, &mbc, NULL);
679 if (FAILED_UNEXPECTEDLY(hr))
680 {
681 UpdateFocus();
682 return hr;
683 }
684
685 _ASSERT(type == MenuBarEntry);
686 if (type != MenuBarEntry)
687 return E_FAIL;
688
689 if (!mbc)
690 return E_FAIL;
691
692 mbc->_SetParentBand(NULL);
693
694 hr = UpdateFocus();
695 if (FAILED_UNEXPECTEDLY(hr))
696 return hr;
697
698 if (m_current)
699 {
700 _ASSERT(m_current->type != TrackedMenuEntry);
701 m_current->mb->_SetChildBand(NULL);
702 }
703
704 return S_OK;
705 }
706
707 HRESULT CMenuFocusManager::PopMenuPopup(CMenuBand * mb)
708 {
709 StackEntryType type;
710 CMenuBand * mbc;
711 HRESULT hr;
712
713 hr = PopFromArray(&type, &mbc, NULL);
714 if (FAILED_UNEXPECTEDLY(hr))
715 {
716 UpdateFocus();
717 return hr;
718 }
719
720 _ASSERT(type == MenuPopupEntry);
721 if (type != MenuPopupEntry)
722 return E_FAIL;
723
724 if (!mbc)
725 return E_FAIL;
726
727 mbc->_SetParentBand(NULL);
728
729 hr = UpdateFocus();
730 if (FAILED_UNEXPECTEDLY(hr))
731 return hr;
732
733 if (m_current)
734 {
735 _ASSERT(m_current->type != TrackedMenuEntry);
736 m_current->mb->_SetChildBand(NULL);
737 }
738
739 return S_OK;
740 }
741
742 HRESULT CMenuFocusManager::PopTrackedPopup(HMENU popup)
743 {
744 StackEntryType type;
745 HMENU hmenu;
746 HRESULT hr;
747
748 hr = PopFromArray(&type, NULL, &hmenu);
749 if (FAILED_UNEXPECTEDLY(hr))
750 {
751 UpdateFocus();
752 return hr;
753 }
754
755 _ASSERT(type == TrackedMenuEntry);
756 if (type != TrackedMenuEntry)
757 return E_FAIL;
758
759 if (hmenu != popup)
760 return E_FAIL;
761
762 hr = UpdateFocus();
763 if (FAILED_UNEXPECTEDLY(hr))
764 return hr;
765
766 return S_OK;
767 }