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.

1504 lines
51 KiB

  1. #include "ctlspriv.h"
  2. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  3. #include <shsemip.h> // SEN_* notifications
  4. #include <commdlg.h> // CDN_* notifications
  5. // Miscellaneous hackery needed in order to include shlobjp.h
  6. #define CONTROLINFO OAIDL_CONTROLINFO
  7. #define LPCONTROLINFO LPOAIDL_CONTROLINFO
  8. #include <shlobj.h>
  9. #include <shlobjp.h> // NMVIEWFOLDER structure
  10. #undef CONTROLINFO
  11. #undef LPCONTROLINFO
  12. //
  13. // Helper function for WOW on NT.
  14. //
  15. // WOW needs to know the size of the notify structure associated with a
  16. // notification. If a 32-bit window has been subclassed by a 16-bit app,
  17. // WOW needs to copy the notify structure into 16-bit space, and then when
  18. // the 16-bit guy does a CallWindowProc(), they have to copy it back into
  19. // 32-bit space. Without the size information, you fault on the
  20. // 32-bit side because the notify structure is incomplete.
  21. //
  22. // Some notifications have multiple structures associated with them, in
  23. // which case you should return the largest possible valid structure.
  24. //
  25. STDAPI_(UINT) WOWGetNotifySize(UINT code)
  26. {
  27. switch (code) {
  28. // Generic comctl32 notifications
  29. case NM_OUTOFMEMORY: return sizeof(NMHDR); // not used
  30. case NM_CLICK: return max(max(
  31. sizeof(NMHDR), // tab, treeview
  32. sizeof(NMCLICK)), // toolbar, statusbar
  33. sizeof(NMITEMACTIVATE)); // listview
  34. case NM_DBLCLK: return max(max(
  35. sizeof(NMHDR), // tab, treeview
  36. sizeof(NMCLICK)), // toolbar, statusbar
  37. sizeof(NMITEMACTIVATE)); // listview
  38. case NM_RETURN: return sizeof(NMHDR);
  39. case NM_RCLICK: return max(max(
  40. sizeof(NMHDR), // header, listview report mode, treeview
  41. sizeof(NMCLICK)), // toolbar, statusbar
  42. sizeof(NMITEMACTIVATE)); // listview icon mode
  43. case NM_RDBLCLK: return max(max(
  44. sizeof(NMHDR), // treeview
  45. sizeof(NMCLICK)), // toolbar, statusbar
  46. sizeof(NMITEMACTIVATE)); // listview
  47. case NM_SETFOCUS: return sizeof(NMHDR);
  48. case NM_KILLFOCUS: return sizeof(NMHDR);
  49. case NM_STARTWAIT: return sizeof(NMHDR); // not used
  50. case NM_ENDWAIT: return sizeof(NMHDR); // not used
  51. case NM_BTNCLK: return sizeof(NMHDR); // not used
  52. case NM_CUSTOMDRAW: return sizeof(NMCUSTOMDRAW);
  53. case NM_HOVER: return sizeof(NMHDR);
  54. case NM_NCHITTEST: return sizeof(NMMOUSE);
  55. case NM_KEYDOWN: return sizeof(NMKEY);
  56. case NM_RELEASEDCAPTURE: return sizeof(NMHDR);
  57. case NM_SETCURSOR: return sizeof(NMMOUSE);
  58. case NM_CHAR: return sizeof(NMCHAR);
  59. case NM_TOOLTIPSCREATED: return sizeof(NMTOOLTIPSCREATED);
  60. case NM_LDOWN: return sizeof(NMCLICK);
  61. case NM_RDOWN: return sizeof(NMCLICK); // not used
  62. // Listview notifications
  63. case LVN_ITEMCHANGING: return sizeof(NMLISTVIEW);
  64. case LVN_ITEMCHANGED: return sizeof(NMLISTVIEW);
  65. case LVN_INSERTITEM: return sizeof(NMLISTVIEW);
  66. case LVN_DELETEITEM: return sizeof(NMLISTVIEW);
  67. case LVN_DELETEALLITEMS: return sizeof(NMLISTVIEW);
  68. case LVN_BEGINLABELEDITA: return sizeof(NMLVDISPINFOA);
  69. case LVN_BEGINLABELEDITW: return sizeof(NMLVDISPINFOW);
  70. case LVN_ENDLABELEDITA: return sizeof(NMLVDISPINFOA);
  71. case LVN_ENDLABELEDITW: return sizeof(NMLVDISPINFOW);
  72. case LVN_COLUMNCLICK: return sizeof(NMLISTVIEW);
  73. case LVN_BEGINDRAG: return sizeof(NMITEMACTIVATE);
  74. case LVN_BEGINRDRAG: return sizeof(NMITEMACTIVATE); // not used
  75. case LVN_ENDDRAG: return sizeof(NMITEMACTIVATE); // not used
  76. case LVN_ENDRDRAG: return sizeof(NMITEMACTIVATE); // not used
  77. case LVN_ODCACHEHINT: return sizeof(NMLVCACHEHINT);
  78. case LVN_ODFINDITEMA: return sizeof(NMLVFINDITEMA);
  79. case LVN_ODFINDITEMW: return sizeof(NMLVFINDITEMW);
  80. case LVN_ITEMACTIVATE: return sizeof(NMITEMACTIVATE);
  81. case LVN_ODSTATECHANGED: return sizeof(NMLVODSTATECHANGE);
  82. // case LVN_PEN: // Pen Windows slackers
  83. case LVN_HOTTRACK: return sizeof(NMLISTVIEW);
  84. case LVN_GETDISPINFOA: return sizeof(NMLVDISPINFOA);
  85. case LVN_GETDISPINFOW: return sizeof(NMLVDISPINFOW);
  86. case LVN_SETDISPINFOA: return sizeof(NMLVDISPINFOA);
  87. case LVN_SETDISPINFOW: return sizeof(NMLVDISPINFOW);
  88. case LVN_KEYDOWN: return sizeof(NMLVKEYDOWN);
  89. case LVN_MARQUEEBEGIN: return sizeof(NMITEMACTIVATE);
  90. case LVN_GETINFOTIPA: return sizeof(NMLVGETINFOTIPA);
  91. case LVN_GETINFOTIPW: return sizeof(NMLVGETINFOTIPW);
  92. case LVN_GETEMPTYTEXTA: return sizeof(NMLVDISPINFOA);
  93. case LVN_GETEMPTYTEXTW: return sizeof(NMLVDISPINFOW);
  94. case LVN_INCREMENTALSEARCHA:return sizeof(NMLVFINDITEMA);
  95. case LVN_INCREMENTALSEARCHW:return sizeof(NMLVFINDITEMW);
  96. // Property sheet notifications
  97. case PSN_SETACTIVE: return sizeof(PSHNOTIFY);
  98. case PSN_KILLACTIVE: return sizeof(PSHNOTIFY);
  99. case PSN_APPLY: return sizeof(PSHNOTIFY);
  100. case PSN_RESET: return sizeof(PSHNOTIFY);
  101. case PSN_HASHELP: return sizeof(PSHNOTIFY); // not used
  102. case PSN_HELP: return sizeof(PSHNOTIFY);
  103. case PSN_WIZBACK: return sizeof(PSHNOTIFY);
  104. case PSN_WIZNEXT: return sizeof(PSHNOTIFY);
  105. case PSN_WIZFINISH: return sizeof(PSHNOTIFY);
  106. case PSN_QUERYCANCEL: return sizeof(PSHNOTIFY);
  107. case PSN_GETOBJECT: return sizeof(NMOBJECTNOTIFY);
  108. case PSN_LASTCHANCEAPPLY: return sizeof(PSHNOTIFY);
  109. case PSN_TRANSLATEACCELERATOR:
  110. return sizeof(PSHNOTIFY);
  111. case PSN_QUERYINITIALFOCUS: return sizeof(PSHNOTIFY);
  112. // Header notifications
  113. case HDN_ITEMCHANGINGA: return sizeof(NMHEADERA);
  114. case HDN_ITEMCHANGINGW: return sizeof(NMHEADERW);
  115. case HDN_ITEMCHANGEDA: return sizeof(NMHEADERA);
  116. case HDN_ITEMCHANGEDW: return sizeof(NMHEADERW);
  117. case HDN_ITEMCLICKA: return sizeof(NMHEADERA);
  118. case HDN_ITEMCLICKW: return sizeof(NMHEADERW);
  119. case HDN_ITEMDBLCLICKA: return sizeof(NMHEADERA);
  120. case HDN_ITEMDBLCLICKW: return sizeof(NMHEADERW);
  121. case HDN_DIVIDERDBLCLICKA: return sizeof(NMHEADERA);
  122. case HDN_DIVIDERDBLCLICKW: return sizeof(NMHEADERW);
  123. case HDN_BEGINTRACKA: return sizeof(NMHEADERA);
  124. case HDN_BEGINTRACKW: return sizeof(NMHEADERW);
  125. case HDN_ENDTRACKA: return sizeof(NMHEADERA);
  126. case HDN_ENDTRACKW: return sizeof(NMHEADERW);
  127. case HDN_TRACKA: return sizeof(NMHEADERA);
  128. case HDN_TRACKW: return sizeof(NMHEADERW);
  129. case HDN_GETDISPINFOA: return sizeof(NMHDDISPINFOA);
  130. case HDN_GETDISPINFOW: return sizeof(NMHDDISPINFOW);
  131. case HDN_BEGINDRAG: return sizeof(NMHEADER); // No strings
  132. case HDN_ENDDRAG: return sizeof(NMHEADER); // No strings
  133. case HDN_FILTERCHANGE: return sizeof(NMHEADER); // No strings
  134. case HDN_FILTERBTNCLICK: return sizeof(NMHDFILTERBTNCLICK);
  135. // Treeview notifications
  136. case TVN_SELCHANGINGA: return sizeof(NMTREEVIEWA);
  137. case TVN_SELCHANGINGW: return sizeof(NMTREEVIEWW);
  138. case TVN_SELCHANGEDA: return sizeof(NMTREEVIEWA);
  139. case TVN_SELCHANGEDW: return sizeof(NMTREEVIEWW);
  140. case TVN_GETDISPINFOA: return sizeof(NMTVDISPINFOA);
  141. case TVN_GETDISPINFOW: return sizeof(NMTVDISPINFOW);
  142. case TVN_SETDISPINFOA: return sizeof(NMTVDISPINFOA);
  143. case TVN_SETDISPINFOW: return sizeof(NMTVDISPINFOW);
  144. case TVN_ITEMEXPANDINGA: return sizeof(NMTREEVIEWA);
  145. case TVN_ITEMEXPANDINGW: return sizeof(NMTREEVIEWW);
  146. case TVN_ITEMEXPANDEDA: return sizeof(NMTREEVIEWA);
  147. case TVN_ITEMEXPANDEDW: return sizeof(NMTREEVIEWW);
  148. case TVN_BEGINDRAGA: return sizeof(NMTREEVIEWA);
  149. case TVN_BEGINDRAGW: return sizeof(NMTREEVIEWW);
  150. case TVN_BEGINRDRAGA: return sizeof(NMTREEVIEWA);
  151. case TVN_BEGINRDRAGW: return sizeof(NMTREEVIEWW);
  152. case TVN_DELETEITEMA: return sizeof(NMTREEVIEWA);
  153. case TVN_DELETEITEMW: return sizeof(NMTREEVIEWW);
  154. case TVN_BEGINLABELEDITA: return sizeof(NMTVDISPINFOA);
  155. case TVN_BEGINLABELEDITW: return sizeof(NMTVDISPINFOW);
  156. case TVN_ENDLABELEDITA: return sizeof(NMTVDISPINFOA);
  157. case TVN_ENDLABELEDITW: return sizeof(NMTVDISPINFOW);
  158. case TVN_KEYDOWN: return sizeof(NMTVKEYDOWN);
  159. case TVN_GETINFOTIPA: return sizeof(NMTVGETINFOTIPA);
  160. case TVN_GETINFOTIPW: return sizeof(NMTVGETINFOTIPW);
  161. case TVN_SINGLEEXPAND: return sizeof(NMTREEVIEW); // No strings
  162. // Rundll32 notifications
  163. case RDN_TASKINFO: return sizeof(RUNDLL_NOTIFY);
  164. // Tooltip notifications
  165. case TTN_GETDISPINFOA: return sizeof(NMTTDISPINFOA);
  166. case TTN_GETDISPINFOW: return sizeof(NMTTDISPINFOW);
  167. case TTN_SHOW: return sizeof(NMTTSHOWINFO);
  168. case TTN_POP: return sizeof(NMHDR);
  169. // Tab control notifications
  170. // WE ARE SUCH HORRIBLE SLACKERS!
  171. //
  172. // Even though commctrl.h says that the shell reserved range is from
  173. // -580 to -589, shsemip.h defines SEN_FIRST as -550, which conflicts
  174. // with TCN_KEYDOWN, so now TCN_KEYDOWN and SEN_DDEEXECUTE have the
  175. // same value.
  176. #ifdef WINNT
  177. case TCN_KEYDOWN: return max(sizeof(NMTCKEYDOWN),
  178. sizeof(NMVIEWFOLDERW));
  179. #else
  180. case TCN_KEYDOWN: return max(sizeof(NMTCKEYDOWN),
  181. sizeof(NMVIEWFOLDERA));
  182. #endif
  183. case TCN_SELCHANGE: return sizeof(NMHDR);
  184. case TCN_SELCHANGING: return sizeof(NMHDR);
  185. case TCN_GETOBJECT: return sizeof(NMOBJECTNOTIFY);
  186. case TCN_FOCUSCHANGE: return sizeof(NMHDR);
  187. // Shell32 notifications
  188. #if 0 // see comment at TCN_KEYDOWN
  189. case SEN_DDEEXECUTE:
  190. #ifdef WINNT
  191. return sizeof(NMVIEWFOLDERW);
  192. #else
  193. return sizeof(NMVIEWFOLDERA);
  194. #endif
  195. #endif
  196. // Comdlg32 notifications
  197. case CDN_INITDONE: return max(sizeof(OFNOTIFYA),
  198. sizeof(OFNOTIFYW));
  199. case CDN_SELCHANGE: return max(sizeof(OFNOTIFYA),
  200. sizeof(OFNOTIFYW));
  201. case CDN_FOLDERCHANGE: return max(sizeof(OFNOTIFYA),
  202. sizeof(OFNOTIFYW));
  203. case CDN_SHAREVIOLATION: return max(sizeof(OFNOTIFYA),
  204. sizeof(OFNOTIFYW));
  205. case CDN_HELP: return max(sizeof(OFNOTIFYA),
  206. sizeof(OFNOTIFYW));
  207. case CDN_FILEOK: return max(sizeof(OFNOTIFYA),
  208. sizeof(OFNOTIFYW));
  209. case CDN_TYPECHANGE: return max(sizeof(OFNOTIFYA),
  210. sizeof(OFNOTIFYW));
  211. case CDN_INCLUDEITEM: return max(sizeof(OFNOTIFYEXA),
  212. sizeof(OFNOTIFYEXW));
  213. // Toolbar notifications
  214. case TBN_GETBUTTONINFOA: return sizeof(NMTOOLBARA);
  215. case TBN_GETBUTTONINFOW: return sizeof(NMTOOLBARW);
  216. case TBN_BEGINDRAG: return sizeof(NMTOOLBAR); // No strings
  217. case TBN_ENDDRAG: return sizeof(NMTOOLBAR); // No strings
  218. case TBN_BEGINADJUST: return sizeof(NMHDR);
  219. case TBN_ENDADJUST: return sizeof(NMHDR);
  220. case TBN_RESET: return sizeof(NMTBCUSTOMIZEDLG);
  221. case TBN_QUERYINSERT: return sizeof(NMTOOLBAR); // No strings
  222. case TBN_QUERYDELETE: return sizeof(NMTOOLBAR); // No strings
  223. case TBN_TOOLBARCHANGE: return sizeof(NMHDR);
  224. case TBN_CUSTHELP: return sizeof(NMHDR);
  225. case TBN_DROPDOWN: return sizeof(NMTOOLBAR); // No strings
  226. case TBN_CLOSEUP: return sizeof(NMHDR); // not used
  227. case TBN_GETOBJECT: return sizeof(NMOBJECTNOTIFY);
  228. case TBN_HOTITEMCHANGE: return sizeof(NMTBHOTITEM);
  229. case TBN_DRAGOUT: return sizeof(NMTOOLBAR); // No strings
  230. case TBN_DELETINGBUTTON: return sizeof(NMTOOLBAR); // No strings
  231. case TBN_GETDISPINFOA: return sizeof(NMTBDISPINFOA);
  232. case TBN_GETDISPINFOW: return sizeof(NMTBDISPINFOW);
  233. case TBN_GETINFOTIPA: return sizeof(NMTBGETINFOTIPA);
  234. case TBN_GETINFOTIPW: return sizeof(NMTBGETINFOTIPW);
  235. case TBN_RESTORE: return sizeof(NMTBRESTORE);
  236. // WE ARE SUCH HORRIBLE SLACKERS!
  237. //
  238. // The TBN_FIRST/TBN_LAST range reserves 20 notifications for toolbar,
  239. // and we overflowed that limit, so now UDN_DELTAPOS and
  240. // TBN_SAVE have the same value.
  241. case TBN_SAVE: return max(sizeof(NMTBSAVE),
  242. sizeof(NMUPDOWN));
  243. case TBN_INITCUSTOMIZE: return sizeof(NMTBCUSTOMIZEDLG);
  244. case TBN_WRAPHOTITEM: return sizeof(NMTBWRAPHOTITEM);
  245. case TBN_DUPACCELERATOR: return sizeof(NMTBDUPACCELERATOR);
  246. case TBN_WRAPACCELERATOR: return sizeof(NMTBWRAPACCELERATOR);
  247. case TBN_DRAGOVER: return sizeof(NMTBHOTITEM);
  248. case TBN_MAPACCELERATOR: return sizeof(NMCHAR);
  249. // Up-down control
  250. #if 0 // see comment at TBN_SAVE
  251. case UDN_DELTAPOS: return sizeof(NMUPDOWN);
  252. #endif
  253. // Monthcal control
  254. case MCN_SELCHANGE: return sizeof(NMSELCHANGE);
  255. case MCN_GETDAYSTATE: return sizeof(NMDAYSTATE);
  256. case MCN_SELECT: return sizeof(NMSELECT);
  257. // Date/time picker control
  258. case DTN_DATETIMECHANGE: return sizeof(NMDATETIMECHANGE);
  259. case DTN_USERSTRINGA: return sizeof(NMDATETIMESTRINGA);
  260. case DTN_USERSTRINGW: return sizeof(NMDATETIMESTRINGW);
  261. case DTN_WMKEYDOWNA: return sizeof(NMDATETIMEWMKEYDOWNA);
  262. case DTN_WMKEYDOWNW: return sizeof(NMDATETIMEWMKEYDOWNW);
  263. case DTN_FORMATA: return sizeof(NMDATETIMEFORMATA);
  264. case DTN_FORMATW: return sizeof(NMDATETIMEFORMATW);
  265. case DTN_FORMATQUERYA: return sizeof(NMDATETIMEFORMATQUERYA);
  266. case DTN_FORMATQUERYW: return sizeof(NMDATETIMEFORMATQUERYW);
  267. case DTN_DROPDOWN: return sizeof(NMHDR);
  268. case DTN_CLOSEUP: return sizeof(NMHDR);
  269. // Comboex notifications
  270. case CBEN_GETDISPINFOA: return sizeof(NMCOMBOBOXEXA);
  271. case CBEN_GETDISPINFOW: return sizeof(NMCOMBOBOXEXW);
  272. case CBEN_INSERTITEM: return sizeof(NMCOMBOBOXEX); // Random character set
  273. case CBEN_DELETEITEM: return sizeof(NMCOMBOBOXEX); // No strings
  274. case CBEN_ITEMCHANGED: return sizeof(NMCOMBOBOXEX); // Not used
  275. case CBEN_BEGINEDIT: return sizeof(NMHDR);
  276. case CBEN_ENDEDITA: return sizeof(NMCBEENDEDITA);
  277. case CBEN_ENDEDITW: return sizeof(NMCBEENDEDITW);
  278. case CBEN_DRAGBEGINA: return sizeof(NMCBEDRAGBEGINA);
  279. case CBEN_DRAGBEGINW: return sizeof(NMCBEDRAGBEGINW);
  280. // Rebar notifications
  281. case RBN_HEIGHTCHANGE: return sizeof(NMHDR);
  282. case RBN_GETOBJECT: return sizeof(NMOBJECTNOTIFY);
  283. case RBN_LAYOUTCHANGED: return sizeof(NMHDR);
  284. case RBN_AUTOSIZE: return sizeof(NMRBAUTOSIZE);
  285. case RBN_BEGINDRAG: return sizeof(NMREBAR);
  286. case RBN_DELETINGBAND: return sizeof(NMREBAR);
  287. case RBN_DELETEDBAND: return sizeof(NMREBAR);
  288. case RBN_CHILDSIZE: return sizeof(NMREBARCHILDSIZE);
  289. // IP address control notification
  290. case IPN_FIELDCHANGED: return sizeof(NMIPADDRESS);
  291. // Status bar notifications
  292. case SBN_SIMPLEMODECHANGE: return sizeof(NMHDR);
  293. // Pager control notifications
  294. case PGN_SCROLL: return sizeof(NMPGSCROLL);
  295. case PGN_CALCSIZE: return sizeof(NMPGCALCSIZE);
  296. default:
  297. break;
  298. }
  299. //
  300. // Categories of notifications we explicitly know nothing about.
  301. //
  302. if (code >= WMN_LAST && code <= WMN_FIRST) { // Internet Mail and News
  303. return 0;
  304. }
  305. if ((int)code >= 0) { // Application-specific notifications
  306. return 0;
  307. }
  308. //
  309. // IF THIS ASSERT FIRES, YOU MUST FIX IT OR YOU WILL BREAK WOW!
  310. //
  311. AssertMsg(0, TEXT("Notification code %d must be added to WOWGetNotifySize"));
  312. return 0;
  313. }
  314. #endif // NEED_WOWGETNOTIFYSIZE_HELPER
  315. LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, int code, NMHDR FAR* pnmhdr, BOOL bUnicode)
  316. {
  317. CONTROLINFO ci;
  318. if (!hwndTo) {
  319. if (IsWindow(hwndFrom))
  320. hwndTo = GetParent(hwndFrom);
  321. if (!hwndTo)
  322. return 0;
  323. }
  324. ci.hwndParent = hwndTo;
  325. ci.hwnd = hwndFrom;
  326. ci.bUnicode = BOOLIFY(bUnicode);
  327. ci.uiCodePage = CP_ACP;
  328. return CCSendNotify(&ci, code, pnmhdr);
  329. }
  330. #ifdef UNICODE
  331. void StringBufferAtoW(UINT uiCodePage, LPVOID pvOrgPtr, DWORD dwOrgSize, CHAR **ppszText)
  332. {
  333. if (pvOrgPtr == *ppszText)
  334. {
  335. // the pointer has not been changed by the callback...
  336. // must convert from A to W in-place
  337. if (dwOrgSize)
  338. {
  339. LPWSTR pszW = ProduceWFromA(uiCodePage, *ppszText);
  340. if (pszW)
  341. {
  342. lstrcpynW((WCHAR *)(*ppszText), pszW, dwOrgSize); // this becomes a W buffer
  343. FreeProducedString(pszW);
  344. }
  345. }
  346. }
  347. else
  348. {
  349. // the pointer has been changed out from underneath us, copy
  350. // unicode back into the original buffer.
  351. ConvertAToWN(uiCodePage, pvOrgPtr, dwOrgSize, *ppszText, -1);
  352. *ppszText = pvOrgPtr;
  353. }
  354. }
  355. typedef struct tagTHUNKSTATE {
  356. LPVOID ts_pvThunk1;
  357. LPVOID ts_pvThunk2;
  358. DWORD ts_dwThunkSize;
  359. } THUNKSTATE;
  360. //
  361. // InOutWtoA/InOutAtoW is for thunking INOUT string parameters.
  362. //
  363. // INOUT parameters always create a hassle.
  364. //
  365. // We need to save both the original ANSI and the
  366. // original UNICODE strings, so that if the app doesn't
  367. // change the ANSI string, we leave the original UNICODE
  368. // string alone. That way, UNICODE item names don't get
  369. // obliterated by the thunk.
  370. //
  371. // The original buffer is saved in pvThunk1.
  372. // We allocate two ANSI buffers.
  373. // pvThunk2 contains the original ANSIfied string.
  374. // pvThunk2+cchTextMax is the buffer we pass to the app.
  375. // On the way back, we compare pvThunk2 with pvThunk2+cchTextMax.
  376. // If they are different, then we unthunk the string; otherwise,
  377. // we leave the original UNICODE buffer alone.
  378. BOOL InOutWtoA(CONTROLINFO *pci, THUNKSTATE *pts, LPWSTR *ppsz, DWORD cchTextMax)
  379. {
  380. pts->ts_pvThunk1 = *ppsz; // Save original buffer
  381. pts->ts_dwThunkSize = cchTextMax;
  382. if (!IsFlagPtr(pts->ts_pvThunk1))
  383. {
  384. pts->ts_pvThunk2 = LocalAlloc(LPTR, cchTextMax * 2 * sizeof(char));
  385. if (!ConvertWToAN(pci->uiCodePage, (LPSTR)pts->ts_pvThunk2, pts->ts_dwThunkSize, (LPWSTR)pts->ts_pvThunk1, -1))
  386. {
  387. LocalFree(pts->ts_pvThunk2);
  388. return 0;
  389. }
  390. *ppsz = (LPWSTR)((LPSTR)pts->ts_pvThunk2 + cchTextMax);
  391. lstrcpyA((LPSTR)*ppsz, pts->ts_pvThunk2);
  392. }
  393. return TRUE;
  394. }
  395. void InOutAtoW(CONTROLINFO *pci, THUNKSTATE *pts, LPSTR *ppsz)
  396. {
  397. if (!IsFlagPtr(pts->ts_pvThunk1))
  398. {
  399. if (!IsFlagPtr(*ppsz) &&
  400. lstrcmpA(pts->ts_pvThunk2, (LPSTR)*ppsz) != 0)
  401. StringBufferAtoW(pci->uiCodePage, pts->ts_pvThunk1, pts->ts_dwThunkSize, ppsz);
  402. LocalFree(pts->ts_pvThunk2);
  403. }
  404. *ppsz = pts->ts_pvThunk1;
  405. }
  406. #endif // UNICODE
  407. LRESULT WINAPI CCSendNotify(CONTROLINFO * pci, int code, LPNMHDR pnmhdr)
  408. {
  409. NMHDR nmhdr;
  410. LONG_PTR id;
  411. #ifdef UNICODE
  412. THUNKSTATE ts = { 0 };
  413. #define pvThunk1 ts.ts_pvThunk1
  414. #define pvThunk2 ts.ts_pvThunk2
  415. #define dwThunkSize ts.ts_dwThunkSize
  416. LRESULT lRet;
  417. BOOL bSet = FALSE;
  418. #endif
  419. HWND hwndParent = pci->hwndParent;
  420. DWORD dwParentPid;
  421. // -1 means Requery on each notify
  422. if ( hwndParent == (HWND)-1 )
  423. {
  424. hwndParent = GetParent(pci->hwnd);
  425. }
  426. // unlikely but it can technically happen -- avoid the rips
  427. if ( hwndParent == NULL )
  428. return 0;
  429. //
  430. // If pci->hwnd is -1, then a WM_NOTIFY is being forwared
  431. // from one control to a parent. EG: Tooltips sent
  432. // a WM_NOTIFY to toolbar, and toolbar is forwarding it
  433. // to the real parent window.
  434. //
  435. if (pci->hwnd != (HWND) -1) {
  436. //
  437. // If this is a child then get its ID. We need to go out of our way to
  438. // avoid calling GetDlgCtrlID on toplevel windows since it will return
  439. // a pseudo-random number (those of you who know what this number is
  440. // keep quiet). Anyway it's kinda hard to figure this out in Windows
  441. // because of the following:
  442. //
  443. // - a window can SetWindowLong(GWL_STYLE, WS_CHILD) but this only
  444. // does about half the work - hence checking the style is out.
  445. // - GetParent will return your OWNER if you are toplevel.
  446. // - there is no GetWindow(...GW_HWNDPARENT) to save us.
  447. //
  448. // Hence we are stuck with calling GetParent and then checking to see
  449. // if it lied and gave us the owner instead. Yuck.
  450. //
  451. id = 0;
  452. if (pci->hwnd) {
  453. HWND hwndParent = GetParent(pci->hwnd);
  454. if (hwndParent && (hwndParent != GetWindow(pci->hwnd, GW_OWNER))) {
  455. id = GetDlgCtrlID(pci->hwnd);
  456. }
  457. }
  458. if (!pnmhdr)
  459. pnmhdr = &nmhdr;
  460. pnmhdr->hwndFrom = pci->hwnd;
  461. pnmhdr->idFrom = id;
  462. pnmhdr->code = code;
  463. } else {
  464. id = pnmhdr->idFrom;
  465. code = pnmhdr->code;
  466. }
  467. // OLE in its massively componentized world sometimes creates
  468. // a control whose parent belongs to another process. (For example,
  469. // when there is a local server embedding.) WM_NOTIFY
  470. // messages can't cross process boundaries, so stop the message
  471. // from going there lest we fault the recipient.
  472. if (!GetWindowThreadProcessId(hwndParent, &dwParentPid) ||
  473. dwParentPid != GetCurrentProcessId())
  474. {
  475. TraceMsg(TF_WARNING, "nf: Not sending WM_NOTIFY %08x across processes", code);
  476. return 0;
  477. }
  478. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  479. ASSERT(code >= 0 || WOWGetNotifySize(code));
  480. #endif // NEED_WOWGETNOTIFYSIZE_HELPER
  481. #ifdef UNICODE
  482. /*
  483. * All the thunking for Notify Messages happens here
  484. */
  485. if (!pci->bUnicode) {
  486. BOOL fThunked = TRUE;
  487. switch( code ) {
  488. case LVN_ODFINDITEMW:
  489. pnmhdr->code = LVN_ODFINDITEMA;
  490. goto ThunkLV_FINDINFO;
  491. case LVN_INCREMENTALSEARCHW:
  492. pnmhdr->code = LVN_INCREMENTALSEARCHA;
  493. goto ThunkLV_FINDINFO;
  494. ThunkLV_FINDINFO:
  495. {
  496. LV_FINDINFO *plvfi;
  497. // Hack Alert! This code assumes that all fields of LV_FINDINFOA and
  498. // LV_FINDINFOW are exactly the same except for the string pointers.
  499. COMPILETIME_ASSERT(sizeof(LV_FINDINFOA) == sizeof(LV_FINDINFOW));
  500. // Since WCHARs are bigger than char, we will just use the
  501. // wchar buffer to hold the chars, and not worry about the extra
  502. // room at the end.
  503. COMPILETIME_ASSERT(sizeof(WCHAR) >= sizeof(char));
  504. plvfi = &((PNM_FINDITEM)pnmhdr)->lvfi;
  505. if (plvfi->flags & (LVFI_STRING | LVFI_PARTIAL | LVFI_SUBSTRING))
  506. {
  507. pvThunk1 = (PVOID)plvfi->psz;
  508. dwThunkSize = lstrlen(pvThunk1) + 1;
  509. plvfi->psz = (LPWSTR)ProduceAFromW(pci->uiCodePage, plvfi->psz);
  510. }
  511. }
  512. break;
  513. case LVN_GETDISPINFOW: {
  514. LV_ITEMW *pitem;
  515. pnmhdr->code = LVN_GETDISPINFOA;
  516. // Hack Alert! This code assumes that all fields of LV_DISPINFOA and
  517. // LV_DISPINFOW are exactly the same except for the string pointers.
  518. COMPILETIME_ASSERT(sizeof(LV_DISPINFOA) == sizeof(LV_DISPINFOW));
  519. // Since WCHARs are bigger than char, we will just use the
  520. // wchar buffer to hold the chars, and not worry about the extra
  521. // room at the end.
  522. COMPILETIME_ASSERT(sizeof(WCHAR) >= sizeof(char));
  523. //
  524. // Some sleazebag code (shell32.dll) just changes the pszText
  525. // pointer to point to the name, so capture the original pointer
  526. // so we can detect this and not smash their data.
  527. //
  528. pitem = &(((LV_DISPINFOW *)pnmhdr)->item);
  529. if (!IsFlagPtr(pitem) && (pitem->mask & LVIF_TEXT) && !IsFlagPtr(pitem->pszText)) {
  530. pvThunk1 = pitem->pszText;
  531. dwThunkSize = pitem->cchTextMax;
  532. }
  533. break;
  534. }
  535. // LVN_ENDLABELEDIT uses an INOUT parameter, never explicitly
  536. // documented as such, but it just happened to be that way,
  537. // and I don't want to take the chance that somebody was relying
  538. // on it.
  539. case LVN_ENDLABELEDITW:
  540. pnmhdr->code = LVN_ENDLABELEDITA;
  541. goto ThunkLV_DISPINFO;
  542. case LVN_BEGINLABELEDITW:
  543. pnmhdr->code = LVN_BEGINLABELEDITA;
  544. goto ThunkLV_DISPINFO;
  545. case LVN_SETDISPINFOW:
  546. pnmhdr->code = LVN_SETDISPINFOA;
  547. goto ThunkLV_DISPINFO;
  548. case LVN_GETEMPTYTEXTW:
  549. pnmhdr->code = LVN_GETEMPTYTEXTA;
  550. goto ThunkLV_DISPINFO;
  551. ThunkLV_DISPINFO: {
  552. LV_ITEMW *pitem;
  553. COMPILETIME_ASSERT(sizeof(LV_ITEMA) == sizeof(LV_ITEMW));
  554. pitem = &(((LV_DISPINFOW *)pnmhdr)->item);
  555. if (pitem->mask & LVIF_TEXT) {
  556. if (!InOutWtoA(pci, &ts, &pitem->pszText, pitem->cchTextMax))
  557. return 0;
  558. }
  559. break;
  560. }
  561. case LVN_GETINFOTIPW: {
  562. NMLVGETINFOTIPW *pgit = (NMLVGETINFOTIPW *)pnmhdr;
  563. COMPILETIME_ASSERT(sizeof(NMLVGETINFOTIPA) == sizeof(NMLVGETINFOTIPW));
  564. pnmhdr->code = LVN_GETINFOTIPA;
  565. if (!InOutWtoA(pci, &ts, &pgit->pszText, pgit->cchTextMax))
  566. return 0;
  567. }
  568. break;
  569. case TVN_GETINFOTIPW:
  570. {
  571. NMTVGETINFOTIPW *pgit = (NMTVGETINFOTIPW *)pnmhdr;
  572. pnmhdr->code = TVN_GETINFOTIPA;
  573. pvThunk1 = pgit->pszText;
  574. dwThunkSize = pgit->cchTextMax;
  575. }
  576. break;
  577. case TBN_GETINFOTIPW:
  578. {
  579. NMTBGETINFOTIPW *pgit = (NMTBGETINFOTIPW *)pnmhdr;
  580. pnmhdr->code = TBN_GETINFOTIPA;
  581. pvThunk1 = pgit->pszText;
  582. dwThunkSize = pgit->cchTextMax;
  583. }
  584. break;
  585. case TVN_SELCHANGINGW:
  586. pnmhdr->code = TVN_SELCHANGINGA;
  587. bSet = TRUE;
  588. // fall through
  589. case TVN_SELCHANGEDW:
  590. if (!bSet) {
  591. pnmhdr->code = TVN_SELCHANGEDA;
  592. bSet = TRUE;
  593. }
  594. /*
  595. * These msgs have a NM_TREEVIEW with both TV_ITEMs filled in
  596. *
  597. * FALL THROUGH TO TVN_DELETEITEM to thunk itemOld then go on for
  598. * the other structure.
  599. */
  600. // fall through
  601. case TVN_DELETEITEMW: {
  602. /*
  603. * This message has a NM_TREEVIEW in lParam with itemOld filled in
  604. */
  605. LPTV_ITEMW pitem;
  606. if (!bSet) {
  607. pnmhdr->code = TVN_DELETEITEMA;
  608. bSet = TRUE;
  609. }
  610. pitem = &(((LPNM_TREEVIEWW)pnmhdr)->itemOld);
  611. // thunk itemOld
  612. if ( (pitem->mask & TVIF_TEXT) && !IsFlagPtr(pitem->pszText)) {
  613. pvThunk2 = pitem->pszText;
  614. pitem->pszText = (LPWSTR)ProduceAFromW(pci->uiCodePage, pvThunk2);
  615. }
  616. // if this is deleteitem then we are done
  617. if (pnmhdr->code == TVN_DELETEITEMA)
  618. break;
  619. /* FALL THROUGH TO TVN_ITEMEXPANDING to thunk itemNew */
  620. }
  621. // fall through
  622. case TVN_ITEMEXPANDINGW:
  623. if (!bSet) {
  624. pnmhdr->code = TVN_ITEMEXPANDINGA;
  625. bSet = TRUE;
  626. }
  627. // fall through
  628. case TVN_ITEMEXPANDEDW:
  629. if (!bSet) {
  630. pnmhdr->code = TVN_ITEMEXPANDEDA;
  631. bSet = TRUE;
  632. }
  633. // fall through
  634. case TVN_BEGINDRAGW:
  635. if (!bSet) {
  636. pnmhdr->code = TVN_BEGINDRAGA;
  637. bSet = TRUE;
  638. }
  639. // fall through
  640. case TVN_BEGINRDRAGW: {
  641. /* these msgs have a NM_TREEVIEW with itemNew TV_ITEM filled in */
  642. LPTV_ITEMW pitem;
  643. if (!bSet) {
  644. pnmhdr->code = TVN_BEGINRDRAGA;
  645. }
  646. pitem = &(((LPNM_TREEVIEWW)pnmhdr)->itemNew);
  647. if ( (pitem->mask & TVIF_TEXT) && !IsFlagPtr(pitem->pszText)) {
  648. pvThunk1 = pitem->pszText;
  649. pitem->pszText = (LPWSTR)ProduceAFromW(pci->uiCodePage, pvThunk1);
  650. }
  651. break;
  652. }
  653. case TVN_SETDISPINFOW:
  654. pnmhdr->code = TVN_SETDISPINFOA;
  655. goto ThunkTV_DISPINFO;
  656. case TVN_BEGINLABELEDITW:
  657. pnmhdr->code = TVN_BEGINLABELEDITA;
  658. goto ThunkTV_DISPINFO;
  659. // TVN_ENDLABELEDIT uses an INOUT parameter, never explicitly
  660. // documented as such, but it just happened to be that way,
  661. // and I don't want to take the chance that somebody was relying
  662. // on it.
  663. case TVN_ENDLABELEDITW:
  664. pnmhdr->code = TVN_ENDLABELEDITA;
  665. goto ThunkTV_DISPINFO;
  666. ThunkTV_DISPINFO: {
  667. /*
  668. * All these messages have a TV_DISPINFO in lParam.
  669. */
  670. LPTV_ITEMW pitem;
  671. pitem = &(((TV_DISPINFOW *)pnmhdr)->item);
  672. if (pitem->mask & TVIF_TEXT) {
  673. if (!InOutWtoA(pci, &ts, &pitem->pszText, pitem->cchTextMax))
  674. return 0;
  675. }
  676. break;
  677. }
  678. #if !defined(UNIX) || defined(ANSI_SHELL32_ON_UNIX)
  679. /* UNIX shell32 TVN_GETDISPINFOA TVN_GETDISPINFOW does the same thing */
  680. case TVN_GETDISPINFOW: {
  681. /*
  682. * All these messages have a TV_DISPINFO in lParam.
  683. */
  684. LPTV_ITEMW pitem;
  685. pnmhdr->code = TVN_GETDISPINFOA;
  686. pitem = &(((TV_DISPINFOW *)pnmhdr)->item);
  687. if ((pitem->mask & TVIF_TEXT) && !IsFlagPtr(pitem->pszText) && pitem->cchTextMax) {
  688. pvThunk1 = pitem->pszText;
  689. dwThunkSize = pitem->cchTextMax;
  690. pvThunk2 = LocalAlloc(LPTR, pitem->cchTextMax * sizeof(char));
  691. pitem->pszText = pvThunk2;
  692. pitem->pszText[0] = TEXT('\0');
  693. }
  694. break;
  695. }
  696. #endif
  697. case HDN_ITEMCHANGINGW:
  698. pnmhdr->code = HDN_ITEMCHANGINGA;
  699. bSet = TRUE;
  700. // fall through
  701. case HDN_ITEMCHANGEDW:
  702. if (!bSet) {
  703. pnmhdr->code = HDN_ITEMCHANGEDA;
  704. bSet = TRUE;
  705. }
  706. // fall through
  707. case HDN_ITEMCLICKW:
  708. if (!bSet) {
  709. pnmhdr->code = HDN_ITEMCLICKA;
  710. bSet = TRUE;
  711. }
  712. // fall through
  713. case HDN_ITEMDBLCLICKW:
  714. if (!bSet) {
  715. pnmhdr->code = HDN_ITEMDBLCLICKA;
  716. bSet = TRUE;
  717. }
  718. // fall through
  719. case HDN_DIVIDERDBLCLICKW:
  720. if (!bSet) {
  721. pnmhdr->code = HDN_DIVIDERDBLCLICKA;
  722. bSet = TRUE;
  723. }
  724. // fall through
  725. case HDN_BEGINTRACKW:
  726. if (!bSet) {
  727. pnmhdr->code = HDN_BEGINTRACKA;
  728. bSet = TRUE;
  729. }
  730. // fall through
  731. case HDN_ENDTRACKW:
  732. if (!bSet) {
  733. pnmhdr->code = HDN_ENDTRACKA;
  734. bSet = TRUE;
  735. }
  736. // fall through
  737. case HDN_TRACKW: {
  738. HD_ITEMW *pitem;
  739. if (!bSet) {
  740. pnmhdr->code = HDN_TRACKA;
  741. }
  742. pitem = ((HD_NOTIFY *)pnmhdr)->pitem;
  743. if ( !IsFlagPtr(pitem) && (pitem->mask & HDI_TEXT) && !IsFlagPtr(pitem->pszText)) {
  744. pvThunk1 = pitem->pszText;
  745. dwThunkSize = pitem->cchTextMax;
  746. pitem->pszText = (LPWSTR)ProduceAFromW(pci->uiCodePage, pvThunk1);
  747. }
  748. if ( !IsFlagPtr(pitem) && (pitem->mask & HDI_FILTER) && pitem->pvFilter )
  749. {
  750. if ( !(pitem->type & HDFT_HASNOVALUE) &&
  751. ((pitem->type & HDFT_ISMASK)==HDFT_ISSTRING) )
  752. {
  753. LPHD_TEXTFILTER ptextFilter = (LPHD_TEXTFILTER)pitem->pvFilter;
  754. pvThunk2 = ptextFilter->pszText;
  755. dwThunkSize = ptextFilter->cchTextMax;
  756. ptextFilter->pszText = (LPWSTR)ProduceAFromW(pci->uiCodePage, pvThunk2);
  757. }
  758. }
  759. break;
  760. }
  761. case CBEN_ENDEDITW:
  762. {
  763. LPNMCBEENDEDITW peew = (LPNMCBEENDEDITW) pnmhdr;
  764. LPNMCBEENDEDITA peea = LocalAlloc(LPTR, sizeof(NMCBEENDEDITA));
  765. if (!peea)
  766. return 0;
  767. peea->hdr = peew->hdr;
  768. peea->hdr.code = CBEN_ENDEDITA;
  769. peea->fChanged = peew->fChanged;
  770. peea->iNewSelection = peew->iNewSelection;
  771. peea->iWhy = peew->iWhy;
  772. ConvertWToAN(pci->uiCodePage, peea->szText, ARRAYSIZE(peea->szText),
  773. peew->szText, -1);
  774. pvThunk1 = pnmhdr;
  775. pnmhdr = &peea->hdr;
  776. ASSERT((LPVOID)pnmhdr == (LPVOID)peea);
  777. break;
  778. }
  779. case CBEN_DRAGBEGINW:
  780. {
  781. LPNMCBEDRAGBEGINW pdbw = (LPNMCBEDRAGBEGINW) pnmhdr;
  782. LPNMCBEDRAGBEGINA pdba = LocalAlloc(LPTR, sizeof(NMCBEDRAGBEGINA));
  783. if (!pdba)
  784. return 0;
  785. pdba->hdr = pdbw->hdr;
  786. pdba->hdr.code = CBEN_DRAGBEGINA;
  787. pdba->iItemid = pdbw->iItemid;
  788. ConvertWToAN(pci->uiCodePage, pdba->szText, ARRAYSIZE(pdba->szText),
  789. pdbw->szText, -1);
  790. pvThunk1 = pnmhdr;
  791. pnmhdr = &pdba->hdr;
  792. ASSERT((LPVOID)pnmhdr == (LPVOID)pdba);
  793. break;
  794. }
  795. case CBEN_GETDISPINFOW: {
  796. PNMCOMBOBOXEXW pnmcbe = (PNMCOMBOBOXEXW)pnmhdr;
  797. pnmhdr->code = CBEN_GETDISPINFOA;
  798. if (pnmcbe->ceItem.mask & CBEIF_TEXT
  799. && !IsFlagPtr(pnmcbe->ceItem.pszText) && pnmcbe->ceItem.cchTextMax) {
  800. pvThunk1 = pnmcbe->ceItem.pszText;
  801. dwThunkSize = pnmcbe->ceItem.cchTextMax;
  802. pvThunk2 = LocalAlloc(LPTR, pnmcbe->ceItem.cchTextMax * sizeof(char));
  803. pnmcbe->ceItem.pszText = pvThunk2;
  804. pnmcbe->ceItem.pszText[0] = TEXT('\0');
  805. }
  806. break;
  807. }
  808. case HDN_GETDISPINFOW: {
  809. LPNMHDDISPINFOW pHDDispInfoW;
  810. pnmhdr->code = HDN_GETDISPINFOA;
  811. pHDDispInfoW = (LPNMHDDISPINFOW) pnmhdr;
  812. pvThunk1 = pHDDispInfoW->pszText;
  813. dwThunkSize = pHDDispInfoW->cchTextMax;
  814. pHDDispInfoW->pszText = LocalAlloc (LPTR, pHDDispInfoW->cchTextMax * sizeof(char));
  815. if (!pHDDispInfoW->pszText) {
  816. pHDDispInfoW->pszText = (LPWSTR) pvThunk1;
  817. break;
  818. }
  819. WideCharToMultiByte(pci->uiCodePage, 0, (LPWSTR)pvThunk1, -1,
  820. (LPSTR)pHDDispInfoW->pszText, pHDDispInfoW->cchTextMax,
  821. NULL, NULL);
  822. break;
  823. }
  824. case TBN_GETBUTTONINFOW:
  825. {
  826. LPTBNOTIFYW pTBNW;
  827. pnmhdr->code = TBN_GETBUTTONINFOA;
  828. pTBNW = (LPTBNOTIFYW)pnmhdr;
  829. pvThunk1 = pTBNW->pszText;
  830. dwThunkSize = pTBNW->cchText;
  831. pvThunk2 = LocalAlloc (LPTR, pTBNW->cchText * sizeof(char));
  832. if (!pvThunk2) {
  833. break;
  834. }
  835. pTBNW->pszText = pvThunk2;
  836. WideCharToMultiByte(pci->uiCodePage, 0, (LPWSTR)pvThunk1, -1,
  837. (LPSTR)pTBNW->pszText, pTBNW->cchText,
  838. NULL, NULL);
  839. }
  840. break;
  841. case TTN_NEEDTEXTW:
  842. {
  843. LPTOOLTIPTEXTA lpTTTA;
  844. LPTOOLTIPTEXTW lpTTTW = (LPTOOLTIPTEXTW) pnmhdr;
  845. lpTTTA = LocalAlloc(LPTR, sizeof(TOOLTIPTEXTA));
  846. if (!lpTTTA)
  847. return 0;
  848. lpTTTA->hdr = lpTTTW->hdr;
  849. lpTTTA->hdr.code = TTN_NEEDTEXTA;
  850. lpTTTA->lpszText = lpTTTA->szText;
  851. lpTTTA->hinst = lpTTTW->hinst;
  852. lpTTTA->uFlags = lpTTTW->uFlags;
  853. lpTTTA->lParam = lpTTTW->lParam;
  854. WideCharToMultiByte(pci->uiCodePage, 0, lpTTTW->szText, -1, lpTTTA->szText, ARRAYSIZE(lpTTTA->szText), NULL, NULL);
  855. pvThunk1 = pnmhdr;
  856. pnmhdr = (NMHDR FAR *)lpTTTA;
  857. }
  858. break;
  859. case DTN_USERSTRINGW:
  860. {
  861. LPNMDATETIMESTRINGW lpDateTimeString = (LPNMDATETIMESTRINGW) pnmhdr;
  862. pnmhdr->code = DTN_USERSTRINGA;
  863. pvThunk1 = ProduceAFromW(pci->uiCodePage, lpDateTimeString->pszUserString);
  864. lpDateTimeString->pszUserString = (LPWSTR) pvThunk1;
  865. }
  866. break;
  867. case DTN_WMKEYDOWNW:
  868. {
  869. LPNMDATETIMEWMKEYDOWNW lpDateTimeWMKeyDown =
  870. (LPNMDATETIMEWMKEYDOWNW) pnmhdr;
  871. pnmhdr->code = DTN_WMKEYDOWNA;
  872. pvThunk1 = ProduceAFromW(pci->uiCodePage, lpDateTimeWMKeyDown->pszFormat);
  873. lpDateTimeWMKeyDown->pszFormat = (LPWSTR) pvThunk1;
  874. }
  875. break;
  876. case DTN_FORMATQUERYW:
  877. {
  878. LPNMDATETIMEFORMATQUERYW lpDateTimeFormatQuery =
  879. (LPNMDATETIMEFORMATQUERYW) pnmhdr;
  880. pnmhdr->code = DTN_FORMATQUERYA;
  881. pvThunk1 = ProduceAFromW(pci->uiCodePage, lpDateTimeFormatQuery->pszFormat);
  882. lpDateTimeFormatQuery->pszFormat = (LPWSTR) pvThunk1;
  883. }
  884. break;
  885. case DTN_FORMATW:
  886. {
  887. LPNMDATETIMEFORMATW lpDateTimeFormat =
  888. (LPNMDATETIMEFORMATW) pnmhdr;
  889. pnmhdr->code = DTN_FORMATA;
  890. pvThunk1 = ProduceAFromW(pci->uiCodePage, lpDateTimeFormat->pszFormat);
  891. lpDateTimeFormat->pszFormat = (LPWSTR) pvThunk1;
  892. }
  893. break;
  894. default:
  895. fThunked = FALSE;
  896. break;
  897. }
  898. #ifdef NEED_WOWGETNOTIFYSIZE_HELPER
  899. ASSERT(code >= 0 || WOWGetNotifySize(code));
  900. #endif // NEED_WOWGETNOTIFYSIZE_HELPER
  901. lRet = SendMessage(hwndParent, WM_NOTIFY, (WPARAM)id, (LPARAM)pnmhdr);
  902. /*
  903. * All the thunking for Notify Messages happens here
  904. */
  905. if (fThunked)
  906. {
  907. switch(pnmhdr->code) {
  908. case LVN_ODFINDITEMA:
  909. case LVN_INCREMENTALSEARCHA:
  910. {
  911. LV_FINDINFO *plvfi = &((PNM_FINDITEM)pnmhdr)->lvfi;
  912. if (pvThunk1)
  913. {
  914. FreeProducedString((LPWSTR)plvfi->psz);
  915. plvfi->psz = pvThunk1;
  916. }
  917. }
  918. break;
  919. case LVN_GETDISPINFOA:
  920. {
  921. LV_ITEMA *pitem = &(((LV_DISPINFOA *)pnmhdr)->item);
  922. // BUGBUG what if pointer is to large buffer?
  923. if (!IsFlagPtr(pitem) && (pitem->mask & LVIF_TEXT) && !IsFlagPtr(pitem->pszText))
  924. {
  925. StringBufferAtoW(pci->uiCodePage, pvThunk1, dwThunkSize, &pitem->pszText);
  926. }
  927. }
  928. break;
  929. case LVN_ENDLABELEDITA:
  930. case LVN_BEGINLABELEDITA:
  931. case LVN_SETDISPINFOA:
  932. case LVN_GETEMPTYTEXTA:
  933. {
  934. LV_ITEMA *pitem = &(((LV_DISPINFOA *)pnmhdr)->item);
  935. InOutAtoW(pci, &ts, &pitem->pszText);
  936. }
  937. break;
  938. case LVN_GETINFOTIPA:
  939. {
  940. NMLVGETINFOTIPA *pgit = (NMLVGETINFOTIPA *)pnmhdr;
  941. InOutAtoW(pci, &ts, &pgit->pszText);
  942. }
  943. break;
  944. case TVN_GETINFOTIPA:
  945. {
  946. NMTVGETINFOTIPA *pgit = (NMTVGETINFOTIPA *)pnmhdr;
  947. StringBufferAtoW(pci->uiCodePage, pvThunk1, dwThunkSize, &pgit->pszText);
  948. }
  949. break;
  950. case TBN_GETINFOTIPA:
  951. {
  952. NMTBGETINFOTIPA *pgit = (NMTBGETINFOTIPA *)pnmhdr;
  953. StringBufferAtoW(pci->uiCodePage, pvThunk1, dwThunkSize, &pgit->pszText);
  954. }
  955. break;
  956. case TVN_SELCHANGINGA:
  957. case TVN_SELCHANGEDA:
  958. case TVN_DELETEITEMA: {
  959. LPTV_ITEMW pitem;
  960. if ( !IsFlagPtr(pvThunk2) ) {
  961. pitem = &(((LPNM_TREEVIEWW)pnmhdr)->itemOld);
  962. FreeProducedString(pitem->pszText);
  963. pitem->pszText = pvThunk2;
  964. }
  965. // if this is delitem, then we are done
  966. if (code == TVN_DELETEITEM)
  967. break;
  968. /* FALL THROUGH TO TVN_ITEMEXPANDING to unthunk itemNew */
  969. }
  970. // fall through
  971. case TVN_ITEMEXPANDINGA:
  972. case TVN_ITEMEXPANDEDA:
  973. case TVN_BEGINDRAGA:
  974. case TVN_BEGINRDRAGA: {
  975. /* these msgs have a NM_TREEVIEW with itemNew TV_ITEM filled in */
  976. LPTV_ITEMW pitem;
  977. if (!IsFlagPtr(pvThunk1)) {
  978. pitem = &(((LPNM_TREEVIEWW)pnmhdr)->itemNew);
  979. FreeProducedString(pitem->pszText);
  980. pitem->pszText = pvThunk1;
  981. }
  982. break;
  983. }
  984. case TVN_SETDISPINFOA:
  985. case TVN_BEGINLABELEDITA:
  986. case TVN_ENDLABELEDITA:
  987. {
  988. LPTV_ITEMA pitem;
  989. pitem = &(((TV_DISPINFOA *)pnmhdr)->item);
  990. InOutAtoW(pci, &ts, &pitem->pszText);
  991. }
  992. break;
  993. case TVN_GETDISPINFOA: {
  994. /*
  995. * This message has a TV_DISPINFO in lParam that wass filled in
  996. * during the callback and needs to be unthunked.
  997. */
  998. LPTV_ITEMW pitem;
  999. pitem = &(((TV_DISPINFOW *)pnmhdr)->item);
  1000. if (!IsFlagPtr(pvThunk1) && (pitem->mask & TVIF_TEXT) && !IsFlagPtr(pitem->pszText)) {
  1001. ConvertAToWN(pci->uiCodePage, pvThunk1, dwThunkSize, (LPSTR)pitem->pszText, -1);
  1002. pitem->pszText = pvThunk1;
  1003. LocalFree(pvThunk2);
  1004. }
  1005. break;
  1006. }
  1007. case HDN_ITEMCHANGINGA:
  1008. case HDN_ITEMCHANGEDA:
  1009. case HDN_ITEMCLICKA:
  1010. case HDN_ITEMDBLCLICKA:
  1011. case HDN_DIVIDERDBLCLICKA:
  1012. case HDN_BEGINTRACKA:
  1013. case HDN_ENDTRACKA:
  1014. case HDN_TRACKA: {
  1015. HD_ITEMW *pitem;
  1016. pitem = ((HD_NOTIFY *)pnmhdr)->pitem;
  1017. if ( !IsFlagPtr(pitem) && (pitem->mask & HDI_TEXT) && !IsFlagPtr(pvThunk1)) {
  1018. ConvertAToWN(pci->uiCodePage, pvThunk1, dwThunkSize, (LPSTR)(pitem->pszText), -1);
  1019. FreeProducedString(pitem->pszText);
  1020. pitem->pszText = pvThunk1;
  1021. }
  1022. if ( !IsFlagPtr(pitem) && (pitem->mask & HDI_FILTER) && pitem->pvFilter && pvThunk2 )
  1023. {
  1024. if ( !(pitem->type & HDFT_HASNOVALUE) &&
  1025. ((pitem->type & HDFT_ISMASK)==HDFT_ISSTRING) )
  1026. {
  1027. LPHD_TEXTFILTER ptextFilter = (LPHD_TEXTFILTER)pitem->pvFilter;
  1028. ConvertAToWN(pci->uiCodePage, pvThunk2, dwThunkSize, (LPSTR)(ptextFilter->pszText), -1);
  1029. FreeProducedString(ptextFilter->pszText);
  1030. ptextFilter->pszText = pvThunk2;
  1031. }
  1032. }
  1033. break;
  1034. }
  1035. case CBEN_ENDEDITA:
  1036. {
  1037. LPNMCBEENDEDITW peew = (LPNMCBEENDEDITW) pvThunk1;
  1038. LPNMCBEENDEDITA peea = (LPNMCBEENDEDITA) pnmhdr;
  1039. // Don't unthunk the string since that destroys unicode round-trip
  1040. // and the client shouldn't be modifying it anyway.
  1041. // ConvertAToWN(pci->uiCodePage, peew->szText, ARRAYSIZE(peew->szText),
  1042. // peea->szText, -1);
  1043. LocalFree(peea);
  1044. }
  1045. break;
  1046. case CBEN_DRAGBEGINA:
  1047. {
  1048. LPNMCBEDRAGBEGINW pdbw = (LPNMCBEDRAGBEGINW) pvThunk1;
  1049. LPNMCBEDRAGBEGINA pdba = (LPNMCBEDRAGBEGINA) pnmhdr;
  1050. // Don't unthunk the string since that destroys unicode round-trip
  1051. // and the client shouldn't be modifying it anyway.
  1052. // ConvertAToWN(pci->uiCodePage, pdbw->szText, ARRAYSIZE(pdbw->szText),
  1053. // pdba->szText, -1);
  1054. LocalFree(pdba);
  1055. }
  1056. break;
  1057. case CBEN_GETDISPINFOA:
  1058. {
  1059. PNMCOMBOBOXEXW pnmcbeW;
  1060. pnmcbeW = (PNMCOMBOBOXEXW)pnmhdr;
  1061. ConvertAToWN(pci->uiCodePage, pvThunk1, dwThunkSize, (LPSTR)(pnmcbeW->ceItem.pszText), -1);
  1062. if (pvThunk2)
  1063. LocalFree(pvThunk2);
  1064. pnmcbeW->ceItem.pszText = pvThunk1;
  1065. }
  1066. break;
  1067. case HDN_GETDISPINFOA:
  1068. {
  1069. LPNMHDDISPINFOW pHDDispInfoW;
  1070. pHDDispInfoW = (LPNMHDDISPINFOW)pnmhdr;
  1071. ConvertAToWN(pci->uiCodePage, pvThunk1, dwThunkSize, (LPSTR)(pHDDispInfoW->pszText), -1);
  1072. LocalFree(pHDDispInfoW->pszText);
  1073. pHDDispInfoW->pszText = pvThunk1;
  1074. }
  1075. break;
  1076. case TBN_GETBUTTONINFOA:
  1077. {
  1078. LPTBNOTIFYW pTBNW;
  1079. pTBNW = (LPTBNOTIFYW)pnmhdr;
  1080. ConvertAToWN(pci->uiCodePage, pvThunk1, dwThunkSize, (LPSTR)(pTBNW->pszText), -1);
  1081. pTBNW->pszText = pvThunk1;
  1082. LocalFree(pvThunk2);
  1083. }
  1084. break;
  1085. case TTN_NEEDTEXTA:
  1086. {
  1087. LPTOOLTIPTEXTA lpTTTA = (LPTOOLTIPTEXTA) pnmhdr;
  1088. LPTOOLTIPTEXTW lpTTTW = (LPTOOLTIPTEXTW) pvThunk1;
  1089. ThunkToolTipTextAtoW (lpTTTA, lpTTTW, pci->uiCodePage);
  1090. LocalFree(lpTTTA);
  1091. }
  1092. break;
  1093. case DTN_USERSTRINGA:
  1094. case DTN_WMKEYDOWNA:
  1095. case DTN_FORMATQUERYA:
  1096. {
  1097. FreeProducedString (pvThunk1);
  1098. }
  1099. break;
  1100. case DTN_FORMATA:
  1101. {
  1102. LPNMDATETIMEFORMATA lpDateTimeFormat = (LPNMDATETIMEFORMATA) pnmhdr;
  1103. FreeProducedString (pvThunk1);
  1104. //
  1105. // pszDisplay and szDisplay are special cases.
  1106. //
  1107. if (lpDateTimeFormat->pszDisplay && *lpDateTimeFormat->pszDisplay) {
  1108. //
  1109. // if pszDisplay still points at szDisplay then thunk
  1110. // in place. Otherwise allocate memory and copy the
  1111. // display string. This buffer will be freeded in monthcal.c
  1112. //
  1113. if (lpDateTimeFormat->pszDisplay == lpDateTimeFormat->szDisplay) {
  1114. CHAR szDisplay[64];
  1115. lstrcpynA (szDisplay, lpDateTimeFormat->szDisplay, 64);
  1116. ConvertAToWN (pci->uiCodePage, (LPWSTR)lpDateTimeFormat->szDisplay, 64,
  1117. szDisplay, -1);
  1118. } else {
  1119. lpDateTimeFormat->pszDisplay =
  1120. (LPSTR) ProduceWFromA (pci->uiCodePage, lpDateTimeFormat->pszDisplay);
  1121. }
  1122. }
  1123. }
  1124. break;
  1125. default:
  1126. /* No thunking needed */
  1127. break;
  1128. }
  1129. }
  1130. return lRet;
  1131. } else
  1132. #endif
  1133. return(SendMessage(hwndParent, WM_NOTIFY, (WPARAM)id, (LPARAM)pnmhdr));
  1134. #undef pvThunk1
  1135. #undef pvThunk2
  1136. #undef dwThunkSize
  1137. }
  1138. LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, int code, NMHDR FAR* pnmhdr)
  1139. {
  1140. CONTROLINFO ci;
  1141. ci.hwndParent = hwndTo;
  1142. ci.hwnd = hwndFrom;
  1143. ci.bUnicode = FALSE;
  1144. ci.uiCodePage = CP_ACP;
  1145. //
  1146. // SendNotify is obsolete. New code should call CCSendNotify
  1147. // instead. However, if something does call SendNotify,
  1148. // it will call SendNotifyEx with FALSE as the Unicode parameter,
  1149. // because it probably is ANSI code.
  1150. //
  1151. return CCSendNotify(&ci, code, pnmhdr);
  1152. }
  1153. DWORD NEAR PASCAL CICustomDrawNotify(LPCONTROLINFO lpci, DWORD dwStage, LPNMCUSTOMDRAW lpnmcd)
  1154. {
  1155. DWORD dwRet = CDRF_DODEFAULT;
  1156. // bail if...
  1157. // this is an item notification, but an item notification wasn't asked for
  1158. if ((dwStage & CDDS_ITEM) && !(lpci->dwCustom & CDRF_NOTIFYITEMDRAW)) {
  1159. return dwRet;
  1160. }
  1161. lpnmcd->dwDrawStage = dwStage;
  1162. dwRet = (DWORD) CCSendNotify(lpci, NM_CUSTOMDRAW, &lpnmcd->hdr);
  1163. // validate the flags
  1164. if (dwRet & ~CDRF_VALIDFLAGS)
  1165. return CDRF_DODEFAULT;
  1166. return dwRet;
  1167. }
  1168. //
  1169. // Too many apps encounter strange behavior when we send out
  1170. // NM_CUSTOMDRAW messages at times unrelated to painting.
  1171. // E.g., NetMeeting and MFC recurse back into ListView_RecomputeLabelSize.
  1172. // CryptUI will fault if it's asked to NM_CUSTOMDRAW before it gets
  1173. // WM_INITDIALOG. So all this fake customdraw stuff is v5 only.
  1174. //
  1175. // And since it is very popular to call back into the control during
  1176. // the handling of NM_CUSTOMDRAW, we protect against recursing ourselves
  1177. // to death by blowing off nested fake customdraw messages.
  1178. DWORD CIFakeCustomDrawNotify(LPCONTROLINFO lpci, DWORD dwStage, LPNMCUSTOMDRAW lpnmcd)
  1179. {
  1180. DWORD dwRet = CDRF_DODEFAULT;
  1181. if (lpci->iVersion >= 5 && !lpci->bInFakeCustomDraw)
  1182. {
  1183. lpci->bInFakeCustomDraw = TRUE;
  1184. dwRet = CICustomDrawNotify(lpci, dwStage, lpnmcd);
  1185. ASSERT(lpci->bInFakeCustomDraw);
  1186. lpci->bInFakeCustomDraw = FALSE;
  1187. }
  1188. return dwRet;
  1189. }
  1190. /*----------------------------------------------------------
  1191. Purpose: Release the capture and tell the parent we've done so.
  1192. Returns: Whether the control is still alive.
  1193. */
  1194. BOOL CCReleaseCapture(CONTROLINFO * pci)
  1195. {
  1196. HWND hwndCtl = pci->hwnd;
  1197. NMHDR nmhdr = {0};
  1198. ReleaseCapture();
  1199. // Tell the parent we've released the capture
  1200. CCSendNotify(pci, NM_RELEASEDCAPTURE, &nmhdr);
  1201. return IsWindow(hwndCtl);
  1202. }
  1203. /*----------------------------------------------------------
  1204. Purpose: Set the capture. If the hwndSet is NULL, it means
  1205. the capture is being released, so tell the parent
  1206. we've done so.
  1207. Use this function if there's a possibility that the
  1208. hwnd may be NULL.
  1209. */
  1210. void CCSetCapture(CONTROLINFO * pci, HWND hwndSet)
  1211. {
  1212. SetCapture(hwndSet);
  1213. if (NULL == hwndSet)
  1214. {
  1215. NMHDR nmhdr = {0};
  1216. // Tell the parent we've released the capture
  1217. CCSendNotify(pci, NM_RELEASEDCAPTURE, &nmhdr);
  1218. }
  1219. }