Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

765 lines
19 KiB

  1. //
  2. // utbtray.cpp
  3. //
  4. #include "private.h"
  5. #include "globals.h"
  6. #include "utbtray.h"
  7. #include "inatlib.h"
  8. #include "xstring.h"
  9. #include "inatlib.h"
  10. #include "tipbar.h"
  11. #include "shlapip.h"
  12. #include "nuiinat.h"
  13. #include "resource.h"
  14. #include "cresstr.h"
  15. #include "cregkey.h"
  16. #include "nuiinat.h"
  17. #include "dlgs.h"
  18. HICON WINAPI TF_GetLangIcon(WORD langid , WCHAR *psz, UINT cchMax);
  19. const char CTrayIconWnd::_szWndClass[] = "CTrayIconWndClass";
  20. extern UINT g_wmTaskbarCreated;
  21. extern CTipbarWnd *g_pTipbarWnd;
  22. /* e0b724e9-6f76-45f7-b4c1-b1c0fabce23e */
  23. const GUID GUID_LBI_TRAYMAIN = {
  24. 0xe0b724e9,
  25. 0x6f76,
  26. 0x45f7,
  27. {0xb4, 0xc1, 0xb1, 0xc0, 0xfa, 0xbc, 0xe2, 0x3e}
  28. };
  29. //////////////////////////////////////////////////////////////////////////////
  30. //
  31. // CTrayIconItem
  32. //
  33. //////////////////////////////////////////////////////////////////////////////
  34. //+---------------------------------------------------------------------------
  35. //
  36. // ctor
  37. //
  38. //----------------------------------------------------------------------------
  39. CTrayIconItem::CTrayIconItem(CTrayIconWnd *ptiwnd)
  40. {
  41. _fIconPrev = FALSE;
  42. _ptiwnd = ptiwnd;
  43. }
  44. //+---------------------------------------------------------------------------
  45. //
  46. // dtor
  47. //
  48. //----------------------------------------------------------------------------
  49. CTrayIconItem::~CTrayIconItem()
  50. {
  51. RemoveIcon();
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Init
  56. //
  57. //----------------------------------------------------------------------------
  58. BOOL CTrayIconItem::_Init(HWND hwnd, UINT uCallbackMessage, UINT uID, REFGUID rguid)
  59. {
  60. _hwnd = hwnd;
  61. _uCallbackMessage = uCallbackMessage;
  62. _uID = uID;
  63. _guidBtnItem = rguid;
  64. return TRUE;
  65. }
  66. //+---------------------------------------------------------------------------
  67. //
  68. // SetIcon
  69. //
  70. //----------------------------------------------------------------------------
  71. BOOL CTrayIconItem::SetIcon(HICON hIcon, const WCHAR *pszTooltip)
  72. {
  73. DWORD dwMessage;
  74. if (!hIcon)
  75. return FALSE;
  76. if (!_fIconPrev)
  77. dwMessage = NIM_ADD;
  78. else
  79. dwMessage = NIM_MODIFY;
  80. if (IsOnNT())
  81. {
  82. NOTIFYICONDATAW tndw;
  83. tndw.cbSize = sizeof(NOTIFYICONDATAW);
  84. tndw.hWnd = _hwnd;
  85. tndw.uCallbackMessage = _uCallbackMessage;
  86. tndw.uID = _uID;
  87. tndw.uFlags = NIF_MESSAGE | NIF_ICON;
  88. tndw.hIcon = hIcon;
  89. if (pszTooltip)
  90. {
  91. tndw.uFlags |= NIF_TIP;
  92. StringCchCopyW(tndw.szTip, ARRAYSIZE(tndw.szTip), pszTooltip);
  93. }
  94. Shell_NotifyIconW(dwMessage, &tndw);
  95. }
  96. else
  97. {
  98. NOTIFYICONDATA tnd;
  99. tnd.cbSize = sizeof(NOTIFYICONDATA);
  100. tnd.hWnd = _hwnd;
  101. tnd.uCallbackMessage = _uCallbackMessage;
  102. tnd.uID = _uID;
  103. tnd.uFlags = NIF_MESSAGE | NIF_ICON;
  104. tnd.hIcon = hIcon;
  105. if (pszTooltip)
  106. {
  107. tnd.uFlags |= NIF_TIP;
  108. StringCchCopyA(tnd.szTip, ARRAYSIZE(tnd.szTip), WtoA(pszTooltip));
  109. }
  110. Shell_NotifyIcon(dwMessage, &tnd);
  111. }
  112. _fIconPrev = TRUE;
  113. _fShownInTray = TRUE;
  114. return TRUE;
  115. }
  116. //+---------------------------------------------------------------------------
  117. //
  118. // RemoveIcon
  119. //
  120. //----------------------------------------------------------------------------
  121. BOOL CTrayIconItem::RemoveIcon()
  122. {
  123. NOTIFYICONDATA tnd;
  124. if (_fIconPrev) // this check is esp useful because we delay load shell32.dll
  125. {
  126. tnd.cbSize = sizeof(NOTIFYICONDATA);
  127. tnd.hWnd = _hwnd;
  128. tnd.uCallbackMessage = _uCallbackMessage;
  129. tnd.uID = _uID;
  130. tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  131. tnd.hIcon = NULL;
  132. tnd.szTip[0] = '\0';
  133. Shell_NotifyIcon(NIM_DELETE, &tnd);
  134. }
  135. _fIconPrev = FALSE;
  136. _fShownInTray = FALSE;
  137. return TRUE;
  138. }
  139. //+---------------------------------------------------------------------------
  140. //
  141. // UpdateMenuRectPoint
  142. //
  143. //----------------------------------------------------------------------------
  144. BOOL CTrayIconItem::UpdateMenuRectPoint()
  145. {
  146. HWND hwndNotify = _ptiwnd->GetNotifyWnd();
  147. GetClientRect(hwndNotify, &_rcClick);
  148. ClientToScreen(hwndNotify, (LPPOINT)&_rcClick.left);
  149. ClientToScreen(hwndNotify, (LPPOINT)&_rcClick.right);
  150. GetCursorPos(&_ptClick);
  151. // *ppt = *(LPPOINT)prc;
  152. // MapWindowPoints(hwndNotify, NULL, ppt, 2);
  153. return TRUE;
  154. }
  155. //////////////////////////////////////////////////////////////////////////////
  156. //
  157. // CButtonIconItem
  158. //
  159. //////////////////////////////////////////////////////////////////////////////
  160. //+---------------------------------------------------------------------------
  161. //
  162. // ctor
  163. //
  164. //----------------------------------------------------------------------------
  165. CButtonIconItem::CButtonIconItem(CTrayIconWnd *ptiwnd, BOOL fMenuButtonItem) : CTrayIconItem(ptiwnd)
  166. {
  167. _fMenuButtonItem = fMenuButtonItem;
  168. }
  169. //+---------------------------------------------------------------------------
  170. //
  171. // dtor
  172. //
  173. //----------------------------------------------------------------------------
  174. CButtonIconItem::~CButtonIconItem()
  175. {
  176. }
  177. //+---------------------------------------------------------------------------
  178. //
  179. // OnMsg
  180. //
  181. //----------------------------------------------------------------------------
  182. BOOL CButtonIconItem::OnMsg(WPARAM wParam, LPARAM lParam)
  183. {
  184. CTipbarThread *ptt;
  185. if ((lParam == WM_LBUTTONDOWN) || (lParam == WM_RBUTTONDOWN) ||
  186. (lParam == WM_LBUTTONDBLCLK) || (lParam == WM_RBUTTONDBLCLK))
  187. {
  188. if (_ptiwnd->_fInTrayMenu)
  189. return FALSE;
  190. g_pTipbarWnd->CancelMenu();
  191. _ptiwnd->_uCurCallbackMessage = _uCallbackMessage;
  192. _ptiwnd->_uCurMouseMessage = (UINT)lParam;
  193. ::KillTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG);
  194. ::SetTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG, g_uTimerElapseTRAYWNDONDELAYMSG, NULL);
  195. ptt = g_pTipbarWnd->GetFocusThread();
  196. g_pTipbarWnd->RestoreLastFocus(&_dwThreadFocus, TRUE);
  197. if (ptt && (ptt->_dwThreadId == _dwThreadFocus))
  198. g_pTipbarWnd->SetWaitNotifyThread(_dwThreadFocus);
  199. else
  200. g_pTipbarWnd->SetWaitNotifyThread(0);
  201. UpdateMenuRectPoint();
  202. }
  203. return TRUE;
  204. }
  205. //+---------------------------------------------------------------------------
  206. //
  207. // OnDelayMsg
  208. //
  209. //----------------------------------------------------------------------------
  210. BOOL CButtonIconItem::OnDelayMsg(UINT uMsg)
  211. {
  212. CTipbarThread *ptt;
  213. CTipbarButtonItem *pLangBtn;
  214. BOOL bRet = FALSE;
  215. _ptiwnd->_fInTrayMenu = TRUE;
  216. Assert((uMsg == WM_LBUTTONDOWN) || (uMsg == WM_RBUTTONDOWN) ||
  217. (uMsg == WM_LBUTTONDBLCLK) || (uMsg == WM_RBUTTONDBLCLK));
  218. g_pTipbarWnd->SetWaitNotifyThread(0);
  219. if (!_dwThreadFocus)
  220. {
  221. //
  222. // we failed to set foreground at OnMsg.
  223. // so we try again here.
  224. //
  225. g_pTipbarWnd->RestoreLastFocus(&_dwThreadFocus, TRUE);
  226. // if (!_dwThreadFocus)
  227. // {
  228. //
  229. // ok now we give up to restore focus.
  230. //
  231. // MessageBeep(0);
  232. // goto Exit;
  233. // }
  234. }
  235. _dwThreadFocus = 0;
  236. ptt = g_pTipbarWnd->GetFocusThread();
  237. if (!ptt)
  238. goto Exit;
  239. if (g_pTipbarWnd->IsInItemChangeOrDirty(ptt))
  240. {
  241. ::KillTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG);
  242. ::SetTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG, g_uTimerElapseTRAYWNDONDELAYMSG, NULL);
  243. goto Exit;
  244. }
  245. pLangBtn = (CTipbarButtonItem *)(ptt->GetItem(_guidBtnItem));
  246. if (!pLangBtn)
  247. {
  248. if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL))
  249. {
  250. pLangBtn = (CTipbarButtonItem *)(ptt->GetItem(GUID_LBI_INATITEM));
  251. if (!pLangBtn)
  252. goto Exit;
  253. }
  254. else
  255. {
  256. //
  257. // In this case, it is MSUTB's CLBarInatItem.
  258. //
  259. bRet = TRUE;
  260. goto Exit;
  261. }
  262. }
  263. if (uMsg == WM_LBUTTONDOWN)
  264. {
  265. if (_fMenuButtonItem)
  266. {
  267. g_pTipbarWnd->CancelMenu();
  268. pLangBtn->DoModalMenu(&_ptClick, &_rcClick);
  269. }
  270. else
  271. {
  272. pLangBtn->OnLeftClick();
  273. }
  274. }
  275. else if (uMsg == WM_RBUTTONDOWN)
  276. {
  277. if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL) ||
  278. IsEqualGUID(_guidBtnItem, GUID_TFCAT_TIP_KEYBOARD))
  279. {
  280. g_pTipbarWnd->ShowContextMenu(_ptClick, &_rcClick, TRUE);
  281. }
  282. else
  283. {
  284. pLangBtn->OnRightClick();
  285. }
  286. }
  287. else if (uMsg == WM_LBUTTONDBLCLK)
  288. {
  289. if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL))
  290. {
  291. g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_SHOWNORMAL);
  292. }
  293. }
  294. bRet = TRUE;
  295. Exit:
  296. _ptiwnd->_fInTrayMenu = FALSE;
  297. return bRet;
  298. }
  299. //////////////////////////////////////////////////////////////////////////////
  300. //
  301. // CMainIconItem
  302. //
  303. //////////////////////////////////////////////////////////////////////////////
  304. //+---------------------------------------------------------------------------
  305. //
  306. // OnDelayMsg
  307. //
  308. //----------------------------------------------------------------------------
  309. BOOL CMainIconItem::OnDelayMsg(UINT uMsg)
  310. {
  311. BOOL bRet = CButtonIconItem::OnDelayMsg(uMsg);
  312. if (!bRet)
  313. return bRet;
  314. if (uMsg == WM_LBUTTONDBLCLK)
  315. {
  316. if (g_pTipbarWnd->_fIsItemShownInFloatingToolbar)
  317. g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_SHOWNORMAL);
  318. }
  319. else if ((uMsg == WM_LBUTTONDOWN) || (uMsg == WM_RBUTTONDOWN))
  320. {
  321. g_pTipbarWnd->ShowContextMenu(_ptClick, &_rcClick, (uMsg == WM_RBUTTONDOWN));
  322. }
  323. return bRet;
  324. }
  325. //////////////////////////////////////////////////////////////////////////////
  326. //
  327. // CTrayIconWnd
  328. //
  329. //////////////////////////////////////////////////////////////////////////////
  330. //+---------------------------------------------------------------------------
  331. //
  332. // ctor
  333. //
  334. //----------------------------------------------------------------------------
  335. CTrayIconWnd::CTrayIconWnd()
  336. {
  337. _uNextMsg = WM_TIW_START;
  338. _uNextID = TIW_INDICATOR_ID_START;
  339. }
  340. //+---------------------------------------------------------------------------
  341. //
  342. // dtor
  343. //
  344. //----------------------------------------------------------------------------
  345. CTrayIconWnd::~CTrayIconWnd()
  346. {
  347. int nCnt = _rgIconItems.Count();
  348. int i;
  349. for ( i = 0; i < nCnt; i++)
  350. {
  351. CTrayIconItem *pItem = _rgIconItems.Get(i);
  352. delete pItem;
  353. }
  354. }
  355. //+---------------------------------------------------------------------------
  356. //
  357. // CreateWnd
  358. //
  359. //----------------------------------------------------------------------------
  360. HWND CTrayIconWnd::CreateWnd()
  361. {
  362. _hWnd = CreateWindowEx(0, _szWndClass, TEXT(""),
  363. WS_DISABLED,
  364. 0, 0, 0, 0,
  365. NULL, 0, g_hInst, this);
  366. FindTrayEtc();
  367. CTrayIconItem **ppItem;
  368. _ptiiMain = new CMainIconItem(this);
  369. if (_ptiiMain)
  370. {
  371. _ptiiMain->Init(_hWnd);
  372. ppItem = _rgIconItems.Append(1);
  373. if (ppItem)
  374. *ppItem = _ptiiMain;
  375. }
  376. return _hWnd;
  377. }
  378. //+---------------------------------------------------------------------------
  379. //
  380. // RegisterClass
  381. //
  382. //----------------------------------------------------------------------------
  383. BOOL CTrayIconWnd::RegisterClass()
  384. {
  385. WNDCLASSEX wc;
  386. memset(&wc, 0, sizeof(wc));
  387. wc.cbSize = sizeof(wc);
  388. wc.style = CS_HREDRAW | CS_VREDRAW ;
  389. wc.hInstance = g_hInst;
  390. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  391. wc.lpfnWndProc = _WndProc;
  392. wc.lpszClassName = _szWndClass;
  393. ::RegisterClassEx(&wc);
  394. return TRUE;
  395. }
  396. //---------------------------------------------------------------------------
  397. //
  398. // BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
  399. //
  400. // Look at the class names using GetClassName to see if you can find the
  401. // Tray notification Window.
  402. //
  403. //---------------------------------------------------------------------------
  404. static TCHAR szNotifyWindow[] = TEXT("TrayNotifyWnd");
  405. BOOL CALLBACK CTrayIconWnd::EnumChildWndProc(HWND hwnd, LPARAM lParam)
  406. {
  407. char szString[50];
  408. CTrayIconWnd *_this = (CTrayIconWnd *)lParam;
  409. GetClassName(hwnd, (LPSTR) szString, sizeof(szString));
  410. if (0 == lstrcmp(szString, szNotifyWindow))
  411. {
  412. _this->_hwndNotify = hwnd;
  413. return FALSE;
  414. }
  415. return TRUE;
  416. }
  417. BOOL CTrayIconWnd::FindTrayEtc()
  418. {
  419. _hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);
  420. if (!_hwndTray)
  421. {
  422. return FALSE;
  423. }
  424. EnumChildWindows(_hwndTray, (WNDENUMPROC)EnumChildWndProc, (LPARAM)this);
  425. if (!_hwndNotify)
  426. {
  427. return FALSE;
  428. }
  429. _dwThreadIdTray = GetWindowThreadProcessId(_hwndTray, NULL);
  430. _hwndProgman = FindWindow("Progman", NULL);
  431. _dwThreadIdProgman = GetWindowThreadProcessId(_hwndProgman, NULL);
  432. return TRUE;
  433. }
  434. //+---------------------------------------------------------------------------
  435. //
  436. // _WndProc
  437. //
  438. //----------------------------------------------------------------------------
  439. void CTrayIconWnd::CallOnDelayMsg()
  440. {
  441. int nCnt = _rgIconItems.Count();
  442. int i;
  443. BOOL bRet = FALSE;
  444. CTrayIconItem *pItem = NULL;
  445. for ( i = 0; i < nCnt; i++)
  446. {
  447. CTrayIconItem *pItemTemp = _rgIconItems.Get(i);
  448. if (_uCurCallbackMessage == pItemTemp->GetMsg())
  449. {
  450. pItem = pItemTemp;
  451. break;
  452. }
  453. }
  454. if (!pItem)
  455. return;
  456. pItem->OnDelayMsg(_uCurMouseMessage);
  457. }
  458. //+---------------------------------------------------------------------------
  459. //
  460. // _WndProc
  461. //
  462. //----------------------------------------------------------------------------
  463. LRESULT CALLBACK CTrayIconWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  464. {
  465. CTrayIconWnd *_this;
  466. switch (uMsg)
  467. {
  468. case WM_CREATE:
  469. SetThis(hWnd, lParam);
  470. break;
  471. case WM_DESTROY:
  472. SetThis(hWnd, 0);
  473. break;
  474. case WM_TIMER:
  475. {
  476. if (wParam == TRAYICONWND_TIMER_ONDELAYMSG)
  477. {
  478. ::KillTimer(hWnd, TRAYICONWND_TIMER_ONDELAYMSG);
  479. _this = GetThis(hWnd);
  480. if (_this)
  481. _this->CallOnDelayMsg();
  482. }
  483. }
  484. break;
  485. default:
  486. if (uMsg >= WM_USER)
  487. {
  488. _this = GetThis(hWnd);
  489. if (!_this || !_this->OnIconMessage(uMsg, wParam, lParam))
  490. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  491. }
  492. else
  493. {
  494. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  495. }
  496. }
  497. return 0;
  498. }
  499. //+---------------------------------------------------------------------------
  500. //
  501. // SetMainIcon
  502. //
  503. //----------------------------------------------------------------------------
  504. BOOL CTrayIconWnd::SetMainIcon(HKL hkl)
  505. {
  506. if (hkl)
  507. {
  508. HICON hIcon;
  509. WCHAR wsz[64];
  510. if (hkl == _ptiiMain->_hkl)
  511. return TRUE;
  512. hIcon = TF_GetLangIcon((LANGID)HandleToUlong(hkl), wsz, ARRAYSIZE(wsz));
  513. if (hIcon)
  514. {
  515. _ptiiMain->SetIcon(hIcon, wsz);
  516. DestroyIcon(hIcon);
  517. }
  518. else
  519. _ptiiMain->SetIcon(LoadIcon(g_hInst,
  520. MAKEINTRESOURCE(ID_ICON_CONTROLBTN)),
  521. CRStr(IDS_CONTROLBTN));
  522. _ptiiMain->_hkl = hkl;
  523. }
  524. else
  525. {
  526. _ptiiMain->RemoveIcon();
  527. _ptiiMain->_hkl = NULL;
  528. }
  529. return TRUE;
  530. }
  531. //+---------------------------------------------------------------------------
  532. //
  533. // OnIconMessage
  534. //
  535. //----------------------------------------------------------------------------
  536. BOOL CTrayIconWnd::OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  537. {
  538. int nCnt = _rgIconItems.Count();
  539. int i;
  540. BOOL bRet = FALSE;
  541. if (g_pTipbarWnd)
  542. g_pTipbarWnd->AttachFocusThread();
  543. for ( i = 0; i < nCnt; i++)
  544. {
  545. CTrayIconItem *pItem = _rgIconItems.Get(i);
  546. if (uMsg == pItem->GetMsg())
  547. {
  548. pItem->OnMsg(wParam, lParam);
  549. bRet = TRUE;
  550. break;
  551. }
  552. }
  553. return bRet;
  554. }
  555. //+---------------------------------------------------------------------------
  556. //
  557. // SetIcon
  558. //
  559. //----------------------------------------------------------------------------
  560. BOOL CTrayIconWnd::SetIcon(REFGUID rguid, BOOL fMenu, HICON hIcon, const WCHAR *pszToolTip)
  561. {
  562. BOOL bRet;
  563. CTrayIconItem *pItem;
  564. pItem = FindIconItem(rguid);
  565. //
  566. // we don't have to create new Itom to be removed.
  567. //
  568. if (!pItem && hIcon)
  569. {
  570. CTrayIconItem **ppItem;
  571. pItem = new CButtonIconItem(this, fMenu);
  572. if (!pItem)
  573. return FALSE;
  574. pItem->_Init(GetWnd(), _uNextMsg, _uNextID, rguid);
  575. _uNextMsg += 2;
  576. _uNextID += 1;
  577. //
  578. // check if these numbers dont go over.
  579. //
  580. Assert(_uNextMsg >= WM_USER);
  581. Assert(_uNextMsg < WM_APP);
  582. Assert(_uNextID < 0x8000000);
  583. ppItem = _rgIconItems.Append(1);
  584. if (ppItem)
  585. *ppItem = pItem;
  586. }
  587. if (!pItem)
  588. return FALSE;
  589. if (hIcon)
  590. bRet = pItem->SetIcon(hIcon, pszToolTip);
  591. else
  592. bRet = pItem->RemoveIcon();
  593. return bRet;
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // RemoveUnusedIcons
  598. //
  599. //----------------------------------------------------------------------------
  600. void CTrayIconWnd::RemoveUnusedIcons(CPtrArray<CTipbarItem> *prgItem)
  601. {
  602. int i,j;
  603. for (i = 0;i < _rgIconItems.Count(); i++)
  604. {
  605. CTrayIconItem *pItem = _rgIconItems.Get(i);
  606. BOOL fFound;
  607. if (IsEqualGUID(GUID_LBI_TRAYMAIN, *pItem->GetGuid()))
  608. continue;
  609. fFound = FALSE;
  610. for (j = 0;j < prgItem->Count(); j++)
  611. {
  612. CTipbarItem *pTipbarItem = prgItem->Get(j);
  613. //
  614. // in case, this item is in tray icon...
  615. // The item may be "show satus" in other thread.
  616. //
  617. // if (!pTipbarItem->IsShown())
  618. // continue;
  619. if (IsEqualGUID(*pTipbarItem->GetGUID(), *pItem->GetGuid()))
  620. {
  621. fFound = TRUE;
  622. break;
  623. }
  624. }
  625. if (!fFound)
  626. {
  627. pItem->RemoveIcon();
  628. }
  629. }
  630. return;
  631. }