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.

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