Source code of Windows XP (NT5)
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.

371 lines
11 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <trayp.h>
  4. TCHAR const c_szTrayClass[] = TEXT(WNDCLASS_TRAYNOTIFY);
  5. STDAPI_(BOOL) Shell_NotifyIcon(DWORD dwMessage, NOTIFYICONDATA *pnid)
  6. {
  7. HWND hwndTray;
  8. SetLastError(0); // Clean any previous last error (code to help catch another bug)
  9. hwndTray = FindWindow(c_szTrayClass, NULL);
  10. if (hwndTray)
  11. {
  12. COPYDATASTRUCT cds;
  13. TRAYNOTIFYDATA tnd = {0};
  14. DWORD_PTR dwRes = FALSE;
  15. DWORD dwValidFlags;
  16. int cbSize = pnid->cbSize;
  17. if (cbSize == sizeof(*pnid))
  18. {
  19. dwValidFlags = NIF_VALID;
  20. }
  21. // Win2K checked for size of this struct
  22. else if (cbSize == NOTIFYICONDATA_V2_SIZE)
  23. {
  24. dwValidFlags = NIF_VALID_V2;
  25. }
  26. else
  27. {
  28. // This will RIP if the app was buggy and passed stack
  29. // garbage as cbSize. Apps got away with this on Win95
  30. // and NT4 because those versions didn't validate cbSize.
  31. // So if we see a strange cbSize, assume it's the V1 size.
  32. RIP(cbSize == NOTIFYICONDATA_V1_SIZE);
  33. cbSize = NOTIFYICONDATA_V1_SIZE;
  34. dwValidFlags = NIF_VALID_V1;
  35. }
  36. #ifdef _WIN64
  37. // Thunking NOTIFYICONDATA to NOTIFYICONDATA32 is annoying
  38. // on Win64 due to variations in the size of HWND and HICON
  39. // We have to copy each field individually.
  40. tnd.nid.dwWnd = PtrToUlong(pnid->hWnd);
  41. tnd.nid.uID = pnid->uID;
  42. tnd.nid.uFlags = pnid->uFlags;
  43. tnd.nid.uCallbackMessage = pnid->uCallbackMessage;
  44. tnd.nid.dwIcon = PtrToUlong(pnid->hIcon);
  45. // The rest of the fields don't change size between Win32 and
  46. // Win64, so just block copy them over
  47. // Toss in an assertion to make sure
  48. COMPILETIME_ASSERT(
  49. sizeof(NOTIFYICONDATA ) - FIELD_OFFSET(NOTIFYICONDATA , szTip) ==
  50. sizeof(NOTIFYICONDATA32) - FIELD_OFFSET(NOTIFYICONDATA32, szTip));
  51. memcpy(&tnd.nid.szTip, &pnid->szTip, cbSize - FIELD_OFFSET(NOTIFYICONDATA, szTip));
  52. #else
  53. // On Win32, the two structures are the same
  54. COMPILETIME_ASSERT(sizeof(NOTIFYICONDATA) == sizeof(NOTIFYICONDATA32));
  55. memcpy(&tnd.nid, pnid, cbSize);
  56. #endif
  57. tnd.nid.cbSize = sizeof(NOTIFYICONDATA32);
  58. // This will RIP if the app was really buggy and passed stack
  59. // garbage as uFlags.
  60. RIP(!(pnid->uFlags & ~dwValidFlags));
  61. tnd.nid.uFlags &= dwValidFlags;
  62. // Toss in an extra NULL to ensure that the tip is NULL terminated...
  63. if (tnd.nid.uFlags & NIF_TIP)
  64. {
  65. tnd.nid.szTip[ARRAYSIZE(tnd.nid.szTip)-1] = TEXT('\0');
  66. }
  67. if ( (cbSize == sizeof(*pnid)) || (cbSize == NOTIFYICONDATA_V2_SIZE) )
  68. {
  69. if (tnd.nid.uFlags & NIF_INFO)
  70. {
  71. tnd.nid.szInfo[ARRAYSIZE(tnd.nid.szInfo)-1] = TEXT('\0');
  72. tnd.nid.szInfoTitle[ARRAYSIZE(tnd.nid.szInfoTitle)-1] = TEXT('\0');
  73. }
  74. }
  75. if (dwMessage == NIM_SETFOCUS)
  76. {
  77. DWORD dwProcId;
  78. GetWindowThreadProcessId(hwndTray, &dwProcId);
  79. AllowSetForegroundWindow(dwProcId);
  80. }
  81. tnd.dwSignature = NI_SIGNATURE;
  82. tnd.dwMessage = dwMessage;
  83. cds.dwData = TCDM_NOTIFY;
  84. cds.cbData = sizeof(tnd);
  85. cds.lpData = &tnd;
  86. if (SendMessageTimeout(hwndTray, WM_COPYDATA, (WPARAM)pnid->hWnd, (LPARAM)&cds,
  87. SMTO_ABORTIFHUNG | SMTO_BLOCK, 4000, &dwRes))
  88. {
  89. return (BOOL) dwRes;
  90. }
  91. }
  92. return FALSE;
  93. }
  94. #ifdef UNICODE
  95. STDAPI_(BOOL) Shell_NotifyIconA(DWORD dwMessage, NOTIFYICONDATAA *pnid)
  96. {
  97. NOTIFYICONDATAW tndw = {0};
  98. tndw.cbSize = sizeof(tndw);
  99. tndw.hWnd = pnid->hWnd;
  100. tndw.uID = pnid->uID;
  101. tndw.uFlags = pnid->uFlags;
  102. tndw.uCallbackMessage = pnid->uCallbackMessage;
  103. tndw.hIcon = pnid->hIcon;
  104. if (pnid->cbSize == sizeof(*pnid))
  105. {
  106. tndw.dwState = pnid->dwState;
  107. tndw.dwStateMask = pnid->dwStateMask;
  108. tndw.uTimeout = pnid->uTimeout;
  109. tndw.dwInfoFlags = pnid->dwInfoFlags;
  110. }
  111. // Transfer those fields we are aware of as of this writing
  112. else if (pnid->cbSize == NOTIFYICONDATAA_V2_SIZE)
  113. {
  114. tndw.cbSize = NOTIFYICONDATAW_V2_SIZE;
  115. tndw.dwState = pnid->dwState;
  116. tndw.dwStateMask = pnid->dwStateMask;
  117. tndw.uTimeout = pnid->uTimeout;
  118. tndw.dwInfoFlags = pnid->dwInfoFlags;
  119. // This will RIP if the app was really buggy and passed stack
  120. // garbage as uFlags. We have to clear out bogus flags to
  121. // avoid accidentally trying to read from invalid data.
  122. RIP(!(pnid->uFlags & ~NIF_VALID_V2));
  123. tndw.uFlags &= NIF_VALID_V2;
  124. }
  125. else
  126. {
  127. // This will RIP if the app was buggy and passed stack
  128. // garbage as cbSize. Apps got away with this on Win95
  129. // and NT4 because those versions didn't validate cbSize.
  130. // So if we see a strange cbSize, assume it's the V1 size.
  131. RIP(pnid->cbSize == (DWORD)NOTIFYICONDATAA_V1_SIZE);
  132. tndw.cbSize = NOTIFYICONDATAW_V1_SIZE;
  133. // This will RIP if the app was really buggy and passed stack
  134. // garbage as uFlags. We have to clear out bogus flags to
  135. // avoid accidentally trying to read from invalid data.
  136. RIP(!(pnid->uFlags & ~NIF_VALID_V1));
  137. tndw.uFlags &= NIF_VALID_V1;
  138. }
  139. if (tndw.uFlags & NIF_TIP)
  140. SHAnsiToUnicode(pnid->szTip, tndw.szTip, ARRAYSIZE(tndw.szTip));
  141. if (tndw.uFlags & NIF_INFO)
  142. {
  143. SHAnsiToUnicode(pnid->szInfo, tndw.szInfo, ARRAYSIZE(tndw.szInfo));
  144. SHAnsiToUnicode(pnid->szInfoTitle, tndw.szInfoTitle, ARRAYSIZE(tndw.szInfoTitle));
  145. }
  146. if (tndw.uFlags & NIF_GUID)
  147. {
  148. memcpy(&(tndw.guidItem), &(pnid->guidItem), sizeof(pnid->guidItem));
  149. }
  150. return Shell_NotifyIconW(dwMessage, &tndw);
  151. }
  152. #else
  153. STDAPI_(BOOL) Shell_NotifyIconW(DWORD dwMessage, NOTIFYICONDATAW *pnid)
  154. {
  155. return FALSE;
  156. }
  157. #endif
  158. //*** CopyIn -- copy app data in to shared region (and create shared)
  159. // ENTRY/EXIT
  160. // return handle on success, NULL on failure
  161. // pvData app buffer
  162. // cbData count
  163. // dwProcId ...
  164. // NOTES
  165. // should make it handle pvData=NULL for cases where param is OUT not INOUT.
  166. //
  167. HANDLE CopyIn(void *pvData, int cbData, DWORD dwProcId)
  168. {
  169. HANDLE hShared = SHAllocShared(NULL, cbData, dwProcId);
  170. if (hShared)
  171. {
  172. void *pvShared = SHLockShared(hShared, dwProcId);
  173. if (pvShared == NULL)
  174. {
  175. SHFreeShared(hShared, dwProcId);
  176. hShared = NULL;
  177. }
  178. else
  179. {
  180. memcpy(pvShared, pvData, cbData);
  181. SHUnlockShared(pvShared);
  182. }
  183. }
  184. return hShared;
  185. }
  186. // copy out to app data from shared region (and free shared)
  187. // ENTRY/EXIT
  188. // return TRUE on success, FALSE on failure.
  189. // hShared shared data, freed when done
  190. // pvData app buffer
  191. // cbData count
  192. BOOL CopyOut(HANDLE hShared, void *pvData, int cbData, DWORD dwProcId)
  193. {
  194. void *pvShared = SHLockShared(hShared, dwProcId);
  195. if (pvShared)
  196. {
  197. memcpy(pvData, pvShared, cbData);
  198. SHUnlockShared(pvShared);
  199. }
  200. SHFreeShared(hShared, dwProcId);
  201. return (pvShared != 0);
  202. }
  203. STDAPI_(UINT_PTR) SHAppBarMessage(DWORD dwMessage, APPBARDATA *pabd)
  204. {
  205. TRAYAPPBARDATA tabd;
  206. UINT_PTR fret = FALSE;
  207. HWND hwndTray = FindWindow(c_szTrayClass, NULL);
  208. if (hwndTray && (pabd->cbSize <= sizeof(*pabd)))
  209. {
  210. COPYDATASTRUCT cds;
  211. RIP(pabd->cbSize == sizeof(*pabd));
  212. #ifdef _WIN64
  213. tabd.abd.dwWnd = PtrToUlong(pabd->hWnd);
  214. tabd.abd.uCallbackMessage = pabd->uCallbackMessage;
  215. tabd.abd.uEdge = pabd->uEdge;
  216. tabd.abd.rc = pabd->rc;
  217. #else
  218. // Sadly, the Win32 compiler doesn't realize that the code
  219. // sequence above can be optimized into a single memcpy, so
  220. // we need to spoon-feed it...
  221. memcpy(&tabd.abd.dwWnd, &pabd->hWnd,
  222. FIELD_OFFSET(APPBARDATA, lParam) - FIELD_OFFSET(APPBARDATA, hWnd));
  223. #endif
  224. tabd.abd.cbSize = sizeof(tabd.abd);
  225. tabd.abd.lParam = pabd->lParam;
  226. tabd.dwMessage = dwMessage;
  227. tabd.hSharedABD = PtrToUlong(NULL);
  228. tabd.dwProcId = GetCurrentProcessId();
  229. cds.dwData = TCDM_APPBAR;
  230. cds.cbData = sizeof(tabd);
  231. cds.lpData = &tabd;
  232. //
  233. // These are the messages that return data back to the caller.
  234. //
  235. switch (dwMessage)
  236. {
  237. case ABM_QUERYPOS:
  238. case ABM_SETPOS:
  239. case ABM_GETTASKBARPOS:
  240. tabd.hSharedABD = PtrToUlong(CopyIn(&tabd.abd, sizeof(tabd.abd), tabd.dwProcId));
  241. if (tabd.hSharedABD == PtrToUlong(NULL))
  242. return FALSE;
  243. break;
  244. }
  245. fret = SendMessage(hwndTray, WM_COPYDATA, (WPARAM)pabd->hWnd, (LPARAM)&cds);
  246. if (tabd.hSharedABD)
  247. {
  248. if (CopyOut(UlongToPtr(tabd.hSharedABD), &tabd.abd, sizeof(tabd.abd), tabd.dwProcId))
  249. {
  250. #ifdef _WIN64
  251. pabd->hWnd = (HWND)UIntToPtr(tabd.abd.dwWnd);
  252. pabd->uCallbackMessage = tabd.abd.uCallbackMessage;
  253. pabd->uEdge = tabd.abd.uEdge;
  254. pabd->rc = tabd.abd.rc;
  255. #else
  256. // Sadly, the Win32 compiler doesn't realize that the code
  257. // sequence above can be optimized into a single memcpy, so
  258. // we need to spoon-feed it...
  259. memcpy(&pabd->hWnd, &tabd.abd.dwWnd,
  260. FIELD_OFFSET(APPBARDATA, lParam) - FIELD_OFFSET(APPBARDATA, hWnd));
  261. #endif
  262. pabd->lParam = (LPARAM)tabd.abd.lParam;
  263. }
  264. else
  265. fret = FALSE;
  266. }
  267. }
  268. return fret;
  269. }
  270. HRESULT _TrayLoadInProc(REFCLSID rclsid, DWORD dwFlags)
  271. {
  272. HWND hwndTray = FindWindow(c_szTrayClass, NULL);
  273. if (hwndTray)
  274. {
  275. COPYDATASTRUCT cds;
  276. LOADINPROCDATA lipd;
  277. lipd.clsid = rclsid;
  278. lipd.dwFlags = dwFlags;
  279. cds.dwData = TCDM_LOADINPROC;
  280. cds.cbData = sizeof(lipd);
  281. cds.lpData = &lipd;
  282. return (HRESULT)SendMessage(hwndTray, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
  283. }
  284. else
  285. {
  286. return E_FAIL;
  287. }
  288. }
  289. STDAPI SHLoadInProc(REFCLSID rclsid)
  290. {
  291. return _TrayLoadInProc(rclsid, LIPF_ENABLE);
  292. }
  293. STDAPI SHEnableServiceObject(REFCLSID rclsid, BOOL fEnable)
  294. {
  295. DWORD dwFlags = fEnable ? LIPF_ENABLE | LIPF_HOLDREF : LIPF_HOLDREF;
  296. return _TrayLoadInProc(rclsid, dwFlags);
  297. }
  298. // used to implement a per process reference count for the main thread
  299. // the browser msg loop and the proxy desktop use this to let other threads
  300. // extend their lifetime.
  301. // there is a thread level equivelent of this, shlwapi SHGetThreadRef()/SHSetThreadRef()
  302. IUnknown *g_punkProcessRef = NULL;
  303. STDAPI_(void) SHSetInstanceExplorer(IUnknown *punk)
  304. {
  305. g_punkProcessRef = punk;
  306. }
  307. // This should be thread safe since we grab the punk locally before
  308. // checking/using it, plus it never gets freed since it is not actually
  309. // alloced in Explorer so we can always use it
  310. STDAPI SHGetInstanceExplorer(IUnknown **ppunk)
  311. {
  312. *ppunk = g_punkProcessRef;
  313. if (*ppunk)
  314. {
  315. (*ppunk)->AddRef();
  316. return NOERROR;
  317. }
  318. return E_FAIL;
  319. }