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.

276 lines
8.5 KiB

  1. #include "shellprv.h"
  2. #include "EBalloon.h"
  3. class CErrorBalloon
  4. {
  5. public:
  6. CErrorBalloon();
  7. ~CErrorBalloon();
  8. HRESULT ShowToolTip(HINSTANCE hInstance, HWND hwndTarget, const POINT *ppt, LPTSTR pszTitle, LPTSTR pszMessage, DWORD dwIconIndex, int iTimeout);
  9. void HideToolTip(BOOL fDestroy);
  10. protected:
  11. HWND _CreateToolTipWindow(HWND hwnd);
  12. static LRESULT CALLBACK _SubclassTipProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, ULONG_PTR dwRefData);
  13. HWND _hwndTarget; // the targeted control hwnd
  14. HWND _hwndToolTip; // the tooltip control
  15. UINT_PTR _uTimerID; // the timer id
  16. };
  17. #define ERRORBALLOONTIMERID 1000
  18. #define EB_WARNINGBELOW 0x00000000 // default value. Balloon tooltips will be shown below the window by default.
  19. #define EB_WARNINGABOVE 0x00000004 // Ballon tooltips will be shown above the window by default.
  20. #define EB_WARNINGCENTERED 0x00000008 // Ballon tooltips will be shown pointing to the center of the window.
  21. CErrorBalloon::CErrorBalloon()
  22. {
  23. // our allocation function should have zeroed our memory. Check to make sure:
  24. ASSERT(0==_hwndToolTip);
  25. ASSERT(0==_uTimerID);
  26. }
  27. CErrorBalloon::~CErrorBalloon()
  28. {
  29. ASSERT(0==_hwndToolTip);
  30. ASSERT(0==_hwndTarget);
  31. }
  32. LRESULT CALLBACK CErrorBalloon::_SubclassTipProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, ULONG_PTR dwRefData)
  33. {
  34. UNREFERENCED_PARAMETER(uID);
  35. CErrorBalloon * pthis = (CErrorBalloon*)dwRefData;
  36. switch (uMsg)
  37. {
  38. case WM_MOUSEACTIVATE: // Never activate tooltip
  39. pthis->HideToolTip(FALSE);
  40. return MA_NOACTIVATEANDEAT;
  41. case WM_DESTROY:
  42. pthis->HideToolTip(TRUE);
  43. delete pthis;
  44. break;
  45. case WM_TIMER:
  46. if (wParam == ERRORBALLOONTIMERID)
  47. {
  48. pthis->HideToolTip(FALSE);
  49. return 0;
  50. }
  51. break;
  52. default:
  53. break;
  54. }
  55. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  56. }
  57. HRESULT CErrorBalloon::ShowToolTip(HINSTANCE hinst, HWND hwndTarget, const POINT *ppt, LPTSTR pszTitle, LPTSTR pszMessage, DWORD dwIconIndex, int iTimeout)
  58. {
  59. if (_hwndToolTip)
  60. {
  61. HideToolTip(FALSE);
  62. }
  63. HWND hwnd = _CreateToolTipWindow(hwndTarget);
  64. if (hwnd)
  65. {
  66. int x, y;
  67. x = ppt->x;
  68. y = ppt->y;
  69. SendMessage(hwnd, TTM_TRACKPOSITION, 0, MAKELONG(x,y));
  70. if (pszTitle)
  71. {
  72. SendMessage(hwnd, TTM_SETTITLE, (WPARAM)dwIconIndex, (LPARAM)pszTitle);
  73. }
  74. TOOLINFO ti = {0};
  75. ti.cbSize = TTTOOLINFOW_V2_SIZE;
  76. ti.hwnd = hwnd;
  77. ti.uId = 1;
  78. ti.lpszText = pszMessage;
  79. SendMessage(hwnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  80. // Show the tooltip
  81. SendMessage(hwnd, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti);
  82. _uTimerID = SetTimer(hwnd, ERRORBALLOONTIMERID, iTimeout, NULL);
  83. if (SetWindowSubclass(hwnd, CErrorBalloon::_SubclassTipProc, (UINT_PTR)this, (LONG_PTR)this))
  84. {
  85. _hwndToolTip = hwnd;
  86. return S_OK;
  87. }
  88. // we blew the subclassing
  89. DestroyWindow(hwnd);
  90. }
  91. return E_FAIL;
  92. }
  93. // CreateToolTipWindow
  94. //
  95. // Creates our tooltip control. We share this one tooltip control and use it for all invalid
  96. // input messages. The control is hiden when not in use and then shown when needed.
  97. //
  98. HWND CErrorBalloon::_CreateToolTipWindow(HWND hwndTarget)
  99. {
  100. HWND hwnd = CreateWindow(
  101. TOOLTIPS_CLASS,
  102. NULL,
  103. WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON,
  104. CW_USEDEFAULT,
  105. CW_USEDEFAULT,
  106. CW_USEDEFAULT,
  107. CW_USEDEFAULT,
  108. hwndTarget,
  109. NULL,
  110. GetModuleHandle(NULL),
  111. NULL);
  112. ASSERT(!_hwndToolTip);
  113. ASSERT(!_hwndTarget);
  114. if (hwnd)
  115. {
  116. TOOLINFO ti = {0};
  117. ti.cbSize = TTTOOLINFOW_V2_SIZE;
  118. ti.uFlags = TTF_TRACK;
  119. ti.hwnd = hwnd;
  120. ti.uId = 1;
  121. // set the version so we can have non buggy mouse event forwarding
  122. SendMessage(hwnd, CCM_SETVERSION, COMCTL32_VERSION, 0);
  123. SendMessage(hwnd, TTM_ADDTOOL, 0, (LPARAM)&ti);
  124. SendMessage(hwnd, TTM_SETMAXTIPWIDTH, 0, 300);
  125. // set tink-tink?
  126. }
  127. return hwnd;
  128. }
  129. void CErrorBalloon::HideToolTip(BOOL fOnDestroy)
  130. {
  131. // When the timer fires we hide the tooltip window
  132. if (fOnDestroy)
  133. {
  134. // we need to tear everything down
  135. if (_uTimerID)
  136. {
  137. KillTimer(_hwndTarget, ERRORBALLOONTIMERID);
  138. _uTimerID = 0;
  139. }
  140. if (_hwndTarget)
  141. {
  142. // RemoveWindowSubclass(_hwndTarget, CErrorBalloon::_SubclassTargetProc, (UINT_PTR)this);
  143. RemoveProp(_hwndTarget, L"ShellConditionalBalloon");
  144. _hwndTarget = NULL;
  145. }
  146. if (_hwndToolTip)
  147. {
  148. RemoveWindowSubclass(_hwndToolTip, CErrorBalloon::_SubclassTipProc, (UINT_PTR)this);
  149. SendMessage(_hwndToolTip, TTM_TRACKACTIVATE, FALSE, 0);
  150. _hwndToolTip = NULL;
  151. }
  152. }
  153. else
  154. DestroyWindow(_hwndToolTip);
  155. }
  156. STDAPI SHShowConditionalBalloon(HWND hwnd, CBSHOW show, CONDITIONALBALLOON *pscb)
  157. {
  158. HRESULT hr = E_OUTOFMEMORY;
  159. if (hwnd)
  160. {
  161. CErrorBalloon *peb = (CErrorBalloon *) GetProp(hwnd, L"ShellConditionalBalloon");
  162. if (show != CBSHOW_HIDE && pscb)
  163. {
  164. DWORD dw = 0;
  165. BOOL fShow = TRUE;
  166. HKEY hkSession = NULL;
  167. if (SUCCEEDED(SHCreateSessionKey(MAXIMUM_ALLOWED, &hkSession)))
  168. {
  169. fShow = (ERROR_SUCCESS != SHGetValue(hkSession, NULL, pscb->pszValue, NULL, NULL, NULL));
  170. }
  171. // check cLimit
  172. if (fShow && pscb->cLimit)
  173. {
  174. ASSERT(pscb->hKey);
  175. DWORD cb = sizeof(dw);
  176. SHGetValue(pscb->hKey, pscb->pszSubKey, pscb->pszValue, NULL, &dw, &cb);
  177. fShow = dw < pscb->cLimit;
  178. }
  179. if (fShow)
  180. {
  181. // we need to show something
  182. if (!peb)
  183. {
  184. peb = new CErrorBalloon();
  185. if (peb && !SetProp(hwnd, L"ShellConditionalBalloon", peb))
  186. {
  187. delete peb;
  188. peb = NULL;
  189. }
  190. }
  191. if (peb)
  192. {
  193. TCHAR szTitle[MAX_PATH];
  194. TCHAR szMessage[INFOTIPSIZE];
  195. LoadString(pscb->hinst, pscb->idsTitle, szTitle, ARRAYSIZE(szTitle));
  196. LoadString(pscb->hinst, pscb->idsMessage, szMessage, ARRAYSIZE(szMessage));
  197. // Set the tooltip display point
  198. //if (pscb->pt.x == -1 && pscb->pt.y == -1)
  199. // _GetTipPoint(hwndTarget, &pscb->pt);
  200. DWORD dwMSecs = pscb->dwMSecs;
  201. if (dwMSecs == 0)
  202. {
  203. // default to 1 sec / 10 chars;
  204. dwMSecs = lstrlen(szMessage) * 100;
  205. if (dw == 0)
  206. dwMSecs *= 5; // first time put it up for a while
  207. }
  208. hr = peb->ShowToolTip(pscb->hinst, hwnd, &pscb->pt, szTitle, szMessage, pscb->ttiIcon, dwMSecs);
  209. if (FAILED(hr))
  210. {
  211. RemoveProp(hwnd, L"ShellConditionalBalloon");
  212. delete peb;
  213. }
  214. if (pscb->cLimit)
  215. {
  216. dw++;
  217. SHSetValueW(pscb->hKey, pscb->pszSubKey, pscb->pszValue, REG_DWORD, &dw, sizeof(dw));
  218. }
  219. }
  220. }
  221. else
  222. hr = S_FALSE;
  223. if (hkSession)
  224. {
  225. SHSetValueW(hkSession, NULL, pscb->pszValue, REG_NONE, NULL, NULL);
  226. RegCloseKey(hkSession);
  227. }
  228. }
  229. else if (peb)
  230. {
  231. peb->HideToolTip(FALSE);
  232. // we delete ourselves during WM_DESTROY
  233. }
  234. }
  235. return hr;
  236. }