xref: /reactos/dll/win32/msutb/msutb.cpp (revision 32d615fc)
1 /*
2  * PROJECT:     ReactOS msutb.dll
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Language Bar (Tipbar)
5  * COPYRIGHT:   Copyright 2023-2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #include "precomp.h"
9 
10 WINE_DEFAULT_DEBUG_CHANNEL(msutb);
11 
12 //#define ENABLE_DESKBAND
13 
14 typedef struct LANGBARITEMSTATE
15 {
16     CLSID m_clsid;
17     DWORD m_dwDemoteLevel;
18     UINT_PTR m_nTimerID;
19     UINT m_uTimeOut;
20     BOOL m_bStartedIntentionally;
21     BOOL m_bDisableDemoting;
22 
23     BOOL IsShown()
24     {
25         return m_dwDemoteLevel < 2;
26     }
27 } LANGBARITEMSTATE, *PLANGBARITEMSTATE;
28 
29 HINSTANCE g_hInst = NULL;
30 UINT g_wmTaskbarCreated = 0;
31 UINT g_uACP = CP_ACP;
32 DWORD g_dwOSInfo = 0;
33 CRITICAL_SECTION g_cs;
34 LONG g_DllRefCount = 0;
35 BOOL g_bWinLogon = FALSE;
36 BOOL g_fInClosePopupTipbar = FALSE;
37 HWND g_hwndParent = NULL;
38 CIC_LIBTHREAD g_libTLS = { NULL, NULL };
39 #ifdef ENABLE_DESKBAND
40 BOOL g_bEnableDeskBand = TRUE;
41 #else
42 BOOL g_bEnableDeskBand = FALSE;
43 #endif
44 
45 BOOL g_bShowTipbar = TRUE;
46 BOOL g_bShowDebugMenu = FALSE;
47 BOOL g_bNewLook = TRUE;
48 BOOL g_bIntelliSense = FALSE;
49 BOOL g_bShowCloseMenu = FALSE;
50 UINT g_uTimeOutNonIntentional = 60 * 1000;
51 UINT g_uTimeOutIntentional = 10 * 60 * 1000;
52 UINT g_uTimeOutMax = 60 * 60 * 1000;
53 BOOL g_bShowMinimizedBalloon = TRUE;
54 POINT g_ptTipbar = { -1, -1 };
55 BOOL g_bExcludeCaptionButtons = TRUE;
56 BOOL g_bShowShadow = FALSE;
57 BOOL g_fTaskbarTheme = TRUE;
58 BOOL g_fVertical = FALSE;
59 UINT g_uTimerElapseSTUBSTART = 100;
60 UINT g_uTimerElapseSTUBEND = 2 * 1000;
61 UINT g_uTimerElapseBACKTOALPHA = 3 * 1000;
62 UINT g_uTimerElapseONTHREADITEMCHANGE = 200;
63 UINT g_uTimerElapseSETWINDOWPOS = 100;
64 UINT g_uTimerElapseONUPDATECALLED = 50;
65 UINT g_uTimerElapseSYSCOLORCHANGED = 20;
66 UINT g_uTimerElapseDISPLAYCHANGE = 20;
67 UINT g_uTimerElapseUPDATEUI = 70;
68 UINT g_uTimerElapseSHOWWINDOW = 50;
69 UINT g_uTimerElapseMOVETOTRAY = 50;
70 UINT g_uTimerElapseTRAYWNDONDELAYMSG = 50;
71 UINT g_uTimerElapseDOACCDEFAULTACTION = 200;
72 UINT g_uTimerElapseENSUREFOCUS = 50;
73 BOOL g_bShowDeskBand = FALSE;
74 UINT g_uTimerElapseSHOWDESKBAND = 3 * 1000;
75 BOOL g_fPolicyDisableCloseButton = FALSE;
76 BOOL g_fPolicyEnableLanguagebarInFullscreen = FALSE;
77 DWORD g_dwWndStyle = 0;
78 DWORD g_dwMenuStyle = 0;
79 DWORD g_dwChildWndStyle = 0;
80 BOOL g_fRTL = FALSE;
81 
82 #define TIMER_ID_DOACCDEFAULTACTION 11
83 
84 EXTERN_C void __cxa_pure_virtual(void)
85 {
86     ERR("__cxa_pure_virtual\n");
87 }
88 
89 class CMsUtbModule : public CComModule
90 {
91 };
92 
93 CMsUtbModule gModule;
94 
95 class CCicLibMenuItem;
96 class CTipbarAccItem;
97 class CUTBMenuItem;
98 class CMainIconItem;
99 class CTrayIconItem;
100 class CTipbarWnd;
101 class CButtonIconItem;
102 class CTrayIconWnd;
103 
104 CTipbarWnd *g_pTipbarWnd = NULL;
105 CTrayIconWnd *g_pTrayIconWnd = NULL;
106 
107 CicArray<HKL> *g_prghklSkipRedrawing = NULL;
108 
109 BOOL IsSkipRedrawHKL(HKL hSkipKL)
110 {
111     if (LOWORD(hSkipKL) == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT))
112         return FALSE; // Japanese HKL will be skipped
113     if (!g_prghklSkipRedrawing)
114         return FALSE;
115 
116     for (size_t iItem = 0; iItem < g_prghklSkipRedrawing->size(); ++iItem)
117     {
118         if ((*g_prghklSkipRedrawing)[iItem] == hSkipKL)
119             return TRUE; // To be skipped
120     }
121 
122     return FALSE; // To be not skipped
123 }
124 
125 BOOL IsBiDiLocalizedSystem(void)
126 {
127     LOCALESIGNATURE Sig;
128     LANGID LangID = ::GetUserDefaultUILanguage();
129     if (!LangID)
130         return FALSE;
131 
132     INT size = sizeof(Sig) / sizeof(WCHAR);
133     if (!::GetLocaleInfoW(LangID, LOCALE_FONTSIGNATURE, (LPWSTR)&Sig, size))
134         return FALSE;
135     return (Sig.lsUsb[3] & 0x8000000) != 0;
136 }
137 
138 BOOL GetFontSig(HWND hWnd, HKL hKL)
139 {
140     LOCALESIGNATURE Sig;
141     INT size = sizeof(Sig) / sizeof(WCHAR);
142     if (!::GetLocaleInfoW(LOWORD(hKL), LOCALE_FONTSIGNATURE, (LPWSTR)&Sig, size))
143         return FALSE;
144 
145     HDC hDC = ::GetDC(hWnd);
146     DWORD CharSet = ::GetTextCharsetInfo(hDC, NULL, 0);
147     CHARSETINFO CharSetInfo;
148     ::TranslateCharsetInfo((DWORD*)(DWORD_PTR)CharSet, &CharSetInfo, TCI_SRCCHARSET);
149     ::ReleaseDC(hWnd, hDC);
150 
151     return !!(CharSetInfo.fs.fsCsb[0] & Sig.lsCsbSupported[0]);
152 }
153 
154 void InitSkipRedrawHKLArray(void)
155 {
156     g_prghklSkipRedrawing = new(cicNoThrow) CicArray<HKL>();
157     if (!g_prghklSkipRedrawing)
158         return;
159 
160     if (g_bEnableDeskBand && (g_dwOSInfo & CIC_OSINFO_XPPLUS))
161     {
162         // Japanese IME will be skipped
163         g_prghklSkipRedrawing->Add((HKL)UlongToHandle(0xE0010411));
164     }
165 
166     CicRegKey regKey;
167     LSTATUS error = regKey.Open(HKEY_LOCAL_MACHINE,
168                                 TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\SkipRedrawHKL"));
169     if (error != ERROR_SUCCESS)
170         return;
171 
172     TCHAR szValueName[256];
173     for (DWORD dwIndex = 0; ; ++dwIndex)
174     {
175         error = regKey.EnumValue(dwIndex, szValueName, _countof(szValueName));
176         if (error != ERROR_SUCCESS)
177             break;
178 
179         if (szValueName[0] == TEXT('0') &&
180             (szValueName[1] == TEXT('x') || szValueName[1] == TEXT('X')))
181         {
182             HKL hKL = (HKL)UlongToHandle(_tcstoul(szValueName, NULL, 16));
183             g_prghklSkipRedrawing->Add(hKL); // This hKL will be skipped
184         }
185     }
186 }
187 
188 void UninitSkipRedrawHKLArray(void)
189 {
190     if (g_prghklSkipRedrawing)
191     {
192         delete g_prghklSkipRedrawing;
193         g_prghklSkipRedrawing = NULL;
194     }
195 }
196 
197 HRESULT GetGlobalCompartment(REFGUID rguid, ITfCompartment **ppComp)
198 {
199     ITfCompartmentMgr *pCompMgr = NULL;
200     HRESULT hr = TF_GetGlobalCompartment(&pCompMgr);
201     if (FAILED(hr))
202         return hr;
203 
204     if (!pCompMgr)
205         return E_FAIL;
206 
207     hr = pCompMgr->GetCompartment(rguid, ppComp);
208     pCompMgr->Release();
209     return hr;
210 }
211 
212 HRESULT GetGlobalCompartmentDWORD(REFGUID rguid, LPDWORD pdwValue)
213 {
214     *pdwValue = 0;
215     ITfCompartment *pComp;
216     HRESULT hr = GetGlobalCompartment(rguid, &pComp);
217     if (SUCCEEDED(hr))
218     {
219         VARIANT vari;
220         hr = pComp->GetValue(&vari);
221         if (hr == S_OK)
222             *pdwValue = V_I4(&vari);
223         pComp->Release();
224     }
225     return hr;
226 }
227 
228 HRESULT SetGlobalCompartmentDWORD(REFGUID rguid, DWORD dwValue)
229 {
230     VARIANT vari;
231     ITfCompartment *pComp;
232     HRESULT hr = GetGlobalCompartment(rguid, &pComp);
233     if (SUCCEEDED(hr))
234     {
235         V_VT(&vari) = VT_I4;
236         V_I4(&vari) = dwValue;
237         hr = pComp->SetValue(0, &vari);
238         pComp->Release();
239     }
240     return hr;
241 }
242 
243 void TurnOffSpeechIfItsOn(void)
244 {
245     DWORD dwValue = 0;
246     HRESULT hr = GetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, &dwValue);
247     if (SUCCEEDED(hr) && dwValue)
248         SetGlobalCompartmentDWORD(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0);
249 }
250 
251 void DoCloseLangbar(void)
252 {
253     ITfLangBarMgr *pLangBarMgr = NULL;
254     HRESULT hr = TF_CreateLangBarMgr(&pLangBarMgr);
255     if (FAILED(hr))
256         return;
257 
258     if (pLangBarMgr)
259     {
260         hr = pLangBarMgr->ShowFloating(TF_SFT_HIDDEN);
261         pLangBarMgr->Release();
262     }
263 
264     if (SUCCEEDED(hr))
265         TurnOffSpeechIfItsOn();
266 
267     CicRegKey regKey;
268     LSTATUS error = regKey.Open(HKEY_CURRENT_USER,
269                                 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
270                                 KEY_ALL_ACCESS);
271     if (error == ERROR_SUCCESS)
272         ::RegDeleteValue(regKey, TEXT("ctfmon.exe"));
273 }
274 
275 INT GetIconIndexFromhKL(_In_ HKL hKL)
276 {
277     HKL hGotKL;
278 
279     INT iKL, cKLs = TF_MlngInfoCount();
280     for (iKL = 0; iKL < cKLs; ++iKL)
281     {
282         if (TF_GetMlngHKL(iKL, &hGotKL, NULL, 0) && hKL == hGotKL)
283             return TF_GetMlngIconIndex(iKL);
284     }
285 
286     if (!TF_GetMlngHKL(0, &hGotKL, NULL, 0))
287         return -1;
288 
289     return TF_GetMlngIconIndex(0);
290 }
291 
292 BOOL GethKLDesc(_In_ HKL hKL, _Out_ LPWSTR pszDesc, _In_ UINT cchDesc)
293 {
294     HKL hGotKL;
295 
296     INT iKL, cKLs = TF_MlngInfoCount();
297     for (iKL = 0; iKL < cKLs; ++iKL)
298     {
299         if (TF_GetMlngHKL(iKL, &hGotKL, pszDesc, cchDesc) && hKL == hGotKL)
300             return TRUE;
301     }
302 
303     return TF_GetMlngHKL(0, &hGotKL, pszDesc, cchDesc);
304 }
305 
306 HRESULT
307 LangBarInsertMenu(
308     _In_ ITfMenu *pMenu,
309     _In_ UINT uId,
310     _In_ LPCWSTR pszText,
311     _In_ BOOL bChecked,
312     _Inout_opt_ HICON hIcon)
313 {
314     HBITMAP hbmp = NULL, hbmpMask = NULL;
315     if (hIcon)
316     {
317         HICON hIconNew = (HICON)::CopyImage(hIcon, IMAGE_ICON, 16, 16, LR_COPYFROMRESOURCE);
318         SIZE iconSize = { 16, 16 };
319         if (!hIconNew)
320             hIconNew = hIcon;
321         if (!cicGetIconBitmaps(hIconNew, &hbmp, &hbmpMask, &iconSize))
322             return E_FAIL;
323         if (hIconNew)
324             ::DestroyIcon(hIconNew);
325         ::DestroyIcon(hIcon);
326     }
327 
328     INT cchText = lstrlenW(pszText);
329     DWORD dwFlags = (bChecked ? TF_LBMENUF_CHECKED : 0);
330     return pMenu->AddMenuItem(uId, dwFlags, hbmp, hbmpMask, pszText, cchText, NULL);
331 }
332 
333 HRESULT LangBarInsertSeparator(_In_ ITfMenu *pMenu)
334 {
335     return pMenu->AddMenuItem(-1, TF_LBMENUF_SEPARATOR, NULL, NULL, NULL, 0, NULL);
336 }
337 
338 // Is it a Far-East language ID?
339 BOOL IsFELangId(LANGID LangID)
340 {
341     switch (LangID)
342     {
343         case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): // Chinese (Simplified)
344         case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): // Chinese (Traditional)
345         case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT): // Japanese
346         case MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT): // Korean
347             return TRUE;
348         default:
349             return FALSE;
350     }
351 }
352 
353 BOOL CheckCloseMenuAvailable(void)
354 {
355     BOOL ret = FALSE;
356     ITfInputProcessorProfiles *pProfiles = NULL;
357     LANGID *pLangIds = NULL;
358     ULONG iItem, cItems;
359 
360     if (g_fPolicyDisableCloseButton)
361         return FALSE;
362 
363     if (g_bShowCloseMenu)
364         return TRUE;
365 
366     if (SUCCEEDED(TF_CreateInputProcessorProfiles(&pProfiles)) &&
367         SUCCEEDED(pProfiles->GetLanguageList(&pLangIds, &cItems)))
368     {
369         for (iItem = 0; iItem < cItems; ++iItem)
370         {
371             if (IsFELangId(pLangIds[iItem]))
372                 break;
373         }
374 
375         ret = (iItem == cItems);
376     }
377 
378     if (pLangIds)
379         CoTaskMemFree(pLangIds);
380     if (pProfiles)
381         pProfiles->Release();
382 
383     return ret;
384 }
385 
386 /// @unimplemented
387 BOOL IsTransparecyAvailable(void)
388 {
389     return FALSE;
390 }
391 
392 static INT CALLBACK
393 FindEAEnumFontProc(ENUMLOGFONT *pLF, NEWTEXTMETRIC *pTM, INT nFontType, LPARAM lParam)
394 {
395     if ((nFontType != TRUETYPE_FONTTYPE) || (pLF->elfLogFont.lfFaceName[0] != '@'))
396         return TRUE;
397     *(BOOL*)lParam = TRUE;
398     return FALSE;
399 }
400 
401 /// Are there East-Asian vertical fonts?
402 BOOL CheckEAFonts(void)
403 {
404     BOOL bHasVertical = FALSE;
405     HDC hDC = ::GetDC(NULL);
406     ::EnumFonts(hDC, NULL, (FONTENUMPROC)FindEAEnumFontProc, (LPARAM)&bHasVertical);
407     ::ReleaseDC(NULL, hDC);
408     return bHasVertical;
409 }
410 
411 BOOL IsDeskBandFromReg()
412 {
413     if (!g_bEnableDeskBand || !(g_dwOSInfo & CIC_OSINFO_XPPLUS)) // Desk band is for XP+
414         return FALSE;
415 
416     CicRegKey regKey;
417     if (regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\")))
418     {
419         DWORD dwValue = 0;
420         regKey.QueryDword(TEXT("ShowDeskBand"), &dwValue);
421         return !!dwValue;
422     }
423 
424     return FALSE;
425 }
426 
427 void SetDeskBandToReg(BOOL bShow)
428 {
429     CicRegKey regKey;
430     if (regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"), KEY_ALL_ACCESS))
431         regKey.SetDword(TEXT("ShowDeskBand"), bShow);
432 }
433 
434 BOOL RegisterComCat(REFCLSID rclsid, REFCATID rcatid, BOOL bRegister)
435 {
436     if (FAILED(::CoInitialize(NULL)))
437         return FALSE;
438 
439     ICatRegister *pCat;
440     HRESULT hr = ::CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER,
441                                     IID_ICatRegister, (void**)&pCat);
442     if (SUCCEEDED(hr))
443     {
444         if (bRegister)
445             hr = pCat->RegisterClassImplCategories(rclsid, 1, const_cast<CATID*>(&rcatid));
446         else
447             hr = pCat->UnRegisterClassImplCategories(rclsid, 1, const_cast<CATID*>(&rcatid));
448 
449         pCat->Release();
450     }
451 
452     ::CoUninitialize();
453 
454     //if (IsIE5())
455     //    ::RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Component Categories\\{00021492-0000-0000-C000-000000000046}\\Enum"));
456 
457     return SUCCEEDED(hr);
458 }
459 
460 BOOL InitFromReg(void)
461 {
462     DWORD dwValue;
463     LSTATUS error;
464 
465     CicRegKey regKey1;
466     error = regKey1.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\"));
467     if (error == ERROR_SUCCESS)
468     {
469         error = regKey1.QueryDword(TEXT("ShowTipbar"), &dwValue);
470         if (error == ERROR_SUCCESS)
471             g_bShowTipbar = !!dwValue;
472     }
473 
474     CicRegKey regKey2;
475     error = regKey2.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
476     if (error == ERROR_SUCCESS)
477     {
478         error = regKey2.QueryDword(TEXT("ShowDebugMenu"), &dwValue);
479         if (error == ERROR_SUCCESS)
480             g_bShowDebugMenu = !!dwValue;
481         error = regKey2.QueryDword(TEXT("NewLook"), &dwValue);
482         if (error == ERROR_SUCCESS)
483             g_bNewLook = !!dwValue;
484         error = regKey2.QueryDword(TEXT("IntelliSense"), &dwValue);
485         if (error == ERROR_SUCCESS)
486             g_bIntelliSense = !!dwValue;
487         error = regKey2.QueryDword(TEXT("ShowCloseMenu"), &dwValue);
488         if (error == ERROR_SUCCESS)
489             g_bShowCloseMenu = !!dwValue;
490         error = regKey2.QueryDword(TEXT("TimeOutNonIntentional"), &dwValue);
491         if (error == ERROR_SUCCESS)
492             g_uTimeOutNonIntentional = 1000 * dwValue;
493         error = regKey2.QueryDword(TEXT("TimeOutIntentional"), &dwValue);
494         if (error == ERROR_SUCCESS)
495         {
496             g_uTimeOutIntentional = 1000 * dwValue;
497             g_uTimeOutMax = 6000 * dwValue;
498         }
499         error = regKey2.QueryDword(TEXT("ShowMinimizedBalloon"), &dwValue);
500         if (error == ERROR_SUCCESS)
501             g_bShowMinimizedBalloon = !!dwValue;
502         error = regKey2.QueryDword(TEXT("Left"), &dwValue);
503         if (error == ERROR_SUCCESS)
504             g_ptTipbar.x = dwValue;
505         error = regKey2.QueryDword(TEXT("Top"), &dwValue);
506         if (error == ERROR_SUCCESS)
507             g_ptTipbar.y = dwValue;
508         error = regKey2.QueryDword(TEXT("ExcludeCaptionButtons"), &dwValue);
509         if (error == ERROR_SUCCESS)
510             g_bExcludeCaptionButtons = !!dwValue;
511         error = regKey2.QueryDword(TEXT("ShowShadow"), &dwValue);
512         if (error == ERROR_SUCCESS)
513             g_bShowShadow = !!dwValue;
514         error = regKey2.QueryDword(TEXT("TaskbarTheme"), &dwValue);
515         if (error == ERROR_SUCCESS)
516             g_fTaskbarTheme = !!dwValue;
517         error = regKey2.QueryDword(TEXT("Vertical"), &dwValue);
518         if (error == ERROR_SUCCESS)
519             g_fVertical = !!dwValue;
520         error = regKey2.QueryDword(TEXT("TimerElapseSTUBSTART"), &dwValue);
521         if (error == ERROR_SUCCESS)
522             g_uTimerElapseSTUBSTART = dwValue;
523         error = regKey2.QueryDword(TEXT("TimerElapseSTUBEND"), &dwValue);
524         if (error == ERROR_SUCCESS)
525             g_uTimerElapseSTUBEND = dwValue;
526         error = regKey2.QueryDword(TEXT("TimerElapseBACKTOALPHA"), &dwValue);
527         if (error == ERROR_SUCCESS)
528             g_uTimerElapseBACKTOALPHA = dwValue;
529         error = regKey2.QueryDword(TEXT("TimerElapseONTHREADITEMCHANGE"), &dwValue);
530         if (error == ERROR_SUCCESS)
531             g_uTimerElapseONTHREADITEMCHANGE = dwValue;
532         error = regKey2.QueryDword(TEXT("TimerElapseSETWINDOWPOS"), &dwValue);
533         if (error == ERROR_SUCCESS)
534             g_uTimerElapseSETWINDOWPOS = dwValue;
535         error = regKey2.QueryDword(TEXT("TimerElapseONUPDATECALLED"), &dwValue);
536         if (error == ERROR_SUCCESS)
537             g_uTimerElapseONUPDATECALLED = dwValue;
538         error = regKey2.QueryDword(TEXT("TimerElapseSYSCOLORCHANGED"), &dwValue);
539         if (error == ERROR_SUCCESS)
540             g_uTimerElapseSYSCOLORCHANGED = dwValue;
541         error = regKey2.QueryDword(TEXT("TimerElapseDISPLAYCHANGE"), &dwValue);
542         if (error == ERROR_SUCCESS)
543             g_uTimerElapseDISPLAYCHANGE = dwValue;
544         error = regKey2.QueryDword(TEXT("TimerElapseUPDATEUI"), &dwValue);
545         if (error == ERROR_SUCCESS)
546             g_uTimerElapseUPDATEUI = dwValue;
547         error = regKey2.QueryDword(TEXT("TimerElapseSHOWWINDOW"), &dwValue);
548         if (error == ERROR_SUCCESS)
549             g_uTimerElapseSHOWWINDOW = dwValue;
550         error = regKey2.QueryDword(TEXT("TimerElapseMOVETOTRAY"), &dwValue);
551         if (error == ERROR_SUCCESS)
552             g_uTimerElapseMOVETOTRAY = dwValue;
553         error = regKey2.QueryDword(TEXT("TimerElapseTRAYWNDONDELAYMSG"), &dwValue);
554         if (error == ERROR_SUCCESS)
555             g_uTimerElapseTRAYWNDONDELAYMSG = dwValue;
556         error = regKey2.QueryDword(TEXT("TimerElapseDOACCDEFAULTACTION"), &dwValue);
557         if (error == ERROR_SUCCESS)
558             g_uTimerElapseDOACCDEFAULTACTION = dwValue;
559         error = regKey2.QueryDword(TEXT("TimerElapseENSUREFOCUS"), &dwValue);
560         if (error == ERROR_SUCCESS)
561             g_uTimerElapseENSUREFOCUS = dwValue;
562         if (g_bEnableDeskBand && (g_dwOSInfo & CIC_OSINFO_XPPLUS))
563         {
564             error = regKey2.QueryDword(TEXT("ShowDeskBand"), &dwValue);
565             if (error == ERROR_SUCCESS)
566                 g_bShowDeskBand = !!dwValue;
567             error = regKey2.QueryDword(TEXT("TimerElapseSHOWWDESKBAND"), &dwValue);
568             if (error == ERROR_SUCCESS)
569                 g_uTimerElapseSHOWDESKBAND = dwValue;
570         }
571     }
572 
573     CicRegKey regKey3;
574     error = regKey3.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Policies\\Microsoft\\MSCTF"));
575     if (error == ERROR_SUCCESS)
576     {
577         error = regKey3.QueryDword(TEXT("DisableCloseButton"), &dwValue);
578         if (error == ERROR_SUCCESS)
579             g_fPolicyDisableCloseButton = !!dwValue;
580     }
581 
582     CicRegKey regKey4;
583     error = regKey4.Open(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Policies\\Microsoft\\MSCTF"));
584     if (error == ERROR_SUCCESS)
585     {
586         error = regKey4.QueryDword(TEXT("EnableLanguagebarInFullscreen"), &dwValue);
587         if (error == ERROR_SUCCESS)
588             g_fPolicyEnableLanguagebarInFullscreen = !!dwValue;
589     }
590 
591     InitSkipRedrawHKLArray();
592 
593     if (g_bNewLook)
594     {
595         g_dwWndStyle = UIF_WINDOW_ENABLETHEMED | UIF_WINDOW_WORKAREA | UIF_WINDOW_TOOLTIP |
596                        UIF_WINDOW_TOOLWINDOW | UIF_WINDOW_TOPMOST;
597         if (g_bShowShadow)
598             g_dwWndStyle |= UIF_WINDOW_SHADOW;
599         g_dwMenuStyle = 0x10000000 | UIF_WINDOW_MONITOR | UIF_WINDOW_SHADOW |
600                         UIF_WINDOW_TOOLWINDOW | UIF_WINDOW_TOPMOST;
601     }
602     else
603     {
604         g_dwWndStyle = UIF_WINDOW_WORKAREA | UIF_WINDOW_TOOLTIP | UIF_WINDOW_DLGFRAME |
605                        UIF_WINDOW_TOPMOST;
606         g_dwMenuStyle = UIF_WINDOW_MONITOR | UIF_WINDOW_DLGFRAME | UIF_WINDOW_TOPMOST;
607     }
608 
609     g_dwChildWndStyle =
610         UIF_WINDOW_ENABLETHEMED | UIF_WINDOW_NOMOUSEMSG | UIF_WINDOW_TOOLTIP | UIF_WINDOW_CHILD;
611 
612     if (IsBiDiLocalizedSystem())
613     {
614         g_dwWndStyle |= UIF_WINDOW_LAYOUTRTL;
615         g_dwChildWndStyle |= UIF_WINDOW_LAYOUTRTL;
616         g_dwMenuStyle |= UIF_WINDOW_LAYOUTRTL;
617         g_fRTL = TRUE;
618     }
619 
620     return TRUE;
621 }
622 
623 /***********************************************************************/
624 
625 struct CShellWndThread
626 {
627     HWND m_hTrayWnd = NULL;
628     HWND m_hProgmanWnd = NULL;
629 
630     HWND GetWndTray()
631     {
632         if (!m_hTrayWnd || !::IsWindow(m_hTrayWnd))
633             m_hTrayWnd = ::FindWindowW(L"Shell_TrayWnd", NULL);
634         return m_hTrayWnd;
635     }
636 
637     HWND GetWndProgman()
638     {
639         if (!m_hProgmanWnd || !::IsWindow(m_hProgmanWnd))
640             m_hProgmanWnd = ::FindWindowW(L"Progman", NULL);
641         return m_hProgmanWnd;
642     }
643 
644     void clear()
645     {
646         m_hTrayWnd = m_hProgmanWnd = NULL;
647     }
648 };
649 
650 /***********************************************************************/
651 
652 class CUTBLangBarDlg
653 {
654 protected:
655     LPTSTR m_pszDialogName;
656     LONG m_cRefs;
657 
658 public:
659     CUTBLangBarDlg() { }
660     virtual ~CUTBLangBarDlg() { }
661 
662     static CUTBLangBarDlg *GetThis(HWND hDlg);
663     static void SetThis(HWND hDlg, CUTBLangBarDlg *pThis);
664     static DWORD WINAPI s_ThreadProc(LPVOID pParam);
665     static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
666 
667     BOOL StartThread();
668     LONG _Release();
669 
670     STDMETHOD_(BOOL, DoModal)(HWND hDlg) = 0;
671     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) = 0;
672     STDMETHOD_(BOOL, IsDlgShown)() = 0;
673     STDMETHOD_(void, SetDlgShown)(BOOL bShown) = 0;
674     STDMETHOD_(BOOL, ThreadProc)();
675 };
676 
677 /***********************************************************************/
678 
679 class CUTBCloseLangBarDlg : public CUTBLangBarDlg
680 {
681 public:
682     CUTBCloseLangBarDlg();
683 
684     static BOOL s_bIsDlgShown;
685 
686     STDMETHOD_(BOOL, DoModal)(HWND hDlg) override;
687     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) override;
688     STDMETHOD_(BOOL, IsDlgShown)() override;
689     STDMETHOD_(void, SetDlgShown)(BOOL bShown) override;
690 };
691 
692 BOOL CUTBCloseLangBarDlg::s_bIsDlgShown = FALSE;
693 
694 /***********************************************************************/
695 
696 class CUTBMinimizeLangBarDlg : public CUTBLangBarDlg
697 {
698 public:
699     CUTBMinimizeLangBarDlg();
700 
701     static BOOL s_bIsDlgShown;
702 
703     STDMETHOD_(BOOL, DoModal)(HWND hDlg) override;
704     STDMETHOD_(BOOL, OnCommand)(HWND hDlg, WPARAM wParam, LPARAM lParam) override;
705     STDMETHOD_(BOOL, IsDlgShown)() override;
706     STDMETHOD_(void, SetDlgShown)(BOOL bShown) override;
707     STDMETHOD_(BOOL, ThreadProc)() override;
708 };
709 
710 BOOL CUTBMinimizeLangBarDlg::s_bIsDlgShown = FALSE;
711 
712 /***********************************************************************/
713 
714 class CCicLibMenu : public ITfMenu
715 {
716 protected:
717     CicArray<CCicLibMenuItem*> m_MenuItems;
718     LONG m_cRefs;
719 
720 public:
721     CCicLibMenu();
722     virtual ~CCicLibMenu();
723 
724     STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj) override;
725     STDMETHOD_(ULONG, AddRef)() override;
726     STDMETHOD_(ULONG, Release)() override;
727     STDMETHOD(AddMenuItem)(
728         UINT uId,
729         DWORD dwFlags,
730         HBITMAP hbmp,
731         HBITMAP hbmpMask,
732         const WCHAR *pch,
733         ULONG cch,
734         ITfMenu **ppSubMenu) override;
735     STDMETHOD_(CCicLibMenu*, CreateSubMenu)();
736     STDMETHOD_(CCicLibMenuItem*, CreateMenuItem)();
737 };
738 
739 /***********************************************************************/
740 
741 class CCicLibMenuItem
742 {
743 protected:
744     DWORD m_uId;
745     DWORD m_dwFlags;
746     HBITMAP m_hbmp;
747     HBITMAP m_hbmpMask;
748     BSTR m_bstrText;
749     ITfMenu *m_pMenu;
750 
751 public:
752     CCicLibMenuItem();
753     virtual ~CCicLibMenuItem();
754 
755     BOOL Init(
756         UINT uId,
757         DWORD dwFlags,
758         HBITMAP hbmp,
759         HBITMAP hbmpMask,
760         const WCHAR *pch,
761         ULONG cch,
762         ITfMenu *pMenu);
763     HBITMAP CreateBitmap(HANDLE hBitmap);
764 };
765 
766 /***********************************************************************/
767 
768 class CTipbarAccessible : public IAccessible
769 {
770 protected:
771     LONG m_cRefs;
772     HWND m_hWnd;
773     IAccessible *m_pStdAccessible;
774     ITypeInfo *m_pTypeInfo;
775     BOOL m_bInitialized;
776     CicArray<CTipbarAccItem*> m_AccItems;
777     LONG m_cSelection;
778     friend class CUTBMenuWnd;
779     friend class CTipbarWnd;
780 
781 public:
782     CTipbarAccessible(CTipbarAccItem *pItem);
783     virtual ~CTipbarAccessible();
784 
785     HRESULT Initialize();
786 
787     BOOL AddAccItem(CTipbarAccItem *pItem);
788     HRESULT RemoveAccItem(CTipbarAccItem *pItem);
789     void ClearAccItems();
790     CTipbarAccItem *AccItemFromID(INT iItem);
791     INT GetIDOfItem(CTipbarAccItem *pTarget);
792 
793     LONG_PTR CreateRefToAccObj(WPARAM wParam);
794     BOOL DoDefaultActionReal(INT nID);
795     void NotifyWinEvent(DWORD event, CTipbarAccItem *pItem);
796     void SetWindow(HWND hWnd);
797 
798     // IUnknown methods
799     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
800     STDMETHOD_(ULONG, AddRef)();
801     STDMETHOD_(ULONG, Release)();
802 
803     // IDispatch methods
804     STDMETHOD(GetTypeInfoCount)(UINT *pctinfo);
805     STDMETHOD(GetTypeInfo)(
806         UINT iTInfo,
807         LCID lcid,
808         ITypeInfo **ppTInfo);
809     STDMETHOD(GetIDsOfNames)(
810         REFIID riid,
811         LPOLESTR *rgszNames,
812         UINT cNames,
813         LCID lcid,
814         DISPID *rgDispId);
815     STDMETHOD(Invoke)(
816         DISPID dispIdMember,
817         REFIID riid,
818         LCID lcid,
819         WORD wFlags,
820         DISPPARAMS *pDispParams,
821         VARIANT *pVarResult,
822         EXCEPINFO *pExcepInfo,
823         UINT *puArgErr);
824 
825     // IAccessible methods
826     STDMETHOD(get_accParent)(IDispatch **ppdispParent);
827     STDMETHOD(get_accChildCount)(LONG *pcountChildren);
828     STDMETHOD(get_accChild)(VARIANT varChildID, IDispatch **ppdispChild);
829     STDMETHOD(get_accName)(VARIANT varID, BSTR *pszName);
830     STDMETHOD(get_accValue)(VARIANT varID, BSTR *pszValue);
831     STDMETHOD(get_accDescription)(VARIANT varID, BSTR *description);
832     STDMETHOD(get_accRole)(VARIANT varID, VARIANT *role);
833     STDMETHOD(get_accState)(VARIANT varID, VARIANT *state);
834     STDMETHOD(get_accHelp)(VARIANT varID, BSTR *help);
835     STDMETHOD(get_accHelpTopic)(BSTR *helpfile, VARIANT varID, LONG *pidTopic);
836     STDMETHOD(get_accKeyboardShortcut)(VARIANT varID, BSTR *shortcut);
837     STDMETHOD(get_accFocus)(VARIANT *pvarID);
838     STDMETHOD(get_accSelection)(VARIANT *pvarID);
839     STDMETHOD(get_accDefaultAction)(VARIANT varID, BSTR *action);
840     STDMETHOD(accSelect)(LONG flagsSelect, VARIANT varID);
841     STDMETHOD(accLocation)(
842         LONG *left,
843         LONG *top,
844         LONG *width,
845         LONG *height,
846         VARIANT varID);
847     STDMETHOD(accNavigate)(LONG dir, VARIANT varStart, VARIANT *pvarEnd);
848     STDMETHOD(accHitTest)(LONG left, LONG top, VARIANT *pvarID);
849     STDMETHOD(accDoDefaultAction)(VARIANT varID);
850     STDMETHOD(put_accName)(VARIANT varID, BSTR name);
851     STDMETHOD(put_accValue)(VARIANT varID, BSTR value);
852 };
853 
854 /***********************************************************************/
855 
856 class CTipbarAccItem
857 {
858 public:
859     CTipbarAccItem() { }
860     virtual ~CTipbarAccItem() { }
861 
862     STDMETHOD_(BSTR, GetAccName)()
863     {
864         return SysAllocString(L"");
865     }
866     STDMETHOD_(BSTR, GetAccValue)()
867     {
868         return NULL;
869     }
870     STDMETHOD_(INT, GetAccRole)()
871     {
872         return 10;
873     }
874     STDMETHOD_(INT, GetAccState)()
875     {
876         return 256;
877     }
878     STDMETHOD_(void, GetAccLocation)(LPRECT lprc)
879     {
880         *lprc = { 0, 0, 0, 0 };
881     }
882     STDMETHOD_(BSTR, GetAccDefaultAction)()
883     {
884         return NULL;
885     }
886     STDMETHOD_(BOOL, DoAccDefaultAction)()
887     {
888         return FALSE;
889     }
890     STDMETHOD_(BOOL, DoAccDefaultActionReal)()
891     {
892         return FALSE;
893     }
894 };
895 
896 /***********************************************************************/
897 
898 class CTipbarCoInitialize
899 {
900 public:
901     BOOL m_bCoInit;
902 
903     CTipbarCoInitialize() : m_bCoInit(FALSE) { }
904     ~CTipbarCoInitialize() { CoUninit(); }
905 
906     HRESULT EnsureCoInit()
907     {
908         if (m_bCoInit)
909             return S_OK;
910         HRESULT hr = ::CoInitialize(NULL);
911         if (FAILED(hr))
912             return hr;
913         m_bCoInit = TRUE;
914         return S_OK;
915     }
916 
917     void CoUninit()
918     {
919         if (m_bCoInit)
920         {
921             ::CoUninitialize();
922             m_bCoInit = FALSE;
923         }
924     }
925 };
926 
927 /***********************************************************************/
928 
929 class CUTBMenuWnd : public CTipbarAccItem, public CUIFMenu
930 {
931 protected:
932     CTipbarCoInitialize m_coInit;
933     CTipbarAccessible *m_pAccessible;
934     UINT m_nMenuWndID;
935     friend class CUTBMenuItem;
936 
937 public:
938     CUTBMenuWnd(HINSTANCE hInst, DWORD style, DWORD dwUnknown14);
939 
940     BOOL StartDoAccDefaultActionTimer(CUTBMenuItem *pTarget);
941 
942     CTipbarAccItem* GetAccItem()
943     {
944         return static_cast<CTipbarAccItem*>(this);
945     }
946     CUIFMenu* GetMenu()
947     {
948         return static_cast<CUIFMenu*>(this);
949     }
950 
951     STDMETHOD_(BSTR, GetAccName)() override;
952     STDMETHOD_(INT, GetAccRole)() override;
953     STDMETHOD_(BOOL, Initialize)() override;
954     STDMETHOD_(void, OnCreate)(HWND hWnd) override;
955     STDMETHOD_(void, OnDestroy)(HWND hWnd) override;
956     STDMETHOD_(HRESULT, OnGetObject)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
957     STDMETHOD_(LRESULT, OnShowWindow)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
958     STDMETHOD_(void, OnTimer)(WPARAM wParam) override;
959 };
960 
961 /***********************************************************************/
962 
963 class CUTBMenuItem : public CTipbarAccItem, public CUIFMenuItem
964 {
965 protected:
966     CUTBMenuWnd *m_pMenuUI;
967     friend class CUTBMenuWnd;
968 
969 public:
970     CUTBMenuItem(CUTBMenuWnd *pMenuUI);
971     ~CUTBMenuItem() override;
972 
973     CUIFMenuItem* GetMenuItem()
974     {
975         return static_cast<CUIFMenuItem*>(this);
976     }
977 
978     STDMETHOD_(BOOL, DoAccDefaultAction)() override;
979     STDMETHOD_(BOOL, DoAccDefaultActionReal)() override;
980     STDMETHOD_(BSTR, GetAccDefaultAction)() override;
981     STDMETHOD_(void, GetAccLocation)(LPRECT lprc) override;
982     STDMETHOD_(BSTR, GetAccName)() override;
983     STDMETHOD_(INT, GetAccRole)() override;
984 };
985 
986 /***********************************************************************/
987 
988 class CModalMenu
989 {
990 public:
991     DWORD m_dwUnknown26;
992     CUTBMenuWnd *m_pMenuUI;
993 
994 public:
995     CModalMenu() { }
996     virtual ~CModalMenu() { }
997 
998     CUTBMenuItem *InsertItem(CUTBMenuWnd *pMenuUI, INT nCommandId, INT nStringID);
999     void PostKey(BOOL bUp, WPARAM wParam, LPARAM lParam);
1000     void CancelMenu();
1001 };
1002 
1003 /***********************************************************************/
1004 
1005 class CTipbarThread;
1006 
1007 class CUTBContextMenu : public CModalMenu
1008 {
1009 public:
1010     CTipbarWnd *m_pTipbarWnd;
1011     CTipbarThread *m_pTipbarThread;
1012 
1013 public:
1014     CUTBContextMenu(CTipbarWnd *pTipbarWnd);
1015 
1016     BOOL Init();
1017     CUTBMenuWnd *CreateMenuUI(BOOL bFlag);
1018 
1019     UINT ShowPopup(
1020         CUIFWindow *pWindow,
1021         POINT pt,
1022         LPCRECT prc,
1023         BOOL bFlag);
1024 
1025     BOOL SelectMenuItem(UINT nCommandId);
1026 };
1027 
1028 /***********************************************************************/
1029 
1030 class CUTBLBarMenuItem;
1031 
1032 class CUTBLBarMenu : public CCicLibMenu
1033 {
1034 protected:
1035     CUTBMenuWnd *m_pMenuUI;
1036     HINSTANCE m_hInst;
1037 
1038 public:
1039     CUTBLBarMenu(HINSTANCE hInst);
1040     ~CUTBLBarMenu() override;
1041 
1042     CUTBMenuWnd *CreateMenuUI();
1043     INT ShowPopup(CUIFWindow *pWindow, POINT pt, LPCRECT prcExclude);
1044 
1045     STDMETHOD_(CCicLibMenuItem*, CreateMenuItem)() override;
1046     STDMETHOD_(CCicLibMenu*, CreateSubMenu)() override;
1047 };
1048 
1049 /***********************************************************************/
1050 
1051 class CUTBLBarMenuItem : public CCicLibMenuItem
1052 {
1053 public:
1054     CUTBLBarMenu *m_pLBarMenu;
1055 
1056 public:
1057     CUTBLBarMenuItem() { m_pLBarMenu = NULL; }
1058     BOOL InsertToUI(CUTBMenuWnd *pMenuUI);
1059 };
1060 
1061 /***********************************************************************/
1062 
1063 class CTipbarGripper : public CUIFGripper
1064 {
1065 protected:
1066     CTipbarWnd *m_pTipbarWnd;
1067     BOOL m_bInDebugMenu;
1068     friend class CTipbarWnd;
1069 
1070 public:
1071     CTipbarGripper(CTipbarWnd *pTipbarWnd, LPCRECT prc, DWORD style);
1072 
1073     STDMETHOD_(void, OnLButtonUp)(LONG x, LONG y) override;
1074     STDMETHOD_(void, OnRButtonUp)(LONG x, LONG y) override;
1075     STDMETHOD_(BOOL, OnSetCursor)(UINT uMsg, LONG x, LONG y) override;
1076 };
1077 
1078 /***********************************************************************/
1079 
1080 class CLangBarItemList : public CicArray<LANGBARITEMSTATE>
1081 {
1082 public:
1083     BOOL IsStartedIntentionally(REFCLSID rclsid);
1084 
1085     LANGBARITEMSTATE *AddItem(REFCLSID rclsid);
1086     void Clear();
1087     BOOL SetDemoteLevel(REFCLSID rclsid, DWORD dwDemoteLevel);
1088 
1089     LANGBARITEMSTATE *FindItem(REFCLSID rclsid);
1090     LANGBARITEMSTATE *GetItemStateFromTimerId(UINT_PTR nTimerID);
1091 
1092     void Load();
1093     void SaveItem(CicRegKey *pRegKey, const LANGBARITEMSTATE *pState);
1094 
1095     void StartDemotingTimer(REFCLSID rclsid, BOOL bIntentional);
1096     UINT_PTR FindDemotingTimerId();
1097 };
1098 
1099 /***********************************************************************/
1100 
1101 class CTrayIconWnd
1102 {
1103 protected:
1104     DWORD m_dwUnknown20;
1105     BOOL m_bBusy;
1106     UINT m_uCallbackMessage;
1107     UINT m_uMsg;
1108     HWND m_hWnd;
1109     DWORD m_dwUnknown21[2];
1110     HWND m_hTrayWnd;
1111     HWND m_hNotifyWnd;
1112     DWORD m_dwTrayWndThreadId;
1113     DWORD m_dwUnknown22;
1114     HWND m_hwndProgman;
1115     DWORD m_dwProgmanThreadId;
1116     CMainIconItem *m_pMainIconItem;
1117     CicArray<CButtonIconItem*> m_Items;
1118     UINT m_uCallbackMsg;
1119     UINT m_uNotifyIconID;
1120     friend class CTipbarWnd;
1121 
1122     static BOOL CALLBACK EnumChildWndProc(HWND hWnd, LPARAM lParam);
1123     static LRESULT CALLBACK _WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
1124 
1125 public:
1126     CTrayIconWnd();
1127     ~CTrayIconWnd();
1128 
1129     static BOOL RegisterClass();
1130     static CTrayIconWnd *GetThis(HWND hWnd);
1131     static void SetThis(HWND hWnd, LPCREATESTRUCT pCS);
1132 
1133     HWND CreateWnd();
1134     void DestroyWnd();
1135 
1136     BOOL SetMainIcon(HKL hKL);
1137     BOOL SetIcon(REFGUID rguid, DWORD dwUnknown24, HICON hIcon, LPCWSTR psz);
1138 
1139     void RemoveAllIcon(DWORD dwFlags);
1140     void RemoveUnusedIcons(int unknown);
1141 
1142     CButtonIconItem *FindIconItem(REFGUID rguid);
1143     BOOL FindTrayEtc();
1144     HWND GetNotifyWnd();
1145     BOOL OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
1146 
1147     void CallOnDelayMsg();
1148 };
1149 
1150 /***********************************************************************/
1151 
1152 class CTrayIconItem
1153 {
1154 protected:
1155     HWND m_hWnd;
1156     UINT m_uCallbackMessage;
1157     UINT m_uNotifyIconID;
1158     DWORD m_dwIconAddOrModify;
1159     BOOL m_bIconAdded;
1160     CTrayIconWnd *m_pTrayIconWnd;
1161     DWORD m_dwUnknown25;
1162     GUID m_guid;
1163     RECT m_rcMenu;
1164     POINT m_ptCursor;
1165     friend class CTrayIconWnd;
1166 
1167 public:
1168     CTrayIconItem(CTrayIconWnd *pTrayIconWnd);
1169     virtual ~CTrayIconItem() { }
1170 
1171     BOOL _Init(HWND hWnd, UINT uCallbackMessage, UINT uNotifyIconID, const GUID& rguid);
1172     BOOL UpdateMenuRectPoint();
1173     BOOL RemoveIcon();
1174 
1175     STDMETHOD_(BOOL, SetIcon)(HICON hIcon, LPCWSTR pszTip);
1176     STDMETHOD_(BOOL, OnMsg)(WPARAM wParam, LPARAM lParam) { return FALSE; };
1177     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) { return 0; };
1178 };
1179 
1180 /***********************************************************************/
1181 
1182 class CButtonIconItem : public CTrayIconItem
1183 {
1184 protected:
1185     DWORD m_dwUnknown24;
1186     HKL m_hKL;
1187     friend class CTrayIconWnd;
1188 
1189 public:
1190     CButtonIconItem(CTrayIconWnd *pWnd, DWORD dwUnknown24);
1191 
1192     STDMETHOD_(BOOL, OnMsg)(WPARAM wParam, LPARAM lParam) override;
1193     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) override;
1194 };
1195 
1196 /***********************************************************************/
1197 
1198 class CMainIconItem : public CButtonIconItem
1199 {
1200 public:
1201     CMainIconItem(CTrayIconWnd *pWnd);
1202 
1203     BOOL Init(HWND hWnd);
1204     STDMETHOD_(BOOL, OnDelayMsg)(UINT uMsg) override;
1205 };
1206 
1207 /***********************************************************************/
1208 
1209 class CLBarItemBase
1210 {
1211 protected:
1212     DWORD m_dwItemStatus;
1213     TF_LANGBARITEMINFO m_NewUIInfo;
1214     WCHAR m_szToolTipText[256];
1215     LONG m_cRefs;
1216     ITfLangBarItemSink *m_pLangBarItemSink;
1217 
1218 public:
1219     CLBarItemBase();
1220     virtual ~CLBarItemBase();
1221 
1222     HRESULT ShowInternal(BOOL bShow, BOOL bUpdate);
1223 
1224     void InitNuiInfo(
1225         REFIID clsidService,
1226         REFGUID guidItem,
1227         DWORD dwStyle,
1228         DWORD ulSort,
1229         LPCWSTR Source);
1230 
1231     HRESULT GetInfo(TF_LANGBARITEMINFO *pInfo);
1232     HRESULT GetStatus(DWORD *pdwStatus);
1233     HRESULT Show(BOOL fShow);
1234     HRESULT GetTooltipString(BSTR *pbstrToolTip);
1235 
1236     HRESULT AdviseSink(REFIID riid, IUnknown *punk, DWORD *pdwCookie);
1237     HRESULT UnadviseSink(DWORD dwCookie);
1238 };
1239 
1240 /***********************************************************************/
1241 
1242 class CLBarItemButtonBase
1243     : public CLBarItemBase
1244     , public ITfLangBarItem
1245     , public ITfLangBarItemButton
1246     , public ITfSource
1247 {
1248 public:
1249     HICON m_hIcon;
1250 
1251 public:
1252     CLBarItemButtonBase() { m_hIcon = NULL; }
1253     ~CLBarItemButtonBase() override;
1254 
1255     // IUnknown methods
1256     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override;
1257     STDMETHOD_(ULONG, AddRef)() override;
1258     STDMETHOD_(ULONG, Release)() override;
1259 
1260     // ITfLangBarItem methods
1261     STDMETHOD(GetInfo)(TF_LANGBARITEMINFO *pInfo) override;
1262     STDMETHOD(GetStatus)(DWORD *pdwStatus) override;
1263     STDMETHOD(Show)(BOOL fShow) override;
1264     STDMETHOD(GetTooltipString)(BSTR *pbstrToolTip) override;
1265 
1266     // ITfLangBarItemButton methods
1267     STDMETHOD(OnClick)(TfLBIClick click, POINT pt, LPCRECT prc) override;
1268     STDMETHOD(InitMenu)(ITfMenu *pMenu) override;
1269     STDMETHOD(OnMenuSelect)(UINT wID) override;
1270     STDMETHOD(GetIcon)(HICON *phIcon) override;
1271     STDMETHOD(GetText)(BSTR *pbstr) override;
1272 
1273     // ITfSource methods
1274     STDMETHOD(AdviseSink)(REFIID riid, IUnknown *punk, DWORD *pdwCookie) override;
1275     STDMETHOD(UnadviseSink)(DWORD dwCookie) override;
1276 };
1277 
1278 /***********************************************************************/
1279 
1280 /// Language Bar international item
1281 class CLBarInatItem : public CLBarItemButtonBase
1282 {
1283 protected:
1284     HKL m_hKL;
1285     DWORD m_dwThreadId;
1286 
1287 public:
1288     CLBarInatItem(DWORD dwThreadId);
1289 
1290     STDMETHOD(InitMenu)(ITfMenu *pMenu) override;
1291     STDMETHOD(OnMenuSelect)(INT nCommandId);
1292     STDMETHOD(GetIcon)(HICON *phIcon) override;
1293     STDMETHOD(GetText)(BSTR *pbstr) override;
1294 };
1295 
1296 /***********************************************************************/
1297 
1298 class CTipbarItem;
1299 class CTipbarBalloonItem;
1300 
1301 class CTipbarThread
1302 {
1303 protected:
1304     CTipbarWnd *m_pTipbarWnd;
1305     ITfLangBarItemMgr *m_pLangBarItemMgr;
1306     CicArray<CTipbarItem*> m_UIObjects;
1307     CicArray<CUIFObject*> m_Separators;
1308     DWORD m_dwUnknown32;
1309     DWORD m_dwThreadId;
1310     DWORD m_dwFlags1;
1311     DWORD m_dwFlags2;
1312     INT m_cxGrip;
1313     INT m_cyGrip;
1314     DWORD m_dwFlags3;
1315     DWORD m_dwUnknown34;
1316     LONG m_cRefs;
1317     friend class CTipbarWnd;
1318     friend class CTipbarItem;
1319 
1320 public:
1321     CTipbarThread(CTipbarWnd *pTipbarWnd);
1322     virtual ~CTipbarThread();
1323 
1324     HRESULT Init(DWORD dwThreadId);
1325 
1326     HRESULT InitItemList();
1327     HRESULT _UninitItemList(BOOL bUnAdvise);
1328 
1329     DWORD IsDirtyItem();
1330     BOOL IsFocusThread();
1331     BOOL IsVertical();
1332 
1333     void AddAllSeparators();
1334     void RemoveAllSeparators();
1335 
1336     void AddUIObjs();
1337     void RemoveUIObjs();
1338 
1339     CTipbarItem *GetItem(REFCLSID rclsid);
1340     void GetTextSize(BSTR bstr, LPSIZE pSize);
1341     void LocateItems();
1342     void MyMoveWnd(LONG xDelta, LONG yDelta);
1343 
1344     HRESULT _UnadviseItemsSink();
1345     LONG _AddRef() { return ++m_cRefs; }
1346     LONG _Release();
1347 
1348     /// @unimplemented
1349     BOOL SetFocus(CTipbarBalloonItem *pTarget)
1350     {
1351         return FALSE;
1352     }
1353 
1354     /// @unimplemented
1355     HRESULT CallOnUpdateHandler()
1356     {
1357         return E_NOTIMPL;
1358     }
1359 
1360     //FIXME
1361 };
1362 
1363 /***********************************************************************/
1364 
1365 class CTipbarItem : public CTipbarAccItem
1366 {
1367 protected:
1368     DWORD m_dwCookie;
1369     TF_LANGBARITEMINFO m_ItemInfo;
1370     DWORD m_dwUnknown16;
1371     DWORD m_dwUnknown17;
1372     CTipbarThread *m_pTipbarThread;
1373     ITfLangBarItem *m_pLangBarItem;
1374     DWORD m_dwUnknown18[2];
1375     DWORD m_dwItemFlags;
1376     DWORD m_dwDirty;
1377     DWORD m_dwUnknown19[4];
1378     friend class CTipbarThread;
1379     friend class CTipbarWnd;
1380 
1381 public:
1382     CTipbarItem(
1383         CTipbarThread *pThread,
1384         ITfLangBarItem *pLangBarItem,
1385         TF_LANGBARITEMINFO *pItemInfo,
1386         DWORD dwUnknown16);
1387     ~CTipbarItem() override;
1388 
1389     void _AddedToUI();
1390     void _RemovedToUI();
1391     void AddRemoveMeToUI(BOOL bFlag);
1392 
1393     BOOL IsConnected();
1394     void ClearConnections();
1395 
1396     void StartDemotingTimer(BOOL bStarted);
1397 
1398     void MyClientToScreen(LPPOINT ppt, LPRECT prc);
1399     void MyClientToScreen(LPRECT prc) { return MyClientToScreen(NULL, prc); }
1400 
1401     STDMETHOD_(BSTR, GetAccName)() override;
1402     STDMETHOD_(void, GetAccLocation)(LPRECT prc) override;
1403     STDMETHOD_(BOOL, DoAccDefaultAction)() override;
1404     STDMETHOD(OnUnknown40)() { return S_OK; }
1405     STDMETHOD(OnUnknown41)() { return S_OK; }
1406     STDMETHOD(OnUnknown42)() { return S_OK; }
1407     STDMETHOD(OnUnknown43)() { return S_OK; }
1408     STDMETHOD(OnUpdate)(DWORD dwDirty);
1409     STDMETHOD(OnUnknown44)() { return S_OK; }
1410     STDMETHOD_(void, OnUnknown45)(DWORD dwDirty, DWORD dwStatus) { }
1411     STDMETHOD_(void, OnUpdateHandler)(ULONG, ULONG);
1412     STDMETHOD(OnUnknown46)(CUIFWindow *pWindow) { return S_OK; }
1413     STDMETHOD(OnUnknown47)(CUIFWindow *pWindow) { return S_OK; }
1414     STDMETHOD(OnUnknown48)() { return S_OK; }
1415     STDMETHOD(OnUnknown49)() { return S_OK; }
1416     STDMETHOD(OnUnknown50)() { return S_OK; }
1417     STDMETHOD(OnUnknown51)() { return S_OK; }
1418     STDMETHOD(OnUnknown52)() { return S_OK; }
1419     STDMETHOD(OnUnknown53)(BSTR bstr) { return S_OK; }
1420     STDMETHOD_(LPCWSTR, OnUnknown55)() { return NULL; }
1421     STDMETHOD(OnUnknown56)() { return S_OK; }
1422     STDMETHOD_(LPCWSTR, GetToolTip)();
1423     STDMETHOD(OnUnknown57)(LPRECT prc) { return S_OK; }
1424     STDMETHOD(OnUnknown58)() { return S_OK; }
1425     STDMETHOD_(void, OnUnknown59)() { }
1426     STDMETHOD_(void, OnUnknown60)() { }
1427     STDMETHOD_(void, OnUnknown61)(HWND) { }
1428     STDMETHOD_(void, OnUnknown62)(HWND) { }
1429     STDMETHOD(OnUnknown63)() { return S_OK; }
1430 };
1431 
1432 /***********************************************************************/
1433 
1434 class CTipbarCtrlButtonHolder;
1435 class CDeskBand;
1436 
1437 // Flags for m_dwTipbarWndFlags
1438 enum
1439 {
1440     TIPBAR_ATTACHED = 0x1,
1441     TIPBAR_CHILD = 0x2,
1442     TIPBAR_VERTICAL = 0x4,
1443     TIPBAR_HIGHCONTRAST = 0x10,
1444     TIPBAR_TRAYICON = 0x20,
1445     TIPBAR_UPDATING = 0x400,
1446     TIPBAR_ENSURING = 0x2000,
1447     TIPBAR_NODESKBAND = 0x4000,
1448     TIPBAR_TOOLBARENDED = 0x10000,
1449     TIPBAR_TOPFIT = 0x40000,
1450     TIPBAR_BOTTOMFIT = 0x80000,
1451     TIPBAR_RIGHTFIT = 0x100000,
1452     TIPBAR_LEFTFIT = 0x200000,
1453 };
1454 
1455 class CTipbarWnd
1456     : public ITfLangBarEventSink
1457     , public ITfLangBarEventSink_P
1458     , public CTipbarAccItem
1459     , public CUIFWindow
1460 {
1461     CTipbarCoInitialize m_coInit;
1462     DWORD m_dwSinkCookie;
1463     CModalMenu *m_pModalMenu;
1464     CTipbarThread *m_pThread;
1465     CLangBarItemList m_LangBarItemList;
1466     DWORD m_dwUnknown20;
1467     CUIFWndFrame *m_pWndFrame;
1468     CTipbarGripper *m_pTipbarGripper;
1469     CTipbarThread *m_pFocusThread;
1470     CicArray<CTipbarThread*> m_Threads;
1471     CicArray<CTipbarThread*> m_ThreadCreatingList;
1472     DWORD m_dwAlphaValue;
1473     DWORD m_dwTipbarWndFlags;
1474     LONG m_ButtonWidth;
1475     DWORD m_dwShowType;
1476     DWORD m_dwUnknown21;
1477     INT m_cxSmallIcon;
1478     INT m_cySmallIcon;
1479     INT m_cxDlgFrameX2;
1480     INT m_cyDlgFrameX2;
1481     HFONT m_hMarlettFont;
1482     HFONT m_hTextFont;
1483     ITfLangBarMgr_P *m_pLangBarMgr;
1484     DWORD m_dwUnknown23;
1485     CTipbarCtrlButtonHolder *m_pTipbarCtrlButtonHolder;
1486     DWORD m_dwUnknown23_1[8];
1487     CUIFWindow *m_pBalloon;
1488     DWORD m_dwChangingThreadId;
1489     LONG m_bInCallOn;
1490     LONG m_X;
1491     LONG m_Y;
1492     LONG m_CX;
1493     LONG m_CY;
1494     CTipbarAccessible *m_pTipbarAccessible;
1495     INT m_nID;
1496     MARGINS m_Margins;
1497     DWORD m_dwUnknown23_5[4];
1498     CTipbarThread *m_pUnknownThread;
1499     CDeskBand *m_pDeskBand;
1500     CShellWndThread m_ShellWndThread;
1501     LONG m_cRefs;
1502     friend class CUTBContextMenu;
1503     friend class CTipbarGripper;
1504     friend class CTipbarThread;
1505     friend class CTipbarItem;
1506     friend class CLBarInatItem;
1507     friend class CMainIconItem;
1508     friend VOID WINAPI ClosePopupTipbar(VOID);
1509     friend BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand *pDeskBand);
1510     friend LONG MyWaitForInputIdle(DWORD dwThreadId, DWORD dwMilliseconds);
1511 
1512 public:
1513     CTipbarWnd(DWORD style);
1514     ~CTipbarWnd() override;
1515 
1516     CUIFWindow *GetWindow()
1517     {
1518         return static_cast<CUIFWindow*>(this);
1519     }
1520 
1521     CTipbarAccItem *GetAccItem()
1522     {
1523         return static_cast<CTipbarAccItem*>(this);
1524     }
1525 
1526     void Init(BOOL bChild, CDeskBand *pDeskBand);
1527     void InitHighContrast();
1528     void InitMetrics();
1529     void InitThemeMargins();
1530     void UnInit();
1531 
1532     BOOL IsFullScreenWindow(HWND hWnd);
1533     BOOL IsHKLToSkipRedrawOnNoItem();
1534     BOOL IsInItemChangeOrDirty(CTipbarThread *pTarget);
1535 
1536     void AddThreadToThreadCreatingList(CTipbarThread *pThread);
1537     void RemoveThredFromThreadCreatingList(CTipbarThread *pTarget);
1538 
1539     void MoveToStub(BOOL bFlag);
1540     void RestoreFromStub();
1541 
1542     INT GetCtrlButtonWidth();
1543     INT GetGripperWidth();
1544     INT GetTipbarHeight();
1545     BOOL AutoAdjustDeskBandSize();
1546     INT AdjustDeskBandSize(BOOL bFlag);
1547     void LocateCtrlButtons();
1548     void AdjustPosOnDisplayChange();
1549     void SetVertical(BOOL bVertical);
1550     void UpdatePosFlags();
1551 
1552     void CancelMenu();
1553     BOOL CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT prc2);
1554     void ClearLBItemList();
1555 
1556     HFONT CreateVerticalFont();
1557     void UpdateVerticalFont();
1558 
1559     void ShowOverScreenSizeBalloon();
1560     void DestroyOverScreenSizeBalloon();
1561     void DestroyWnd();
1562 
1563     HKL GetFocusKeyboardLayout();
1564     void KillOnTheadItemChangeTimer();
1565 
1566     UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT uElapse);
1567     BOOL KillTimer(UINT_PTR uIDEvent);
1568 
1569     void MoveToTray();
1570     void MyClientToScreen(LPPOINT lpPoint, LPRECT prc);
1571     void SavePosition();
1572     void SetAlpha(BYTE bAlpha, BOOL bFlag);
1573     BOOL SetLangBand(BOOL bDeskBand, BOOL bFlag2);
1574     void SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight);
1575     void SetShowText(BOOL bShow);
1576     void SetShowTrayIcon(BOOL bShow);
1577 
1578     void ShowContextMenu(POINT pt, LPCRECT prc, BOOL bFlag);
1579     void StartBackToAlphaTimer();
1580     BOOL StartDoAccDefaultActionTimer(CTipbarItem *pTarget);
1581 
1582     void StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId);
1583     void StopModalInput(DWORD dwThreadId);
1584 
1585     CTipbarThread *_CreateThread(DWORD dwThreadId);
1586     CTipbarThread *_FindThread(DWORD dwThreadId);
1587     void EnsureFocusThread();
1588     HRESULT SetFocusThread(CTipbarThread *pFocusThread);
1589     HRESULT AttachFocusThread();
1590     void RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev);
1591     void CleanUpThreadPointer(CTipbarThread *pThread, BOOL bRemove);
1592     void TerminateAllThreads(BOOL bFlag);
1593     void OnTerminateToolbar();
1594     HRESULT OnThreadTerminateInternal(DWORD dwThreadId);
1595 
1596     /// @unimplemented
1597     HRESULT OnThreadItemChangeInternal(DWORD dwThreadId)
1598     {
1599         return E_NOTIMPL;
1600     }
1601 
1602     // IUnknown methods
1603     STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
1604     STDMETHOD_(ULONG, AddRef)();
1605     STDMETHOD_(ULONG, Release)();
1606 
1607     // ITfLangBarEventSink methods
1608     STDMETHOD(OnSetFocus)(DWORD dwThreadId) override;
1609     STDMETHOD(OnThreadTerminate)(DWORD dwThreadId) override;
1610     STDMETHOD(OnThreadItemChange)(DWORD dwThreadId) override;
1611     STDMETHOD(OnModalInput)(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1612     STDMETHOD(ShowFloating)(DWORD dwFlags) override;
1613     STDMETHOD(GetItemFloatingRect)(DWORD dwThreadId, REFGUID rguid, RECT *prc) override;
1614 
1615     // ITfLangBarEventSink_P methods
1616     STDMETHOD(OnLangBarUpdate)(TfLBIClick click, BOOL bFlag) override;
1617 
1618     // CTipbarAccItem methods
1619     STDMETHOD_(BSTR, GetAccName)() override;
1620     STDMETHOD_(void, GetAccLocation)(LPRECT lprc) override;
1621 
1622     // CUIFWindow methods
1623     STDMETHOD_(void, PaintObject)(HDC hDC, LPCRECT prc) override;
1624     STDMETHOD_(DWORD, GetWndStyle)() override;
1625     STDMETHOD_(void, Move)(INT x, INT y, INT nWidth, INT nHeight) override;
1626     STDMETHOD_(void, OnMouseOutFromWindow)(LONG x, LONG y) override;
1627     STDMETHOD_(void, OnCreate)(HWND hWnd) override;
1628     STDMETHOD_(void, OnDestroy)(HWND hWnd) override;
1629     STDMETHOD_(void, OnTimer)(WPARAM wParam) override;
1630     STDMETHOD_(void, OnSysColorChange)() override;
1631     STDMETHOD_(void, OnEndSession)(HWND hWnd, WPARAM wParam, LPARAM lParam) override;
1632     STDMETHOD_(void, OnUser)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1633     STDMETHOD_(LRESULT, OnWindowPosChanged)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1634     STDMETHOD_(LRESULT, OnWindowPosChanging)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1635     STDMETHOD_(LRESULT, OnShowWindow)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1636     STDMETHOD_(LRESULT, OnSettingChange)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1637     STDMETHOD_(LRESULT, OnDisplayChange)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1638     STDMETHOD_(HRESULT, OnGetObject)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1639     STDMETHOD_(BOOL, OnEraseBkGnd)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override;
1640     STDMETHOD_(void, OnThemeChanged)(HWND hWnd, WPARAM wParam, LPARAM lParam) override;
1641     STDMETHOD_(void, UpdateUI)(LPCRECT prc) override;
1642     STDMETHOD_(void, HandleMouseMsg)(UINT uMsg, LONG x, LONG y) override;
1643 };
1644 
1645 /***********************************************************************/
1646 
1647 #ifdef ENABLE_DESKBAND
1648 class CDeskBand
1649 {
1650 public:
1651     // FIXME: Implement this
1652 };
1653 #endif
1654 
1655 /***********************************************************************
1656  * CUTBLangBarDlg
1657  */
1658 
1659 CUTBLangBarDlg *CUTBLangBarDlg::GetThis(HWND hDlg)
1660 {
1661     return (CUTBLangBarDlg*)::GetWindowLongPtr(hDlg, DWLP_USER);
1662 }
1663 
1664 void CUTBLangBarDlg::SetThis(HWND hDlg, CUTBLangBarDlg *pThis)
1665 {
1666     ::SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pThis);
1667 }
1668 
1669 DWORD WINAPI CUTBLangBarDlg::s_ThreadProc(LPVOID pParam)
1670 {
1671     return ((CUTBLangBarDlg *)pParam)->ThreadProc();
1672 }
1673 
1674 BOOL CUTBLangBarDlg::StartThread()
1675 {
1676     if (IsDlgShown())
1677         return FALSE;
1678 
1679     SetDlgShown(TRUE);
1680 
1681     DWORD dwThreadId;
1682     HANDLE hThread = ::CreateThread(NULL, 0, s_ThreadProc, this, 0, &dwThreadId);
1683     if (!hThread)
1684     {
1685         SetDlgShown(FALSE);
1686         return TRUE;
1687     }
1688 
1689     ++m_cRefs;
1690     ::CloseHandle(hThread);
1691     return TRUE;
1692 }
1693 
1694 LONG CUTBLangBarDlg::_Release()
1695 {
1696     if (--m_cRefs == 0)
1697     {
1698         delete this;
1699         return 0;
1700     }
1701     return m_cRefs;
1702 }
1703 
1704 STDMETHODIMP_(BOOL) CUTBLangBarDlg::ThreadProc()
1705 {
1706     extern HINSTANCE g_hInst;
1707     ::DialogBoxParam(g_hInst, m_pszDialogName, NULL, DlgProc, (LPARAM)this);
1708     SetDlgShown(FALSE);
1709     _Release();
1710     return TRUE;
1711 }
1712 
1713 INT_PTR CALLBACK
1714 CUTBLangBarDlg::DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
1715 {
1716     if (uMsg == WM_INITDIALOG)
1717     {
1718         SetThis(hDlg, (CUTBLangBarDlg *)lParam);
1719         ::ShowWindow(hDlg, SW_RESTORE);
1720         ::UpdateWindow(hDlg);
1721         return TRUE;
1722     }
1723 
1724     if (uMsg == WM_COMMAND)
1725     {
1726         CUTBLangBarDlg *pThis = CUTBLangBarDlg::GetThis(hDlg);
1727         pThis->OnCommand(hDlg, wParam, lParam);
1728         return TRUE;
1729     }
1730 
1731     return FALSE;
1732 }
1733 
1734 /***********************************************************************
1735  * CUTBCloseLangBarDlg
1736  */
1737 
1738 CUTBCloseLangBarDlg::CUTBCloseLangBarDlg()
1739 {
1740     m_cRefs = 1;
1741 
1742     if (!(g_dwOSInfo & CIC_OSINFO_XPPLUS))
1743         m_pszDialogName = MAKEINTRESOURCE(IDD_CLOSELANGBARNOBAND);
1744     else
1745         m_pszDialogName = MAKEINTRESOURCE(IDD_CLOSELANGBAR);
1746 }
1747 
1748 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::DoModal(HWND hDlg)
1749 {
1750     CicRegKey regKey;
1751     LSTATUS error;
1752     DWORD dwValue = FALSE;
1753     error = regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1754     if (error == ERROR_SUCCESS)
1755         regKey.QueryDword(TEXT("DontShowCloseLangBarDlg"), &dwValue);
1756 
1757     if (dwValue)
1758         return FALSE;
1759 
1760     StartThread();
1761     return TRUE;
1762 }
1763 
1764 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
1765 {
1766     switch (LOWORD(wParam))
1767     {
1768         case IDOK:
1769             DoCloseLangbar();
1770             if (::IsDlgButtonChecked(hDlg, IDC_CLOSELANGBAR_CHECK))
1771             {
1772                 CicRegKey regKey;
1773                 LSTATUS error;
1774                 error = regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1775                 if (error == ERROR_SUCCESS)
1776                     regKey.SetDword(TEXT("DontShowCloseLangBarDlg"), TRUE);
1777             }
1778             ::EndDialog(hDlg, TRUE);
1779             break;
1780 
1781         case IDCANCEL:
1782             ::EndDialog(hDlg, FALSE);
1783             break;
1784 
1785         default:
1786             return FALSE;
1787     }
1788     return TRUE;
1789 }
1790 
1791 STDMETHODIMP_(BOOL) CUTBCloseLangBarDlg::IsDlgShown()
1792 {
1793     return s_bIsDlgShown;
1794 }
1795 
1796 STDMETHODIMP_(void) CUTBCloseLangBarDlg::SetDlgShown(BOOL bShown)
1797 {
1798     s_bIsDlgShown = bShown;
1799 }
1800 
1801 /***********************************************************************
1802  * CUTBMinimizeLangBarDlg
1803  */
1804 
1805 CUTBMinimizeLangBarDlg::CUTBMinimizeLangBarDlg()
1806 {
1807     m_cRefs = 1;
1808     if (!(g_dwOSInfo & CIC_OSINFO_XPPLUS))
1809         m_pszDialogName = MAKEINTRESOURCE(IDD_MINIMIZELANGBARNOBAND);
1810     else
1811         m_pszDialogName = MAKEINTRESOURCE(IDD_MINIMIZELANGBAR);
1812 }
1813 
1814 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::DoModal(HWND hDlg)
1815 {
1816     CicRegKey regKey;
1817     LSTATUS error;
1818 
1819     DWORD dwValue = FALSE;
1820     error = regKey.Open(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1821     if (error == ERROR_SUCCESS)
1822         regKey.QueryDword(TEXT("DontShowMinimizeLangBarDlg"), &dwValue);
1823 
1824     if (dwValue)
1825         return FALSE;
1826 
1827     StartThread();
1828     return TRUE;
1829 }
1830 
1831 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
1832 {
1833     switch (LOWORD(wParam))
1834     {
1835         case IDOK:
1836             if (::IsDlgButtonChecked(hDlg, IDC_MINIMIZELANGBAR_CHECK))
1837             {
1838                 LSTATUS error;
1839                 CicRegKey regKey;
1840                 error = regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\"));
1841                 if (error == ERROR_SUCCESS)
1842                     regKey.SetDword(TEXT("DontShowMinimizeLangBarDlg"), TRUE);
1843             }
1844             ::EndDialog(hDlg, TRUE);
1845             break;
1846         case IDCANCEL:
1847             ::EndDialog(hDlg, FALSE);
1848             break;
1849         default:
1850             return FALSE;
1851     }
1852     return TRUE;
1853 }
1854 
1855 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::IsDlgShown()
1856 {
1857     return s_bIsDlgShown;
1858 }
1859 
1860 STDMETHODIMP_(void) CUTBMinimizeLangBarDlg::SetDlgShown(BOOL bShown)
1861 {
1862     s_bIsDlgShown = bShown;
1863 }
1864 
1865 STDMETHODIMP_(BOOL) CUTBMinimizeLangBarDlg::ThreadProc()
1866 {
1867     ::Sleep(700);
1868     return CUTBLangBarDlg::ThreadProc();
1869 }
1870 
1871 /***********************************************************************
1872  * CCicLibMenu
1873  */
1874 
1875 CCicLibMenu::CCicLibMenu() : m_cRefs(1)
1876 {
1877 }
1878 
1879 CCicLibMenu::~CCicLibMenu()
1880 {
1881     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
1882     {
1883         delete m_MenuItems[iItem];
1884         m_MenuItems[iItem] = NULL;
1885     }
1886 }
1887 
1888 STDMETHODIMP CCicLibMenu::QueryInterface(REFIID riid, LPVOID *ppvObj)
1889 {
1890     static const QITAB c_tab[] =
1891     {
1892         QITABENT(CCicLibMenu, ITfMenu),
1893         { NULL }
1894     };
1895     return ::QISearch(this, c_tab, riid, ppvObj);
1896 }
1897 
1898 STDMETHODIMP_(ULONG) CCicLibMenu::AddRef()
1899 {
1900     return ++m_cRefs;
1901 }
1902 
1903 STDMETHODIMP_(ULONG) CCicLibMenu::Release()
1904 {
1905     if (--m_cRefs == 0)
1906     {
1907         delete this;
1908         return 0;
1909     }
1910     return m_cRefs;
1911 }
1912 
1913 STDMETHODIMP_(CCicLibMenu*) CCicLibMenu::CreateSubMenu()
1914 {
1915     return new(cicNoThrow) CCicLibMenu();
1916 }
1917 
1918 STDMETHODIMP_(CCicLibMenuItem*) CCicLibMenu::CreateMenuItem()
1919 {
1920     return new(cicNoThrow) CCicLibMenuItem();
1921 }
1922 
1923 STDMETHODIMP CCicLibMenu::AddMenuItem(
1924     UINT uId,
1925     DWORD dwFlags,
1926     HBITMAP hbmp,
1927     HBITMAP hbmpMask,
1928     const WCHAR *pch,
1929     ULONG cch,
1930     ITfMenu **ppSubMenu)
1931 {
1932     if (ppSubMenu)
1933         *ppSubMenu = NULL;
1934 
1935     CCicLibMenu *pSubMenu = NULL;
1936     if (dwFlags & TF_LBMENUF_SUBMENU)
1937     {
1938         if (!ppSubMenu)
1939             return E_INVALIDARG;
1940         pSubMenu = CreateSubMenu();
1941     }
1942 
1943     CCicLibMenuItem *pMenuItem = CreateMenuItem();
1944     if (!pMenuItem)
1945         return E_OUTOFMEMORY;
1946 
1947     if (!pMenuItem->Init(uId, dwFlags, hbmp, hbmpMask, pch, cch, pSubMenu))
1948         return E_FAIL;
1949 
1950     if (ppSubMenu && pSubMenu)
1951     {
1952         *ppSubMenu = pSubMenu;
1953         pSubMenu->AddRef();
1954     }
1955 
1956     m_MenuItems.Add(pMenuItem);
1957     return S_OK;
1958 }
1959 
1960 /***********************************************************************
1961  * CCicLibMenuItem
1962  */
1963 
1964 CCicLibMenuItem::CCicLibMenuItem()
1965 {
1966     m_uId = 0;
1967     m_dwFlags = 0;
1968     m_hbmp = NULL;
1969     m_hbmpMask = NULL;
1970     m_bstrText = NULL;
1971     m_pMenu = NULL;
1972 }
1973 
1974 CCicLibMenuItem::~CCicLibMenuItem()
1975 {
1976     if (m_pMenu)
1977     {
1978         m_pMenu->Release();
1979         m_pMenu = NULL;
1980     }
1981 
1982     if (m_hbmp)
1983     {
1984         ::DeleteObject(m_hbmp);
1985         m_hbmp = NULL;
1986     }
1987 
1988     if (m_hbmpMask)
1989     {
1990         ::DeleteObject(m_hbmpMask);
1991         m_hbmpMask = NULL;
1992     }
1993 
1994     ::SysFreeString(m_bstrText);
1995     m_bstrText = NULL;
1996 }
1997 
1998 BOOL CCicLibMenuItem::Init(
1999     UINT uId,
2000     DWORD dwFlags,
2001     HBITMAP hbmp,
2002     HBITMAP hbmpMask,
2003     const WCHAR *pch,
2004     ULONG cch,
2005     ITfMenu *pMenu)
2006 {
2007     m_uId = uId;
2008     m_dwFlags = dwFlags;
2009     m_bstrText = ::SysAllocStringLen(pch, cch);
2010     if (!m_bstrText && cch)
2011         return FALSE;
2012 
2013     m_pMenu = pMenu;
2014     m_hbmp = CreateBitmap(hbmp);
2015     m_hbmpMask = CreateBitmap(hbmpMask);
2016     if (hbmp)
2017         ::DeleteObject(hbmp);
2018     if (hbmpMask)
2019         ::DeleteObject(hbmpMask);
2020 
2021     return TRUE;
2022 }
2023 
2024 HBITMAP CCicLibMenuItem::CreateBitmap(HANDLE hBitmap)
2025 {
2026     if (!hBitmap)
2027         return NULL;
2028 
2029     HDC hDC = ::CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
2030     if (!hDC)
2031         return NULL;
2032 
2033     HBITMAP hbmMem = NULL;
2034 
2035     BITMAP bm;
2036     ::GetObject(hBitmap, sizeof(bm), &bm);
2037 
2038     HGDIOBJ hbmOld1 = NULL;
2039     HDC hdcMem1 = ::CreateCompatibleDC(hDC);
2040     if (hdcMem1)
2041         hbmOld1 = ::SelectObject(hdcMem1, hBitmap);
2042 
2043     HGDIOBJ hbmOld2 = NULL;
2044     HDC hdcMem2 = ::CreateCompatibleDC(hDC);
2045     if (hdcMem2)
2046     {
2047         hbmMem = ::CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
2048         hbmOld2 = ::SelectObject(hdcMem2, hbmMem);
2049     }
2050 
2051     ::BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
2052 
2053     if (hbmOld1)
2054         ::SelectObject(hdcMem1, hbmOld1);
2055     if (hbmOld2)
2056         ::SelectObject(hdcMem2, hbmOld2);
2057 
2058     ::DeleteDC(hDC);
2059     if (hdcMem1)
2060         ::DeleteDC(hdcMem1);
2061     if (hdcMem2)
2062         ::DeleteDC(hdcMem2);
2063 
2064     return hbmMem;
2065 }
2066 
2067 /***********************************************************************
2068  * CTipbarAccessible
2069  */
2070 
2071 CTipbarAccessible::CTipbarAccessible(CTipbarAccItem *pItem)
2072 {
2073     m_cRefs = 1;
2074     m_hWnd = NULL;
2075     m_pTypeInfo = NULL;
2076     m_pStdAccessible = NULL;
2077     m_bInitialized = FALSE;
2078     m_cSelection = 1;
2079     m_AccItems.Add(pItem);
2080     ++g_DllRefCount;
2081 }
2082 
2083 CTipbarAccessible::~CTipbarAccessible()
2084 {
2085     m_pTypeInfo = m_pTypeInfo;
2086     if (m_pTypeInfo)
2087     {
2088         m_pTypeInfo->Release();
2089         m_pTypeInfo = NULL;
2090     }
2091     if (m_pStdAccessible)
2092     {
2093         m_pStdAccessible->Release();
2094         m_pStdAccessible = NULL;
2095     }
2096     --g_DllRefCount;
2097 }
2098 
2099 HRESULT CTipbarAccessible::Initialize()
2100 {
2101     m_bInitialized = TRUE;
2102 
2103     HRESULT hr = ::CreateStdAccessibleObject(m_hWnd, OBJID_CLIENT, IID_IAccessible,
2104                                              (void **)&m_pStdAccessible);
2105     if (FAILED(hr))
2106         return hr;
2107 
2108     ITypeLib *pTypeLib;
2109     hr = ::LoadRegTypeLib(LIBID_Accessibility, 1, 0, 0, &pTypeLib);
2110     if (FAILED(hr))
2111         hr = ::LoadTypeLib(L"OLEACC.DLL", &pTypeLib);
2112 
2113     if (SUCCEEDED(hr))
2114     {
2115         hr = pTypeLib->GetTypeInfoOfGuid(IID_IAccessible, &m_pTypeInfo);
2116         pTypeLib->Release();
2117     }
2118 
2119     return hr;
2120 }
2121 
2122 BOOL CTipbarAccessible::AddAccItem(CTipbarAccItem *pItem)
2123 {
2124     return m_AccItems.Add(pItem);
2125 }
2126 
2127 HRESULT CTipbarAccessible::RemoveAccItem(CTipbarAccItem *pItem)
2128 {
2129     for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem)
2130     {
2131         if (m_AccItems[iItem] == pItem)
2132         {
2133             m_AccItems.Remove(iItem, 1);
2134             break;
2135         }
2136     }
2137     return S_OK;
2138 }
2139 
2140 void CTipbarAccessible::ClearAccItems()
2141 {
2142     m_AccItems.clear();
2143 }
2144 
2145 CTipbarAccItem *CTipbarAccessible::AccItemFromID(INT iItem)
2146 {
2147     if (iItem < 0 || (INT)m_AccItems.size() <= iItem)
2148         return NULL;
2149     return m_AccItems[iItem];
2150 }
2151 
2152 INT CTipbarAccessible::GetIDOfItem(CTipbarAccItem *pTarget)
2153 {
2154     for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem)
2155     {
2156         if (pTarget == m_AccItems[iItem])
2157             return (INT)iItem;
2158     }
2159     return -1;
2160 }
2161 
2162 LONG_PTR CTipbarAccessible::CreateRefToAccObj(WPARAM wParam)
2163 {
2164     return ::LresultFromObject(IID_IAccessible, wParam, this);
2165 }
2166 
2167 BOOL CTipbarAccessible::DoDefaultActionReal(INT nID)
2168 {
2169     CTipbarAccItem *pItem = AccItemFromID(nID);
2170     if (!pItem)
2171         return FALSE;
2172     return pItem->DoAccDefaultActionReal();
2173 }
2174 
2175 void CTipbarAccessible::NotifyWinEvent(DWORD event, CTipbarAccItem *pItem)
2176 {
2177     INT nID = GetIDOfItem(pItem);
2178     if (nID < 0)
2179         return;
2180 
2181     ::NotifyWinEvent(event, m_hWnd, -4, nID);
2182 }
2183 
2184 void CTipbarAccessible::SetWindow(HWND hWnd)
2185 {
2186     m_hWnd = hWnd;
2187 }
2188 
2189 STDMETHODIMP CTipbarAccessible::QueryInterface(
2190     REFIID riid,
2191     void **ppvObject)
2192 {
2193     static const QITAB c_tab[] =
2194     {
2195         QITABENT(CTipbarAccessible, IDispatch),
2196         QITABENT(CTipbarAccessible, IAccessible),
2197         { NULL }
2198     };
2199     return ::QISearch(this, c_tab, riid, ppvObject);
2200 }
2201 
2202 STDMETHODIMP_(ULONG) CTipbarAccessible::AddRef()
2203 {
2204     return ::InterlockedIncrement(&m_cRefs);
2205 }
2206 
2207 STDMETHODIMP_(ULONG) CTipbarAccessible::Release()
2208 {
2209     LONG count = ::InterlockedDecrement(&m_cRefs);
2210     if (count == 0)
2211     {
2212         delete this;
2213         return 0;
2214     }
2215     return count;
2216 }
2217 
2218 STDMETHODIMP CTipbarAccessible::GetTypeInfoCount(UINT *pctinfo)
2219 {
2220     if (!pctinfo)
2221         return E_INVALIDARG;
2222     *pctinfo = (m_pTypeInfo == NULL);
2223     return S_OK;
2224 }
2225 
2226 STDMETHODIMP CTipbarAccessible::GetTypeInfo(
2227     UINT iTInfo,
2228     LCID lcid,
2229     ITypeInfo **ppTInfo)
2230 {
2231     if (!ppTInfo)
2232         return E_INVALIDARG;
2233     *ppTInfo = NULL;
2234     if (iTInfo != 0)
2235         return TYPE_E_ELEMENTNOTFOUND;
2236     if (!m_pTypeInfo)
2237         return E_NOTIMPL;
2238     *ppTInfo = m_pTypeInfo;
2239     m_pTypeInfo->AddRef();
2240     return S_OK;
2241 }
2242 
2243 STDMETHODIMP CTipbarAccessible::GetIDsOfNames(
2244     REFIID riid,
2245     LPOLESTR *rgszNames,
2246     UINT cNames,
2247     LCID lcid,
2248     DISPID *rgDispId)
2249 {
2250     if (!m_pTypeInfo)
2251         return E_NOTIMPL;
2252     return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
2253 }
2254 
2255 STDMETHODIMP CTipbarAccessible::Invoke(
2256     DISPID dispIdMember,
2257     REFIID riid,
2258     LCID lcid,
2259     WORD wFlags,
2260     DISPPARAMS *pDispParams,
2261     VARIANT *pVarResult,
2262     EXCEPINFO *pExcepInfo,
2263     UINT *puArgErr)
2264 {
2265     if (!m_pTypeInfo)
2266         return E_NOTIMPL;
2267     return m_pTypeInfo->Invoke(this,
2268                                dispIdMember,
2269                                wFlags,
2270                                pDispParams,
2271                                pVarResult,
2272                                pExcepInfo,
2273                                puArgErr);
2274 }
2275 
2276 STDMETHODIMP CTipbarAccessible::get_accParent(IDispatch **ppdispParent)
2277 {
2278     return m_pStdAccessible->get_accParent(ppdispParent);
2279 }
2280 
2281 STDMETHODIMP CTipbarAccessible::get_accChildCount(LONG *pcountChildren)
2282 {
2283     if (!pcountChildren)
2284         return E_INVALIDARG;
2285     INT cItems = (INT)m_AccItems.size();
2286     if (!cItems)
2287         return E_FAIL;
2288     *pcountChildren = cItems - 1;
2289     return S_OK;
2290 }
2291 
2292 STDMETHODIMP CTipbarAccessible::get_accChild(
2293     VARIANT varChildID,
2294     IDispatch **ppdispChild)
2295 {
2296     if (!ppdispChild)
2297         return E_INVALIDARG;
2298     *ppdispChild = NULL;
2299     return S_FALSE;
2300 }
2301 
2302 STDMETHODIMP CTipbarAccessible::get_accName(
2303     VARIANT varID,
2304     BSTR *pszName)
2305 {
2306     if (!pszName)
2307         return E_INVALIDARG;
2308     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2309     if (!pItem)
2310         return E_INVALIDARG;
2311     *pszName = pItem->GetAccName();
2312     if (!*pszName)
2313         return DISP_E_MEMBERNOTFOUND;
2314     return S_OK;
2315 }
2316 
2317 STDMETHODIMP CTipbarAccessible::get_accValue(
2318     VARIANT varID,
2319     BSTR *pszValue)
2320 {
2321     if (!pszValue)
2322         return E_INVALIDARG;
2323     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2324     if (!pItem)
2325         return E_INVALIDARG;
2326     *pszValue = pItem->GetAccValue();
2327     if (!*pszValue)
2328         return DISP_E_MEMBERNOTFOUND;
2329     return S_OK;
2330 }
2331 
2332 STDMETHODIMP CTipbarAccessible::get_accDescription(
2333     VARIANT varID,
2334     BSTR *description)
2335 {
2336     if (!description)
2337         return E_INVALIDARG;
2338     return m_pStdAccessible->get_accDescription(varID, description);
2339 }
2340 
2341 STDMETHODIMP CTipbarAccessible::get_accRole(
2342     VARIANT varID,
2343     VARIANT *role)
2344 {
2345     if (!role)
2346         return E_INVALIDARG;
2347     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2348     if (!pItem)
2349         return E_INVALIDARG;
2350     V_VT(role) = VT_I4;
2351     V_I4(role) = pItem->GetAccRole();
2352     return S_OK;
2353 }
2354 
2355 STDMETHODIMP CTipbarAccessible::get_accState(
2356     VARIANT varID,
2357     VARIANT *state)
2358 {
2359     if (!state)
2360         return E_INVALIDARG;
2361     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2362     if (!pItem)
2363         return E_INVALIDARG;
2364     V_VT(state) = VT_I4;
2365     V_I4(state) = pItem->GetAccState();
2366     return S_OK;
2367 }
2368 
2369 STDMETHODIMP CTipbarAccessible::get_accHelp(VARIANT varID, BSTR *help)
2370 {
2371     return DISP_E_MEMBERNOTFOUND;
2372 }
2373 
2374 STDMETHODIMP CTipbarAccessible::get_accHelpTopic(
2375     BSTR *helpfile,
2376     VARIANT varID,
2377     LONG *pidTopic)
2378 {
2379     return DISP_E_MEMBERNOTFOUND;
2380 }
2381 
2382 STDMETHODIMP CTipbarAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *shortcut)
2383 {
2384     return DISP_E_MEMBERNOTFOUND;
2385 }
2386 
2387 STDMETHODIMP CTipbarAccessible::get_accFocus(VARIANT *pvarID)
2388 {
2389     if (!pvarID)
2390         return E_INVALIDARG;
2391     V_VT(pvarID) = VT_EMPTY;
2392     return S_FALSE;
2393 }
2394 
2395 STDMETHODIMP CTipbarAccessible::get_accSelection(VARIANT *pvarID)
2396 {
2397     if (!pvarID)
2398         return E_INVALIDARG;
2399 
2400     V_VT(pvarID) = VT_EMPTY;
2401 
2402     INT cItems = (INT)m_AccItems.size();
2403     if (cItems < m_cSelection)
2404         return S_FALSE;
2405 
2406     if (cItems > m_cSelection)
2407     {
2408         V_VT(pvarID) = VT_I4;
2409         V_I4(pvarID) = m_cSelection;
2410     }
2411 
2412     return S_OK;
2413 }
2414 
2415 STDMETHODIMP CTipbarAccessible::get_accDefaultAction(
2416     VARIANT varID,
2417     BSTR *action)
2418 {
2419     if (!action)
2420         return E_INVALIDARG;
2421     *action = NULL;
2422 
2423     if (V_VT(&varID) != VT_I4)
2424         return E_INVALIDARG;
2425 
2426     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2427     if (!pItem)
2428         return DISP_E_MEMBERNOTFOUND;
2429     *action = pItem->GetAccDefaultAction();
2430     if (!*action)
2431         return S_FALSE;
2432     return S_OK;
2433 }
2434 
2435 STDMETHODIMP CTipbarAccessible::accSelect(
2436     LONG flagsSelect,
2437     VARIANT varID)
2438 {
2439     if ((flagsSelect & SELFLAG_ADDSELECTION) && (flagsSelect & SELFLAG_REMOVESELECTION))
2440         return E_INVALIDARG;
2441     if (flagsSelect & (SELFLAG_TAKEFOCUS | SELFLAG_ADDSELECTION | SELFLAG_EXTENDSELECTION))
2442         return S_FALSE;
2443     if (flagsSelect & SELFLAG_REMOVESELECTION)
2444         return S_OK;
2445     if (V_VT(&varID) != VT_I4)
2446         return E_INVALIDARG;
2447     if (flagsSelect & SELFLAG_TAKESELECTION)
2448     {
2449         m_cSelection = V_I4(&varID);
2450         return S_OK;
2451     }
2452     return S_FALSE;
2453 }
2454 
2455 STDMETHODIMP CTipbarAccessible::accLocation(
2456     LONG *left,
2457     LONG *top,
2458     LONG *width,
2459     LONG *height,
2460     VARIANT varID)
2461 {
2462     if (!left || !top || !width || !height)
2463         return E_INVALIDARG;
2464 
2465     if (!V_I4(&varID))
2466         return m_pStdAccessible->accLocation(left, top, width, height, varID);
2467 
2468     RECT rc;
2469     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2470     pItem->GetAccLocation(&rc);
2471 
2472     *left = rc.left;
2473     *top = rc.top;
2474     *width = rc.right - rc.left;
2475     *height = rc.bottom - rc.top;
2476     return S_OK;
2477 }
2478 
2479 STDMETHODIMP CTipbarAccessible::accNavigate(
2480     LONG dir,
2481     VARIANT varStart,
2482     VARIANT *pvarEnd)
2483 {
2484     if (m_AccItems.size() <= 1)
2485     {
2486         V_VT(pvarEnd) = VT_EMPTY;
2487         return S_OK;
2488     }
2489 
2490     switch (dir)
2491     {
2492         case NAVDIR_UP:
2493         case NAVDIR_LEFT:
2494         case NAVDIR_PREVIOUS:
2495             V_VT(pvarEnd) = VT_I4;
2496             V_I4(pvarEnd) = V_I4(&varStart) - 1;
2497             if (V_I4(&varStart) - 1 <= 0)
2498                 V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1);
2499             return S_OK;
2500 
2501         case NAVDIR_DOWN:
2502         case NAVDIR_RIGHT:
2503         case NAVDIR_NEXT:
2504             V_VT(pvarEnd) = VT_I4;
2505             V_I4(pvarEnd) = V_I4(&varStart) + 1;
2506             if ((INT)m_AccItems.size() <= V_I4(&varStart) + 1)
2507                 V_I4(pvarEnd) = 1;
2508             return S_OK;
2509 
2510         case NAVDIR_FIRSTCHILD:
2511             V_VT(pvarEnd) = VT_I4;
2512             V_I4(pvarEnd) = 1;
2513             return S_OK;
2514 
2515         case NAVDIR_LASTCHILD:
2516             V_VT(pvarEnd) = VT_I4;
2517             V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1);
2518             return S_OK;
2519 
2520         default:
2521             break;
2522     }
2523 
2524     V_VT(pvarEnd) = VT_EMPTY;
2525     return S_OK;
2526 }
2527 
2528 STDMETHODIMP CTipbarAccessible::accHitTest(LONG left, LONG top, VARIANT *pvarID)
2529 {
2530     if (!pvarID)
2531         return E_INVALIDARG;
2532     POINT Point = { left, top };
2533     RECT Rect;
2534     ::ScreenToClient(m_hWnd, &Point);
2535     ::GetClientRect(m_hWnd, &Rect);
2536 
2537     if (!::PtInRect(&Rect, Point))
2538     {
2539         V_VT(pvarID) = VT_EMPTY;
2540         return S_OK;
2541     }
2542 
2543     V_VT(pvarID) = VT_I4;
2544     V_I4(pvarID) = 0;
2545 
2546     for (size_t iItem = 1; iItem < m_AccItems.size(); ++iItem)
2547     {
2548         CTipbarAccItem *pItem = m_AccItems[iItem];
2549         if (pItem)
2550         {
2551             pItem->GetAccLocation(&Rect);
2552             if (::PtInRect(&Rect, Point))
2553             {
2554                 V_I4(pvarID) = iItem;
2555                 break;
2556             }
2557         }
2558     }
2559 
2560     return S_OK;
2561 }
2562 
2563 STDMETHODIMP CTipbarAccessible::accDoDefaultAction(VARIANT varID)
2564 {
2565     if (V_VT(&varID) != VT_I4)
2566         return E_INVALIDARG;
2567     CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID));
2568     if (!pItem)
2569         return DISP_E_MEMBERNOTFOUND;
2570     return (pItem->DoAccDefaultAction() ? S_OK : S_FALSE);
2571 }
2572 
2573 STDMETHODIMP CTipbarAccessible::put_accName(VARIANT varID, BSTR name)
2574 {
2575     return S_FALSE;
2576 }
2577 
2578 STDMETHODIMP CTipbarAccessible::put_accValue(VARIANT varID, BSTR value)
2579 {
2580     return S_FALSE;
2581 }
2582 
2583 /***********************************************************************
2584  * CUTBMenuWnd
2585  */
2586 
2587 CUTBMenuWnd::CUTBMenuWnd(HINSTANCE hInst, DWORD style, DWORD dwUnknown14)
2588     : CUIFMenu(hInst, style, dwUnknown14)
2589 {
2590 }
2591 
2592 BOOL CUTBMenuWnd::StartDoAccDefaultActionTimer(CUTBMenuItem *pTarget)
2593 {
2594     if (!m_pAccessible)
2595         return FALSE;
2596 
2597     m_nMenuWndID = m_pAccessible->GetIDOfItem(pTarget);
2598     if (!m_nMenuWndID || m_nMenuWndID == (UINT)-1)
2599         return FALSE;
2600 
2601     if (::IsWindow(m_hWnd))
2602     {
2603         ::KillTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION);
2604         ::SetTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION, g_uTimerElapseDOACCDEFAULTACTION, NULL);
2605     }
2606 
2607     return TRUE;
2608 }
2609 
2610 STDMETHODIMP_(BSTR) CUTBMenuWnd::GetAccName()
2611 {
2612     WCHAR szText[64];
2613     LoadStringW(g_hInst, IDS_MENUWND, szText, _countof(szText));
2614     return ::SysAllocString(szText);
2615 }
2616 
2617 STDMETHODIMP_(INT) CUTBMenuWnd::GetAccRole()
2618 {
2619     return 9;
2620 }
2621 
2622 STDMETHODIMP_(BOOL) CUTBMenuWnd::Initialize()
2623 {
2624     CTipbarAccessible *pAccessible = new(cicNoThrow) CTipbarAccessible(GetAccItem());
2625     if (pAccessible)
2626         m_pAccessible = pAccessible;
2627 
2628     return CUIFObject::Initialize();
2629 }
2630 
2631 STDMETHODIMP_(void) CUTBMenuWnd::OnCreate(HWND hWnd)
2632 {
2633     if (m_pAccessible)
2634         m_pAccessible->SetWindow(hWnd);
2635 }
2636 
2637 STDMETHODIMP_(void) CUTBMenuWnd::OnDestroy(HWND hWnd)
2638 {
2639     if (m_pAccessible)
2640     {
2641         m_pAccessible->NotifyWinEvent(EVENT_OBJECT_DESTROY, GetAccItem());
2642         m_pAccessible->ClearAccItems();
2643         m_pAccessible->Release();
2644         m_pAccessible = NULL;
2645     }
2646     m_coInit.CoUninit();
2647 }
2648 
2649 STDMETHODIMP_(HRESULT)
2650 CUTBMenuWnd::OnGetObject(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2651 {
2652     if (lParam != -4)
2653         return S_OK;
2654 
2655     if (!m_pAccessible)
2656         return E_OUTOFMEMORY;
2657 
2658     if (m_pAccessible->m_bInitialized)
2659         return m_pAccessible->CreateRefToAccObj(wParam);
2660 
2661     if (SUCCEEDED(m_coInit.EnsureCoInit()))
2662     {
2663         HRESULT hr = m_pAccessible->Initialize();
2664         if (FAILED(hr))
2665         {
2666             m_pAccessible->Release();
2667             m_pAccessible = NULL;
2668             return hr;
2669         }
2670 
2671         m_pAccessible->NotifyWinEvent(EVENT_OBJECT_CREATE, GetAccItem());
2672         return m_pAccessible->CreateRefToAccObj(wParam);
2673     }
2674 
2675     return S_OK;
2676 }
2677 
2678 STDMETHODIMP_(LRESULT)
2679 CUTBMenuWnd::OnShowWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2680 {
2681     if (m_pAccessible)
2682     {
2683         if (wParam)
2684         {
2685             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_SHOW, GetAccItem());
2686             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_FOCUS, GetAccItem());
2687         }
2688         else
2689         {
2690             m_pAccessible->NotifyWinEvent(EVENT_OBJECT_HIDE, GetAccItem());
2691         }
2692     }
2693 
2694     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
2695 }
2696 
2697 STDMETHODIMP_(void) CUTBMenuWnd::OnTimer(WPARAM wParam)
2698 {
2699     if (wParam == TIMER_ID_DOACCDEFAULTACTION)
2700     {
2701         ::KillTimer(m_hWnd, TIMER_ID_DOACCDEFAULTACTION);
2702         if (m_pAccessible && m_nMenuWndID)
2703         {
2704             m_pAccessible->DoDefaultActionReal(m_nMenuWndID);
2705             m_nMenuWndID = 0;
2706         }
2707     }
2708 }
2709 
2710 /***********************************************************************
2711  * CUTBMenuItem
2712  */
2713 
2714 CUTBMenuItem::CUTBMenuItem(CUTBMenuWnd *pMenuUI)
2715     : CUIFMenuItem(pMenuUI ? pMenuUI->GetMenu() : NULL)
2716 {
2717     m_pMenuUI = pMenuUI;
2718 }
2719 
2720 CUTBMenuItem::~CUTBMenuItem()
2721 {
2722     if (m_hbmColor)
2723     {
2724         ::DeleteObject(m_hbmColor);
2725         m_hbmColor = NULL;
2726     }
2727     if (m_hbmMask)
2728     {
2729         ::DeleteObject(m_hbmMask);
2730         m_hbmMask = NULL;
2731     }
2732 }
2733 
2734 STDMETHODIMP_(BOOL) CUTBMenuItem::DoAccDefaultAction()
2735 {
2736     if (!m_pMenuUI)
2737         return FALSE;
2738 
2739     m_pMenuUI->StartDoAccDefaultActionTimer(this);
2740     return TRUE;
2741 }
2742 
2743 STDMETHODIMP_(BOOL) CUTBMenuItem::DoAccDefaultActionReal()
2744 {
2745     if (!m_pSubMenu)
2746         OnLButtonUp(0, 0);
2747     else
2748         ShowSubPopup();
2749     return TRUE;
2750 }
2751 
2752 STDMETHODIMP_(BSTR) CUTBMenuItem::GetAccDefaultAction()
2753 {
2754     WCHAR szText[64];
2755     ::LoadStringW(g_hInst, IDS_LEFTCLICK, szText, _countof(szText));
2756     return ::SysAllocString(szText);
2757 }
2758 
2759 STDMETHODIMP_(void) CUTBMenuItem::GetAccLocation(LPRECT lprc)
2760 {
2761     GetRect(lprc);
2762     ::ClientToScreen(m_pMenuUI->m_hWnd, (LPPOINT)lprc);
2763     ::ClientToScreen(m_pMenuUI->m_hWnd, (LPPOINT)&lprc->right);
2764 }
2765 
2766 STDMETHODIMP_(BSTR) CUTBMenuItem::GetAccName()
2767 {
2768     return ::SysAllocString(m_pszMenuItemLeft);
2769 }
2770 
2771 /// @unimplemented
2772 STDMETHODIMP_(INT) CUTBMenuItem::GetAccRole()
2773 {
2774     if (FALSE) //FIXME
2775         return 21;
2776     return 12;
2777 }
2778 
2779 /***********************************************************************
2780  * CModalMenu
2781  */
2782 
2783 CUTBMenuItem *
2784 CModalMenu::InsertItem(CUTBMenuWnd *pMenuUI, INT nCommandId, INT nStringID)
2785 {
2786     CUTBMenuItem *pMenuItem = new(cicNoThrow) CUTBMenuItem(pMenuUI);
2787     if (!pMenuItem)
2788         return NULL;
2789 
2790     WCHAR szText[256];
2791     ::LoadStringW(g_hInst, nStringID, szText, _countof(szText));
2792 
2793     if (pMenuItem->Initialize() &&
2794         pMenuItem->Init(nCommandId, szText) &&
2795         pMenuUI->InsertItem(pMenuItem))
2796     {
2797         return pMenuItem;
2798     }
2799 
2800     delete pMenuItem;
2801     return NULL;
2802 }
2803 
2804 void CModalMenu::PostKey(BOOL bUp, WPARAM wParam, LPARAM lParam)
2805 {
2806     m_pMenuUI->PostKey(bUp, wParam, lParam);
2807 }
2808 
2809 void CModalMenu::CancelMenu()
2810 {
2811     if (m_pMenuUI)
2812         m_pMenuUI->CancelMenu();
2813 }
2814 
2815 /***********************************************************************
2816  * CUTBContextMenu
2817  */
2818 
2819 CUTBContextMenu::CUTBContextMenu(CTipbarWnd *pTipbarWnd)
2820 {
2821     m_pTipbarWnd = pTipbarWnd;
2822 }
2823 
2824 /// @implemented
2825 BOOL CUTBContextMenu::Init()
2826 {
2827     m_pTipbarThread = m_pTipbarWnd->m_pFocusThread;
2828     return !!m_pTipbarThread;
2829 }
2830 
2831 /// @unimplemented
2832 CUTBMenuWnd *CUTBContextMenu::CreateMenuUI(BOOL bFlag)
2833 {
2834     DWORD dwStatus = 0;
2835 
2836     if (FAILED(m_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus)))
2837         return NULL;
2838 
2839     CUTBMenuWnd *pMenuUI = new (cicNoThrow) CUTBMenuWnd(g_hInst, g_dwMenuStyle, 0);
2840     if (!pMenuUI)
2841         return NULL;
2842 
2843     pMenuUI->Initialize();
2844 
2845     if (dwStatus & (TF_SFT_DESKBAND | TF_SFT_MINIMIZED))
2846     {
2847         CUTBMenuItem *pRestoreLangBar = InsertItem(pMenuUI, ID_RESTORELANGBAR, IDS_RESTORELANGBAR2);
2848         if (pRestoreLangBar && !m_pTipbarWnd->m_dwUnknown20)
2849             pRestoreLangBar->Gray(TRUE);
2850     }
2851     else
2852     {
2853         InsertItem(pMenuUI, ID_DESKBAND, IDS_MINIMIZE);
2854 
2855         if (bFlag)
2856         {
2857             if (IsTransparecyAvailable())
2858             {
2859                 if (dwStatus & TF_LBI_BALLOON)
2860                 {
2861                     InsertItem(pMenuUI, ID_TRANS, IDS_TRANSPARENCY);
2862                 }
2863                 else
2864                 {
2865                     CUTBMenuItem *pTransparency = InsertItem(pMenuUI, ID_NOTRANS, IDS_TRANSPARENCY);
2866                     if (pTransparency)
2867                         pTransparency->Check(TRUE);
2868                 }
2869             }
2870 
2871             if (!(dwStatus & TF_SFT_LABELS))
2872             {
2873                 InsertItem(pMenuUI, ID_LABELS, IDS_TEXTLABELS);
2874             }
2875             else
2876             {
2877                 CUTBMenuItem *pTextLabels = InsertItem(pMenuUI, ID_NOLABELS, IDS_TEXTLABELS);
2878                 if (pTextLabels)
2879                     pTextLabels->Check(TRUE);
2880             }
2881 
2882             CUTBMenuItem *pVertical = InsertItem(pMenuUI, ID_VERTICAL, IDS_VERTICAL);
2883             if (pVertical)
2884                 pVertical->Check(!!(m_pTipbarWnd->m_dwTipbarWndFlags & TIPBAR_VERTICAL));
2885         }
2886     }
2887 
2888     if (bFlag)
2889     {
2890         CUTBMenuItem *pExtraIcons = NULL;
2891 
2892         if (dwStatus & TF_SFT_EXTRAICONSONMINIMIZED)
2893         {
2894             pExtraIcons = InsertItem(pMenuUI, ID_NOEXTRAICONS, IDS_EXTRAICONS);
2895             if (pExtraIcons)
2896                 pExtraIcons->Check(TRUE);
2897         }
2898         else
2899         {
2900             pExtraIcons = CModalMenu::InsertItem(pMenuUI, ID_EXTRAICONS, IDS_EXTRAICONS);
2901         }
2902 
2903         if (pExtraIcons)
2904         {
2905             if (::GetKeyboardLayoutList(0, NULL) == 1)
2906             {
2907                 pExtraIcons->Check(TRUE);
2908                 pExtraIcons->Gray(TRUE);
2909             }
2910             else
2911             {
2912                 pExtraIcons->Gray(FALSE);
2913             }
2914         }
2915 
2916         if (dwStatus & TF_SFT_DESKBAND)
2917             InsertItem(pMenuUI, ID_ADJUSTDESKBAND, IDS_ADJUSTLANGBAND);
2918 
2919         InsertItem(pMenuUI, ID_SETTINGS, IDS_SETTINGS);
2920 
2921         if (CheckCloseMenuAvailable())
2922             InsertItem(pMenuUI, ID_CLOSELANGBAR, IDS_CLOSELANGBAR);
2923     }
2924 
2925     return pMenuUI;
2926 }
2927 
2928 UINT
2929 CUTBContextMenu::ShowPopup(
2930     CUIFWindow *pWindow,
2931     POINT pt,
2932     LPCRECT prc,
2933     BOOL bFlag)
2934 {
2935     if (g_bWinLogon)
2936         return 0;
2937 
2938     if (m_pMenuUI)
2939         return -1;
2940 
2941     m_pMenuUI = CreateMenuUI(bFlag);
2942     if (!m_pMenuUI)
2943         return 0;
2944 
2945     UINT nCommandId = m_pMenuUI->ShowModalPopup(pWindow, prc, TRUE);
2946 
2947     if (m_pMenuUI)
2948     {
2949         delete m_pMenuUI;
2950         m_pMenuUI = NULL;
2951     }
2952 
2953     return nCommandId;
2954 }
2955 
2956 /// @unimplemented
2957 BOOL CUTBContextMenu::SelectMenuItem(UINT nCommandId)
2958 {
2959     switch (nCommandId)
2960     {
2961         case ID_TRANS:
2962             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_LOWTRANSPARENCY);
2963             break;
2964 
2965         case ID_NOTRANS:
2966             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOTRANSPARENCY);
2967             break;
2968 
2969         case ID_LABELS:
2970             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_LABELS);
2971             break;
2972 
2973         case ID_NOLABELS:
2974             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOLABELS);
2975             break;
2976 
2977         case ID_DESKBAND:
2978         {
2979             if (!g_bEnableDeskBand || !(g_dwOSInfo & CIC_OSINFO_XPPLUS))
2980             {
2981                 m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_MINIMIZED);
2982             }
2983             else
2984             {
2985                 DWORD dwStatus;
2986                 m_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus);
2987 
2988                 if (dwStatus & TF_SFT_DESKBAND)
2989                     break;
2990 
2991                 m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND);
2992             }
2993 
2994             CUTBMinimizeLangBarDlg *pDialog = new(cicNoThrow) CUTBMinimizeLangBarDlg();
2995             if (pDialog)
2996             {
2997                 pDialog->DoModal(*m_pTipbarWnd->GetWindow());
2998                 pDialog->_Release();
2999             }
3000             break;
3001         }
3002 
3003         case ID_CLOSELANGBAR:
3004         {
3005             CUTBCloseLangBarDlg *pDialog = new(cicNoThrow) CUTBCloseLangBarDlg();
3006             if (pDialog)
3007             {
3008                 BOOL bOK = pDialog->DoModal(*m_pTipbarWnd->GetWindow());
3009                 pDialog->_Release();
3010                 if (!bOK)
3011                     DoCloseLangbar();
3012             }
3013             break;
3014         }
3015 
3016         case ID_EXTRAICONS:
3017             m_pTipbarWnd->m_dwTipbarWndFlags &= ~TIPBAR_NODESKBAND;
3018             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_EXTRAICONSONMINIMIZED);
3019             break;
3020 
3021         case ID_NOEXTRAICONS:
3022             m_pTipbarWnd->m_dwTipbarWndFlags &= ~TIPBAR_NODESKBAND;
3023             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_NOEXTRAICONSONMINIMIZED);
3024             break;
3025 
3026         case ID_RESTORELANGBAR:
3027             m_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_LBI_ICON);
3028             break;
3029 
3030         case ID_VERTICAL:
3031             m_pTipbarWnd->SetVertical(!!(m_pTipbarWnd->m_dwTipbarWndFlags & TIPBAR_VERTICAL));
3032             break;
3033 
3034         case ID_ADJUSTDESKBAND:
3035             m_pTipbarWnd->AdjustDeskBandSize(TRUE);
3036             break;
3037 
3038         case ID_SETTINGS:
3039             TF_RunInputCPL();
3040             break;
3041 
3042         default:
3043             break;
3044     }
3045 
3046     return TRUE;
3047 }
3048 
3049 /***********************************************************************
3050  * CTrayIconItem
3051  */
3052 
3053 CTrayIconItem::CTrayIconItem(CTrayIconWnd *pTrayIconWnd)
3054 {
3055     m_dwIconAddOrModify = NIM_ADD;
3056     m_pTrayIconWnd = pTrayIconWnd;
3057 }
3058 
3059 BOOL
3060 CTrayIconItem::_Init(
3061     HWND hWnd,
3062     UINT uCallbackMessage,
3063     UINT uNotifyIconID,
3064     const GUID& rguid)
3065 {
3066     m_hWnd = hWnd;
3067     m_uCallbackMessage = uCallbackMessage;
3068     m_uNotifyIconID = uNotifyIconID;
3069     m_guid = rguid;
3070     return TRUE;
3071 }
3072 
3073 BOOL CTrayIconItem::RemoveIcon()
3074 {
3075     if (m_dwIconAddOrModify == NIM_MODIFY)
3076     {
3077         NOTIFYICONDATAW NotifyIcon = { sizeof(NotifyIcon), m_hWnd, m_uNotifyIconID };
3078         NotifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
3079         NotifyIcon.uCallbackMessage = m_uCallbackMessage;
3080         ::Shell_NotifyIconW(NIM_DELETE, &NotifyIcon);
3081     }
3082 
3083     m_dwIconAddOrModify = NIM_ADD;
3084     m_bIconAdded = TRUE;
3085     return TRUE;
3086 }
3087 
3088 BOOL CTrayIconItem::SetIcon(HICON hIcon, LPCWSTR pszTip)
3089 {
3090     if (!hIcon)
3091         return FALSE;
3092 
3093     NOTIFYICONDATAW NotifyIcon = { sizeof(NotifyIcon), m_hWnd, m_uNotifyIconID };
3094     NotifyIcon.uFlags = NIF_ICON | NIF_MESSAGE;
3095     NotifyIcon.uCallbackMessage = m_uCallbackMessage;
3096     NotifyIcon.hIcon = hIcon;
3097     if (pszTip)
3098     {
3099         NotifyIcon.uFlags |= NIF_TIP;
3100         StringCchCopyW(NotifyIcon.szTip, _countof(NotifyIcon.szTip), pszTip);
3101     }
3102 
3103     ::Shell_NotifyIconW(m_dwIconAddOrModify, &NotifyIcon);
3104 
3105     m_dwIconAddOrModify = NIM_MODIFY;
3106     m_bIconAdded = NIM_MODIFY;
3107     return TRUE;
3108 }
3109 
3110 BOOL CTrayIconItem::UpdateMenuRectPoint()
3111 {
3112     HWND hNotifyWnd = m_pTrayIconWnd->GetNotifyWnd();
3113     ::GetClientRect(hNotifyWnd, &m_rcMenu);
3114     ::ClientToScreen(hNotifyWnd, (LPPOINT)&m_rcMenu);
3115     ::ClientToScreen(hNotifyWnd, (LPPOINT)&m_rcMenu.right);
3116     ::GetCursorPos(&m_ptCursor);
3117     return TRUE;
3118 }
3119 
3120 /***********************************************************************
3121  * CButtonIconItem
3122  */
3123 
3124 CButtonIconItem::CButtonIconItem(CTrayIconWnd *pWnd, DWORD dwUnknown24)
3125     : CTrayIconItem(pWnd)
3126 {
3127     m_dwUnknown24 = dwUnknown24;
3128 }
3129 
3130 /// @unimplemented
3131 STDMETHODIMP_(BOOL) CButtonIconItem::OnMsg(WPARAM wParam, LPARAM lParam)
3132 {
3133     switch (lParam)
3134     {
3135         case WM_LBUTTONDOWN:
3136         case WM_RBUTTONDOWN:
3137         case WM_LBUTTONDBLCLK:
3138         case WM_RBUTTONDBLCLK:
3139             break;
3140         default:
3141             return TRUE;
3142     }
3143 
3144     //FIXME
3145     return TRUE;
3146 }
3147 
3148 /// @unimplemented
3149 STDMETHODIMP_(BOOL) CButtonIconItem::OnDelayMsg(UINT uMsg)
3150 {
3151     //FIXME
3152     return FALSE;
3153 }
3154 
3155 /***********************************************************************
3156  * CMainIconItem
3157  */
3158 
3159 /// @implemented
3160 CMainIconItem::CMainIconItem(CTrayIconWnd *pWnd)
3161     : CButtonIconItem(pWnd, 1)
3162 {
3163 }
3164 
3165 /// @implemented
3166 BOOL CMainIconItem::Init(HWND hWnd)
3167 {
3168     return CTrayIconItem::_Init(hWnd, WM_USER, 0, GUID_LBI_TRAYMAIN);
3169 }
3170 
3171 /// @implemented
3172 STDMETHODIMP_(BOOL) CMainIconItem::OnDelayMsg(UINT uMsg)
3173 {
3174     if (!CButtonIconItem::OnDelayMsg(uMsg))
3175         return 0;
3176 
3177     if (uMsg == WM_LBUTTONDBLCLK)
3178     {
3179         if (g_pTipbarWnd->m_dwUnknown20)
3180             g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_SHOWNORMAL);
3181     }
3182     else if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN)
3183     {
3184         g_pTipbarWnd->ShowContextMenu(m_ptCursor, &m_rcMenu, uMsg == WM_RBUTTONDOWN);
3185     }
3186     return TRUE;
3187 }
3188 
3189 /***********************************************************************
3190  * CTrayIconWnd
3191  */
3192 
3193 CTrayIconWnd::CTrayIconWnd()
3194 {
3195     m_uCallbackMsg = WM_USER + 0x1000;
3196     m_uNotifyIconID = 0x1000;
3197 }
3198 
3199 CTrayIconWnd::~CTrayIconWnd()
3200 {
3201     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3202     {
3203         auto& pItem = m_Items[iItem];
3204         if (pItem)
3205         {
3206             delete pItem;
3207             pItem = NULL;
3208         }
3209     }
3210 }
3211 
3212 void CTrayIconWnd::CallOnDelayMsg()
3213 {
3214     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3215     {
3216         auto pItem = m_Items[iItem];
3217         if (pItem && m_uCallbackMessage == pItem->m_uCallbackMessage)
3218         {
3219             pItem->OnDelayMsg(m_uMsg);
3220             break;
3221         }
3222     }
3223 }
3224 
3225 HWND CTrayIconWnd::CreateWnd()
3226 {
3227     m_hWnd = ::CreateWindowEx(0, TEXT("CTrayIconWndClass"), NULL, WS_DISABLED,
3228                               0, 0, 0, 0, NULL, NULL, g_hInst, this);
3229     FindTrayEtc();
3230 
3231     m_pMainIconItem = new(cicNoThrow) CMainIconItem(this);
3232     if (m_pMainIconItem)
3233     {
3234         m_pMainIconItem->Init(m_hWnd);
3235         m_Items.Add(m_pMainIconItem);
3236     }
3237 
3238     return m_hWnd;
3239 }
3240 
3241 void CTrayIconWnd::DestroyWnd()
3242 {
3243     ::DestroyWindow(m_hWnd);
3244     m_hWnd = NULL;
3245 }
3246 
3247 BOOL CALLBACK CTrayIconWnd::EnumChildWndProc(HWND hWnd, LPARAM lParam)
3248 {
3249     CTrayIconWnd *pWnd = (CTrayIconWnd *)lParam;
3250 
3251     TCHAR ClassName[60];
3252     ::GetClassName(hWnd, ClassName, _countof(ClassName));
3253     if (lstrcmp(ClassName, TEXT("TrayNotifyWnd")) != 0)
3254         return TRUE;
3255 
3256     pWnd->m_hNotifyWnd = hWnd;
3257     return FALSE;
3258 }
3259 
3260 CButtonIconItem *CTrayIconWnd::FindIconItem(REFGUID rguid)
3261 {
3262     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3263     {
3264         auto pItem = m_Items[iItem];
3265         if (IsEqualGUID(rguid, pItem->m_guid))
3266             return pItem;
3267     }
3268     return NULL;
3269 }
3270 
3271 BOOL CTrayIconWnd::FindTrayEtc()
3272 {
3273     m_hTrayWnd = ::FindWindow(TEXT("Shell_TrayWnd"), NULL);
3274     if (!m_hTrayWnd)
3275         return FALSE;
3276 
3277     ::EnumChildWindows(m_hTrayWnd, EnumChildWndProc, (LPARAM)this);
3278     if (!m_hNotifyWnd)
3279         return FALSE;
3280     m_dwTrayWndThreadId = ::GetWindowThreadProcessId(m_hTrayWnd, NULL);
3281     m_hwndProgman = FindWindow(TEXT("Progman"), NULL);
3282     m_dwProgmanThreadId = ::GetWindowThreadProcessId(m_hwndProgman, NULL);
3283     return TRUE;
3284 }
3285 
3286 HWND CTrayIconWnd::GetNotifyWnd()
3287 {
3288     if (!::IsWindow(m_hNotifyWnd))
3289         FindTrayEtc();
3290     return m_hNotifyWnd;
3291 }
3292 
3293 /// @implemented
3294 BOOL CTrayIconWnd::OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
3295 {
3296     if (g_pTipbarWnd)
3297         g_pTipbarWnd->AttachFocusThread();
3298 
3299     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3300     {
3301         auto *pItem = m_Items[iItem];
3302         if (pItem)
3303         {
3304             if (uMsg == pItem->m_uCallbackMessage)
3305             {
3306                 pItem->OnMsg(wParam, lParam);
3307                 return TRUE;
3308             }
3309         }
3310     }
3311     return FALSE;
3312 }
3313 
3314 BOOL CTrayIconWnd::RegisterClass()
3315 {
3316     WNDCLASSEX wc = { sizeof(wc) };
3317     wc.style = CS_HREDRAW | CS_VREDRAW;
3318     wc.hInstance = g_hInst;
3319     wc.hCursor = ::LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
3320     wc.lpfnWndProc = CTrayIconWnd::_WndProc;
3321     wc.lpszClassName = TEXT("CTrayIconWndClass");
3322     ::RegisterClassEx(&wc);
3323     return TRUE;
3324 }
3325 
3326 void CTrayIconWnd::RemoveAllIcon(DWORD dwFlags)
3327 {
3328     for (size_t iItem = 0; iItem < m_Items.size(); ++iItem)
3329     {
3330         auto pItem = m_Items[iItem];
3331         if (dwFlags & 0x1)
3332         {
3333             if (IsEqualGUID(pItem->m_guid, GUID_LBI_INATITEM) ||
3334                 IsEqualGUID(pItem->m_guid, GUID_LBI_CTRL))
3335             {
3336                 continue;
3337             }
3338         }
3339 
3340         if (dwFlags & 0x2)
3341         {
3342             if (IsEqualGUID(pItem->m_guid, GUID_TFCAT_TIP_KEYBOARD))
3343                 continue;
3344         }
3345 
3346         if (pItem->m_uNotifyIconID < 0x1000)
3347             continue;
3348 
3349         pItem->RemoveIcon();
3350     }
3351 }
3352 
3353 /// @unimplemented
3354 void CTrayIconWnd::RemoveUnusedIcons(int unknown)
3355 {
3356     //FIXME
3357 }
3358 
3359 BOOL CTrayIconWnd::SetIcon(REFGUID rguid, DWORD dwUnknown24, HICON hIcon, LPCWSTR psz)
3360 {
3361     CButtonIconItem *pItem = FindIconItem(rguid);
3362     if (!pItem)
3363     {
3364         if (!hIcon)
3365             return FALSE;
3366         pItem = new(cicNoThrow) CButtonIconItem(this, dwUnknown24);
3367         if (!pItem)
3368             return FALSE;
3369 
3370         pItem->_Init(m_hWnd, m_uCallbackMsg, m_uNotifyIconID, rguid);
3371         m_uCallbackMsg += 2;
3372         ++m_uNotifyIconID;
3373         m_Items.Add(pItem);
3374     }
3375 
3376     if (!hIcon)
3377         return pItem->RemoveIcon();
3378 
3379     return pItem->SetIcon(hIcon, psz);
3380 }
3381 
3382 BOOL CTrayIconWnd::SetMainIcon(HKL hKL)
3383 {
3384     if (!hKL)
3385     {
3386         m_pMainIconItem->RemoveIcon();
3387         m_pMainIconItem->m_hKL = NULL;
3388         return TRUE;
3389     }
3390 
3391     if (hKL != m_pMainIconItem->m_hKL)
3392     {
3393         WCHAR szText[64];
3394         HICON hIcon = TF_GetLangIcon(LOWORD(hKL), szText, _countof(szText));
3395         if (hIcon)
3396         {
3397             m_pMainIconItem->SetIcon(hIcon, szText);
3398             ::DestroyIcon(hIcon);
3399         }
3400         else
3401         {
3402             ::LoadStringW(g_hInst, IDS_RESTORELANGBAR, szText, _countof(szText));
3403             hIcon = ::LoadIconW(g_hInst, MAKEINTRESOURCEW(IDI_MAINICON));
3404             m_pMainIconItem->SetIcon(hIcon, szText);
3405         }
3406 
3407         m_pMainIconItem->m_hKL = hKL;
3408     }
3409 
3410     return TRUE;
3411 }
3412 
3413 CTrayIconWnd *CTrayIconWnd::GetThis(HWND hWnd)
3414 {
3415     return (CTrayIconWnd *)::GetWindowLongPtr(hWnd, GWL_USERDATA);
3416 }
3417 
3418 void CTrayIconWnd::SetThis(HWND hWnd, LPCREATESTRUCT pCS)
3419 {
3420     if (pCS)
3421         ::SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)pCS->lpCreateParams);
3422     else
3423         ::SetWindowLongPtr(hWnd, GWL_USERDATA, 0);
3424 }
3425 
3426 LRESULT CALLBACK
3427 CTrayIconWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3428 {
3429     CTrayIconWnd *pThis;
3430     switch (uMsg)
3431     {
3432         case WM_CREATE:
3433             CTrayIconWnd::SetThis(hWnd, (LPCREATESTRUCT)lParam);
3434             break;
3435         case WM_DESTROY:
3436             ::SetWindowLongPtr(hWnd, GWL_USERDATA, 0);
3437             break;
3438         case WM_TIMER:
3439             if (wParam == 100)
3440             {
3441                 ::KillTimer(hWnd, 100);
3442                 pThis = CTrayIconWnd::GetThis(hWnd);
3443                 if (pThis)
3444                     pThis->CallOnDelayMsg();
3445             }
3446             break;
3447         default:
3448         {
3449             if (uMsg < WM_USER)
3450                 return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
3451             pThis = CTrayIconWnd::GetThis(hWnd);
3452             if (pThis && pThis->OnIconMessage(uMsg, wParam, lParam))
3453                 break;
3454             return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
3455         }
3456     }
3457     return 0;
3458 }
3459 
3460 /***********************************************************************
3461  * CLBarItemBase
3462  */
3463 
3464 CLBarItemBase::CLBarItemBase()
3465 {
3466     m_dwItemStatus = 0;
3467     m_szToolTipText[0] = 0;
3468     m_cRefs = 1;
3469     m_pLangBarItemSink = NULL;
3470 }
3471 
3472 CLBarItemBase::~CLBarItemBase()
3473 {
3474     if (m_pLangBarItemSink)
3475         m_pLangBarItemSink->Release();
3476 }
3477 
3478 HRESULT
3479 CLBarItemBase::AdviseSink(
3480     REFIID riid,
3481     IUnknown *punk,
3482     DWORD *pdwCookie)
3483 {
3484     if (IsEqualIID(riid, IID_ITfLangBarItemSink) || m_pLangBarItemSink)
3485         return TF_E_NOOBJECT;
3486 
3487     HRESULT hr = punk->QueryInterface(IID_ITfLangBarItemSink, (void **)&m_pLangBarItemSink);
3488     if (SUCCEEDED(hr))
3489         *pdwCookie = 0x80000001;
3490     return hr;
3491 }
3492 
3493 HRESULT CLBarItemBase::UnadviseSink(DWORD dwCookie)
3494 {
3495     if (dwCookie != 0x80000001)
3496         return E_FAIL;
3497 
3498     if (!m_pLangBarItemSink)
3499         return E_UNEXPECTED;
3500 
3501     m_pLangBarItemSink->Release();
3502     m_pLangBarItemSink = NULL;
3503     return S_OK;
3504 }
3505 
3506 void
3507 CLBarItemBase::InitNuiInfo(
3508     REFIID clsidService,
3509     REFGUID guidItem,
3510     DWORD dwStyle,
3511     DWORD ulSort,
3512     LPCWSTR Source)
3513 {
3514     m_NewUIInfo.clsidService = clsidService;
3515     m_NewUIInfo.guidItem = guidItem;
3516     m_NewUIInfo.dwStyle = dwStyle;
3517     m_NewUIInfo.ulSort = ulSort;
3518     StringCchCopyW(m_NewUIInfo.szDescription, _countof(m_NewUIInfo.szDescription), Source);
3519 }
3520 
3521 HRESULT
3522 CLBarItemBase::ShowInternal(BOOL bShow, BOOL bUpdate)
3523 {
3524     DWORD dwOldStatus = m_dwItemStatus;
3525 
3526     if (bShow)
3527         m_dwItemStatus &= ~TF_LBI_STATUS_HIDDEN;
3528     else
3529         m_dwItemStatus |= TF_LBI_STATUS_HIDDEN;
3530 
3531     if (bUpdate && (dwOldStatus != m_dwItemStatus))
3532     {
3533         if (m_pLangBarItemSink)
3534             m_pLangBarItemSink->OnUpdate(TF_LBI_STATUS);
3535     }
3536 
3537     return S_OK;
3538 }
3539 
3540 HRESULT CLBarItemBase::GetInfo(TF_LANGBARITEMINFO *pInfo)
3541 {
3542     CopyMemory(pInfo, &m_NewUIInfo, sizeof(*pInfo));
3543     return S_OK;
3544 }
3545 
3546 HRESULT CLBarItemBase::GetStatus(DWORD *pdwStatus)
3547 {
3548     *pdwStatus = m_dwItemStatus;
3549     return S_OK;
3550 }
3551 
3552 HRESULT CLBarItemBase::Show(BOOL fShow)
3553 {
3554     return ShowInternal(fShow, TRUE);
3555 }
3556 
3557 HRESULT CLBarItemBase::GetTooltipString(BSTR *pbstrToolTip)
3558 {
3559     if (!pbstrToolTip)
3560         return E_INVALIDARG;
3561     BSTR bstr = ::SysAllocString(m_szToolTipText);
3562     *pbstrToolTip = bstr;
3563     return bstr ? S_OK : E_OUTOFMEMORY;
3564 }
3565 
3566 /***********************************************************************
3567  * CUTBLBarMenu
3568  */
3569 
3570 CUTBLBarMenu::CUTBLBarMenu(HINSTANCE hInst) : CCicLibMenu()
3571 {
3572     m_hInst = hInst;
3573 }
3574 
3575 CUTBLBarMenu::~CUTBLBarMenu()
3576 {
3577 }
3578 
3579 STDMETHODIMP_(CCicLibMenuItem*) CUTBLBarMenu::CreateMenuItem()
3580 {
3581     CUTBLBarMenuItem *pItem = new(cicNoThrow) CUTBLBarMenuItem();
3582     if (!pItem)
3583         return NULL;
3584     pItem->m_pLBarMenu = this;
3585     return pItem;
3586 }
3587 
3588 CUTBMenuWnd *CUTBLBarMenu::CreateMenuUI()
3589 {
3590     CUTBMenuWnd *pMenuUI = new(cicNoThrow) CUTBMenuWnd(m_hInst, g_dwMenuStyle, 0);
3591     if (!pMenuUI)
3592         return NULL;
3593 
3594     pMenuUI->Initialize();
3595     for (size_t iItem = 0; iItem < m_MenuItems.size(); ++iItem)
3596     {
3597         CUTBLBarMenuItem *pItem = (CUTBLBarMenuItem *)m_MenuItems[iItem];
3598         pItem->InsertToUI(pMenuUI);
3599     }
3600 
3601     return pMenuUI;
3602 }
3603 
3604 STDMETHODIMP_(CCicLibMenu*) CUTBLBarMenu::CreateSubMenu()
3605 {
3606     return new(cicNoThrow) CUTBLBarMenu(m_hInst);
3607 }
3608 
3609 INT CUTBLBarMenu::ShowPopup(CUIFWindow *pWindow, POINT pt, LPCRECT prcExclude)
3610 {
3611     if (m_pMenuUI)
3612         return 0;
3613 
3614     m_pMenuUI = CreateMenuUI();
3615     if (!m_pMenuUI)
3616         return -1;
3617 
3618     INT nCommandId = m_pMenuUI->ShowModalPopup(pWindow, prcExclude, TRUE);
3619 
3620     if (m_pMenuUI)
3621     {
3622         delete m_pMenuUI;
3623         m_pMenuUI = NULL;
3624     }
3625 
3626     return nCommandId;
3627 }
3628 
3629 /***********************************************************************
3630  * CUTBLBarMenuItem
3631  */
3632 
3633 /// @unimplemented
3634 BOOL CUTBLBarMenuItem::InsertToUI(CUTBMenuWnd *pMenuUI)
3635 {
3636     if ((m_dwFlags & 4) != 0)
3637     {
3638         pMenuUI->InsertSeparator();
3639         return TRUE;
3640     }
3641     if (m_dwFlags & 2)
3642     {
3643         //FIXME
3644     }
3645     else
3646     {
3647         //FIXME
3648     }
3649     return FALSE;
3650 }
3651 
3652 /***********************************************************************
3653  * CLBarItemButtonBase
3654  */
3655 
3656 CLBarItemButtonBase::~CLBarItemButtonBase()
3657 {
3658     if (m_hIcon)
3659     {
3660         ::DestroyIcon(m_hIcon);
3661         m_hIcon = NULL;
3662     }
3663 }
3664 
3665 STDMETHODIMP CLBarItemButtonBase::QueryInterface(REFIID riid, void **ppvObject)
3666 {
3667     static const QITAB c_tab[] =
3668     {
3669         QITABENT(CLBarItemButtonBase, ITfLangBarItem),
3670         QITABENT(CLBarItemButtonBase, ITfLangBarItemButton),
3671         QITABENT(CLBarItemButtonBase, ITfSource),
3672         { NULL }
3673     };
3674     return ::QISearch(this, c_tab, riid, ppvObject);
3675 }
3676 
3677 STDMETHODIMP_(ULONG) CLBarItemButtonBase::AddRef()
3678 {
3679     return ++m_cRefs;
3680 }
3681 
3682 STDMETHODIMP_(ULONG) CLBarItemButtonBase::Release()
3683 {
3684     if (--m_cRefs == 0)
3685     {
3686         delete this;
3687         return 0;
3688     }
3689     return m_cRefs;
3690 }
3691 
3692 /// @unimplemented
3693 STDMETHODIMP CLBarItemButtonBase::OnClick(TfLBIClick click, POINT pt, LPCRECT prc)
3694 {
3695     if (click == TF_LBI_CLK_RIGHT)
3696     {
3697         return E_NOTIMPL; //FIXME
3698     }
3699     if (click == TF_LBI_CLK_LEFT)
3700     {
3701         return E_NOTIMPL; //FIXME
3702     }
3703     return E_NOTIMPL;
3704 }
3705 
3706 STDMETHODIMP CLBarItemButtonBase::InitMenu(ITfMenu *pMenu)
3707 {
3708     return E_NOTIMPL;
3709 }
3710 
3711 STDMETHODIMP CLBarItemButtonBase::OnMenuSelect(UINT wID)
3712 {
3713     return E_NOTIMPL;
3714 }
3715 
3716 STDMETHODIMP CLBarItemButtonBase::GetIcon(HICON *phIcon)
3717 {
3718     return E_NOTIMPL;
3719 }
3720 
3721 STDMETHODIMP CLBarItemButtonBase::GetText(BSTR *pbstr)
3722 {
3723     if (!pbstr)
3724         return E_INVALIDARG;
3725     *pbstr = ::SysAllocString(m_NewUIInfo.szDescription);
3726     return (*pbstr ? S_OK : E_OUTOFMEMORY);
3727 }
3728 
3729 STDMETHODIMP CLBarItemButtonBase::GetInfo(TF_LANGBARITEMINFO *pInfo)
3730 {
3731     return CLBarItemBase::GetInfo(pInfo);
3732 }
3733 
3734 STDMETHODIMP CLBarItemButtonBase::GetStatus(DWORD *pdwStatus)
3735 {
3736     return CLBarItemBase::GetStatus(pdwStatus);
3737 }
3738 
3739 STDMETHODIMP CLBarItemButtonBase::Show(BOOL fShow)
3740 {
3741     return CLBarItemBase::Show(fShow);
3742 }
3743 
3744 STDMETHODIMP CLBarItemButtonBase::GetTooltipString(BSTR *pbstrToolTip)
3745 {
3746     return CLBarItemBase::GetTooltipString(pbstrToolTip);
3747 }
3748 
3749 STDMETHODIMP CLBarItemButtonBase::AdviseSink(
3750     REFIID riid,
3751     IUnknown *punk,
3752     DWORD *pdwCookie)
3753 {
3754     return CLBarItemBase::AdviseSink(riid, punk, pdwCookie);
3755 }
3756 
3757 STDMETHODIMP CLBarItemButtonBase::UnadviseSink(DWORD dwCookie)
3758 {
3759     return CLBarItemBase::UnadviseSink(dwCookie);
3760 }
3761 
3762 /***********************************************************************
3763  * CLBarInatItem
3764  */
3765 
3766 CLBarInatItem::CLBarInatItem(DWORD dwThreadId)
3767 {
3768     WCHAR szText[256];
3769     ::LoadStringW(g_hInst, IDS_LANGUAGE, szText, _countof(szText));
3770     InitNuiInfo(CLSID_SYSTEMLANGBARITEM, GUID_LBI_INATITEM, 0x20001, 0, szText);
3771 
3772     ::LoadStringW(g_hInst, IDS_LANGUAGEBUTTON, szText, _countof(szText));
3773     StringCchCopyW(m_szToolTipText, _countof(m_szToolTipText), szText);
3774     m_dwThreadId = dwThreadId;
3775     m_hKL = ::GetKeyboardLayout(m_dwThreadId);
3776 
3777     TF_InitMlngInfo();
3778     ShowInternal(TF_MlngInfoCount() > 1, 0);
3779 }
3780 
3781 STDMETHODIMP CLBarInatItem::GetIcon(HICON *phIcon)
3782 {
3783     HICON hIcon = NULL;
3784     INT iIndex = GetIconIndexFromhKL(m_hKL);
3785     if (iIndex != -1)
3786         hIcon = TF_InatExtractIcon(iIndex);
3787     *phIcon = hIcon;
3788     return S_OK;
3789 }
3790 
3791 STDMETHODIMP CLBarInatItem::GetText(BSTR *pbstr)
3792 {
3793     if (!pbstr)
3794         return E_INVALIDARG;
3795 
3796     WCHAR szText[256];
3797     if (!GethKLDesc(m_hKL, szText, _countof(szText)))
3798         return GetText(pbstr);
3799 
3800     *pbstr = ::SysAllocString(szText);
3801     return S_OK;
3802 }
3803 
3804 STDMETHODIMP CLBarInatItem::InitMenu(ITfMenu *pMenu)
3805 {
3806     TF_InitMlngInfo();
3807 
3808     INT iKL, cKLs = TF_MlngInfoCount();
3809     for (iKL = 0; iKL < cKLs; ++iKL)
3810     {
3811         HKL hKL;
3812         WCHAR szDesc[128];
3813         if (TF_GetMlngHKL(iKL, &hKL, szDesc, _countof(szDesc)))
3814         {
3815             HICON hIcon = NULL;
3816             INT iIndex = GetIconIndexFromhKL(hKL);
3817             if (iIndex != -1)
3818                 hIcon = TF_InatExtractIcon(iIndex);
3819 
3820             LangBarInsertMenu(pMenu, iKL, szDesc, (hKL == m_hKL), hIcon);
3821         }
3822     }
3823 
3824     DWORD dwStatus;
3825     if (g_pTipbarWnd &&
3826         g_pTipbarWnd->m_pLangBarMgr &&
3827         SUCCEEDED(g_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus)) &&
3828         (dwStatus & (TF_SFT_DESKBAND | TF_SFT_MINIMIZED)))
3829     {
3830         LangBarInsertSeparator(pMenu);
3831 
3832         WCHAR szText[256];
3833         ::LoadStringW(g_hInst, IDS_RESTORELANGBAR2, szText, _countof(szText));
3834         LangBarInsertMenu(pMenu, 2000, szText, FALSE, NULL);
3835     }
3836 
3837     return S_OK;
3838 }
3839 
3840 STDMETHODIMP CLBarInatItem::OnMenuSelect(INT nCommandId)
3841 {
3842     HKL hKL;
3843 
3844     if (nCommandId == 2000)
3845     {
3846         if (g_pTipbarWnd)
3847         {
3848             ITfLangBarMgr *pLangBarMgr = g_pTipbarWnd->m_pLangBarMgr;
3849             if (pLangBarMgr)
3850                 pLangBarMgr->ShowFloating(TF_SFT_SHOWNORMAL);
3851         }
3852     }
3853     else if (TF_GetMlngHKL(nCommandId, &hKL, NULL, 0))
3854     {
3855         g_pTipbarWnd->RestoreLastFocus(NULL, !!(g_pTipbarWnd->m_dwTipbarWndFlags & TIPBAR_CHILD));
3856         HWND hwndFore = ::GetForegroundWindow();
3857         if (m_dwThreadId == ::GetWindowThreadProcessId(hwndFore, NULL))
3858         {
3859             BOOL FontSig = GetFontSig(hwndFore, hKL);
3860             ::PostMessage(hwndFore, WM_INPUTLANGCHANGEREQUEST, FontSig, (LPARAM)hKL);
3861         }
3862     }
3863 
3864     return S_OK;
3865 }
3866 
3867 /***********************************************************************
3868  * CTipbarGripper
3869  */
3870 
3871 CTipbarGripper::CTipbarGripper(CTipbarWnd *pTipbarWnd, LPCRECT prc, DWORD style)
3872     : CUIFGripper((pTipbarWnd ? pTipbarWnd->GetWindow() : NULL), prc, style)
3873 {
3874     m_bInDebugMenu = FALSE;
3875     m_pTipbarWnd = pTipbarWnd;
3876 }
3877 
3878 /// @unimplemented
3879 STDMETHODIMP_(void) CTipbarGripper::OnLButtonUp(LONG x, LONG y)
3880 {
3881     m_pTipbarWnd->RestoreFromStub();
3882 
3883     if (g_bEnableDeskBand && (g_dwOSInfo & CIC_OSINFO_XPPLUS))
3884     {
3885         APPBARDATA AppBar = { sizeof(AppBar) };
3886         AppBar.hWnd = ::FindWindowW(L"Shell_TrayWnd", NULL);
3887         if (::SHAppBarMessage(ABM_GETTASKBARPOS, &AppBar))
3888         {
3889             RECT rc = AppBar.rc;
3890             POINT pt;
3891             ::GetCursorPos(&pt);
3892             if (g_pTipbarWnd && ::PtInRect(&rc, pt))
3893                 g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND |
3894                                                           TF_SFT_EXTRAICONSONMINIMIZED);
3895         }
3896     }
3897 
3898     CUIFGripper::OnLButtonUp(x, y);
3899     m_pTipbarWnd->UpdatePosFlags();
3900 }
3901 
3902 /// @unimplemented
3903 STDMETHODIMP_(void) CTipbarGripper::OnRButtonUp(LONG x, LONG y)
3904 {
3905     if (g_bShowDebugMenu)
3906     {
3907         // FIXME: Debugging feature
3908     }
3909 }
3910 
3911 STDMETHODIMP_(BOOL) CTipbarGripper::OnSetCursor(UINT uMsg, LONG x, LONG y)
3912 {
3913     if (m_bInDebugMenu)
3914         return FALSE;
3915 
3916     return CUIFGripper::OnSetCursor(uMsg, x, y);
3917 }
3918 
3919 /***********************************************************************
3920  * CLangBarItemList
3921  */
3922 
3923 BOOL CLangBarItemList::IsStartedIntentionally(REFCLSID rclsid)
3924 {
3925     auto *pItem = FindItem(rclsid);
3926     if (!pItem)
3927         return FALSE;
3928     return pItem->m_bStartedIntentionally;
3929 }
3930 
3931 LANGBARITEMSTATE *CLangBarItemList::AddItem(REFCLSID rclsid)
3932 {
3933     auto *pItem = FindItem(rclsid);
3934     if (pItem)
3935         return pItem;
3936 
3937     pItem = Append(1);
3938     if (!pItem)
3939         return NULL;
3940 
3941     ZeroMemory(pItem, sizeof(*pItem));
3942     pItem->m_clsid = rclsid;
3943     pItem->m_dwDemoteLevel = 0;
3944     return pItem;
3945 }
3946 
3947 void CLangBarItemList::Clear()
3948 {
3949     clear();
3950 
3951     CicRegKey regKey;
3952     LSTATUS error;
3953     error = regKey.Open(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\LangBar", KEY_ALL_ACCESS);
3954     if (error == ERROR_SUCCESS)
3955         regKey.RecurseDeleteKey(L"ItemState");
3956 }
3957 
3958 BOOL CLangBarItemList::SetDemoteLevel(REFCLSID rclsid, DWORD dwDemoteLevel)
3959 {
3960     auto *pItem = AddItem(rclsid);
3961     if (!pItem)
3962         return TRUE;
3963 
3964     pItem->m_dwDemoteLevel = dwDemoteLevel;
3965     if (!pItem->IsShown())
3966     {
3967         if (pItem->m_nTimerID)
3968         {
3969             if (g_pTipbarWnd)
3970                 g_pTipbarWnd->KillTimer(pItem->m_nTimerID);
3971             pItem->m_nTimerID = 0;
3972             pItem->m_uTimeOut = 0;
3973         }
3974         pItem->m_bDisableDemoting = FALSE;
3975     }
3976 
3977     SaveItem(0, pItem);
3978     return TRUE;
3979 }
3980 
3981 LANGBARITEMSTATE *CLangBarItemList::FindItem(REFCLSID rclsid)
3982 {
3983     for (size_t iItem = 0; iItem < size(); ++iItem)
3984     {
3985         auto& item = (*this)[iItem];
3986         if (IsEqualCLSID(item.m_clsid, rclsid))
3987             return &item;
3988     }
3989     return NULL;
3990 }
3991 
3992 LANGBARITEMSTATE *CLangBarItemList::GetItemStateFromTimerId(UINT_PTR nTimerID)
3993 {
3994     for (size_t iItem = 0; iItem < size(); ++iItem)
3995     {
3996         auto& item = (*this)[iItem];
3997         if (item.m_nTimerID == nTimerID)
3998             return &item;
3999     }
4000     return NULL;
4001 }
4002 
4003 void CLangBarItemList::Load()
4004 {
4005     CicRegKey regKey;
4006     LSTATUS error;
4007     error = regKey.Open(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\LangBar\\ItemState");
4008     if (error != ERROR_SUCCESS)
4009         return;
4010 
4011     WCHAR szKeyName[MAX_PATH];
4012     for (DWORD dwIndex = 0; ; ++dwIndex)
4013     {
4014         error = ::RegEnumKeyW(regKey, dwIndex, szKeyName, _countof(szKeyName));
4015         if (error != ERROR_SUCCESS)
4016             break;
4017 
4018         CLSID clsid;
4019         if (::CLSIDFromString(szKeyName, &clsid) != S_OK)
4020             continue;
4021 
4022         CicRegKey regKey2;
4023         error = regKey2.Open(regKey, szKeyName);
4024         if (error != ERROR_SUCCESS)
4025             continue;
4026 
4027         auto *pItem = AddItem(clsid);
4028         if (!pItem)
4029             continue;
4030 
4031         DWORD Data = 0;
4032         regKey2.QueryDword(L"DemoteLevel", &Data);
4033         pItem->m_dwDemoteLevel = Data;
4034         regKey2.QueryDword(L"DisableDemoting", &Data);
4035         pItem->m_bDisableDemoting = !!Data;
4036     }
4037 }
4038 
4039 void CLangBarItemList::SaveItem(CicRegKey *pRegKey, const LANGBARITEMSTATE *pState)
4040 {
4041     LSTATUS error;
4042     CicRegKey regKey;
4043 
4044     if (!pRegKey)
4045     {
4046         error = regKey.Create(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\CTF\\LangBar\\ItemState");
4047         if (error != ERROR_SUCCESS)
4048             return;
4049 
4050         pRegKey = &regKey;
4051     }
4052 
4053     WCHAR szSubKey[MAX_PATH];
4054     ::StringFromGUID2(pState->m_clsid, szSubKey, _countof(szSubKey));
4055 
4056     if (pState->m_dwDemoteLevel || pState->m_bDisableDemoting)
4057     {
4058         CicRegKey regKey2;
4059         error = regKey2.Create(*pRegKey, szSubKey);
4060         if (error == ERROR_SUCCESS)
4061         {
4062             DWORD dwDemoteLevel = pState->m_dwDemoteLevel;
4063             if (dwDemoteLevel)
4064                 regKey2.SetDword(L"DemoteLevel", dwDemoteLevel);
4065             else
4066                 regKey2.DeleteValue(L"DemoteLevel");
4067 
4068             regKey2.SetDword(L"DisableDemoting", pState->m_bDisableDemoting);
4069         }
4070     }
4071     else
4072     {
4073         pRegKey->RecurseDeleteKey(szSubKey);
4074     }
4075 }
4076 
4077 void CLangBarItemList::StartDemotingTimer(REFCLSID rclsid, BOOL bIntentional)
4078 {
4079     if (!g_bIntelliSense)
4080         return;
4081 
4082     auto *pItem = AddItem(rclsid);
4083     if (!pItem || pItem->m_bDisableDemoting)
4084         return;
4085 
4086     if (pItem->m_nTimerID)
4087     {
4088         if (!bIntentional)
4089             return;
4090 
4091         if (g_pTipbarWnd)
4092             g_pTipbarWnd->KillTimer(pItem->m_nTimerID);
4093 
4094         pItem->m_nTimerID = 0;
4095     }
4096 
4097     pItem->m_bStartedIntentionally |= bIntentional;
4098 
4099     UINT uTimeOut = (bIntentional ? g_uTimeOutIntentional : g_uTimeOutNonIntentional);
4100     pItem->m_uTimeOut += uTimeOut;
4101 
4102     if (pItem->m_uTimeOut < g_uTimeOutMax)
4103     {
4104         UINT_PTR uDemotingTimerId = FindDemotingTimerId();
4105         pItem->m_nTimerID = uDemotingTimerId;
4106         if (uDemotingTimerId)
4107         {
4108             if (g_pTipbarWnd)
4109                 g_pTipbarWnd->SetTimer(uDemotingTimerId, uTimeOut);
4110         }
4111     }
4112     else
4113     {
4114         pItem->m_bDisableDemoting = TRUE;
4115     }
4116 }
4117 
4118 UINT_PTR CLangBarItemList::FindDemotingTimerId()
4119 {
4120     UINT_PTR nTimerID = 10000;
4121 
4122     if (empty())
4123         return nTimerID;
4124 
4125     for (;;)
4126     {
4127         size_t iItem = 0;
4128 
4129         while ((*this)[iItem].m_nTimerID != nTimerID)
4130         {
4131             ++iItem;
4132             if (iItem >= size())
4133                 return nTimerID;
4134         }
4135 
4136         ++nTimerID;
4137         if (nTimerID >= 10050)
4138             return 0;
4139     }
4140 }
4141 
4142 /***********************************************************************
4143  * CTipbarWnd
4144  */
4145 
4146 /// @unimplemented
4147 CTipbarWnd::CTipbarWnd(DWORD style)
4148     : CUIFWindow(g_hInst, style)
4149 {
4150     m_dwUnknown23_1[4] = 0;
4151     m_dwUnknown23_1[5] = 0;
4152     m_dwUnknown23_1[6] = 0;
4153     m_dwUnknown23_1[7] = 0;
4154 
4155     RECT rc;
4156     cicGetScreenRect(g_ptTipbar, &rc);
4157 
4158     //FIXME: Fix g_ptTipbar
4159 
4160     Move(g_ptTipbar.x, g_ptTipbar.y, 100, 24);
4161     UpdatePosFlags();
4162 
4163     m_hMarlettFont = ::CreateFontW(8, 8, 0, 0, FW_NORMAL, 0, 0, 0,
4164                                    SYMBOL_CHARSET, 0, 0, 0, 0, L"Marlett");
4165 
4166     ITfLangBarMgr *pLangBarMgr = NULL;
4167     if (SUCCEEDED(TF_CreateLangBarMgr(&pLangBarMgr)) && pLangBarMgr)
4168     {
4169         pLangBarMgr->QueryInterface(IID_ITfLangBarMgr_P, (void **)&m_pLangBarMgr);
4170         pLangBarMgr->Release();
4171     }
4172 
4173     if (style & UIF_WINDOW_ENABLETHEMED)
4174     {
4175         if (g_fTaskbarTheme)
4176         {
4177             m_iPartId = 1;
4178             m_iStateId = 1;
4179             m_pszClassList = L"TASKBAR";
4180         }
4181         else
4182         {
4183             m_iPartId = 0;
4184             m_iStateId = 1;
4185             m_pszClassList = L"REBAR";
4186         }
4187     }
4188 
4189     SetVertical(g_fVertical);
4190 
4191     m_cRefs = 1;
4192 }
4193 
4194 CTipbarWnd::~CTipbarWnd()
4195 {
4196     UnInit();
4197 
4198     if (m_hMarlettFont)
4199         ::DeleteObject(m_hMarlettFont);
4200     if (m_hTextFont)
4201         ::DeleteObject(m_hTextFont);
4202 
4203     TFUninitLib_Thread(&g_libTLS);
4204 }
4205 
4206 /// @unimplemented
4207 void CTipbarWnd::Init(BOOL bChild, CDeskBand *pDeskBand)
4208 {
4209     if (bChild)
4210         m_dwTipbarWndFlags |= TIPBAR_CHILD;
4211     else
4212         m_dwTipbarWndFlags &= ~TIPBAR_CHILD;
4213 
4214     if (m_dwTipbarWndFlags & TIPBAR_CHILD)
4215         m_dwTipbarWndFlags &= TIPBAR_HIGHCONTRAST;
4216 
4217     m_pDeskBand = pDeskBand;
4218 
4219     RECT rc = { 0, 0, 0, 0 };
4220 
4221     if (g_bNewLook && !m_pWndFrame && (m_style & 0x20000000))
4222     {
4223         CUIFWndFrame *pWndFrame = new(cicNoThrow) CUIFWndFrame(GetWindow(), &rc, 0);
4224         if (pWndFrame)
4225         {
4226             pWndFrame->Initialize();
4227             AddUIObj(m_pWndFrame);
4228         }
4229     }
4230 
4231     if (!m_pTipbarGripper && !(m_dwTipbarWndFlags & TIPBAR_CHILD))
4232     {
4233         m_pTipbarGripper =
4234             new(cicNoThrow) CTipbarGripper(this, &rc, !!(m_dwTipbarWndFlags & TIPBAR_VERTICAL));
4235         if (m_pTipbarGripper)
4236         {
4237             m_pTipbarGripper->Initialize();
4238             AddUIObj(m_pTipbarGripper);
4239         }
4240     }
4241 
4242     //FIXME: CTipbarCtrlButtonHolder
4243 
4244     if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
4245     {
4246         Move(m_nLeft, m_nTop, GetTipbarHeight(), 0);
4247     }
4248     else
4249     {
4250         Move(m_nLeft, m_nTop, 0, GetTipbarHeight());
4251     }
4252 }
4253 
4254 void CTipbarWnd::InitHighContrast()
4255 {
4256     m_dwTipbarWndFlags &= ~TIPBAR_HIGHCONTRAST;
4257 
4258     HIGHCONTRAST HiCon = { sizeof(HiCon) };
4259     if (::SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HiCon), &HiCon, 0))
4260     {
4261         if (HiCon.dwFlags & HCF_HIGHCONTRASTON)
4262             m_dwTipbarWndFlags |= TIPBAR_HIGHCONTRAST;
4263     }
4264 }
4265 
4266 void CTipbarWnd::InitMetrics()
4267 {
4268     m_cxSmallIcon = ::GetSystemMetrics(SM_CXSMICON);
4269     m_cySmallIcon = ::GetSystemMetrics(SM_CYSMICON);
4270 
4271     DWORD_PTR style = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
4272     if (style & WS_DLGFRAME)
4273     {
4274         m_cxDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CXDLGFRAME);
4275         m_cyDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CYDLGFRAME);
4276     }
4277     else if (style & WS_BORDER)
4278     {
4279         m_cxDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CXBORDER);
4280         m_cyDlgFrameX2 = 2 * ::GetSystemMetrics(SM_CYBORDER);
4281     }
4282     else
4283     {
4284         m_cxDlgFrameX2 = m_cyDlgFrameX2 = 0;
4285     }
4286 }
4287 
4288 void CTipbarWnd::InitThemeMargins()
4289 {
4290     ZeroMemory(&m_Margins, sizeof(m_Margins));
4291 
4292     CUIFTheme theme;
4293     m_dwUnknown23_5[0] = 6;
4294     m_dwUnknown23_5[1] = 6;
4295     m_dwUnknown23_5[2] = 0;
4296     m_ButtonWidth = GetSystemMetrics(SM_CXSIZE);
4297 
4298     theme.m_iPartId = 1;
4299     theme.m_iStateId = 0;
4300     theme.m_pszClassList = L"TOOLBAR";
4301     if (SUCCEEDED(theme.InternalOpenThemeData(m_hWnd)))
4302     {
4303         ::GetThemeMargins(theme.m_hTheme, NULL, theme.m_iPartId, 1, 3602, NULL, &m_Margins);
4304         m_dwUnknown23_5[0] = 4;
4305         m_dwUnknown23_5[1] = 2;
4306         m_dwUnknown23_5[2] = 1;
4307     }
4308     theme.CloseThemeData();
4309 
4310     theme.m_iPartId = 18;
4311     theme.m_iStateId = 0;
4312     theme.m_pszClassList = L"WINDOW";
4313     if (SUCCEEDED(theme.InternalOpenThemeData(m_hWnd)))
4314     {
4315         SIZE partSize;
4316         ::GetThemePartSize(theme.m_hTheme, NULL, theme.m_iPartId, 1, 0, TS_TRUE, &partSize);
4317         INT size = ::GetThemeSysSize(theme.m_hTheme, 31);
4318         m_ButtonWidth = MulDiv(size, partSize.cx, partSize.cy);
4319     }
4320     theme.CloseThemeData();
4321 }
4322 
4323 void CTipbarWnd::UnInit()
4324 {
4325     SetFocusThread(NULL);
4326     for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
4327     {
4328         CTipbarThread* pThread = m_Threads[iItem];
4329         if (pThread)
4330         {
4331             pThread->_UninitItemList(TRUE);
4332             pThread->m_pTipbarWnd = NULL;
4333             pThread->_Release();
4334         }
4335     }
4336     m_Threads.clear();
4337 
4338     if (m_pLangBarMgr)
4339         m_pLangBarMgr->UnAdviseEventSink(m_dwSinkCookie);
4340 
4341     if (m_pLangBarMgr)
4342     {
4343         m_pLangBarMgr->Release();
4344         m_pLangBarMgr = NULL;
4345     }
4346 }
4347 
4348 BOOL CTipbarWnd::IsFullScreenWindow(HWND hWnd)
4349 {
4350     if (g_fPolicyEnableLanguagebarInFullscreen)
4351         return FALSE;
4352 
4353     DWORD_PTR style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
4354     if (!(style & WS_VISIBLE) || (style & WS_CAPTION))
4355         return FALSE;
4356 
4357     DWORD_PTR exstyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE);
4358     if (exstyle & WS_EX_LAYERED)
4359         return FALSE;
4360 
4361     if ((exstyle & WS_EX_TOOLWINDOW) && (hWnd == m_ShellWndThread.GetWndProgman()))
4362         return FALSE;
4363 
4364     return !!cicIsFullScreenSize(hWnd);
4365 }
4366 
4367 BOOL CTipbarWnd::IsHKLToSkipRedrawOnNoItem()
4368 {
4369     HKL hKL = GetFocusKeyboardLayout();
4370     return IsSkipRedrawHKL(hKL);
4371 }
4372 
4373 BOOL CTipbarWnd::IsInItemChangeOrDirty(CTipbarThread *pTarget)
4374 {
4375     if (pTarget->m_dwThreadId == m_dwChangingThreadId)
4376         return TRUE;
4377     return pTarget->IsDirtyItem();
4378 }
4379 
4380 void CTipbarWnd::AddThreadToThreadCreatingList(CTipbarThread *pThread)
4381 {
4382     m_ThreadCreatingList.Add(pThread);
4383 }
4384 
4385 void CTipbarWnd::RemoveThredFromThreadCreatingList(CTipbarThread *pTarget)
4386 {
4387     ssize_t iItem = m_ThreadCreatingList.Find(pTarget);
4388     if (iItem >= 0)
4389         m_ThreadCreatingList.Remove(iItem);
4390 }
4391 
4392 void CTipbarWnd::MoveToStub(BOOL bFlag)
4393 {
4394     m_dwTipbarWndFlags |= 0x40;
4395 
4396     RECT rcWorkArea;
4397     ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
4398 
4399     if (bFlag)
4400     {
4401         m_nLeft = rcWorkArea.right - 38;
4402         m_dwTipbarWndFlags &= ~0x80;
4403     }
4404     else
4405     {
4406         RECT Rect;
4407         ::GetWindowRect(m_hWnd, &Rect);
4408         m_nLeft = rcWorkArea.right + Rect.left - Rect.right;
4409         m_dwTipbarWndFlags |= 0x80;
4410     }
4411 
4412     m_nTop = rcWorkArea.bottom - m_cyDlgFrameX2 - GetTipbarHeight();
4413 
4414     if (m_pFocusThread)
4415         m_pFocusThread->MyMoveWnd(0, 0);
4416 }
4417 
4418 void CTipbarWnd::RestoreFromStub()
4419 {
4420     m_dwTipbarWndFlags &= 0x3F;
4421     KillTimer(1);
4422     KillTimer(2);
4423 }
4424 
4425 /// @unimplemented
4426 INT CTipbarWnd::GetCtrlButtonWidth()
4427 {
4428     return 0;
4429 }
4430 
4431 INT CTipbarWnd::GetGripperWidth()
4432 {
4433     if (m_dwTipbarWndFlags & 2)
4434         return 0;
4435 
4436     if (!m_pTipbarGripper || FAILED(m_pTipbarGripper->EnsureThemeData(m_hWnd)))
4437         return 5;
4438 
4439     INT width = -1;
4440     SIZE partSize;
4441     HDC hDC = ::GetDC(m_hWnd);
4442     if (SUCCEEDED(m_pTipbarGripper->GetThemePartSize(hDC, 1, 0, TS_TRUE, &partSize)))
4443     {
4444         INT cx = partSize.cx;
4445         if (m_dwTipbarWndFlags & 4)
4446             cx = partSize.cy;
4447         width = cx + 4;
4448     }
4449     ::ReleaseDC(m_hWnd, hDC);
4450 
4451     return ((width < 0) ? 5 : width);
4452 }
4453 
4454 INT CTipbarWnd::GetTipbarHeight()
4455 {
4456     SIZE size = { 0, 0 };
4457     if (m_pWndFrame)
4458         m_pWndFrame->GetFrameSize(&size);
4459     INT cy = m_Margins.cyBottomHeight + m_Margins.cyTopHeight + 2;
4460     if (cy < 6)
4461         cy = 6;
4462     return m_cySmallIcon + cy + (2 * size.cy);
4463 }
4464 
4465 BOOL CTipbarWnd::AutoAdjustDeskBandSize()
4466 {
4467     if ((m_dwTipbarWndFlags & TIPBAR_NODESKBAND) ||
4468         !m_pFocusThread ||
4469         (m_pFocusThread->m_dwFlags1 & 0x800))
4470     {
4471         return FALSE;
4472     }
4473 
4474     DWORD dwOldWndFlags = m_dwTipbarWndFlags;
4475     m_dwTipbarWndFlags &= ~0x8000;
4476 
4477     if (!AdjustDeskBandSize(!(dwOldWndFlags & 0x8000)))
4478         return FALSE;
4479 
4480     m_dwTipbarWndFlags |= TIPBAR_NODESKBAND;
4481     return TRUE;
4482 }
4483 
4484 /// @unimplemented
4485 INT CTipbarWnd::AdjustDeskBandSize(BOOL bFlag)
4486 {
4487     return 0;
4488 }
4489 
4490 /// @unimplemented
4491 void CTipbarWnd::LocateCtrlButtons()
4492 {
4493 }
4494 
4495 void CTipbarWnd::AdjustPosOnDisplayChange()
4496 {
4497     RECT rcWorkArea;
4498     RECT rc = { m_nLeft, m_nTop, m_nLeft + m_nWidth, m_nTop + m_nHeight };
4499     if (!GetWorkArea(&rc, &rcWorkArea))
4500         return;
4501 
4502     INT x = m_nLeft, y = m_nTop;
4503     if (m_dwTipbarWndFlags & TIPBAR_LEFTFIT)
4504         x = rcWorkArea.left;
4505     if (m_dwTipbarWndFlags & TIPBAR_TOPFIT)
4506         y = rcWorkArea.top;
4507     if (m_dwTipbarWndFlags & TIPBAR_RIGHTFIT)
4508         x = rcWorkArea.right - m_nWidth;
4509     if (m_dwTipbarWndFlags & TIPBAR_BOTTOMFIT)
4510         y = rcWorkArea.bottom - m_nHeight;
4511     if (x != m_nLeft || y != m_nTop)
4512         Move(x, y, m_nWidth, m_nHeight);
4513 }
4514 
4515 void CTipbarWnd::SetVertical(BOOL bVertical)
4516 {
4517     if (bVertical)
4518         m_dwTipbarWndFlags |= TIPBAR_VERTICAL;
4519     else
4520         m_dwTipbarWndFlags &= ~TIPBAR_VERTICAL;
4521 
4522     if (m_pTipbarGripper)
4523     {
4524         DWORD style = m_pTipbarGripper->m_style;
4525         if (bVertical)
4526             style |= 0x1;
4527         else
4528             style &= 0x1;
4529         m_pTipbarGripper->SetStyle(style);
4530     }
4531 
4532     if (g_fTaskbarTheme)
4533         SetActiveTheme(L"TASKBAR", !!(m_dwTipbarWndFlags & TIPBAR_VERTICAL), 1);
4534 
4535     if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
4536     {
4537         if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
4538         {
4539             Move(m_nLeft, m_nTop, GetTipbarHeight(), 0);
4540         }
4541         else
4542         {
4543             Move(m_nLeft, m_nTop, 0, GetTipbarHeight());
4544         }
4545     }
4546 
4547     if (m_hWnd)
4548     {
4549         KillTimer(7);
4550         SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4551     }
4552 }
4553 
4554 void CTipbarWnd::UpdatePosFlags()
4555 {
4556     if (m_dwTipbarWndFlags & TIPBAR_CHILD)
4557         return;
4558 
4559     RECT rc = { m_nLeft, m_nTop, m_nLeft + m_nWidth, m_nTop + m_nHeight }, rcWorkArea;
4560     if (!GetWorkArea(&rc, &rcWorkArea))
4561         return;
4562 
4563     if (rcWorkArea.left + 2 < m_nLeft)
4564         m_dwTipbarWndFlags &= ~TIPBAR_LEFTFIT;
4565     else
4566         m_dwTipbarWndFlags |= TIPBAR_LEFTFIT;
4567 
4568     if (rcWorkArea.top + 2 < m_nTop)
4569         m_dwTipbarWndFlags &= ~TIPBAR_TOPFIT;
4570     else
4571         m_dwTipbarWndFlags |= TIPBAR_TOPFIT;
4572 
4573     if (m_nLeft + m_nWidth < rcWorkArea.right - 2)
4574         m_dwTipbarWndFlags &= ~TIPBAR_RIGHTFIT;
4575     else
4576         m_dwTipbarWndFlags |= TIPBAR_RIGHTFIT;
4577 
4578     if (m_nTop + m_nHeight < rcWorkArea.bottom - 2)
4579         m_dwTipbarWndFlags &= ~TIPBAR_BOTTOMFIT;
4580     else
4581         m_dwTipbarWndFlags |= TIPBAR_BOTTOMFIT;
4582 }
4583 
4584 void CTipbarWnd::CancelMenu()
4585 {
4586     if (!m_pThread)
4587         return;
4588 
4589     CTipbarWnd *pTipbarWnd = m_pThread->m_pTipbarWnd;
4590     if (pTipbarWnd)
4591     {
4592         if (pTipbarWnd->m_pLangBarMgr)
4593             pTipbarWnd->StartModalInput(NULL, m_pThread->m_dwThreadId);
4594     }
4595 
4596     m_pModalMenu->CancelMenu();
4597     StartBackToAlphaTimer();
4598 }
4599 
4600 BOOL CTipbarWnd::CheckExcludeCaptionButtonMode(LPRECT prc1, LPCRECT prc2)
4601 {
4602     return (prc1->top < prc2->top + 5) && (prc2->right <= prc1->right + (5 * m_ButtonWidth));
4603 }
4604 
4605 void CTipbarWnd::ClearLBItemList()
4606 {
4607     m_LangBarItemList.Clear();
4608     if (m_pFocusThread)
4609         OnThreadItemChange(m_pFocusThread->m_dwThreadId);
4610 }
4611 
4612 HFONT CTipbarWnd::CreateVerticalFont()
4613 {
4614     if (!m_hWnd)
4615         return NULL;
4616 
4617     CUIFTheme theme;
4618     theme.m_iPartId = 1;
4619     theme.m_iStateId = 0;
4620     theme.m_pszClassList = L"TOOLBAR";
4621 
4622     LOGFONTW lf;
4623     if (FAILED(theme.InternalOpenThemeData(m_hWnd)) ||
4624         FAILED(::GetThemeFont(theme.m_hTheme, NULL, theme.m_iPartId, 0, 210, &lf)))
4625     {
4626         ::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
4627     }
4628 
4629     lf.lfEscapement = lf.lfOrientation = 2700;
4630     lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4631 
4632     if (CheckEAFonts())
4633     {
4634         WCHAR szText[LF_FACESIZE];
4635         szText[0] = L'@';
4636         StringCchCopyW(&szText[1], _countof(szText) - 1, lf.lfFaceName);
4637         StringCchCopyW(lf.lfFaceName, _countof(lf.lfFaceName), szText);
4638     }
4639 
4640     return ::CreateFontIndirectW(&lf);
4641 }
4642 
4643 void CTipbarWnd::UpdateVerticalFont()
4644 {
4645     if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
4646     {
4647         if (m_hTextFont)
4648         {
4649             ::DeleteObject(m_hTextFont);
4650             SetFontToThis(NULL);
4651             m_hTextFont = NULL;
4652         }
4653         m_hTextFont = CreateVerticalFont();
4654         SetFontToThis(m_hTextFont);
4655     }
4656     else
4657     {
4658         SetFontToThis(NULL);
4659     }
4660 }
4661 
4662 /// @unimplemented
4663 void CTipbarWnd::ShowOverScreenSizeBalloon()
4664 {
4665     //FIXME: CTipbarCtrlButtonHolder
4666 }
4667 
4668 void CTipbarWnd::DestroyOverScreenSizeBalloon()
4669 {
4670     if (m_pBalloon)
4671     {
4672         if (::IsWindow(*m_pBalloon))
4673             ::DestroyWindow(*m_pBalloon);
4674         delete m_pBalloon;
4675         m_pBalloon = NULL;
4676     }
4677 }
4678 
4679 void CTipbarWnd::DestroyWnd()
4680 {
4681     if (::IsWindow(m_hWnd))
4682         ::DestroyWindow(m_hWnd);
4683 }
4684 
4685 HKL CTipbarWnd::GetFocusKeyboardLayout()
4686 {
4687     DWORD dwThreadId = 0;
4688     if (m_pFocusThread)
4689         dwThreadId = m_pFocusThread->m_dwThreadId;
4690     return ::GetKeyboardLayout(dwThreadId);
4691 }
4692 
4693 void CTipbarWnd::KillOnTheadItemChangeTimer()
4694 {
4695     DWORD dwChangingThreadId = m_dwChangingThreadId;
4696     m_dwChangingThreadId = 0;
4697     KillTimer(4);
4698 
4699     if (dwChangingThreadId)
4700     {
4701         CTipbarThread *pThread = _FindThread(dwChangingThreadId);
4702         if (pThread)
4703             pThread->m_dwUnknown34 |= 0x1;
4704     }
4705 }
4706 
4707 UINT_PTR CTipbarWnd::SetTimer(UINT_PTR nIDEvent, UINT uElapse)
4708 {
4709     if (::IsWindow(m_hWnd))
4710         return ::SetTimer(m_hWnd, nIDEvent, uElapse, NULL);
4711     return 0;
4712 }
4713 
4714 BOOL CTipbarWnd::KillTimer(UINT_PTR uIDEvent)
4715 {
4716     if (::IsWindow(m_hWnd))
4717         return ::KillTimer(m_hWnd, uIDEvent);
4718     return FALSE;
4719 }
4720 
4721 /// @unimplemented
4722 void CTipbarWnd::MoveToTray()
4723 {
4724     if (!g_bEnableDeskBand || !(g_dwOSInfo & CIC_OSINFO_XPPLUS))
4725     {
4726         //FIXME
4727     }
4728 }
4729 
4730 void CTipbarWnd::MyClientToScreen(LPPOINT lpPoint, LPRECT prc)
4731 {
4732     if (lpPoint)
4733         ::ClientToScreen(m_hWnd, lpPoint);
4734 
4735     if (prc)
4736     {
4737         ::ClientToScreen(m_hWnd, (LPPOINT)prc);
4738         ::ClientToScreen(m_hWnd, (LPPOINT)&prc->right);
4739     }
4740 }
4741 
4742 void CTipbarWnd::SavePosition()
4743 {
4744     CicRegKey regKey;
4745     if (regKey.Create(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\CTF\\MSUTB\\")))
4746     {
4747         POINT pt = { 0, 0 };
4748         ::ClientToScreen(m_hWnd, &pt);
4749         regKey.SetDword(TEXT("Left"), pt.x);
4750         regKey.SetDword(TEXT("Top"), pt.y);
4751         regKey.SetDword(TEXT("Vertical"), !!(m_dwTipbarWndFlags & TIPBAR_VERTICAL));
4752     }
4753 }
4754 
4755 /// @unimplemented
4756 void CTipbarWnd::SetAlpha(BYTE bAlpha, BOOL bFlag)
4757 {
4758 }
4759 
4760 BOOL CTipbarWnd::SetLangBand(BOOL bDeskBand, BOOL bFlag2)
4761 {
4762     if (bDeskBand == !!(m_dwShowType & TF_SFT_DESKBAND))
4763         return TRUE;
4764 
4765     BOOL ret = TRUE;
4766     HWND hwndTray = m_ShellWndThread.GetWndTray();
4767     if (bFlag2 && hwndTray)
4768     {
4769         DWORD_PTR dwResult;
4770         HWND hImeWnd = ::ImmGetDefaultIMEWnd(hwndTray);
4771         if (hImeWnd)
4772             ::SendMessageTimeout(hImeWnd, WM_IME_SYSTEM, 0x24 - bDeskBand, (LPARAM)hwndTray,
4773                                  (SMTO_BLOCK | SMTO_ABORTIFHUNG), 5000, &dwResult);
4774         else
4775             ::SendMessageTimeout(hwndTray, 0x505, 0, bDeskBand,
4776                                  (SMTO_BLOCK | SMTO_ABORTIFHUNG), 5000, &dwResult);
4777     }
4778     else
4779     {
4780         ret = FALSE;
4781     }
4782 
4783     if (!(m_dwTipbarWndFlags & TIPBAR_CHILD) && bDeskBand)
4784     {
4785         KillTimer(7);
4786         SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
4787     }
4788 
4789     return ret;
4790 }
4791 
4792 void CTipbarWnd::SetMoveRect(INT X, INT Y, INT nWidth, INT nHeight)
4793 {
4794     if (m_dwTipbarWndFlags & TIPBAR_CHILD)
4795     {
4796         m_nWidth = nWidth;
4797         m_nHeight = nHeight;
4798         return;
4799     }
4800 
4801     ++m_bInCallOn;
4802 
4803     m_dwTipbarWndFlags |= TIPBAR_UPDATING;
4804 
4805     m_X = X;
4806     m_Y = Y;
4807     m_CX = nWidth;
4808     m_CY = nHeight;
4809 
4810     RECT rc;
4811     SIZE size = { 0, 0 };
4812     if (m_pWndFrame)
4813     {
4814         ::SetRect(&rc, 0, 0, nWidth - m_cxDlgFrameX2, nHeight - m_cyDlgFrameX2);
4815         m_pWndFrame->SetRect(&rc);
4816         m_pWndFrame->GetFrameSize(&size);
4817     }
4818 
4819     if (m_pTipbarGripper)
4820     {
4821         if (m_dwTipbarWndFlags & TIPBAR_VERTICAL)
4822         {
4823             INT GripperWidth = GetGripperWidth();
4824             ::SetRect(&rc, size.cx, size.cy, nWidth - m_cxDlgFrameX2 - size.cx, size.cy + GripperWidth);
4825         }
4826         else
4827         {
4828             INT GripperWidth = GetGripperWidth();
4829             INT y1 = nHeight - m_cyDlgFrameX2 - size.cy;
4830             ::SetRect(&rc, size.cx, size.cy, size.cx + GripperWidth, y1);
4831         }
4832         m_pTipbarGripper->SetRect(&rc);
4833     }
4834 
4835     --m_bInCallOn;
4836 }
4837 
4838 void CTipbarWnd::SetShowText(BOOL bShow)
4839 {
4840     if (bShow)
4841         m_dwTipbarWndFlags |= TIPBAR_HIGHCONTRAST;
4842     else
4843         m_dwTipbarWndFlags &= ~TIPBAR_HIGHCONTRAST;
4844 
4845     if (m_pFocusThread)
4846         OnThreadItemChange(m_pFocusThread->m_dwThreadId);
4847 
4848     TerminateAllThreads(FALSE);
4849 }
4850 
4851 void CTipbarWnd::SetShowTrayIcon(BOOL bShow)
4852 {
4853     if (m_dwTipbarWndFlags & TIPBAR_TRAYICON)
4854         m_dwTipbarWndFlags &= ~TIPBAR_TRAYICON;
4855     else
4856         m_dwTipbarWndFlags |= TIPBAR_TRAYICON;
4857 
4858     if ((m_dwTipbarWndFlags & TIPBAR_TRAYICON) && m_pFocusThread)
4859     {
4860         KillTimer(10);
4861         SetTimer(10, g_uTimerElapseMOVETOTRAY);
4862     }
4863     else if (g_pTrayIconWnd)
4864     {
4865         g_pTrayIconWnd->SetMainIcon(NULL);
4866         g_pTrayIconWnd->RemoveAllIcon(0);
4867     }
4868 }
4869 
4870 void CTipbarWnd::ShowContextMenu(POINT pt, LPCRECT prc, BOOL bFlag)
4871 {
4872     AddRef();
4873 
4874     RECT rc;
4875     if (!prc)
4876     {
4877         rc = { pt.x, pt.y, pt.x, pt.y };
4878         prc = &rc;
4879     }
4880 
4881     if (m_pFocusThread)
4882     {
4883         CUTBContextMenu *pContextMenu = new(cicNoThrow) CUTBContextMenu(this);
4884         if (pContextMenu)
4885         {
4886             if (pContextMenu->Init())
4887             {
4888                 m_pThread = m_pFocusThread;
4889                 StartModalInput(this, m_pFocusThread->m_dwThreadId);
4890 
4891                 m_pModalMenu = pContextMenu;
4892                 DWORD dwCommandId = pContextMenu->ShowPopup(GetWindow(), pt, prc, bFlag);
4893                 m_pModalMenu = NULL;
4894 
4895                 if (m_pThread)
4896                     StopModalInput(m_pThread->m_dwThreadId);
4897 
4898                 m_pThread = NULL;
4899 
4900                 if (dwCommandId != (DWORD)-1)
4901                     pContextMenu->SelectMenuItem(dwCommandId);
4902             }
4903 
4904             delete pContextMenu;
4905         }
4906     }
4907 
4908     Release();
4909 }
4910 
4911 void CTipbarWnd::StartBackToAlphaTimer()
4912 {
4913     UINT uTime = ::GetDoubleClickTime();
4914     ::SetTimer(m_hWnd, 3, 3 * uTime, NULL);
4915 }
4916 
4917 BOOL CTipbarWnd::StartDoAccDefaultActionTimer(CTipbarItem *pTarget)
4918 {
4919     if (!m_pTipbarAccessible)
4920         return FALSE;
4921     INT IDOfItem = m_pTipbarAccessible->GetIDOfItem(pTarget);
4922     m_nID = IDOfItem;
4923     if (!IDOfItem || IDOfItem == -1)
4924         return FALSE;
4925     KillTimer(11);
4926     SetTimer(11, g_uTimerElapseDOACCDEFAULTACTION);
4927     return TRUE;
4928 }
4929 
4930 void CTipbarWnd::StartModalInput(ITfLangBarEventSink *pSink, DWORD dwThreadId)
4931 {
4932     if (!m_pLangBarMgr)
4933         return;
4934 
4935     m_pLangBarMgr->SetModalInput(pSink, dwThreadId, 0);
4936     if (g_pTrayIconWnd)
4937         m_pLangBarMgr->SetModalInput(pSink, g_pTrayIconWnd->m_dwTrayWndThreadId, 0);
4938 
4939     DWORD dwCurThreadId = ::GetCurrentThreadId();
4940     m_pLangBarMgr->SetModalInput(pSink, dwCurThreadId, 1);
4941 }
4942 
4943 void CTipbarWnd::StopModalInput(DWORD dwThreadId)
4944 {
4945     if (!m_pLangBarMgr)
4946         return;
4947 
4948     m_pLangBarMgr->SetModalInput(NULL, dwThreadId, 0);
4949     if (g_pTrayIconWnd)
4950         m_pLangBarMgr->SetModalInput(NULL, g_pTrayIconWnd->m_dwTrayWndThreadId, 0);
4951 
4952     DWORD dwCurThreadId = ::GetCurrentThreadId();
4953     m_pLangBarMgr->SetModalInput(NULL, dwCurThreadId, 0);
4954 }
4955 
4956 LONG MyWaitForInputIdle(DWORD dwThreadId, DWORD dwMilliseconds)
4957 {
4958     if (g_pTipbarWnd && (g_pTipbarWnd->m_dwShowType & TF_SFT_DESKBAND))
4959         return 0;
4960 
4961     if (TF_IsInMarshaling(dwThreadId))
4962         return STATUS_TIMEOUT;
4963 
4964     DWORD dwFlags1 = 0, dwFlags2 = 0;
4965     if (!TF_GetThreadFlags(dwThreadId, &dwFlags1, &dwFlags2, NULL) && dwFlags2)
4966         return -1;
4967 
4968     return TF_CheckThreadInputIdle(dwThreadId, dwMilliseconds);
4969 }
4970 
4971 CTipbarThread *CTipbarWnd::_CreateThread(DWORD dwThreadId)
4972 {
4973     CTipbarThread *pTarget = _FindThread(dwThreadId);
4974     if (pTarget)
4975         return pTarget;
4976 
4977     MyWaitForInputIdle(dwThreadId, 2000);
4978 
4979     pTarget = new(cicNoThrow) CTipbarThread(this);
4980     if (!pTarget)
4981         return NULL;
4982 
4983     AddThreadToThreadCreatingList(pTarget);
4984 
4985     HRESULT hr = pTarget->Init(dwThreadId);
4986 
4987     RemoveThredFromThreadCreatingList(pTarget);
4988 
4989     if (SUCCEEDED(hr) && !m_Threads.Add(pTarget))
4990     {
4991         pTarget->_UninitItemList(TRUE);
4992         pTarget->m_pTipbarWnd = NULL;
4993         pTarget->_Release();
4994         return NULL;
4995     }
4996 
4997     return pTarget;
4998 }
4999 
5000 CTipbarThread *CTipbarWnd::_FindThread(DWORD dwThreadId)
5001 {
5002     if (g_bWinLogon)
5003         return NULL;
5004 
5005     CTipbarThread *pTarget = NULL;
5006     for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
5007     {
5008         CTipbarThread *pThread = m_Threads[iItem];
5009         if (pThread && pThread->m_dwThreadId == dwThreadId)
5010         {
5011             pTarget = pThread;
5012             break;
5013         }
5014     }
5015 
5016     if (!pTarget)
5017         return NULL;
5018 
5019     DWORD dwFlags1, dwFlags2, dwFlags3;
5020     TF_GetThreadFlags(dwThreadId, &dwFlags1, &dwFlags2, &dwFlags3);
5021 
5022     if (!dwFlags2 || (dwFlags2 != pTarget->m_dwFlags2) || (dwFlags3 != pTarget->m_dwFlags3))
5023     {
5024         OnThreadTerminateInternal(dwThreadId);
5025         return NULL;
5026     }
5027 
5028     return pTarget;
5029 }
5030 
5031 void CTipbarWnd::EnsureFocusThread()
5032 {
5033     if (m_pFocusThread || (m_dwTipbarWndFlags & (TIPBAR_TOOLBARENDED | TIPBAR_ENSURING)))
5034         return;
5035 
5036     m_dwTipbarWndFlags |= TIPBAR_ENSURING;
5037 
5038     HWND hwndFore = ::GetForegroundWindow();
5039     if (!hwndFore)
5040         return;
5041 
5042     DWORD dwThreadId = ::GetWindowThreadProcessId(hwndFore, NULL);
5043     if (dwThreadId)
5044         OnSetFocus(dwThreadId);
5045 
5046     m_dwTipbarWndFlags &= ~TIPBAR_ENSURING;
5047 }
5048 
5049 HRESULT CTipbarWnd::SetFocusThread(CTipbarThread *pFocusThread)
5050 {
5051     if (pFocusThread == m_pFocusThread)
5052         return S_OK;
5053 
5054     DWORD dwThreadId = ::GetCurrentThreadId();
5055     DestroyOverScreenSizeBalloon();
5056 
5057     if (m_pFocusThread)
5058     {
5059         m_pFocusThread->SetFocus(NULL);
5060         ::AttachThreadInput(dwThreadId, m_pFocusThread->m_dwThreadId, FALSE);
5061     }
5062 
5063     m_dwTipbarWndFlags &= ~TIPBAR_ATTACHED;
5064     m_pFocusThread = pFocusThread;
5065     return S_OK;
5066 }
5067 
5068 HRESULT CTipbarWnd::AttachFocusThread()
5069 {
5070     if (m_dwTipbarWndFlags & TIPBAR_ATTACHED)
5071         return S_FALSE;
5072 
5073     if (m_pFocusThread)
5074     {
5075         DWORD dwThreadId = ::GetCurrentThreadId();
5076         ::AttachThreadInput(dwThreadId, m_pFocusThread->m_dwThreadId, TRUE);
5077         m_dwTipbarWndFlags |= TIPBAR_ATTACHED;
5078     }
5079 
5080     return S_OK;
5081 }
5082 
5083 void CTipbarWnd::RestoreLastFocus(DWORD *pdwThreadId, BOOL fPrev)
5084 {
5085     if (m_pLangBarMgr)
5086         m_pLangBarMgr->RestoreLastFocus(pdwThreadId, fPrev);
5087 }
5088 
5089 void CTipbarWnd::CleanUpThreadPointer(CTipbarThread *pThread, BOOL bRemove)
5090 {
5091     if (bRemove)
5092     {
5093         ssize_t iItem = m_Threads.Find(pThread);
5094         if (iItem >= 0)
5095             m_Threads.Remove(iItem);
5096     }
5097 
5098     if (pThread == m_pFocusThread)
5099         SetFocusThread(NULL);
5100 
5101     if (pThread == m_pThread)
5102         m_pThread = NULL;
5103 
5104     if (pThread == m_pUnknownThread)
5105         m_pUnknownThread = NULL;
5106 }
5107 
5108 void CTipbarWnd::TerminateAllThreads(BOOL bFlag)
5109 {
5110     const size_t cItems = m_Threads.size();
5111 
5112     DWORD *pdwThreadIds = new(cicNoThrow) DWORD[cItems];
5113     if (!pdwThreadIds)
5114         return;
5115 
5116     for (size_t iItem = 0; iItem < cItems; ++iItem)
5117     {
5118         pdwThreadIds[iItem] = 0;
5119         CTipbarThread* pThread = m_Threads[iItem];
5120         if (pThread && (bFlag || (pThread != m_pFocusThread)))
5121         {
5122             pdwThreadIds[iItem] = pThread->m_dwThreadId;
5123         }
5124     }
5125 
5126     for (size_t iItem = 0; iItem < cItems; ++iItem)
5127     {
5128         if (pdwThreadIds[iItem])
5129             OnThreadTerminateInternal(pdwThreadIds[iItem]);
5130     }
5131 
5132     delete[] pdwThreadIds;
5133 }
5134 
5135 STDMETHODIMP CTipbarWnd::QueryInterface(REFIID riid, void **ppvObj)
5136 {
5137     static const QITAB c_tab[] =
5138     {
5139         QITABENT(CTipbarWnd, ITfLangBarEventSink),
5140         QITABENT(CTipbarWnd, ITfLangBarEventSink_P),
5141         { NULL }
5142     };
5143     return ::QISearch(this, c_tab, riid, ppvObj);
5144 }
5145 
5146 STDMETHODIMP_(ULONG) CTipbarWnd::AddRef()
5147 {
5148     return ++m_cRefs;
5149 }
5150 
5151 STDMETHODIMP_(ULONG) CTipbarWnd::Release()
5152 {
5153     if (--m_cRefs == 0)
5154     {
5155         delete this;
5156         return 0;
5157     }
5158     return m_cRefs;
5159 }
5160 
5161 /// @unimplemented
5162 STDMETHODIMP CTipbarWnd::OnSetFocus(DWORD dwThreadId)
5163 {
5164     return E_NOTIMPL;
5165 }
5166 
5167 STDMETHODIMP CTipbarWnd::OnThreadTerminate(DWORD dwThreadId)
5168 {
5169     HRESULT hr;
5170     ++m_bInCallOn;
5171     AddRef();
5172     {
5173         hr = OnThreadTerminateInternal(dwThreadId);
5174         if (!m_pFocusThread)
5175             EnsureFocusThread();
5176     }
5177     --m_bInCallOn;
5178     Release();
5179     return hr;
5180 }
5181 
5182 HRESULT CTipbarWnd::OnThreadTerminateInternal(DWORD dwThreadId)
5183 {
5184     for (size_t iItem = 0; iItem < m_Threads.size(); ++iItem)
5185     {
5186         CTipbarThread *pThread = m_Threads[iItem];
5187         if (pThread && pThread->m_dwThreadId == dwThreadId)
5188         {
5189             m_Threads.Remove(iItem);
5190             pThread->RemoveUIObjs();
5191             CleanUpThreadPointer(pThread, FALSE);
5192             pThread->_UninitItemList(TRUE);
5193             pThread->m_pTipbarWnd = NULL;
5194             pThread->_Release();
5195             break;
5196         }
5197     }
5198 
5199     return S_OK;
5200 }
5201 
5202 STDMETHODIMP CTipbarWnd::OnThreadItemChange(DWORD dwThreadId)
5203 {
5204     if (m_dwTipbarWndFlags & TIPBAR_TOOLBARENDED)
5205         return S_OK;
5206     if (!(m_dwTipbarWndFlags & TIPBAR_CHILD) && (m_dwShowType & TF_SFT_DESKBAND))
5207         return S_OK;
5208 
5209     CTipbarThread *pThread = _FindThread(dwThreadId);
5210     if (pThread)
5211     {
5212         if ((!m_dwUnknown23 || m_dwUnknown23 == dwThreadId) && pThread == m_pFocusThread)
5213         {
5214             KillOnTheadItemChangeTimer();
5215             m_dwChangingThreadId = dwThreadId;
5216             KillTimer(6);
5217             SetTimer(4, g_uTimerElapseONTHREADITEMCHANGE);
5218         }
5219         else
5220         {
5221             pThread->m_dwUnknown34 |= 0x1;
5222         }
5223     }
5224     else
5225     {
5226         for (size_t iItem = 0; iItem < m_ThreadCreatingList.size(); ++iItem)
5227         {
5228             CTipbarThread *pItem = m_ThreadCreatingList[iItem];
5229             if (pItem && pItem->m_dwThreadId == dwThreadId)
5230             {
5231                 pItem->m_dwUnknown34 |= 0x1;
5232             }
5233         }
5234     }
5235 
5236     return S_OK;
5237 }
5238 
5239 STDMETHODIMP CTipbarWnd::OnModalInput(DWORD dwThreadId, UINT uMsg, WPARAM wParam, LPARAM lParam)
5240 {
5241     switch (uMsg)
5242     {
5243         case WM_NCLBUTTONDOWN:
5244         case WM_NCRBUTTONDOWN:
5245         case WM_NCMBUTTONDOWN:
5246         case WM_LBUTTONUP:
5247         case WM_RBUTTONUP:
5248         case WM_MBUTTONUP:
5249             break;
5250 
5251         case WM_NCLBUTTONUP:
5252         case WM_NCRBUTTONUP:
5253         case WM_NCMBUTTONUP:
5254             if (m_pThread)
5255             {
5256                 CUTBMenuWnd *pMenuUI = m_pModalMenu->m_pMenuUI;
5257                 if (pMenuUI)
5258                 {
5259                     HWND hWnd = *pMenuUI;
5260                     if (hWnd)
5261                     {
5262                         POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) };
5263                         ::ScreenToClient(hWnd, &pt);
5264                         uMsg += WM_LBUTTONUP - WM_NCLBUTTONUP;
5265                         ::PostMessage(m_hWnd, uMsg, wParam, MAKELPARAM(pt.x, pt.y));
5266                     }
5267                 }
5268             }
5269             break;
5270 
5271         default:
5272         {
5273             if (uMsg == WM_KEYDOWN || uMsg == WM_KEYUP)
5274             {
5275                 if (m_pThread)
5276                     m_pModalMenu->PostKey(uMsg == WM_KEYUP, wParam, lParam);
5277             }
5278             else
5279             {
5280                 CancelMenu();
5281             }
5282             break;
5283         }
5284     }
5285 
5286     return 0;
5287 }
5288 
5289 /// @unimplemented
5290 STDMETHODIMP CTipbarWnd::ShowFloating(DWORD dwFlags)
5291 {
5292     return E_NOTIMPL;
5293 }
5294 
5295 STDMETHODIMP CTipbarWnd::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
5296 {
5297     if (m_dwTipbarWndFlags & TIPBAR_TRAYICON)
5298         return E_UNEXPECTED;
5299 
5300     if (!m_pFocusThread || (m_pFocusThread->m_dwThreadId != dwThreadId))
5301         return E_FAIL;
5302 
5303     for (size_t iItem = 0; iItem < m_pFocusThread->m_UIObjects.size(); ++iItem)
5304     {
5305         CTipbarItem* pItem = m_pFocusThread->m_UIObjects[iItem];
5306         if (pItem)
5307         {
5308             if ((pItem->m_dwItemFlags & 0x8) && IsEqualGUID(pItem->m_ItemInfo.guidItem, rguid))
5309             {
5310                 pItem->OnUnknown57(prc);
5311                 return S_OK;
5312             }
5313         }
5314     }
5315 
5316     return E_FAIL;
5317 }
5318 
5319 /// @unimplemented
5320 STDMETHODIMP CTipbarWnd::OnLangBarUpdate(TfLBIClick click, BOOL bFlag)
5321 {
5322     return E_NOTIMPL;
5323 }
5324 
5325 STDMETHODIMP_(BSTR) CTipbarWnd::GetAccName()
5326 {
5327     WCHAR szText[256];
5328     ::LoadStringW(g_hInst, IDS_LANGUAGEBAR, szText, _countof(szText));
5329     return ::SysAllocString(szText);
5330 }
5331 
5332 STDMETHODIMP_(void) CTipbarWnd::GetAccLocation(LPRECT lprc)
5333 {
5334     GetRect(lprc);
5335 }
5336 
5337 STDMETHODIMP_(void) CTipbarWnd::PaintObject(HDC hDC, LPCRECT prc)
5338 {
5339     if (m_dwTipbarWndFlags & TIPBAR_UPDATING)
5340     {
5341         Move(m_X, m_Y, m_CX, m_CY);
5342         m_dwTipbarWndFlags &= ~TIPBAR_UPDATING;
5343     }
5344 
5345     if (!m_pFocusThread || !m_pFocusThread->IsDirtyItem())
5346     {
5347         m_pFocusThread->CallOnUpdateHandler();
5348         if (g_pTipbarWnd)
5349             CUIFWindow::PaintObject(hDC, prc);
5350     }
5351 }
5352 
5353 STDMETHODIMP_(DWORD) CTipbarWnd::GetWndStyle()
5354 {
5355     return CUIFWindow::GetWndStyle() & ~WS_BORDER;
5356 }
5357 
5358 STDMETHODIMP_(void) CTipbarWnd::Move(INT x, INT y, INT nWidth, INT nHeight)
5359 {
5360     CUIFWindow::Move(x, y, nWidth, nHeight);
5361 }
5362 
5363 STDMETHODIMP_(void) CTipbarWnd::OnMouseOutFromWindow(LONG x, LONG y)
5364 {
5365     StartBackToAlphaTimer();
5366     if ((m_dwTipbarWndFlags & 0x40) && (m_dwTipbarWndFlags & 0x80))
5367         SetTimer(2, g_uTimerElapseSTUBEND);
5368 }
5369 
5370 /// @unimplemented
5371 STDMETHODIMP_(void) CTipbarWnd::OnCreate(HWND hWnd)
5372 {
5373 }
5374 
5375 STDMETHODIMP_(void) CTipbarWnd::OnDestroy(HWND hWnd)
5376 {
5377     CancelMenu();
5378 
5379     if (m_pTipbarAccessible)
5380         m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_DESTROY, GetAccItem());
5381 
5382     OnTerminateToolbar();
5383     if (m_pTipbarAccessible)
5384     {
5385         m_pTipbarAccessible->ClearAccItems();
5386         m_pTipbarAccessible->Release();
5387         m_pTipbarAccessible = NULL;
5388     }
5389 
5390     m_coInit.CoUninit();
5391 
5392     if (m_pLangBarMgr)
5393         m_pLangBarMgr->UnAdviseEventSink(m_dwSinkCookie);
5394 }
5395 
5396 /// @unimplemented
5397 STDMETHODIMP_(void) CTipbarWnd::OnTimer(WPARAM wParam)
5398 {
5399     AddRef();
5400     switch (wParam)
5401     {
5402         case 1:
5403             KillTimer(1);
5404             MoveToStub(FALSE);
5405             break;
5406         case 2:
5407             KillTimer(2);
5408             MoveToStub(TRUE);
5409             break;
5410         case 3:
5411             KillTimer(3);
5412             SetAlpha((BYTE)m_dwAlphaValue, TRUE);
5413             break;
5414         case 4:
5415         {
5416             LONG status = MyWaitForInputIdle(m_dwChangingThreadId, 2000);
5417             if (status)
5418             {
5419                 if (status != STATUS_TIMEOUT)
5420                 {
5421                     KillTimer(4);
5422                     m_dwChangingThreadId = 0;
5423                 }
5424             }
5425             else if (!m_pThread)
5426             {
5427                 KillTimer(4);
5428                 DWORD dwOldThreadId = m_dwChangingThreadId;
5429                 m_dwChangingThreadId = 0;
5430                 OnThreadItemChangeInternal(dwOldThreadId);
5431             }
5432             break;
5433         }
5434         case 5:
5435             KillTimer(5);
5436             ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
5437             break;
5438         case 6:
5439             KillTimer(6);
5440             if (m_pFocusThread)
5441             {
5442                 if (m_pFocusThread->m_dwThreadId != m_dwChangingThreadId &&
5443                     !m_pFocusThread->CallOnUpdateHandler())
5444                 {
5445                     if (m_pFocusThread)
5446                         OnThreadItemChange(m_pFocusThread->m_dwThreadId);
5447                 }
5448             }
5449             break;
5450         case 7:
5451         {
5452             DWORD dwThreadId = 0;
5453             if (KillTimer(7))
5454             {
5455                 if (m_pFocusThread)
5456                     dwThreadId = m_pFocusThread->m_dwThreadId;
5457 
5458                 TerminateAllThreads(TRUE);
5459                 UpdateVerticalFont();
5460 
5461                 if (dwThreadId)
5462                     OnSetFocus(dwThreadId);
5463 
5464                 InitMetrics();
5465                 // FIXME: CTipbarCtrlButtonHolder
5466 
5467                 InitHighContrast();
5468                 SetAlpha(0xFF, TRUE);
5469                 ::RedrawWindow(m_hWnd, NULL, NULL, (RDW_FRAME | RDW_UPDATENOW | RDW_INVALIDATE));
5470             }
5471             break;
5472         }
5473         case 8:
5474             KillTimer(8);
5475             UpdateUI(NULL);
5476             break;
5477         case 9:
5478             KillTimer(9);
5479             //FIXME
5480             if (m_pUnknownThread == m_pFocusThread)
5481                 Show(!!(m_dwUnknown23_5[3] & 0x80000000));
5482             m_pUnknownThread = NULL;
5483             if ((m_dwUnknown23_5[3] & 0x2))
5484                 ShowOverScreenSizeBalloon();
5485             break;
5486         case 10:
5487             KillTimer(10);
5488             MoveToTray();
5489             break;
5490         case 11:
5491             KillTimer(11);
5492             if (m_pTipbarAccessible)
5493             {
5494                 if (m_nID)
5495                 {
5496                     m_pTipbarAccessible->DoDefaultActionReal(m_nID);
5497                     m_nID = 0;
5498                 }
5499             }
5500             break;
5501         case 12:
5502             KillTimer(12);
5503             AdjustPosOnDisplayChange();
5504             break;
5505         case 13:
5506 #ifdef ENABLE_DESKBAND
5507             if (!m_pDeskBand || !m_pDeskBand->m_dwUnknown19)
5508             {
5509                 KillTimer(13);
5510                 if (!m_pFocusThread)
5511                 EnsureFocusThread();
5512             }
5513 #endif
5514             break;
5515         case 14:
5516             if (SetLangBand(TRUE, TRUE))
5517             {
5518                 m_dwShowType = TF_SFT_DESKBAND;
5519                 KillTimer(14);
5520             }
5521             break;
5522         default:
5523         {
5524             if (10000 <= wParam && wParam < 10050)
5525             {
5526                 auto *pItem = m_LangBarItemList.GetItemStateFromTimerId(wParam);
5527                 if (pItem)
5528                 {
5529                     auto& clsid = pItem->m_clsid;
5530                     m_LangBarItemList.SetDemoteLevel(pItem->m_clsid, 2);
5531                     if (m_pFocusThread)
5532                     {
5533                         auto *pThreadItem = m_pFocusThread->GetItem(clsid);
5534                         if (pThreadItem)
5535                             pThreadItem->AddRemoveMeToUI(FALSE);
5536                     }
5537                 }
5538             }
5539             break;
5540         }
5541     }
5542 
5543     Release();
5544 }
5545 
5546 STDMETHODIMP_(void) CTipbarWnd::OnSysColorChange()
5547 {
5548     KillTimer(7);
5549     SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
5550 }
5551 
5552 void CTipbarWnd::OnTerminateToolbar()
5553 {
5554     m_dwTipbarWndFlags |= TIPBAR_TOOLBARENDED;
5555     DestroyOverScreenSizeBalloon();
5556     TerminateAllThreads(TRUE);
5557     if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
5558         SavePosition();
5559 }
5560 
5561 STDMETHODIMP_(void) CTipbarWnd::OnEndSession(HWND hWnd, WPARAM wParam, LPARAM lParam)
5562 {
5563     if (!g_bWinLogon)
5564         OnTerminateToolbar();
5565 
5566     if (wParam) // End session?
5567     {
5568         if (lParam & ENDSESSION_LOGOFF)
5569         {
5570             KillTimer(9);
5571             Show(FALSE);
5572         }
5573         else
5574         {
5575             OnTerminateToolbar();
5576 
5577             AddRef();
5578             ::DestroyWindow(hWnd);
5579             Release();
5580         }
5581     }
5582 }
5583 
5584 STDMETHODIMP_(void) CTipbarWnd::OnUser(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5585 {
5586     if (uMsg == WM_USER + 1)
5587     {
5588         POINT pt = { (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) };
5589         ::ClientToScreen(m_hWnd, &pt);
5590         ShowContextMenu(pt, NULL, TRUE);
5591     }
5592     else if (uMsg == g_wmTaskbarCreated)
5593     {
5594         m_ShellWndThread.clear();
5595     }
5596 }
5597 
5598 STDMETHODIMP_(LRESULT)
5599 CTipbarWnd::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5600 {
5601     if (m_pFocusThread)
5602     {
5603         for (size_t iItem = 0; iItem < m_pFocusThread->m_UIObjects.size(); ++iItem)
5604         {
5605             CTipbarItem *pItem = m_pFocusThread->m_UIObjects[iItem];
5606             if (pItem)
5607                 pItem->OnUnknown44();
5608         }
5609     }
5610 
5611     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
5612 }
5613 
5614 STDMETHODIMP_(LRESULT)
5615 CTipbarWnd::OnWindowPosChanging(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5616 {
5617     LPWINDOWPOS pWP = (LPWINDOWPOS)lParam;
5618     if (!(pWP->flags & SWP_NOZORDER))
5619     {
5620         if (!m_pThread && (!m_pToolTip || !m_pToolTip->m_bShowToolTip))
5621             pWP->hwndInsertAfter = NULL;
5622     }
5623     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
5624 }
5625 
5626 STDMETHODIMP_(LRESULT)
5627 CTipbarWnd::OnShowWindow(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5628 {
5629     if (m_pTipbarAccessible)
5630     {
5631         if (wParam) // Show?
5632         {
5633             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_SHOW, GetAccItem());
5634             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_FOCUS, GetAccItem());
5635         }
5636         else
5637         {
5638             m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_HIDE, GetAccItem());
5639         }
5640     }
5641     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
5642 }
5643 
5644 STDMETHODIMP_(LRESULT)
5645 CTipbarWnd::OnSettingChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5646 {
5647     if (!wParam || wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETHIGHCONTRAST)
5648     {
5649         KillTimer(7);
5650         SetTimer(7, g_uTimerElapseSYSCOLORCHANGED);
5651     }
5652     return 0;
5653 }
5654 
5655 STDMETHODIMP_(LRESULT)
5656 CTipbarWnd::OnDisplayChange(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5657 {
5658     if (!(m_dwTipbarWndFlags & TIPBAR_CHILD))
5659     {
5660         KillTimer(12);
5661         SetTimer(12, g_uTimerElapseDISPLAYCHANGE);
5662     }
5663     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
5664 }
5665 
5666 STDMETHODIMP_(HRESULT)
5667 CTipbarWnd::OnGetObject(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5668 {
5669     if (lParam != -4)
5670         return S_OK;
5671     if (!m_pTipbarAccessible)
5672         return E_OUTOFMEMORY;
5673 
5674     if (m_pTipbarAccessible->m_bInitialized)
5675         return m_pTipbarAccessible->CreateRefToAccObj(wParam);
5676 
5677     HRESULT hr = S_OK;
5678     if (SUCCEEDED(m_coInit.EnsureCoInit()))
5679     {
5680         hr = m_pTipbarAccessible->Initialize();
5681         if (FAILED(hr))
5682         {
5683             m_pTipbarAccessible->Release();
5684             m_pTipbarAccessible = NULL;
5685             return hr;
5686         }
5687 
5688         m_pTipbarAccessible->NotifyWinEvent(EVENT_OBJECT_CREATE, GetAccItem());
5689         return m_pTipbarAccessible->CreateRefToAccObj(wParam);
5690     }
5691 
5692     return hr;
5693 }
5694 
5695 STDMETHODIMP_(BOOL) CTipbarWnd::OnEraseBkGnd(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5696 {
5697     return TRUE;
5698 }
5699 
5700 STDMETHODIMP_(void) CTipbarWnd::OnThemeChanged(HWND hWnd, WPARAM wParam, LPARAM lParam)
5701 {
5702     CUIFWindow::OnThemeChanged(hWnd, wParam, lParam);
5703 }
5704 
5705 STDMETHODIMP_(void) CTipbarWnd::UpdateUI(LPCRECT prc)
5706 {
5707     KillTimer(8);
5708 
5709     if (m_dwChangingThreadId || m_bInCallOn || (m_pFocusThread && m_pFocusThread->IsDirtyItem()))
5710     {
5711         SetTimer(8, g_uTimerElapseUPDATEUI);
5712         return;
5713     }
5714 
5715     if (m_dwTipbarWndFlags & TIPBAR_UPDATING)
5716     {
5717         ++m_bInCallOn;
5718         Move(m_X, m_Y, m_CX, m_CY);
5719         m_dwTipbarWndFlags &= ~TIPBAR_UPDATING;
5720         --m_bInCallOn;
5721     }
5722 
5723     CUIFWindow::UpdateUI(NULL);
5724 }
5725 
5726 /// @unimplemented
5727 STDMETHODIMP_(void) CTipbarWnd::HandleMouseMsg(UINT uMsg, LONG x, LONG y)
5728 {
5729 }
5730 
5731 /***********************************************************************
5732  * CTipbarThread
5733  */
5734 
5735 CTipbarThread::CTipbarThread(CTipbarWnd *pTipbarWnd)
5736 {
5737     m_pTipbarWnd = pTipbarWnd;
5738     m_dwThreadId = 0;
5739     m_pLangBarItemMgr = NULL;
5740     m_cRefs = 1;
5741 }
5742 
5743 CTipbarThread::~CTipbarThread()
5744 {
5745     if (m_pTipbarWnd)
5746     {
5747         RemoveUIObjs();
5748         m_pTipbarWnd->CleanUpThreadPointer(this, 1);
5749     }
5750 
5751     _UninitItemList(1);
5752 
5753     if (m_pLangBarItemMgr)
5754     {
5755         m_pLangBarItemMgr->Release();
5756         m_pLangBarItemMgr = NULL;
5757     }
5758 }
5759 
5760 HRESULT CTipbarThread::Init(DWORD dwThreadId)
5761 {
5762     m_dwThreadId = dwThreadId;
5763     if (!TF_GetThreadFlags(dwThreadId, &m_dwFlags1, &m_dwFlags2, &m_dwFlags3))
5764         return E_FAIL;
5765     if (m_dwFlags1 & 0x8)
5766         return S_OK;
5767     return m_pTipbarWnd->m_pLangBarMgr->GetThreadLangBarItemMgr(m_dwThreadId,
5768                                                                 &m_pLangBarItemMgr,
5769                                                                 &dwThreadId);
5770 }
5771 
5772 /// @unimplemented
5773 HRESULT CTipbarThread::InitItemList()
5774 {
5775     return E_NOTIMPL;
5776 }
5777 
5778 HRESULT CTipbarThread::_UninitItemList(BOOL bUnAdvise)
5779 {
5780     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5781     {
5782         CTipbarItem* pItem = m_UIObjects[iItem];
5783         if (pItem)
5784             pItem->m_dwItemFlags |= 0x10;
5785     }
5786 
5787     HRESULT hr = S_OK;
5788     if (bUnAdvise)
5789     {
5790         if (m_dwThreadId == ::GetCurrentThreadId() || !MyWaitForInputIdle(m_dwThreadId, 2000))
5791             hr = _UnadviseItemsSink();
5792     }
5793 
5794     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5795     {
5796         CTipbarItem* pItem = m_UIObjects[iItem];
5797         if (pItem)
5798         {
5799             if (m_pTipbarWnd)
5800                 pItem->OnUnknown47(m_pTipbarWnd->GetWindow());
5801 
5802             pItem->ClearConnections();
5803 
5804             if (m_pTipbarWnd)
5805                 pItem->OnUnknown50();
5806             else
5807                 pItem->OnUnknown51();
5808 
5809             pItem->OnUnknown59();
5810             pItem->OnUnknown42();
5811         }
5812     }
5813 
5814     m_UIObjects.clear();
5815 
5816     RemoveAllSeparators();
5817 
5818     return hr;
5819 }
5820 
5821 void CTipbarThread::AddAllSeparators()
5822 {
5823     for (size_t iItem = 0; iItem < m_Separators.size(); ++iItem)
5824     {
5825         CUIFObject *pItem = m_Separators[iItem];
5826         if (pItem)
5827             m_pTipbarWnd->AddUIObj(pItem);
5828     }
5829 }
5830 
5831 void CTipbarThread::RemoveAllSeparators()
5832 {
5833     for (size_t iItem = 0; iItem < m_Separators.size(); ++iItem)
5834     {
5835         CUIFObject *pItem = m_Separators[iItem];
5836         if (pItem)
5837         {
5838             if (m_pTipbarWnd)
5839                 m_pTipbarWnd->RemoveUIObj(pItem);
5840             delete pItem;
5841         }
5842     }
5843     m_Separators.clear();
5844 }
5845 
5846 void CTipbarThread::AddUIObjs()
5847 {
5848     _AddRef();
5849 
5850     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5851     {
5852         CTipbarItem* pItem = m_UIObjects[iItem];
5853         if (pItem && (pItem->m_dwItemFlags & 0x8))
5854         {
5855             pItem->OnUnknown46(m_pTipbarWnd ? m_pTipbarWnd->GetWindow() : NULL);
5856         }
5857     }
5858 
5859     AddAllSeparators();
5860     MyMoveWnd(0, 0);
5861 
5862     _Release();
5863 }
5864 
5865 void CTipbarThread::RemoveUIObjs()
5866 {
5867     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5868     {
5869         CTipbarItem* pItem = m_UIObjects[iItem];
5870         if (pItem)
5871         {
5872             pItem->OnUnknown47(m_pTipbarWnd ? m_pTipbarWnd->GetWindow() : NULL);
5873         }
5874     }
5875     RemoveAllSeparators();
5876 }
5877 
5878 CTipbarItem *CTipbarThread::GetItem(REFCLSID rclsid)
5879 {
5880     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5881     {
5882         auto *pItem = m_UIObjects[iItem];
5883         if (pItem && IsEqualCLSID(pItem->m_ItemInfo.guidItem, rclsid))
5884             return pItem;
5885     }
5886     return NULL;
5887 }
5888 
5889 void CTipbarThread::GetTextSize(BSTR bstr, LPSIZE pSize)
5890 {
5891     HWND hWnd = *m_pTipbarWnd->GetWindow();
5892 
5893     HGDIOBJ hFontOld = NULL;
5894 
5895     HDC hDC = ::GetDC(hWnd);
5896     if (FAILED(m_pTipbarWnd->EnsureThemeData(*m_pTipbarWnd->GetWindow())))
5897     {
5898         HFONT hFont = m_pTipbarWnd->m_hFont;
5899         if (hFont)
5900             hFontOld = ::SelectObject(hDC, hFont);
5901         INT cch = ::SysStringLen(bstr);
5902         ::GetTextExtentPoint32W(hDC, bstr, cch, pSize);
5903         if (hFontOld)
5904             ::SelectObject(hDC, hFontOld);
5905     }
5906     else
5907     {
5908         CUIFTheme theme;
5909         theme.m_iPartId = 1;
5910         theme.m_iStateId = 0;
5911         theme.m_pszClassList = L"TOOLBAR";
5912 
5913         HFONT hFont = NULL;
5914 
5915         if (SUCCEEDED(theme.InternalOpenThemeData(hWnd)))
5916         {
5917             LOGFONTW lf;
5918             if (SUCCEEDED(::GetThemeFont(theme.m_hTheme, NULL, theme.m_iPartId, 0, 210, &lf)))
5919             {
5920                 hFont = ::CreateFontIndirectW(&lf);
5921                 if (hFont)
5922                     hFontOld = ::SelectObject(hDC, hFont);
5923             }
5924 
5925             RECT rc;
5926             INT cch = ::SysStringLen(bstr);
5927             ::GetThemeTextExtent(theme.m_hTheme, hDC, theme.m_iPartId, 0, bstr, cch, 0, NULL, &rc);
5928 
5929             pSize->cx = rc.right;
5930             pSize->cy = rc.bottom;
5931         }
5932 
5933         if (hFontOld)
5934             ::SelectObject(hDC, hFontOld);
5935         if (hFont)
5936             ::DeleteObject(hFont);
5937     }
5938 
5939     ::ReleaseDC(hWnd, hDC);
5940 }
5941 
5942 DWORD CTipbarThread::IsDirtyItem()
5943 {
5944     DWORD dwDirty = 0;
5945     for (size_t iItem = 0; iItem < m_UIObjects.size(); ++iItem)
5946     {
5947         CTipbarItem* pItem = m_UIObjects[iItem];
5948         if (pItem)
5949             dwDirty |= pItem->m_dwDirty;
5950     }
5951     return dwDirty;
5952 }
5953 
5954 BOOL CTipbarThread::IsFocusThread()
5955 {
5956     if (!m_pTipbarWnd)
5957         return FALSE;
5958     return this == m_pTipbarWnd->m_pFocusThread;
5959 }
5960 
5961 BOOL CTipbarThread::IsVertical()
5962 {
5963     if (!m_pTipbarWnd)
5964         return FALSE;
5965     return !!(m_pTipbarWnd->m_dwTipbarWndFlags & TIPBAR_VERTICAL);
5966 }
5967 
5968 /// @unimplemented
5969 void CTipbarThread::LocateItems()
5970 {
5971 }
5972 
5973 LONG CTipbarThread::_Release()
5974 {
5975     if (--m_cRefs == 0)
5976     {
5977         delete this;
5978         return 0;
5979     }
5980     return m_cRefs;
5981 }
5982 
5983 HRESULT CTipbarThread::_UnadviseItemsSink()
5984 {
5985     if (!m_pLangBarItemMgr)
5986         return E_FAIL;
5987 
5988     DWORD *pdwCoolkies = new(cicNoThrow) DWORD[m_UIObjects.size()];
5989     if (!pdwCoolkies)
5990         return E_OUTOFMEMORY;
5991 
5992     const size_t cItems = m_UIObjects.size();
5993     for (size_t iItem = 0; iItem < cItems; ++iItem)
5994     {
5995         CTipbarItem* pItem = m_UIObjects[iItem];
5996         if (pItem)
5997             pdwCoolkies[iItem] = pItem->m_dwCookie;
5998     }
5999 
6000     HRESULT hr = m_pLangBarItemMgr->UnadviseItemsSink((LONG)cItems, pdwCoolkies);
6001 
6002     delete[] pdwCoolkies;
6003 
6004     return hr;
6005 }
6006 
6007 void CTipbarThread::MyMoveWnd(LONG xDelta, LONG yDelta)
6008 {
6009     if (!m_pTipbarWnd || (m_pTipbarWnd->m_pFocusThread != this))
6010         return;
6011 
6012     RECT Rect, rcWorkArea;
6013     m_pTipbarWnd->GetRect(&Rect);
6014     POINT pt = { Rect.left, Rect.top };
6015     cicGetWorkAreaRect(pt, &rcWorkArea);
6016 
6017     ::GetWindowRect(*m_pTipbarWnd->GetWindow(), &Rect);
6018 
6019     LONG X0 = Rect.left + xDelta, Y0 = Rect.top + yDelta;
6020     if (m_pTipbarWnd->m_dwTipbarWndFlags & 0x1000)
6021     {
6022         if (m_pTipbarWnd->CheckExcludeCaptionButtonMode(&Rect, &rcWorkArea))
6023         {
6024             X0 = rcWorkArea.right - (3 * m_pTipbarWnd->m_ButtonWidth +
6025                                      m_pTipbarWnd->m_cxDlgFrameX2 + m_cxGrip);
6026             Y0 = 0;
6027         }
6028         else
6029         {
6030             m_pTipbarWnd->m_dwTipbarWndFlags &= ~0x1000;
6031         }
6032     }
6033 
6034     if (IsVertical())
6035     {
6036         LONG width = m_pTipbarWnd->m_cxDlgFrameX2 + m_pTipbarWnd->GetTipbarHeight();
6037         LONG height = m_cyGrip + m_pTipbarWnd->m_cyDlgFrameX2;
6038         m_pTipbarWnd->SetMoveRect(X0, Y0, width, height);
6039     }
6040     else
6041     {
6042         LONG width = m_cxGrip + m_pTipbarWnd->m_cxDlgFrameX2;
6043         LONG height = m_pTipbarWnd->m_cyDlgFrameX2 + m_pTipbarWnd->GetTipbarHeight();
6044         m_pTipbarWnd->SetMoveRect(X0, Y0, width, height);
6045     }
6046 
6047     SIZE frameSize = { 0, 0 };
6048     if (m_pTipbarWnd->m_pWndFrame)
6049         m_pTipbarWnd->m_pWndFrame->GetFrameSize(&frameSize);
6050 
6051     m_pTipbarWnd->LocateCtrlButtons();
6052     m_pTipbarWnd->AutoAdjustDeskBandSize();
6053 }
6054 
6055 /***********************************************************************
6056  * CTipbarItem
6057  */
6058 
6059 CTipbarItem::CTipbarItem(
6060     CTipbarThread *pThread,
6061     ITfLangBarItem *pLangBarItem,
6062     TF_LANGBARITEMINFO *pItemInfo,
6063     DWORD dwUnknown16)
6064 {
6065     m_dwUnknown19[1] = 0;
6066     m_dwUnknown19[2] = 0;
6067     m_dwUnknown19[3] = 0;
6068     m_pTipbarThread = pThread;
6069     m_ItemInfo = *pItemInfo;
6070     m_pLangBarItem = pLangBarItem;
6071     m_pLangBarItem->AddRef();
6072     m_dwItemFlags = 0;
6073     m_dwUnknown16 = dwUnknown16;
6074     m_dwDirty = 0x1001F;
6075 }
6076 
6077 CTipbarItem::~CTipbarItem()
6078 {
6079     if (g_pTipbarWnd)
6080     {
6081         if (g_pTipbarWnd->m_pTipbarAccessible)
6082             g_pTipbarWnd->m_pTipbarAccessible->RemoveAccItem(this);
6083     }
6084 
6085     if (m_pLangBarItem)
6086         m_pLangBarItem->Release();
6087 }
6088 
6089 void CTipbarItem::_AddedToUI()
6090 {
6091     if (!IsConnected())
6092         return;
6093 
6094     OnUnknown41();
6095 
6096     m_dwItemFlags |= 0x2;
6097 
6098     DWORD dwStatus;
6099     if (m_dwDirty)
6100     {
6101         if (m_dwDirty & 0x10000)
6102             m_pLangBarItem->GetStatus(&dwStatus);
6103         else
6104             dwStatus = 0;
6105         OnUnknown45(m_dwDirty, dwStatus);
6106         m_dwDirty = 0;
6107     }
6108 
6109     if (m_pTipbarThread)
6110     {
6111         CTipbarWnd *pTipbarWnd = m_pTipbarThread->m_pTipbarWnd;
6112         if (pTipbarWnd)
6113         {
6114             CTipbarAccessible *pTipbarAccessible = pTipbarWnd->m_pTipbarAccessible;
6115             if (pTipbarAccessible)
6116                 pTipbarAccessible->AddAccItem(this);
6117         }
6118     }
6119 
6120     OnUnknown42();
6121 }
6122 
6123 void CTipbarItem::_RemovedToUI()
6124 {
6125     m_dwItemFlags &= ~0x2;
6126 
6127     if (g_pTipbarWnd)
6128     {
6129         CTipbarAccessible *pAccessible = g_pTipbarWnd->m_pTipbarAccessible;
6130         if (pAccessible)
6131             pAccessible->RemoveAccItem(this);
6132     }
6133 }
6134 
6135 void CTipbarItem::AddRemoveMeToUI(BOOL bFlag)
6136 {
6137     if (!IsConnected())
6138         return;
6139 
6140     m_pTipbarThread->LocateItems();
6141 
6142     if (!IsConnected())
6143         return;
6144 
6145     m_pTipbarThread->AddAllSeparators();
6146 
6147     CTipbarWnd *pTipbarWnd = m_pTipbarThread->m_pTipbarWnd;
6148     if (bFlag)
6149         OnUnknown46(pTipbarWnd ? pTipbarWnd->GetWindow() : NULL);
6150     else
6151         OnUnknown47(pTipbarWnd ? pTipbarWnd->GetWindow() : NULL);
6152 }
6153 
6154 BOOL CTipbarItem::IsConnected()
6155 {
6156     return (!(m_dwItemFlags & 0x10) && m_pTipbarThread && m_pTipbarThread->m_pTipbarWnd &&
6157             m_pLangBarItem);
6158 }
6159 
6160 void CTipbarItem::ClearConnections()
6161 {
6162     m_pTipbarThread = NULL;
6163     if (m_pLangBarItem)
6164     {
6165         m_pLangBarItem->Release();
6166         m_pLangBarItem = NULL;
6167     }
6168 }
6169 
6170 /// @unimplemented
6171 void CTipbarItem::StartDemotingTimer(BOOL bStarted)
6172 {
6173     if (!g_bIntelliSense)
6174         return;
6175 
6176     if (!m_pTipbarThread)
6177         return;
6178 
6179     CTipbarWnd *pTipbarWnd = m_pTipbarThread->m_pTipbarWnd;
6180     if (!pTipbarWnd)
6181         return;
6182 
6183     //FIXME
6184 }
6185 
6186 STDMETHODIMP_(BOOL) CTipbarItem::DoAccDefaultAction()
6187 {
6188     if (!m_pTipbarThread)
6189         return FALSE;
6190     CTipbarWnd *pTipbarWnd = m_pTipbarThread->m_pTipbarWnd;
6191     if (!pTipbarWnd)
6192         return FALSE;
6193     pTipbarWnd->StartDoAccDefaultActionTimer(this);
6194     return TRUE;
6195 }
6196 
6197 /// @unimplemented
6198 STDMETHODIMP_(void) CTipbarItem::OnUpdateHandler(ULONG, ULONG)
6199 {
6200 }
6201 
6202 STDMETHODIMP_(void) CTipbarItem::GetAccLocation(LPRECT prc)
6203 {
6204     OnUnknown57(prc);
6205 }
6206 
6207 STDMETHODIMP_(BSTR) CTipbarItem::GetAccName()
6208 {
6209     return ::SysAllocString(m_ItemInfo.szDescription);
6210 }
6211 
6212 STDMETHODIMP_(LPCWSTR) CTipbarItem::GetToolTip()
6213 {
6214     OnUnknown41();
6215 
6216     if (!(m_dwItemFlags & 0x1))
6217     {
6218         m_dwItemFlags |= 0x1;
6219 
6220         BSTR bstrString;
6221         if (FAILED(m_pLangBarItem->GetTooltipString(&bstrString)))
6222             return NULL;
6223 
6224         if (bstrString)
6225         {
6226             OnUnknown53(bstrString);
6227             ::SysFreeString(bstrString);
6228         }
6229     }
6230 
6231     LPCWSTR pszToolTip = OnUnknown55();
6232 
6233     OnUnknown42();
6234 
6235     return pszToolTip;
6236 }
6237 
6238 HRESULT CTipbarItem::OnUpdate(DWORD dwDirty)
6239 {
6240     if (!IsConnected())
6241         return S_OK;
6242 
6243     m_dwDirty |= dwDirty;
6244     m_dwItemFlags |= 0x20;
6245 
6246     if ((dwDirty & 0x10000) || (m_dwItemFlags & 0x6))
6247     {
6248         if (m_pTipbarThread)
6249         {
6250             CTipbarWnd *pTipBarWnd = m_pTipbarThread->m_pTipbarWnd;
6251             if (pTipBarWnd && *pTipBarWnd)
6252             {
6253                 pTipBarWnd->KillTimer(6);
6254                 pTipBarWnd->SetTimer(6, g_uTimerElapseONUPDATECALLED);
6255             }
6256         }
6257     }
6258 
6259     return S_OK;
6260 }
6261 
6262 void CTipbarItem::MyClientToScreen(LPPOINT ppt, LPRECT prc)
6263 {
6264     if (!m_pTipbarThread)
6265         return;
6266     if (m_pTipbarThread->m_pTipbarWnd)
6267         m_pTipbarThread->m_pTipbarWnd->MyClientToScreen(ppt, prc);
6268 }
6269 
6270 /***********************************************************************
6271  *              GetTipbarInternal
6272  */
6273 BOOL GetTipbarInternal(HWND hWnd, DWORD dwFlags, CDeskBand *pDeskBand)
6274 {
6275     BOOL bParent = !!(dwFlags & 0x80000000);
6276     g_bWinLogon = !!(dwFlags & 0x1);
6277 
6278     InitFromReg();
6279 
6280     if (!g_bShowTipbar)
6281         return FALSE;
6282 
6283     if (bParent)
6284     {
6285         g_pTrayIconWnd = new(cicNoThrow) CTrayIconWnd();
6286         if (!g_pTrayIconWnd)
6287             return FALSE;
6288         g_pTrayIconWnd->CreateWnd();
6289     }
6290 
6291     g_pTipbarWnd = new(cicNoThrow) CTipbarWnd(bParent ? g_dwWndStyle : g_dwChildWndStyle);
6292     if (!g_pTipbarWnd || !g_pTipbarWnd->Initialize())
6293         return FALSE;
6294 
6295     g_pTipbarWnd->Init(!bParent, pDeskBand);
6296     g_pTipbarWnd->CreateWnd(hWnd);
6297 
6298     ::SetWindowText(*g_pTipbarWnd, TEXT("TF_FloatingLangBar_WndTitle"));
6299 
6300     DWORD dwOldStatus = 0;
6301     if (!bParent)
6302     {
6303         g_pTipbarWnd->m_pLangBarMgr->GetPrevShowFloatingStatus(&dwOldStatus);
6304         g_pTipbarWnd->m_pLangBarMgr->ShowFloating(TF_SFT_DESKBAND);
6305     }
6306 
6307     DWORD dwStatus;
6308     g_pTipbarWnd->m_pLangBarMgr->GetShowFloatingStatus(&dwStatus);
6309     g_pTipbarWnd->ShowFloating(dwStatus);
6310 
6311     if (!bParent && (dwOldStatus & TF_SFT_DESKBAND))
6312         g_pTipbarWnd->m_dwTipbarWndFlags |= TIPBAR_NODESKBAND;
6313 
6314     g_hwndParent = hWnd;
6315     return TRUE;
6316 }
6317 
6318 /***********************************************************************
6319  *              GetLibTls (MSUTB.@)
6320  *
6321  * @implemented
6322  */
6323 EXTERN_C PCIC_LIBTHREAD WINAPI
6324 GetLibTls(VOID)
6325 {
6326     TRACE("()\n");
6327     return &g_libTLS;
6328 }
6329 
6330 /***********************************************************************
6331  *              GetPopupTipbar (MSUTB.@)
6332  *
6333  * @implemented
6334  */
6335 EXTERN_C BOOL WINAPI
6336 GetPopupTipbar(HWND hWnd, BOOL fWinLogon)
6337 {
6338     TRACE("(%p, %d)\n", hWnd, fWinLogon);
6339 
6340     if (!fWinLogon)
6341         TurnOffSpeechIfItsOn();
6342 
6343     return GetTipbarInternal(hWnd, fWinLogon | 0x80000000, NULL);
6344 }
6345 
6346 /***********************************************************************
6347  *              SetRegisterLangBand (MSUTB.@)
6348  *
6349  * @implemented
6350  */
6351 EXTERN_C HRESULT WINAPI
6352 SetRegisterLangBand(BOOL bRegister)
6353 {
6354     TRACE("(%d)\n", bRegister);
6355 
6356     if (!g_bEnableDeskBand || !(g_dwOSInfo & CIC_OSINFO_XPPLUS)) // Desk band is for XP+
6357         return E_FAIL;
6358 
6359     BOOL bDeskBand = IsDeskBandFromReg();
6360     if (bDeskBand == bRegister)
6361         return S_OK;
6362 
6363     SetDeskBandToReg(bRegister);
6364 
6365     if (!RegisterComCat(CLSID_MSUTBDeskBand, CATID_DeskBand, bRegister))
6366         return TF_E_NOLOCK;
6367 
6368     return S_OK;
6369 }
6370 
6371 /***********************************************************************
6372  *              ClosePopupTipbar (MSUTB.@)
6373  *
6374  * @implemented
6375  */
6376 EXTERN_C VOID WINAPI
6377 ClosePopupTipbar(VOID)
6378 {
6379     TRACE("()\n");
6380 
6381     if (g_fInClosePopupTipbar)
6382         return;
6383 
6384     g_fInClosePopupTipbar = TRUE;
6385 
6386     if (g_pTipbarWnd)
6387     {
6388         g_pTipbarWnd->m_pDeskBand = NULL;
6389         g_pTipbarWnd->DestroyWnd();
6390         g_pTipbarWnd->Release();
6391         g_pTipbarWnd = NULL;
6392     }
6393 
6394     if (g_pTrayIconWnd)
6395     {
6396         g_pTrayIconWnd->DestroyWnd();
6397         delete g_pTrayIconWnd;
6398         g_pTrayIconWnd = NULL;
6399     }
6400 
6401     UninitSkipRedrawHKLArray();
6402 
6403     g_fInClosePopupTipbar = FALSE;
6404 }
6405 
6406 /***********************************************************************
6407  *              DllRegisterServer (MSUTB.@)
6408  *
6409  * @implemented
6410  */
6411 STDAPI DllRegisterServer(VOID)
6412 {
6413     TRACE("()\n");
6414     return gModule.DllRegisterServer(FALSE);
6415 }
6416 
6417 /***********************************************************************
6418  *              DllUnregisterServer (MSUTB.@)
6419  *
6420  * @implemented
6421  */
6422 STDAPI DllUnregisterServer(VOID)
6423 {
6424     TRACE("()\n");
6425     return gModule.DllUnregisterServer(FALSE);
6426 }
6427 
6428 /***********************************************************************
6429  *              DllCanUnloadNow (MSUTB.@)
6430  *
6431  * @implemented
6432  */
6433 STDAPI DllCanUnloadNow(VOID)
6434 {
6435     TRACE("()\n");
6436     return gModule.DllCanUnloadNow() && (g_DllRefCount == 0);
6437 }
6438 
6439 /***********************************************************************
6440  *              DllGetClassObject (MSUTB.@)
6441  *
6442  * @implemented
6443  */
6444 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
6445 {
6446     TRACE("()\n");
6447     return gModule.DllGetClassObject(rclsid, riid, ppv);
6448 }
6449 
6450 /// @implemented
6451 HRESULT APIENTRY
6452 MsUtbCoCreateInstance(
6453     REFCLSID rclsid,
6454     LPUNKNOWN pUnkOuter,
6455     DWORD dwClsContext,
6456     REFIID iid,
6457     LPVOID *ppv)
6458 {
6459     if (IsEqualCLSID(rclsid, CLSID_TF_CategoryMgr))
6460         return TF_CreateCategoryMgr((ITfCategoryMgr**)ppv);
6461     if (IsEqualCLSID(rclsid, CLSID_TF_DisplayAttributeMgr))
6462         return TF_CreateDisplayAttributeMgr((ITfDisplayAttributeMgr **)ppv);
6463     return cicRealCoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv);
6464 }
6465 
6466 BEGIN_OBJECT_MAP(ObjectMap)
6467 #ifdef ENABLE_DESKBAND
6468     OBJECT_ENTRY(CLSID_MSUTBDeskBand, CDeskBand) // FIXME: Implement this
6469 #endif
6470 END_OBJECT_MAP()
6471 
6472 EXTERN_C VOID TFUninitLib(VOID)
6473 {
6474     // Do nothing
6475 }
6476 
6477 /// @implemented
6478 BOOL ProcessAttach(HINSTANCE hinstDLL)
6479 {
6480     ::InitializeCriticalSectionAndSpinCount(&g_cs, 0);
6481 
6482     g_hInst = hinstDLL;
6483 
6484     cicGetOSInfo(&g_uACP, &g_dwOSInfo);
6485 
6486     TFInitLib(MsUtbCoCreateInstance);
6487     cicInitUIFLib();
6488 
6489     CTrayIconWnd::RegisterClass();
6490 
6491     g_wmTaskbarCreated = RegisterWindowMessageW(L"TaskbarCreated");
6492 
6493     gModule.Init(ObjectMap, hinstDLL, NULL);
6494     ::DisableThreadLibraryCalls(hinstDLL);
6495 
6496     return TRUE;
6497 }
6498 
6499 /// @implemented
6500 VOID ProcessDetach(HINSTANCE hinstDLL)
6501 {
6502     cicDoneUIFLib();
6503     TFUninitLib();
6504     ::DeleteCriticalSection(&g_cs);
6505     gModule.Term();
6506 }
6507 
6508 /// @implemented
6509 EXTERN_C BOOL WINAPI
6510 DllMain(
6511     _In_ HINSTANCE hinstDLL,
6512     _In_ DWORD dwReason,
6513     _Inout_opt_ LPVOID lpvReserved)
6514 {
6515     switch (dwReason)
6516     {
6517         case DLL_PROCESS_ATTACH:
6518         {
6519             TRACE("(%p, %lu, %p)\n", hinstDLL, dwReason, lpvReserved);
6520             if (!ProcessAttach(hinstDLL))
6521             {
6522                 ProcessDetach(hinstDLL);
6523                 return FALSE;
6524             }
6525             break;
6526         }
6527         case DLL_PROCESS_DETACH:
6528         {
6529             ProcessDetach(hinstDLL);
6530             break;
6531         }
6532     }
6533     return TRUE;
6534 }
6535