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