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.

2014 lines
86 KiB

  1. /*++
  2. Copyright (c) 2000-2001, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. usermsgs.c
  5. APIs found in this file:
  6. GodotDoCallback
  7. GodotTransmitMessage
  8. GodotReceiveMessage
  9. GodotDispatchMessage
  10. Helper functions
  11. MapCatureMessage
  12. TransmitHelper
  13. This function does not currently handle ANSI caller to a UNICODE window.
  14. All other calls are handled properly.
  15. CONSIDER: To fully implement the capture window stuff, we would
  16. need to support these callback functions:
  17. capErrorCallback
  18. capStatusCallback
  19. Revision History:
  20. 6 Feb 2001 v-michka Created.
  21. --*/
  22. #include "precomp.h"
  23. // Internal MFC messages
  24. #define WM_SETMESSAGESTRING 0x0362 // wParam = nIDS (or 0),
  25. // lParam = lpszOther (or NULL)
  26. // Must dynamically link to "BroadcastSystemMessage" because it
  27. // does not exist as "BroadcastSystemMessageA" on all platforms.
  28. typedef BOOL (__stdcall *PFNbsma) (DWORD, LPDWORD, UINT, WPARAM, LPARAM);
  29. static PFNbsma s_pfnBSMA;
  30. // forward declares
  31. LRESULT TransmitHelper(MESSAGETYPES mt, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam,
  32. WNDPROC lpPrevWndFunc, SENDASYNCPROC lpCallBack, ULONG_PTR dwData,
  33. UINT fuFlags, UINT uTimeout, PDWORD_PTR lpdwResult);
  34. /*-------------------------------
  35. MapCaptureMessage
  36. Simple function that maps one message type to
  37. another (A->W and W->A) for video captures
  38. -------------------------------*/
  39. UINT MapCaptureMessage(UINT uMsg)
  40. {
  41. if(uMsg >= WM_CAP_UNICODE_START)
  42. return(uMsg - WM_CAP_UNICODE_START);
  43. else
  44. return(uMsg + WM_CAP_UNICODE_START);
  45. }
  46. /*-------------------------------
  47. GodotDoCallback
  48. Our global wrapper around callback functions; all callbacks that need random
  49. conversions done go through this proc. Note that all callers will be Unicode
  50. windows so we do not have to check for this here.
  51. -------------------------------*/
  52. LRESULT GodotDoCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, WNDPROC lpfn, BOOL fUniSrc, FAUXPROCTYPE fpt)
  53. {
  54. LRESULT RetVal = 0;
  55. BOOL fUniDst;
  56. fUniDst = (! DoesProcExpectAnsi(hWnd, lpfn, fpt));
  57. if(!fUniDst && !fUniSrc)
  58. {
  59. // Call through via CallWindowProcA with no conversion
  60. // Note that this is the only place in this entire function where we use
  61. // CallWindowProc, since either the user or the system is expecting ANSI.
  62. // Note that on Win9x, the base wndproc can be a thunked function sitting
  63. // in USER.EXE; only CallWindowProcA can manage that sort of detail.
  64. return(CallWindowProcA(lpfn, hWnd, uMsg, wParam, lParam));
  65. }
  66. else if(fUniDst && fUniSrc)
  67. {
  68. // Pure Unicode: Call directly, no conversion needed
  69. // Note that we do not currently use this!!!
  70. return((* lpfn)(hWnd, uMsg, wParam, lParam));
  71. }
  72. else if(!fUniDst && fUniSrc)
  73. {
  74. // We need to convert from Unicode to ANSI, so use
  75. // our own GodotTransmitMessage to do the work.
  76. return(GodotTransmitMessage(mtCallWindowProc, hWnd, uMsg, wParam, lParam, lpfn, 0, 0, 0, 0, 0));
  77. }
  78. else // (fUniDst && !fUniSrc)
  79. {
  80. switch(uMsg)
  81. {
  82. case WM_CHAR:
  83. case EM_SETPASSWORDCHAR:
  84. case WM_DEADCHAR:
  85. case WM_SYSCHAR:
  86. case WM_SYSDEADCHAR:
  87. case WM_MENUCHAR:
  88. if(FDBCS_CPG(g_acp))
  89. {
  90. WPARAM wParamW = 0;
  91. static CHAR s_ch[3] = "\0";
  92. // We have to go through all this nonsense because DBCS characters
  93. // arrive one byte at a time. Most of this code is never used because
  94. // DBCS chars OUGHT to be handled by WM_IME_CHAR below.
  95. if(!s_ch[0])
  96. {
  97. // No lead byte already waiting for trail byte
  98. s_ch[0] = *(char *)wParam;
  99. if(IsDBCSLeadByteEx(g_acp, *(char *)wParam))
  100. {
  101. // This is a lead byte. Save it and wait for trail byte
  102. RetVal = FALSE;
  103. }
  104. // Not a DBCS character. Convert to Unicode.
  105. MultiByteToWideChar(g_acp, 0, s_ch, 1, (WCHAR *)&wParamW, 1);
  106. // Reset to indicate no Lead byte waiting
  107. s_ch[0] = 0 ;
  108. RetVal = TRUE;
  109. }
  110. else
  111. {
  112. // Have lead byte, wParam should contain the trail byte
  113. s_ch[1] = *(char *)wParam;
  114. // Convert both bytes into one Unicode character
  115. MultiByteToWideChar(g_acp, 0, s_ch, 2, (WCHAR *)&wParamW, 1);
  116. // Reset to non-waiting state
  117. s_ch[0] = 0;
  118. RetVal = TRUE;
  119. }
  120. break;
  121. }
  122. // Not a DBCS system, so fall through here
  123. case WM_IME_CHAR:
  124. case WM_IME_COMPOSITION:
  125. {
  126. WPARAM wParamW = 0;
  127. MultiByteToWideChar(g_acp, 0, (CHAR *)&wParam, g_mcs, (WCHAR *)&wParamW, 1);
  128. RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParam);
  129. WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (CHAR *)&wParam, g_mcs, NULL, NULL);
  130. break;
  131. }
  132. case WM_CHARTOITEM:
  133. {
  134. // Mask off the hiword bits, convert, then stick the hiword bits back on.
  135. WPARAM wParamW = 0;
  136. WPARAM wpT = wParam & 0xFFFF;
  137. MultiByteToWideChar(g_acp, 0, (CHAR *)&wpT, g_mcs, (WCHAR *)&wParamW, 1);
  138. RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParam);
  139. WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (CHAR *)&wpT, g_mcs, NULL, NULL);
  140. wParam = MAKELONG(LOWORD(wpT),HIWORD(wParam));
  141. break;
  142. }
  143. case (WM_USER + 25): // might be WM_CAP_FILE_SAVEDIBA
  144. case (WM_USER + 23): // might be WM_CAP_FILE_SAVEASA
  145. case (WM_USER + 66): // might be WM_CAP_SET_MCI_DEVICEA
  146. case (WM_USER + 80): // might be WM_CAP_PAL_OPENA
  147. case (WM_USER + 81): // might be WM_CAP_PAL_SAVEA
  148. case (WM_USER + 20): // might be WM_CAP_FILE_SET_CAPTURE_FILEA
  149. if(!IsCaptureWindow(hWnd))
  150. {
  151. // The numbers are right, but its not a capture window, so
  152. // do not convert. Instead, just pass as is.
  153. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  154. }
  155. else
  156. {
  157. // No memory? If the alloc fails, we eat the results.
  158. LPARAM lParamW;
  159. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  160. RetVal = (* lpfn)(hWnd, MapCaptureMessage(uMsg), wParam, lParamW);
  161. if(ar == arAlloc)
  162. GodotHeapFree((LPWSTR)lParamW);
  163. }
  164. break;
  165. case CB_ADDSTRING:
  166. case CB_DIR:
  167. case CB_FINDSTRING:
  168. case CB_FINDSTRINGEXACT:
  169. case CB_INSERTSTRING:
  170. case CB_SELECTSTRING:
  171. {
  172. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  173. if(((styl & CBS_OWNERDRAWFIXED) ||
  174. (styl & CBS_OWNERDRAWVARIABLE)) &&
  175. (!(styl & CBS_HASSTRINGS)))
  176. {
  177. // Owner draw combo box which does not have strings stored
  178. // (See Windows Bugs # 356304 for details here)
  179. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  180. }
  181. else
  182. {
  183. // No memory? If the alloc fails, we eat the results.
  184. LPARAM lParamW;
  185. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  186. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  187. if(ar == arAlloc)
  188. GodotHeapFree((LPWSTR)lParamW);
  189. }
  190. }
  191. break;
  192. case LB_ADDSTRING:
  193. case LB_ADDFILE:
  194. case LB_DIR:
  195. case LB_FINDSTRING:
  196. case LB_FINDSTRINGEXACT:
  197. case LB_INSERTSTRING:
  198. case LB_SELECTSTRING:
  199. {
  200. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  201. if(((styl & LBS_OWNERDRAWFIXED) ||
  202. (styl & LBS_OWNERDRAWVARIABLE)) &&
  203. (!(styl & LBS_HASSTRINGS)))
  204. {
  205. // Owner draw listbox which does not have strings stored
  206. // (See Windows Bugs # 356304 for details here)
  207. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  208. }
  209. else
  210. {
  211. // No memory? If the alloc fails, we eat the results.
  212. LPARAM lParamW;
  213. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  214. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  215. if(ar == arAlloc)
  216. GodotHeapFree((LPWSTR)lParamW);
  217. }
  218. break;
  219. }
  220. case EM_REPLACESEL:
  221. case WM_SETTEXT:
  222. case WM_DEVMODECHANGE:
  223. case WM_SETTINGCHANGE:
  224. case WM_SETMESSAGESTRING: // MFC internal msg
  225. {
  226. // No memory? If the alloc fails, we eat the results.
  227. LPARAM lParamW;
  228. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  229. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  230. if(ar == arAlloc)
  231. GodotHeapFree((LPWSTR)lParamW);
  232. break;
  233. }
  234. case WM_DDE_EXECUTE:
  235. // wParam is the client window hWnd, lParam is the command LPTSTR.
  236. // Only convert lParam if both client and server windows are Unicode
  237. if(GetUnicodeWindowProp((HWND)hWnd) && GetUnicodeWindowProp((HWND)wParam))
  238. {
  239. // No memory? If the alloc fails, we eat the results.
  240. LPARAM lParamW;
  241. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  242. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  243. if(ar == arAlloc)
  244. GodotHeapFree((LPWSTR)lParamW);
  245. }
  246. else
  247. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  248. break;
  249. case EM_GETLINE:
  250. {
  251. // lParam is a pointer to the buffer that receives a copy of the line. Before
  252. // sending the message, set the first word of this buffer to the size, in TCHARs,
  253. // of the buffer. For ANSI text, this is the number of bytes; for Unicode text,
  254. // this is the numer of characters. The size in the first word is overwritten by
  255. // the copied line.
  256. size_t cchlParam = (WORD)lParam + 1;
  257. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
  258. if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
  259. {
  260. RetVal = WideCharToMultiByte(g_acp,
  261. 0,
  262. (LPWSTR)lParamW,
  263. RetVal + 1,
  264. (LPSTR)lParam,
  265. cchlParam,
  266. NULL,
  267. NULL);
  268. if(RetVal)
  269. RetVal--;
  270. }
  271. else
  272. {
  273. if((LPSTR)lParam)
  274. *((LPSTR)lParam) = '\0';
  275. }
  276. if(lParamW)
  277. GodotHeapFree((LPWSTR)lParamW);
  278. }
  279. case LB_GETTEXT:
  280. {
  281. // lParam is a pointer to the buffer that will receive the string; it is type
  282. // LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
  283. // space for the string and a terminating null character. An LB_GETTEXTLEN message
  284. // can be sent before the LB_GETTEXT message to retrieve the length, in TCHARs, of
  285. // the string.
  286. size_t cchlParam = SendMessageA(hWnd, LB_GETTEXTLEN, wParam, 0) + 1;
  287. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
  288. if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
  289. {
  290. RetVal = WideCharToMultiByte(g_acp,
  291. 0,
  292. (LPWSTR)lParamW,
  293. RetVal + 1,
  294. (LPSTR)lParam,
  295. cchlParam,
  296. NULL,
  297. NULL);
  298. if(RetVal)
  299. RetVal--;
  300. }
  301. else
  302. {
  303. if((LPSTR)lParam)
  304. *((LPSTR)lParam) = '\0';
  305. }
  306. if(lParamW)
  307. GodotHeapFree((LPWSTR)lParamW);
  308. break;
  309. }
  310. case CB_GETLBTEXT:
  311. {
  312. // lParam is a pointer to the buffer that will receive the string; it is type
  313. // LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
  314. // space for the string and a terminating null character. An CB_GETLBTEXTLEN message
  315. // can be sent before the CB_GETLBTEXT message to retrieve the length, in TCHARs, of
  316. // the string.
  317. size_t cchlParam = SendMessageA(hWnd, CB_GETLBTEXTLEN, wParam, 0) + 1;
  318. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(cchlParam * sizeof(WCHAR));
  319. if((RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW)) && lParamW)
  320. {
  321. RetVal = WideCharToMultiByte(g_acp,
  322. 0,
  323. (LPWSTR)lParamW,
  324. RetVal + 1,
  325. (LPSTR)lParam,
  326. cchlParam,
  327. NULL,
  328. NULL);
  329. if(RetVal)
  330. RetVal--;
  331. }
  332. else
  333. {
  334. if((LPSTR)lParam)
  335. *((LPSTR)lParam) = '\0';
  336. }
  337. if(lParamW)
  338. GodotHeapFree((LPWSTR)lParamW);
  339. break;
  340. }
  341. case (WM_USER + 67): // might be WM_CAP_GET_MCI_DEVICEA
  342. case (WM_USER + 12): // might be WM_CAP_DRIVER_GET_NAMEA
  343. case (WM_USER + 13): // might be WM_CAP_DRIVER_GET_VERSIONA
  344. case (WM_USER + 21): // might be WM_CAP_FILE_GET_CAPTURE_FILEA
  345. if(!IsCaptureWindow(hWnd))
  346. {
  347. // The numbers are right, but its not a capture window, so
  348. // do not convert. Instead, just pass as is.
  349. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  350. break;
  351. }
  352. // If we are still here, then it is a capture message.
  353. // So lets map it and fall through.
  354. uMsg = MapCaptureMessage(uMsg);
  355. case WM_GETTEXT:
  356. case WM_ASKCBFORMATNAME:
  357. {
  358. // wParam specifies the buffer size of the string lParam (includes the terminating null).
  359. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc((UINT)wParam * sizeof(WCHAR));
  360. if(RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW))
  361. {
  362. RetVal = WideCharToMultiByte(g_acp,
  363. 0,
  364. (LPWSTR)lParamW,
  365. RetVal + 1,
  366. (LPSTR)lParam,
  367. (UINT)wParam,
  368. NULL,
  369. NULL);
  370. if(RetVal)
  371. RetVal--;
  372. }
  373. else
  374. {
  375. if((LPSTR)lParam)
  376. *((LPSTR)lParam) = '\0';
  377. }
  378. if(lParamW)
  379. GodotHeapFree((LPWSTR)lParamW);
  380. break;
  381. }
  382. case (WM_USER + 1):
  383. if(IsFontDialog(hWnd))
  384. {
  385. // This is a WM_CHOOSEFONT_GETLOGFONT msg
  386. LPARAM lParamW = (LPARAM)(LPLOGFONTW)GodotHeapAlloc(sizeof(LOGFONTW));
  387. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  388. LogFontAfromW((LPLOGFONTA)lParam, (LPLOGFONTW)lParamW);
  389. if(lParamW)
  390. GodotHeapFree((LPWSTR)lParamW);
  391. }
  392. else
  393. {
  394. // This would be one of the common control msgs we do not handle
  395. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  396. break;
  397. }
  398. break;
  399. case (WM_USER + 100):
  400. if(IsNewFileOpenDialog(hWnd))
  401. {
  402. // This is a CDM_GETSPEC msg
  403. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
  404. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  405. WideCharToMultiByte(g_acp, 0,
  406. (LPWSTR)lParamW, wParam,
  407. (LPSTR)lParam, wParam,
  408. NULL, NULL);
  409. RetVal = lstrlenA( (LPSTR)lParam);
  410. if(lParamW)
  411. GodotHeapFree((LPWSTR)lParamW);
  412. }
  413. else
  414. {
  415. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  416. }
  417. break;
  418. case (WM_USER + 101):
  419. if(IsFontDialog(hWnd))
  420. {
  421. // This is a WM_CHOOSEFONT_SETLOGFONT msg
  422. LPARAM lParamW = (LPARAM)(LPLOGFONTW)GodotHeapAlloc(sizeof(LOGFONTW));
  423. LogFontWfromA((LPLOGFONTW)lParamW, (LPLOGFONTA)lParam);
  424. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  425. if(lParamW)
  426. GodotHeapFree((LPLOGFONTW)lParamW);
  427. }
  428. else if(IsNewFileOpenDialog(hWnd))
  429. {
  430. // This is a CDM_GETFILEPATH msg
  431. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
  432. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  433. WideCharToMultiByte(g_acp, 0,
  434. (LPWSTR)lParamW, wParam,
  435. (LPSTR)lParam, wParam,
  436. NULL, NULL);
  437. RetVal = lstrlenA( (LPSTR)lParam);
  438. if(lParamW)
  439. GodotHeapFree((LPWSTR)lParamW);
  440. }
  441. else
  442. {
  443. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  444. }
  445. break;
  446. case (WM_USER + 102):
  447. if(IsFontDialog(hWnd))
  448. {
  449. // This is a WM_CHOOSEFONT_SETFLAGS msg
  450. // The docs claim that lParam has a CHOOSEFONT struct but the code shows
  451. // that it only has the Flags in it, so pass it as is
  452. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  453. }
  454. else if(IsNewFileOpenDialog(hWnd))
  455. {
  456. // This is a CDM_GETFOLDERPATH
  457. // lParam is a buffer for the path of the open folder
  458. LPARAM lParamW = (LPARAM)(LPWSTR)GodotHeapAlloc(wParam * sizeof(WCHAR));
  459. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  460. WideCharToMultiByte(g_acp, 0,
  461. (LPWSTR)lParamW, wParam,
  462. (LPSTR)lParam, wParam,
  463. NULL, NULL);
  464. RetVal = lstrlenA( (LPSTR)lParam);
  465. if(lParamW)
  466. GodotHeapFree((LPWSTR)lParamW);
  467. }
  468. else
  469. {
  470. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  471. }
  472. break;
  473. case (WM_USER + 104):
  474. if(IsNewFileOpenDialog(hWnd))
  475. {
  476. // This is a CDM_SETCONTROLTEXT message
  477. // lParam is the control text (wParam is the control ID)
  478. // No memory? If the alloc fails, we eat the results.
  479. LPARAM lParamW;
  480. WPARAM wParamW;
  481. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  482. wParamW = gwcslen((LPWSTR)lParamW);
  483. RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParamW);
  484. if(ar == arAlloc)
  485. GodotHeapFree((LPWSTR)lParamW);
  486. }
  487. else
  488. {
  489. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  490. }
  491. break;
  492. case (WM_USER + 106):
  493. if(IsNewFileOpenDialog(hWnd))
  494. {
  495. // This is a CDM_SETDEFEXT message
  496. // lParam is the extension
  497. // No memory? If the alloc fails, we eat the results.
  498. LPARAM lParamW;
  499. WPARAM wParamW;
  500. ALLOCRETURN ar = GodotToUnicodeOnHeap((LPSTR)lParam, &(LPWSTR)lParamW);
  501. wParamW = gwcslen((LPWSTR)lParamW);
  502. RetVal = (* lpfn)(hWnd, uMsg, wParamW, lParamW);
  503. if(ar == arAlloc)
  504. GodotHeapFree((LPWSTR)lParamW);
  505. }
  506. else
  507. {
  508. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  509. }
  510. break;
  511. case WM_CREATE:
  512. case WM_NCCREATE:
  513. {
  514. LPCREATESTRUCTA lpcsA = (LPCREATESTRUCTA)lParam;
  515. CREATESTRUCTW cs;
  516. ALLOCRETURN arName = arNoAlloc;
  517. ALLOCRETURN arClass = arNoAlloc;
  518. ZeroMemory(&cs, sizeof(CREATESTRUCTW));
  519. cs.lpCreateParams = lpcsA->lpCreateParams;
  520. cs.hInstance = lpcsA->hInstance;
  521. cs.hMenu = lpcsA->hMenu;
  522. cs.hwndParent = lpcsA->hwndParent;
  523. cs.cy = lpcsA->cy;
  524. cs.cx = lpcsA->cx;
  525. cs.y = lpcsA->y;
  526. cs.x = lpcsA->x;
  527. cs.style = lpcsA->style;
  528. cs.dwExStyle = lpcsA->dwExStyle;
  529. arName = GodotToUnicodeOnHeap(lpcsA->lpszName, &(LPWSTR)(cs.lpszName));
  530. arClass = GodotToUnicodeOnHeap(lpcsA->lpszClass, &(LPWSTR)(cs.lpszClass));
  531. RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&cs);
  532. // Free up strings if we allocated any
  533. if(arName==arAlloc)
  534. GodotHeapFree((LPWSTR)(cs.lpszName));
  535. if(arClass==arAlloc)
  536. GodotHeapFree((LPWSTR)(cs.lpszClass));
  537. break;
  538. }
  539. case WM_MDICREATE:
  540. {
  541. // wParam is not used, lParam is a pointer to an MDICREATESTRUCT structure containing
  542. // information that the system uses to create the MDI child window.
  543. LPMDICREATESTRUCTA lpmcsiA = (LPMDICREATESTRUCTA)lParam;
  544. MDICREATESTRUCTW mcsi;
  545. ALLOCRETURN arTitle = arNoAlloc;
  546. ALLOCRETURN arClass = arNoAlloc;
  547. ZeroMemory(&mcsi, sizeof(MDICREATESTRUCTW));
  548. mcsi.hOwner = lpmcsiA->hOwner;
  549. mcsi.x = lpmcsiA->x;
  550. mcsi.y = lpmcsiA->y;
  551. mcsi.cx = lpmcsiA->cx;
  552. mcsi.cy = lpmcsiA->cy;
  553. mcsi.style = lpmcsiA->style;
  554. mcsi.lParam = lpmcsiA->lParam;
  555. arTitle = GodotToUnicodeOnHeap(lpmcsiA->szTitle, &(LPWSTR)(mcsi.szTitle));
  556. arClass = GodotToUnicodeOnHeap(lpmcsiA->szClass, &(LPWSTR)(mcsi.szClass));
  557. RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&mcsi);
  558. // Free up strings if we allocated any
  559. if(arTitle==arAlloc)
  560. GodotHeapFree((LPWSTR)(mcsi.szTitle));
  561. if(arClass==arAlloc)
  562. GodotHeapFree((LPWSTR)(mcsi.szClass));
  563. break;
  564. }
  565. case WM_DEVICECHANGE:
  566. {
  567. switch(wParam)
  568. {
  569. case DBT_CUSTOMEVENT:
  570. case DBT_DEVICEARRIVAL:
  571. case DBT_DEVICEQUERYREMOVE:
  572. case DBT_DEVICEQUERYREMOVEFAILED:
  573. case DBT_DEVICEREMOVECOMPLETE:
  574. case DBT_DEVICEREMOVEPENDING:
  575. case DBT_DEVICETYPESPECIFIC:
  576. {
  577. // lParam contains info about the device. We interrogate it as if it were
  578. // a PDEV_BROADCAST_HDR in order to find out what it really is, then convert
  579. // as needed
  580. if (((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
  581. {
  582. PDEV_BROADCAST_DEVICEINTERFACE_A pdbdia = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam;
  583. DEV_BROADCAST_DEVICEINTERFACE_W dbdi;
  584. ALLOCRETURN arName = arNoAlloc;
  585. ZeroMemory(&dbdi, sizeof(DEV_BROADCAST_DEVICEINTERFACE_W));
  586. dbdi.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W);
  587. dbdi.dbcc_devicetype = pdbdia->dbcc_devicetype;
  588. dbdi.dbcc_reserved = pdbdia->dbcc_reserved;
  589. dbdi.dbcc_classguid = pdbdia->dbcc_classguid;
  590. arName = GodotToUnicodeOnHeap(pdbdia->dbcc_name, *(LPWSTR**)(dbdi.dbcc_name));
  591. RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&dbdi);
  592. if(arName==arAlloc)
  593. GodotHeapFree(dbdi.dbcc_name);
  594. }
  595. else if(((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_PORT)
  596. {
  597. PDEV_BROADCAST_PORT_A pdbpa = (PDEV_BROADCAST_PORT_A)lParam;
  598. DEV_BROADCAST_PORT_W dbp;
  599. ALLOCRETURN arName = arNoAlloc;
  600. ZeroMemory(&dbp, sizeof(DEV_BROADCAST_PORT_W));
  601. dbp.dbcp_size = sizeof(DEV_BROADCAST_PORT_W);
  602. dbp.dbcp_devicetype = pdbpa->dbcp_devicetype;
  603. dbp.dbcp_reserved = pdbpa->dbcp_reserved;
  604. arName = GodotToUnicodeOnHeap(pdbpa->dbcp_name, *(LPWSTR**)(dbp.dbcp_name));
  605. RetVal = (* lpfn)(hWnd, uMsg, wParam, (LPARAM)&dbp);
  606. if(arName==arAlloc)
  607. GodotHeapFree(dbp.dbcp_name);
  608. }
  609. else
  610. {
  611. // No changes needed! There are no strings in the other structures.
  612. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  613. }
  614. break;
  615. }
  616. case DBT_USERDEFINED:
  617. // No UNICODE string in this one, so fall through
  618. default:
  619. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  620. break;
  621. }
  622. break;
  623. }
  624. default:
  625. {
  626. // Lets get our registered messages, if we haven't yet.
  627. if(!msgHELPMSGSTRING)
  628. msgHELPMSGSTRING = RegisterWindowMessage(HELPMSGSTRINGA);
  629. if(!msgFINDMSGSTRING)
  630. msgFINDMSGSTRING = RegisterWindowMessage(FINDMSGSTRINGA);
  631. if((uMsg == msgHELPMSGSTRING) &&
  632. (((LPOPENFILENAMEA)lParam)->lStructSize == OPENFILENAME_SIZE_VERSION_400A))
  633. {
  634. WCHAR drive[_MAX_DRIVE];
  635. WCHAR dir[_MAX_DIR];
  636. WCHAR file[_MAX_FNAME];
  637. LPOPENFILENAMEA lpofnA = (LPOPENFILENAMEA)lParam;
  638. OPENFILENAMEW ofn;
  639. ALLOCRETURN arCustomFilter = arNoAlloc;
  640. ALLOCRETURN arFile = arNoAlloc;
  641. ALLOCRETURN arFileTitle = arNoAlloc;
  642. // lParam is an LPOPENFILENAMEA to be converted. Copy all the
  643. // members that the user might expect.
  644. ZeroMemory(&ofn, OPENFILENAME_SIZE_VERSION_400W);
  645. ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
  646. arCustomFilter = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrCustomFilter,
  647. lpofnA->nMaxCustFilter,
  648. &ofn.lpstrCustomFilter,
  649. g_acp);
  650. ofn.nMaxCustFilter = gwcslen(ofn.lpstrCustomFilter);
  651. ofn.nFilterIndex = lpofnA->nFilterIndex;
  652. ofn.nMaxFile = lpofnA->nMaxFile * sizeof(WCHAR);
  653. arFile = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrFile,
  654. lpofnA->nMaxFile,
  655. &ofn.lpstrFile,
  656. g_acp);
  657. ofn.nMaxFile = gwcslen(ofn.lpstrFile);
  658. arFileTitle = GodotToUnicodeCpgCchOnHeap(lpofnA->lpstrFileTitle,
  659. lpofnA->nMaxFileTitle,
  660. &ofn.lpstrFileTitle,
  661. g_acp);
  662. ofn.nMaxFileTitle = gwcslen(ofn.lpstrFileTitle);
  663. ofn.Flags = lpofnA->Flags;
  664. // nFileOffset and nFileExtension are to provide info about the
  665. // file name and extension location in lpstrFile, but there is
  666. // no reasonable way to get it from the return so we just recalc
  667. gwsplitpath(ofn.lpstrFile, drive, dir, file, NULL);
  668. ofn.nFileOffset = (gwcslen(drive) + gwcslen(dir));
  669. ofn.nFileExtension = ofn.nFileOffset + gwcslen(file);
  670. RetVal = (*lpfn)(hWnd, uMsg, wParam, (LPARAM)&ofn);
  671. // Free up some memory if we allocated any
  672. if(arCustomFilter==arAlloc)
  673. GodotHeapFree(ofn.lpstrCustomFilter);
  674. if(arFile==arAlloc)
  675. GodotHeapFree(ofn.lpstrFile);
  676. if(arFileTitle==arAlloc)
  677. GodotHeapFree(ofn.lpstrFileTitle);
  678. }
  679. else if(((uMsg == msgFINDMSGSTRING) || (uMsg == msgHELPMSGSTRING)) &&
  680. ((((LPFINDREPLACEW)lParam)->lStructSize) == sizeof(FINDREPLACEA)))
  681. {
  682. LPFINDREPLACEW lpfr = (LPFINDREPLACEW)lParam;
  683. // lParam is an LPFINDREPLACEW that we passed on through.
  684. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  685. if((lpfr->Flags & FR_DIALOGTERM) &&
  686. ((lpfr->lpfnHook == &FRHookProcFind) || (lpfr->lpfnHook == &FRHookProcReplace)))
  687. {
  688. // Now handle our cleanup. I do not think this should
  689. // be needed, but it can't hurt to do it just in case.
  690. LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
  691. // They are destroying the dialog, so unhook ourselves
  692. // and clean up the dialog (if we have not done it yet).
  693. if(lpfr->lpfnHook == &FRHookProcFind)
  694. {
  695. // Find dialog, not yet cleaned up
  696. lpfr->lpfnHook = lpgti->pfnFindText;
  697. if(lpfr->lpfnHook == NULL)
  698. lpfr->Flags &= ~FR_ENABLEHOOK;
  699. }
  700. else if(lpfr->lpfnHook == &FRHookProcReplace)
  701. {
  702. // Replace dialog, not yet cleaned up
  703. lpfr->lpfnHook = lpgti->pfnReplaceText;
  704. if(lpfr->lpfnHook == NULL)
  705. lpfr->Flags &= ~FR_ENABLEHOOK;
  706. }
  707. }
  708. }
  709. else if((uMsg == msgHELPMSGSTRING) &&
  710. ((LPCHOOSEFONTA)lParam)->lStructSize == sizeof(CHOOSEFONTA))
  711. {
  712. LPCHOOSEFONTA lpcfA = (LPCHOOSEFONTA)lParam;
  713. CHOOSEFONTW cf;
  714. LPARAM lParamW;
  715. ALLOCRETURN ar = arNoAlloc;
  716. // lParam is an LPCHOOSEFONTA to be converted. Copy all the
  717. // members that the user might expect.
  718. ZeroMemory(&cf, sizeof(CHOOSEFONTW));
  719. cf.lStructSize = sizeof(CHOOSEFONTW);
  720. cf.hDC = lpcfA->hDC;
  721. LogFontWfromA(cf.lpLogFont, lpcfA->lpLogFont);
  722. cf.iPointSize = lpcfA->iPointSize;
  723. cf.Flags = lpcfA->Flags;
  724. cf.rgbColors = lpcfA->rgbColors;
  725. cf.lCustData = lpcfA->lCustData;
  726. cf.nFontType = lpcfA->nFontType;
  727. cf.nSizeMin = lpcfA->nSizeMin;
  728. cf.nSizeMax = lpcfA->nSizeMax;
  729. ar = GodotToUnicodeOnHeap(lpcfA->lpszStyle, &(cf.lpszStyle));
  730. lParamW = (LPARAM)&cf;
  731. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParamW);
  732. if(ar==arAlloc)
  733. GodotHeapFree((LPWSTR)cf.lpszStyle);
  734. }
  735. else
  736. {
  737. // No translation needed, as far as we know.
  738. RetVal = (* lpfn)(hWnd, uMsg, wParam, lParam);
  739. }
  740. break;
  741. }
  742. }
  743. return(RetVal);
  744. }
  745. }
  746. /*-------------------------------
  747. GodotTransmitMessage
  748. Our global wrapper for sending out messages (SendMessage, et. al.).
  749. Its fundamental purpose:
  750. 1) Convert back to Ansi, as expected
  751. 2) Call the function as specified by mt
  752. 3) Convert to Unicode, as expected
  753. -------------------------------*/
  754. LRESULT GodotTransmitMessage(
  755. MESSAGETYPES mt, // Type of message function
  756. HWND hWnd, // handle to window - overloaded for thread id in PostThreadMessage
  757. UINT Msg, // message
  758. WPARAM wParamW, // first message parameter
  759. LPARAM lParamW, // second message parameter
  760. WNDPROC lpPrevWndFunc, // pointer to previous procedure - overloaded for multiple hook procs
  761. SENDASYNCPROC lpCallBack, // callback function
  762. ULONG_PTR dwData, // application-defined value - overloaded for DefFrameProc as second hWnd
  763. UINT fuFlags, // send options -- overloaded for BroadcastSystemMessages as dwFlags
  764. UINT uTimeout, // time-out duration
  765. PDWORD_PTR lpdwResult // retval for synch. -- overloaded BroadcastSystemMessages lpdwRecipients
  766. )
  767. {
  768. LRESULT retval = 0;
  769. WPARAM wParam = 0;
  770. LPARAM lParam = 0;
  771. size_t cchlParam;
  772. // Some flags we will need for our message handling
  773. BOOL fUnicodeProc = (! DoesProcExpectAnsi(hWnd, lpPrevWndFunc, fptUnknown));
  774. /*
  775. fUnicodeProc == Does the wndproc being called expect Unicode messages?
  776. */
  777. if((!fUnicodeProc) && (mt==mtCallWindowProcA) ||
  778. (fUnicodeProc) && ((mt==mtCallWindowProc)))
  779. {
  780. // The wndproc either expects ANSI and the caller has used one of the ANSI
  781. // functions or it expects Unicode and they have used CallWindowProcW. In
  782. // these cases, we do no conversions here
  783. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  784. lpPrevWndFunc, lpCallBack, dwData,
  785. fuFlags, uTimeout, lpdwResult);
  786. }
  787. else
  788. {
  789. switch(Msg)
  790. {
  791. case WM_CHAR:
  792. case EM_SETPASSWORDCHAR:
  793. case WM_DEADCHAR:
  794. case WM_SYSCHAR:
  795. case WM_SYSDEADCHAR:
  796. case WM_MENUCHAR:
  797. // All these messages require the wParamW to be converted from Unicode
  798. wParam = 0;
  799. WideCharToMultiByte(g_acp, 0, (WCHAR *)&wParamW, 1, (char *)&wParam, g_mcs, NULL, NULL);
  800. if(FDBCS_CPG(g_acp))
  801. {
  802. if(!wParam)
  803. {
  804. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
  805. lpPrevWndFunc, lpCallBack, dwData,
  806. fuFlags, uTimeout, lpdwResult);
  807. break;
  808. }
  809. else if(IsDBCSLeadByte(*(char *)(LOBYTE(wParam))))
  810. {
  811. // Ok, its a DBCS code page and wParam contains a DBCS character.
  812. // we must send two WM_CHAR messages, one with each byte in it
  813. char sz[2];
  814. sz[0] = *(char *)LOBYTE(wParam);
  815. sz[1] = *(char *)HIBYTE(wParam);
  816. retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)&sz[0], lParamW,
  817. lpPrevWndFunc, lpCallBack, dwData,
  818. fuFlags, uTimeout, lpdwResult);
  819. if(retval==0)
  820. {
  821. // The first byte was handled, so send the second byte
  822. retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)&sz[1], lParamW,
  823. lpPrevWndFunc, lpCallBack, dwData,
  824. fuFlags, uTimeout, lpdwResult);
  825. }
  826. MultiByteToWideChar(g_acp, 0, (char *)&sz[0], g_mcs, (WCHAR *)&wParamW, 1);
  827. break;
  828. }
  829. }
  830. /*
  831. if(FDBCS_CPG(g_acp) && (IsDBCSLeadByte((LOBYTE(wParam)))))
  832. {
  833. // Ok, its a DBCS code page and wParam contains a DBCS character.
  834. // we must send two WM_CHAR messages, one with each byte in it
  835. retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)LOBYTE(wParam), lParamW,
  836. lpPrevWndFunc, lpCallBack, dwData,
  837. fuFlags, uTimeout, lpdwResult);
  838. if(retval==0)
  839. {
  840. // The first byte was handled, so send the second byte
  841. retval = TransmitHelper(mt, hWnd, Msg, (WPARAM)HIBYTE(wParam), lParamW,
  842. lpPrevWndFunc, lpCallBack, dwData,
  843. fuFlags, uTimeout, lpdwResult);
  844. }
  845. break;
  846. }
  847. */
  848. // Not a DBCS code page, or at least not a DBCS character, so we just fall through now.
  849. case WM_IME_CHAR:
  850. case WM_IME_COMPOSITION:
  851. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
  852. lpPrevWndFunc, lpCallBack, dwData,
  853. fuFlags, uTimeout, lpdwResult);
  854. MultiByteToWideChar(g_acp, 0, (char *)&wParam, g_mcs, (WCHAR *)&wParamW, 1);
  855. break;
  856. case WM_CHARTOITEM:
  857. {
  858. // Mask off the hiword bits, convert, then stick the hiword bits back on.
  859. WPARAM wpT = wParamW & 0xFFFF;
  860. WideCharToMultiByte(g_acp, 0, (WCHAR *)&wpT, 1, (char *)&wParam, g_mcs, NULL, NULL);
  861. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParamW,
  862. lpPrevWndFunc, lpCallBack, dwData,
  863. fuFlags, uTimeout, lpdwResult);
  864. MultiByteToWideChar(g_acp, 0, (char *)&wParam, g_mcs, (WCHAR *)&wpT, 1);
  865. wParamW = MAKELONG(LOWORD(wpT),HIWORD(wParamW));
  866. break;
  867. }
  868. case (WM_USER + 125): // might be WM_CAP_FILE_SAVEDIBW:
  869. case (WM_USER + 123): // might be WM_CAP_FILE_SAVEASW:
  870. case (WM_USER + 166): // might be WM_CAP_SET_MCI_DEVICEW:
  871. case (WM_USER + 180): // might be WM_CAP_PAL_OPENW:
  872. case (WM_USER + 181): // might be WM_CAP_PAL_SAVEW:
  873. case (WM_USER + 120): // might be WM_CAP_FILE_SET_CAPTURE_FILEW:
  874. if(!IsCaptureWindow(hWnd))
  875. {
  876. // The numbers are right, but its not a capture window, so
  877. // do not convert. Instead, just pass as is.
  878. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
  879. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  880. }
  881. else
  882. {
  883. // No memory? If the alloc fails, we eat the results.
  884. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  885. if(ar != arFailed)
  886. {
  887. Msg = MapCaptureMessage(Msg);
  888. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  889. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  890. }
  891. if(ar == arAlloc)
  892. GodotHeapFree((LPSTR)lParam);
  893. }
  894. break;
  895. case CB_ADDSTRING:
  896. case CB_DIR:
  897. case CB_FINDSTRING:
  898. case CB_FINDSTRINGEXACT:
  899. case CB_INSERTSTRING:
  900. case CB_SELECTSTRING:
  901. {
  902. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  903. if(((styl & CBS_OWNERDRAWFIXED) ||
  904. (styl & CBS_OWNERDRAWVARIABLE)) &&
  905. (!(styl & CBS_HASSTRINGS)))
  906. {
  907. // Owner draw combo box which does not have strings stored
  908. // (See Windows Bugs # 356304 for details here)
  909. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
  910. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  911. }
  912. else
  913. {
  914. // No memory? If the alloc fails, we eat the results.
  915. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  916. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  917. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  918. if(ar == arAlloc)
  919. GodotHeapFree((LPSTR)lParam);
  920. }
  921. break;
  922. }
  923. case LB_ADDFILE:
  924. case LB_ADDSTRING:
  925. case LB_DIR:
  926. case LB_FINDSTRING:
  927. case LB_FINDSTRINGEXACT:
  928. case LB_INSERTSTRING:
  929. case LB_SELECTSTRING:
  930. {
  931. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  932. if(((styl & LBS_OWNERDRAWFIXED) ||
  933. (styl & LBS_OWNERDRAWVARIABLE)) &&
  934. (!(styl & LBS_HASSTRINGS)))
  935. {
  936. // Owner draw listbox which does not have strings stored
  937. // (See Windows Bugs # 356304 for details here)
  938. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
  939. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  940. }
  941. else
  942. {
  943. // No memory? If the alloc fails, we eat the results.
  944. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  945. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  946. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  947. if(ar == arAlloc)
  948. GodotHeapFree((LPSTR)lParam);
  949. }
  950. break;
  951. }
  952. case EM_REPLACESEL:
  953. case WM_SETTEXT:
  954. case WM_DEVMODECHANGE:
  955. case WM_SETTINGCHANGE:
  956. case WM_SETMESSAGESTRING: // MFC internal msg
  957. {
  958. // All these messages require a string in lParam to be converted from Unicode
  959. // No memory? If the alloc fails, we eat the results.
  960. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  961. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  962. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  963. if(ar == arAlloc)
  964. GodotHeapFree((LPSTR)lParam);
  965. break;
  966. }
  967. case WM_DDE_EXECUTE:
  968. // wParam is the client window hWnd, lParam is the command LPTSTR.
  969. // Only convert lParam if both client and server windows are Unicode
  970. if(GetUnicodeWindowProp((HWND)wParamW))
  971. {
  972. // No memory? If the alloc fails, we eat the results.
  973. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  974. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  975. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  976. if(ar == arAlloc)
  977. GodotHeapFree((LPSTR)lParam);
  978. }
  979. else
  980. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
  981. lpPrevWndFunc, lpCallBack, dwData,
  982. fuFlags, uTimeout, lpdwResult);
  983. break;
  984. case EM_GETLINE:
  985. // lParam is a pointer to the buffer that receives a copy of the line. Before
  986. // sending the message, set the first word of this buffer to the size, in TCHARs,
  987. // of the buffer. For ANSI text, this is the number of bytes; for Unicode text,
  988. // this is the numer of characters. The size in the first word is overwritten by
  989. // the copied line.
  990. cchlParam = (WORD)lParamW;
  991. lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
  992. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  993. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  994. if(retval)
  995. {
  996. retval = MultiByteToWideChar(g_acp,
  997. 0,
  998. (LPSTR)lParam,
  999. retval + 1,
  1000. (LPWSTR)lParamW,
  1001. cchlParam);
  1002. if(retval)
  1003. retval--;
  1004. }
  1005. else
  1006. {
  1007. if((LPWSTR)lParamW)
  1008. *((LPWSTR)lParamW) = L'\0';
  1009. }
  1010. if(lParam)
  1011. GodotHeapFree((LPSTR)lParam);
  1012. break;
  1013. case LB_GETTEXT:
  1014. // lParam is a pointer to the buffer that will receive the string; it is type
  1015. // LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
  1016. // space for the string and a terminating null character. An LB_GETTEXTLEN message
  1017. // can be sent before the LB_GETTEXT message to retrieve the length, in TCHARs, of
  1018. // the string.
  1019. cchlParam = SendMessageA(hWnd, LB_GETTEXTLEN, wParamW, 0) + 1;
  1020. lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
  1021. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  1022. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1023. if(retval)
  1024. {
  1025. retval = MultiByteToWideChar(g_acp,
  1026. 0,
  1027. (LPSTR)lParam,
  1028. retval + 1,
  1029. (LPWSTR)lParamW,
  1030. cchlParam);
  1031. if(retval)
  1032. retval--;
  1033. }
  1034. else
  1035. {
  1036. if((LPWSTR)lParamW)
  1037. *((LPWSTR)lParamW) = L'\0';
  1038. }
  1039. if(lParam)
  1040. GodotHeapFree((LPSTR)lParam);
  1041. break;
  1042. case LB_GETTEXTLEN:
  1043. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1044. lpPrevWndFunc, lpCallBack, dwData,
  1045. fuFlags, uTimeout, lpdwResult);
  1046. if(FDBCS_CPG(g_acp))
  1047. {
  1048. // In the DBCS case, LB_GETTEXTLEN returns number of bytes, but
  1049. // we need to get the number of characters for the Unicode case.
  1050. LPSTR lpsz = GodotHeapAlloc(retval + 1);
  1051. if(lpsz)
  1052. {
  1053. cchlParam = TransmitHelper(mt, hWnd, LB_GETTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
  1054. lpPrevWndFunc, lpCallBack, dwData,
  1055. fuFlags, uTimeout, lpdwResult);
  1056. if(cchlParam > 0)
  1057. {
  1058. LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
  1059. size_t cch = (cchlParam + 1) * sizeof(WCHAR);
  1060. retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
  1061. if(lpwz)
  1062. GodotHeapFree(lpwz);
  1063. }
  1064. GodotHeapFree(lpsz);
  1065. }
  1066. }
  1067. break;
  1068. case CB_GETLBTEXT:
  1069. // lParam is a pointer to the buffer that will receive the string; it is type
  1070. // LPTSTR which is subsequently cast to an LPARAM. The buffer must have sufficient
  1071. // space for the string and a terminating null character. An CB_GETLBTEXTLEN message
  1072. // can be sent before the CB_GETLBTEXT message to retrieve the length, in TCHARs, of
  1073. // the string.
  1074. cchlParam = SendMessageA(hWnd, CB_GETLBTEXTLEN, wParamW, 0) + 1;
  1075. lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
  1076. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  1077. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1078. if(retval)
  1079. {
  1080. retval = MultiByteToWideChar(g_acp,
  1081. 0,
  1082. (LPSTR)lParam,
  1083. retval + 1,
  1084. (LPWSTR)lParamW,
  1085. cchlParam);
  1086. if(retval)
  1087. retval--;
  1088. }
  1089. else
  1090. {
  1091. if((LPWSTR)lParamW)
  1092. *((LPWSTR)lParamW) = L'\0';
  1093. }
  1094. if(lParam)
  1095. GodotHeapFree((LPSTR)lParam);
  1096. break;
  1097. case CB_GETLBTEXTLEN:
  1098. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1099. lpPrevWndFunc, lpCallBack, dwData,
  1100. fuFlags, uTimeout, lpdwResult);
  1101. if(FDBCS_CPG(g_acp))
  1102. {
  1103. // In the DBCS case, CB_GETLBTEXTLEN returns number of bytes, but
  1104. // we need to get the number of characters for the Unicode case.
  1105. LPSTR lpsz = GodotHeapAlloc(retval + 1);
  1106. if(lpsz)
  1107. {
  1108. cchlParam = TransmitHelper(mt, hWnd, CB_GETLBTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
  1109. lpPrevWndFunc, lpCallBack, dwData,
  1110. fuFlags, uTimeout, lpdwResult);
  1111. if(cchlParam > 0)
  1112. {
  1113. LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
  1114. if(lpwz)
  1115. {
  1116. size_t cch = (cchlParam + 1) * sizeof(WCHAR);
  1117. retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
  1118. GodotHeapFree(lpwz);
  1119. }
  1120. }
  1121. GodotHeapFree(lpsz);
  1122. }
  1123. }
  1124. break;
  1125. case (WM_USER + 167): // might be WM_CAP_GET_MCI_DEVICEW
  1126. case (WM_USER + 112): // might be WM_CAP_DRIVER_GET_NAMEW:
  1127. case (WM_USER + 113): // might be WM_CAP_DRIVER_GET_VERSIONW:
  1128. case (WM_USER + 121): // might be WM_CAP_FILE_GET_CAPTURE_FILEW:
  1129. if(!IsCaptureWindow(hWnd))
  1130. {
  1131. // The numbers are right, but its not a capture window, so
  1132. // do not convert. Instead, just pass as is.
  1133. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
  1134. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1135. break;
  1136. }
  1137. // If we are still here, then it is a capture message. So lets map
  1138. // it and faill through.
  1139. Msg = MapCaptureMessage(Msg);
  1140. case WM_GETTEXT:
  1141. // wParam specifies the size of the buffer in the string in lParam
  1142. cchlParam = (size_t)wParamW;
  1143. lParam = (LPARAM)(LPSTR)GodotHeapAlloc(cchlParam * g_mcs);
  1144. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  1145. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1146. if(retval)
  1147. {
  1148. retval = MultiByteToWideChar(g_acp,
  1149. 0,
  1150. (LPSTR)lParam,
  1151. retval + 1,
  1152. (LPWSTR)lParamW,
  1153. cchlParam);
  1154. if(retval)
  1155. retval--;
  1156. }
  1157. else
  1158. {
  1159. if((LPWSTR)lParamW)
  1160. *((LPWSTR)lParamW) = L'\0';
  1161. }
  1162. if(lParam)
  1163. GodotHeapFree((LPSTR)lParam);
  1164. break;
  1165. case WM_GETTEXTLENGTH:
  1166. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1167. lpPrevWndFunc, lpCallBack, dwData,
  1168. fuFlags, uTimeout, lpdwResult);
  1169. if(FDBCS_CPG(g_acp))
  1170. {
  1171. // In the DBCS case, WM_GETTEXTLENGTH returns number of bytes, but
  1172. // we need to get the number of characters for the Unicode case.
  1173. // If any of the allocs fail, we will live with the less than perfect
  1174. // result we have in hand
  1175. LPSTR lpsz = GodotHeapAlloc(retval + 1);
  1176. if(lpsz)
  1177. {
  1178. cchlParam = TransmitHelper(mt, hWnd, WM_GETTEXT, (WPARAM)(retval + 1), (LPARAM)lpsz,
  1179. lpPrevWndFunc, lpCallBack, dwData,
  1180. fuFlags, uTimeout, lpdwResult);
  1181. if(cchlParam > 0)
  1182. {
  1183. LPWSTR lpwz = GodotHeapAlloc((cchlParam + 1) * sizeof(WCHAR));
  1184. if(lpwz)
  1185. {
  1186. size_t cch = (cchlParam + 1) * sizeof(WCHAR);
  1187. retval = MultiByteToWideChar(g_acp, 0, lpsz, cchlParam, lpwz, cch);
  1188. GodotHeapFree(lpwz);
  1189. }
  1190. }
  1191. GodotHeapFree(lpsz);
  1192. }
  1193. }
  1194. break;
  1195. case (WM_USER + 1):
  1196. if(IsFontDialog(hWnd))
  1197. {
  1198. // This is a WM_CHOOSEFONT_GETLOGFONT msg
  1199. LOGFONTA lfa;
  1200. lParam = (LPARAM)&lfa;
  1201. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
  1202. lpPrevWndFunc, lpCallBack, dwData,
  1203. fuFlags, uTimeout, lpdwResult);
  1204. LogFontWfromA((LPLOGFONTW)lParamW, (LPLOGFONTA)lParam);
  1205. }
  1206. else
  1207. {
  1208. // This would be one of the common control msgs we do not handle
  1209. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1210. lpPrevWndFunc, lpCallBack, dwData,
  1211. fuFlags, uTimeout, lpdwResult);
  1212. break;
  1213. }
  1214. break;
  1215. case (WM_USER + 100):
  1216. if(IsNewFileOpenDialog(hWnd))
  1217. {
  1218. // This is a CDM_GETSPEC msg
  1219. wParam = wParamW * g_mcs;
  1220. (LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
  1221. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
  1222. lpPrevWndFunc, lpCallBack, dwData,
  1223. fuFlags, uTimeout, lpdwResult);
  1224. MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
  1225. retval = gwcslen((LPWSTR)lParamW);
  1226. if(lParam)
  1227. GodotHeapFree((LPSTR)lParam);
  1228. }
  1229. else
  1230. {
  1231. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1232. lpPrevWndFunc, lpCallBack, dwData,
  1233. fuFlags, uTimeout, lpdwResult);
  1234. }
  1235. break;
  1236. case (WM_USER + 101):
  1237. if(IsFontDialog(hWnd))
  1238. {
  1239. // This is a WM_CHOOSEFONT_SETLOGFONT msg
  1240. LOGFONTA lfa;
  1241. lParam = (LPARAM)&lfa;
  1242. LogFontAfromW((LPLOGFONTA)lParam, (LPLOGFONTW)lParamW);
  1243. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
  1244. lpPrevWndFunc, lpCallBack, dwData,
  1245. fuFlags, uTimeout, lpdwResult);
  1246. }
  1247. else if(IsNewFileOpenDialog(hWnd))
  1248. {
  1249. // This is a CDM_GETFILEPATH msg
  1250. wParam = wParamW * g_mcs;
  1251. (LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
  1252. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
  1253. lpPrevWndFunc, lpCallBack, dwData,
  1254. fuFlags, uTimeout, lpdwResult);
  1255. MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
  1256. retval = gwcslen((LPWSTR)lParamW);
  1257. if(lParam)
  1258. GodotHeapFree((LPSTR)lParam);
  1259. }
  1260. else
  1261. {
  1262. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1263. lpPrevWndFunc, lpCallBack, dwData,
  1264. fuFlags, uTimeout, lpdwResult);
  1265. }
  1266. break;
  1267. case (WM_USER + 102):
  1268. if(IsFontDialog(hWnd))
  1269. {
  1270. // This is a WM_CHOOSEFONT_SETFLAGS msg
  1271. // The docs claim that lParam has a CHOOSEFONT struct but the code shows
  1272. // that it only has the Flags in it
  1273. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1274. lpPrevWndFunc, lpCallBack, dwData,
  1275. fuFlags, uTimeout, lpdwResult);
  1276. }
  1277. else if(IsNewFileOpenDialog(hWnd))
  1278. {
  1279. // This is a CDM_GETFOLDERPATH
  1280. // lParam is a buffer for the path of the open folder
  1281. wParam = wParamW * g_mcs;
  1282. (LPSTR)lParam = (LPSTR)GodotHeapAlloc(wParam);
  1283. retval = TransmitHelper(mt, hWnd, Msg, wParam, lParam,
  1284. lpPrevWndFunc, lpCallBack, dwData,
  1285. fuFlags, uTimeout, lpdwResult);
  1286. MultiByteToWideChar(g_acp, 0, (LPSTR)lParam, wParam, (LPWSTR)lParamW, wParamW);
  1287. retval = gwcslen((LPWSTR)lParamW);
  1288. if(lParam)
  1289. GodotHeapFree((LPSTR)lParam);
  1290. }
  1291. else
  1292. {
  1293. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1294. lpPrevWndFunc, lpCallBack, dwData,
  1295. fuFlags, uTimeout, lpdwResult);
  1296. }
  1297. break;
  1298. case (WM_USER + 104):
  1299. if(IsNewFileOpenDialog(hWnd))
  1300. {
  1301. // This is a CDM_SETCONTROLTEXT message
  1302. // lParam is the control text (wParam is the control ID)
  1303. // No memory? If the alloc fails, we eat the results.
  1304. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  1305. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  1306. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1307. if(ar == arAlloc)
  1308. GodotHeapFree((LPSTR)lParam);
  1309. }
  1310. else
  1311. {
  1312. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1313. lpPrevWndFunc, lpCallBack, dwData,
  1314. fuFlags, uTimeout, lpdwResult);
  1315. }
  1316. break;
  1317. case (WM_USER + 106):
  1318. if(IsNewFileOpenDialog(hWnd))
  1319. {
  1320. // This is a CDM_SETDEFEXT message
  1321. // lParam is the extension
  1322. // No memory? If the alloc fails, we eat the results.
  1323. ALLOCRETURN ar = GodotToAcpOnHeap((LPWSTR)lParamW, &(LPSTR)lParam);
  1324. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam, lpPrevWndFunc,
  1325. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1326. if(ar == arAlloc)
  1327. GodotHeapFree((LPSTR)lParam);
  1328. }
  1329. else
  1330. {
  1331. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1332. lpPrevWndFunc, lpCallBack, dwData,
  1333. fuFlags, uTimeout, lpdwResult);
  1334. }
  1335. break;
  1336. case EM_GETPASSWORDCHAR:
  1337. {
  1338. // All these messages require that the (single char) retval be converted to Unicode
  1339. // CONSIDER: is this always single character?
  1340. LRESULT retvalA = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1341. lpPrevWndFunc, lpCallBack, dwData,
  1342. fuFlags, uTimeout, lpdwResult);
  1343. MultiByteToWideChar(g_acp, 0,
  1344. (char *)&retvalA,
  1345. g_mcs,
  1346. (WCHAR *)&retval,
  1347. sizeof(WCHAR));
  1348. break;
  1349. }
  1350. case WM_CREATE:
  1351. case WM_NCCREATE:
  1352. {
  1353. LPCREATESTRUCTW lpcs = (LPCREATESTRUCTW)lParamW;
  1354. CREATESTRUCTA csA;
  1355. ALLOCRETURN arClass = arNoAlloc;
  1356. ALLOCRETURN arName = arNoAlloc;
  1357. ZeroMemory(&csA, sizeof(CREATESTRUCTA));
  1358. csA.lpCreateParams = lpcs->lpCreateParams;
  1359. csA.hInstance = lpcs->hInstance;
  1360. csA.hMenu = lpcs->hMenu;
  1361. csA.hwndParent = lpcs->hwndParent;
  1362. csA.cy = lpcs->cy;
  1363. csA.cx = lpcs->cx;
  1364. csA.y = lpcs->y;
  1365. csA.x = lpcs->x;
  1366. csA.style = lpcs->style;
  1367. csA.dwExStyle = lpcs->dwExStyle;
  1368. arClass = GodotToAcpOnHeap(lpcs->lpszClass, &(LPSTR)(csA.lpszClass));
  1369. arName = GodotToAcpOnHeap(lpcs->lpszName, &(LPSTR)(csA.lpszName));
  1370. lParam = (LPARAM)&csA;
  1371. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParam,
  1372. lpPrevWndFunc, lpCallBack, dwData,
  1373. fuFlags, uTimeout, lpdwResult);
  1374. if(arClass==arAlloc)
  1375. GodotHeapFree((LPSTR)csA.lpszClass);
  1376. if(arName==arAlloc)
  1377. GodotHeapFree((LPSTR)csA.lpszName);
  1378. break;
  1379. }
  1380. case WM_MDICREATE:
  1381. // wParam is not used, lParam is a pointer to an MDICREATESTRUCT structure containing
  1382. // information that the system uses to create the MDI child window.
  1383. {
  1384. LPMDICREATESTRUCTW lpmcsi = (LPMDICREATESTRUCTW)lParamW;
  1385. MDICREATESTRUCTA mcsiA;
  1386. ALLOCRETURN arClass = arNoAlloc;
  1387. ALLOCRETURN arTitle = arNoAlloc;
  1388. ZeroMemory(&mcsiA, sizeof(MDICREATESTRUCTA));
  1389. mcsiA.hOwner = lpmcsi->hOwner;
  1390. mcsiA.x = lpmcsi->x;
  1391. mcsiA.y = lpmcsi->y;
  1392. mcsiA.cx = lpmcsi->cx;
  1393. mcsiA.cy = lpmcsi->cy;
  1394. mcsiA.style = lpmcsi->style;
  1395. mcsiA.lParam = lpmcsi->lParam;
  1396. arClass = GodotToAcpOnHeap(lpmcsi->szClass, &(LPSTR)(mcsiA.szClass));
  1397. arTitle = GodotToAcpOnHeap(lpmcsi->szTitle, &(LPSTR)(mcsiA.szTitle));
  1398. retval = TransmitHelper(mt, hWnd, Msg, wParamW, (LPARAM)&mcsiA,
  1399. lpPrevWndFunc, lpCallBack, dwData,
  1400. fuFlags, uTimeout, lpdwResult);
  1401. if(arClass==arAlloc)
  1402. GodotHeapFree((LPSTR)mcsiA.szClass);
  1403. if(arTitle==arAlloc)
  1404. GodotHeapFree((LPSTR)mcsiA.szTitle);
  1405. }
  1406. break;
  1407. default:
  1408. // Lets get our registered messages, if we haven't yet.
  1409. if(!msgHELPMSGSTRING)
  1410. msgHELPMSGSTRING = RegisterWindowMessage(HELPMSGSTRINGA);
  1411. if(!msgFINDMSGSTRING)
  1412. msgFINDMSGSTRING = RegisterWindowMessage(FINDMSGSTRINGA);
  1413. if(((Msg == msgFINDMSGSTRING) || (Msg == msgHELPMSGSTRING)) &&
  1414. ((((LPFINDREPLACEW)lParamW)->lStructSize) == sizeof(FINDREPLACEA)))
  1415. {
  1416. LPFINDREPLACEW lpfr;
  1417. // No translation needed
  1418. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW,
  1419. lpPrevWndFunc, lpCallBack, dwData,
  1420. fuFlags, uTimeout, lpdwResult);
  1421. lpfr = (LPFINDREPLACEW)lParamW;
  1422. if((lpfr->Flags & FR_DIALOGTERM) &&
  1423. ((lpfr->lpfnHook == &FRHookProcFind) || (lpfr->lpfnHook == &FRHookProcReplace)))
  1424. {
  1425. // Now handle our cleanup. I do not think this should
  1426. // be needed, but it can't hurt to do it just in case.
  1427. LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
  1428. // They are destroying the dialog, so unhook ourselves
  1429. // and clean up the dialog (if we have not done it yet).
  1430. if(lpfr->lpfnHook == &FRHookProcFind)
  1431. {
  1432. // Find dialog, not yet cleaned up
  1433. lpfr->lpfnHook = lpgti->pfnFindText;
  1434. if(lpfr->lpfnHook == NULL)
  1435. lpfr->Flags &= ~FR_ENABLEHOOK;
  1436. }
  1437. else if(lpfr->lpfnHook == &FRHookProcReplace)
  1438. {
  1439. // Replace dialog, not yet cleaned up
  1440. lpfr->lpfnHook = lpgti->pfnReplaceText;
  1441. if(lpfr->lpfnHook == NULL)
  1442. lpfr->Flags &= ~FR_ENABLEHOOK;
  1443. }
  1444. }
  1445. }
  1446. else if((Msg == msgHELPMSGSTRING) &&
  1447. ((LPCHOOSEFONTA)lParamW)->lStructSize == sizeof(CHOOSEFONTA))
  1448. {
  1449. LPCHOOSEFONTW lpcf = (LPCHOOSEFONTW)lParamW;
  1450. CHOOSEFONTA cfA;
  1451. ALLOCRETURN ar = arNoAlloc;
  1452. // lParam is an LPCHOOSEFONTW to be converted. Copy all the
  1453. // members that the user might expect.
  1454. ZeroMemory(&cfA, sizeof(CHOOSEFONTA));
  1455. cfA.lStructSize = sizeof(CHOOSEFONTA);
  1456. cfA.hDC = lpcf->hDC;
  1457. LogFontAfromW(cfA.lpLogFont, lpcf->lpLogFont);
  1458. cfA.iPointSize = lpcf->iPointSize;
  1459. cfA.Flags = lpcf->Flags;
  1460. cfA.rgbColors = lpcf->rgbColors;
  1461. cfA.lCustData = lpcf->lCustData;
  1462. ar = GodotToAcpOnHeap(lpcf->lpszStyle, &(cfA.lpszStyle));
  1463. cfA.nFontType = lpcf->nFontType;
  1464. cfA.nSizeMin = lpcf->nSizeMin;
  1465. cfA.nSizeMax = lpcf->nSizeMax;
  1466. retval = TransmitHelper(mt, hWnd, Msg, wParamW, (LPARAM)&cfA, lpPrevWndFunc,
  1467. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1468. if(ar==arAlloc)
  1469. GodotHeapFree(cfA.lpszStyle);
  1470. break;
  1471. }
  1472. else
  1473. {
  1474. // No translation needed
  1475. retval = TransmitHelper(mt, hWnd, Msg, wParamW, lParamW, lpPrevWndFunc,
  1476. lpCallBack, dwData, fuFlags, uTimeout, lpdwResult);
  1477. break;
  1478. }
  1479. }
  1480. }
  1481. return (retval);
  1482. }
  1483. /*-------------------------------
  1484. TransmitHelper
  1485. Our helper function that handles the proper one of
  1486. the twelve functions that call GodotTransmitMessage
  1487. -------------------------------*/
  1488. LRESULT TransmitHelper(
  1489. MESSAGETYPES mt,
  1490. HWND hWnd,
  1491. UINT Msg,
  1492. WPARAM wParam,
  1493. LPARAM lParam,
  1494. WNDPROC lpPrevWndFunc,
  1495. SENDASYNCPROC lpCallBack,
  1496. ULONG_PTR dwData,
  1497. UINT fuFlags,
  1498. UINT uTimeout,
  1499. PDWORD_PTR lpdwResult
  1500. )
  1501. {
  1502. LRESULT RetVal;
  1503. switch(mt)
  1504. {
  1505. case mtSendMessage:
  1506. {
  1507. // We have to special case the WM_MDICREATE case, because it creates a window and we
  1508. // thus have to do the hook, etc. Note that currently it is only done in SendMessage,
  1509. // not in any other call -- this matches the docs, and we cannot risk hitting a
  1510. // recursive situation here.
  1511. if(Msg==WM_MDICREATE)
  1512. {
  1513. LPGODOTTLSINFO lpgti = GetThreadInfoSafe(TRUE);
  1514. if(lpgti)
  1515. INIT_WINDOW_SNIFF(lpgti->hHook);
  1516. RetVal=SendMessageA(hWnd, Msg, wParam, lParam);
  1517. if(lpgti)
  1518. TERM_WINDOW_SNIFF(lpgti->hHook);
  1519. }
  1520. else
  1521. {
  1522. RetVal=SendMessageA(hWnd, Msg, wParam, lParam);
  1523. }
  1524. break;
  1525. }
  1526. case mtSendMessageCallback:
  1527. RetVal=(LRESULT)SendMessageCallbackA(hWnd, Msg, wParam, lParam, lpCallBack, dwData);
  1528. break;
  1529. case mtSendMessageTimeout:
  1530. RetVal=SendMessageTimeoutA(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult);
  1531. break;
  1532. case mtSendNotifyMessage:
  1533. RetVal=(LRESULT)SendNotifyMessageA(hWnd, Msg, wParam, lParam);
  1534. break;
  1535. case mtPostMessage:
  1536. RetVal=(LRESULT)PostMessageA(hWnd, Msg, wParam, lParam);
  1537. break;
  1538. case mtPostThreadMessage:
  1539. // hWnd is overloaded in this case to be the thread ID
  1540. RetVal=(LRESULT)PostThreadMessageA((DWORD)hWnd, Msg, wParam, lParam);
  1541. break;
  1542. case mtCallWindowProc:
  1543. case mtCallWindowProcA:
  1544. {
  1545. WNDPROC lpfn = WndprocFromFauxWndproc(hWnd, lpPrevWndFunc, fptUnknown);
  1546. // If the wndproc was not a "faux" one or if the wndproc
  1547. // is expecting ANSI (or both!), then use CallWindowProcA,
  1548. // since that is what the wndproc would expect. Otherwise,
  1549. // use Unicode and call the function directly.
  1550. if((lpfn==lpPrevWndFunc) || (DoesProcExpectAnsi(hWnd, lpfn, fptUnknown)))
  1551. {
  1552. if(lpfn)
  1553. RetVal=((CallWindowProcA)(lpfn, hWnd, Msg, wParam, lParam));
  1554. }
  1555. else
  1556. {
  1557. if(lpfn)
  1558. RetVal=((* lpfn)(hWnd, Msg, wParam, lParam));
  1559. }
  1560. break;
  1561. }
  1562. case mtDefWindowProc:
  1563. RetVal=DefWindowProcA(hWnd, Msg, wParam, lParam);
  1564. break;
  1565. case mtDefDlgProc:
  1566. RetVal=DefDlgProcA(hWnd, Msg, wParam, lParam);
  1567. break;
  1568. case mtDefFrameProc:
  1569. // dwData is overload in this case to ve the second hWnd param
  1570. RetVal=DefFrameProcA(hWnd, (HWND)dwData, Msg, wParam, lParam);
  1571. break;
  1572. case mtDefMDIChildProc:
  1573. RetVal=DefMDIChildProcA(hWnd, Msg, wParam, lParam);
  1574. break;
  1575. case mtBroadcastSystemMessage:
  1576. if (s_pfnBSMA == NULL)
  1577. {
  1578. s_pfnBSMA = (PFNbsma)GetProcAddress(GetUserHandle(), "BroadcastSystemMessageA");
  1579. if (s_pfnBSMA == NULL)
  1580. s_pfnBSMA = (PFNbsma)GetProcAddress(GetUserHandle(), "BroadcastSystemMessage");
  1581. }
  1582. if (s_pfnBSMA)
  1583. // fuFlags is overloaded here as the dwFlags broadcast options
  1584. // lpdwResult is overloaded here as the passed in lpdwRecipients
  1585. RetVal=(s_pfnBSMA((DWORD)fuFlags, lpdwResult, Msg, wParam, lParam));
  1586. else
  1587. {
  1588. // Should be impossible!!!
  1589. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1590. RetVal=(-1);
  1591. }
  1592. break;
  1593. default:
  1594. // Should also be impossible!!!
  1595. RetVal=(0);
  1596. break;
  1597. }
  1598. return(RetVal);
  1599. }
  1600. /*-------------------------------
  1601. GodotReceiveMessage
  1602. Our global wrapper for getting messages (GetMessage, et. al.). Does all precall
  1603. and postcall conversions needed for any string values that are used
  1604. -------------------------------*/
  1605. BOOL GodotReceiveMessage(MESSAGETYPES mt, LPMSG lpMsg, HWND hWnd, UINT wMin, UINT wMax, UINT wRemoveMsg)
  1606. {
  1607. BOOL retval;
  1608. MSG MsgA;
  1609. // call stuff
  1610. switch(mt)
  1611. {
  1612. case mtGetMessage:
  1613. retval = (GetMessageA)(&MsgA, hWnd, wMin, wMax);
  1614. break;
  1615. case mtPeekMessage:
  1616. retval = (PeekMessageA)(&MsgA, hWnd, wMin, wMax, wRemoveMsg);
  1617. break;
  1618. }
  1619. // Copy some defaults (we will override for specific messages, as needed)
  1620. lpMsg->wParam = MsgA.wParam;
  1621. lpMsg->lParam = MsgA.lParam;
  1622. lpMsg->hwnd = MsgA.hwnd;
  1623. lpMsg->message = MsgA.message;
  1624. lpMsg->time = MsgA.time;
  1625. lpMsg->pt.x = MsgA.pt.x;
  1626. lpMsg->pt.y = MsgA.pt.y;
  1627. // The caller is always expecting Unicode here, so we must ALWAYS convert.
  1628. switch(MsgA.message)
  1629. {
  1630. case EM_SETPASSWORDCHAR:
  1631. case WM_CHAR:
  1632. case WM_DEADCHAR:
  1633. case WM_SYSCHAR:
  1634. case WM_SYSDEADCHAR:
  1635. case WM_MENUCHAR:
  1636. case WM_IME_CHAR:
  1637. case WM_IME_COMPOSITION:
  1638. // All these messages require the wParam to be converted to Unicode
  1639. MultiByteToWideChar(g_acp, 0, (char *)&(MsgA.wParam), g_mcs, (WCHAR *)&(lpMsg->wParam), 1);
  1640. break;
  1641. case WM_CHARTOITEM:
  1642. {
  1643. // Mask off the hiword bits, convert, then stick the hiword bits back on.
  1644. WPARAM wpT = MsgA.wParam & 0xFFFF;
  1645. MultiByteToWideChar(g_acp, 0, (char *)&(wpT), g_mcs, (WCHAR *)&(lpMsg->wParam), 1);
  1646. lpMsg->wParam = MAKELONG(LOWORD(wpT),HIWORD(MsgA.wParam));
  1647. break;
  1648. }
  1649. case CB_ADDSTRING:
  1650. case CB_DIR:
  1651. case CB_FINDSTRING:
  1652. case CB_FINDSTRINGEXACT:
  1653. case CB_INSERTSTRING:
  1654. case CB_SELECTSTRING:
  1655. {
  1656. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  1657. if(!(((styl & CBS_OWNERDRAWFIXED) ||
  1658. (styl & CBS_OWNERDRAWVARIABLE)) &&
  1659. (!(styl & CBS_HASSTRINGS))))
  1660. {
  1661. // Owner draw combo box which does not have strings stored
  1662. // (See Windows Bugs # 356304 for details here)
  1663. if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
  1664. {
  1665. MultiByteToWideChar(g_acp, 0,
  1666. (LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
  1667. (LPWSTR)(lpMsg->lParam), MsgA.wParam);
  1668. }
  1669. }
  1670. }
  1671. break;
  1672. case LB_ADDSTRING:
  1673. case LB_ADDFILE:
  1674. case LB_DIR:
  1675. case LB_FINDSTRING:
  1676. case LB_FINDSTRINGEXACT:
  1677. case LB_INSERTSTRING:
  1678. case LB_SELECTSTRING:
  1679. {
  1680. LONG styl = GetWindowLongA(hWnd, GWL_STYLE);
  1681. if(!(((styl & LBS_OWNERDRAWFIXED) ||
  1682. (styl & LBS_OWNERDRAWVARIABLE)) &&
  1683. (!(styl & LBS_HASSTRINGS))))
  1684. {
  1685. // Owner draw listbox which does not have strings stored
  1686. // (See Windows Bugs # 356304 for details here)
  1687. if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
  1688. {
  1689. MultiByteToWideChar(g_acp, 0,
  1690. (LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
  1691. (LPWSTR)(lpMsg->lParam), MsgA.wParam);
  1692. }
  1693. }
  1694. }
  1695. break;
  1696. case EM_REPLACESEL:
  1697. case WM_SETTEXT:
  1698. case WM_DEVMODECHANGE:
  1699. case WM_SETTINGCHANGE:
  1700. case WM_SETMESSAGESTRING: // MFC internal msg
  1701. if(FSTRING_VALID((LPSTR)(MsgA.lParam)))
  1702. {
  1703. // All these messages require the lParam to be converted to Unicode
  1704. // CONSIDER: Is that string buffer size right?
  1705. MultiByteToWideChar(g_acp, 0,
  1706. (LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
  1707. (LPWSTR)(lpMsg->lParam), MsgA.wParam);
  1708. }
  1709. case WM_DDE_EXECUTE:
  1710. // wParam is the client window hWnd, lParam is the command LPTSTR.
  1711. // Only convert lParam if both client and server windows are Unicode
  1712. if(GetUnicodeWindowProp((HWND)lpMsg->wParam))
  1713. {
  1714. MultiByteToWideChar(g_acp, 0,
  1715. (LPSTR)(MsgA.lParam), ((MsgA.wParam) * g_mcs),
  1716. (LPWSTR)(lpMsg->lParam), MsgA.wParam);
  1717. }
  1718. break;
  1719. }
  1720. // Get out of here
  1721. return (retval);
  1722. }
  1723. /*-------------------------------
  1724. GodotDispatchMessage
  1725. Handles all the message dispatch functions
  1726. -------------------------------*/
  1727. LRESULT GodotDispatchMessage(MESSAGETYPES mt, HWND hDlg, HACCEL hAccTable, LPMSG lpMsg)
  1728. {
  1729. // Begin locals
  1730. LRESULT RetVal;
  1731. ALLOCRETURN ar = arNoAlloc;
  1732. MSG MsgA;
  1733. // We will override some of these params later, as needed
  1734. MsgA.wParam = lpMsg->wParam;
  1735. MsgA.lParam = lpMsg->lParam;
  1736. MsgA.hwnd = lpMsg->hwnd;
  1737. MsgA.message = lpMsg->message;
  1738. MsgA.time = lpMsg->time;
  1739. MsgA.pt = lpMsg->pt;
  1740. // The caller is always passing Unicode here, so we must ALWAYS convert.
  1741. switch(lpMsg->message)
  1742. {
  1743. case EM_SETPASSWORDCHAR:
  1744. case WM_CHAR:
  1745. case WM_DEADCHAR:
  1746. case WM_SYSCHAR:
  1747. case WM_SYSDEADCHAR:
  1748. case WM_MENUCHAR:
  1749. case WM_IME_CHAR:
  1750. case WM_IME_COMPOSITION:
  1751. // All these messages require the wParam to be converted from Unicode
  1752. WideCharToMultiByte(g_acp, 0,
  1753. (WCHAR *)&(lpMsg->wParam), 1,
  1754. (CHAR *)&(MsgA.wParam), g_mcs, NULL, NULL);
  1755. break;
  1756. case WM_CHARTOITEM:
  1757. {
  1758. // Mask off the hiword bits, convert, then stick the hiword bits back on.
  1759. WPARAM wpT = lpMsg->wParam & 0xFFFF;
  1760. WideCharToMultiByte(g_acp, 0,
  1761. (WCHAR *)&(wpT), 1,
  1762. (CHAR *)&(MsgA.wParam), g_mcs, NULL, NULL);
  1763. MsgA.wParam = MAKELONG(LOWORD(wpT),HIWORD(lpMsg->wParam));
  1764. break;
  1765. }
  1766. case CB_ADDSTRING:
  1767. case LB_ADDFILE:
  1768. case CB_DIR:
  1769. case CB_FINDSTRING:
  1770. case CB_FINDSTRINGEXACT:
  1771. case CB_INSERTSTRING:
  1772. case CB_SELECTSTRING:
  1773. {
  1774. LONG styl = GetWindowLongA(hDlg, GWL_STYLE);
  1775. if(!(((styl & CBS_OWNERDRAWFIXED) ||
  1776. (styl & CBS_OWNERDRAWVARIABLE)) &&
  1777. (!(styl & CBS_HASSTRINGS))))
  1778. {
  1779. // Owner draw combobox which does not have strings stored
  1780. // (See Windows Bugs # 356304 for details here)
  1781. ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
  1782. }
  1783. break;
  1784. }
  1785. case LB_ADDSTRING:
  1786. case LB_DIR:
  1787. case LB_FINDSTRING:
  1788. case LB_FINDSTRINGEXACT:
  1789. case LB_INSERTSTRING:
  1790. case LB_SELECTSTRING:
  1791. {
  1792. LONG styl = GetWindowLongA(hDlg, GWL_STYLE);
  1793. if(!(((styl & LBS_OWNERDRAWFIXED) ||
  1794. (styl & LBS_OWNERDRAWVARIABLE)) &&
  1795. (!(styl & LBS_HASSTRINGS))))
  1796. {
  1797. // Owner draw listbox which does not have strings stored
  1798. // (See Windows Bugs # 356304 for details here)
  1799. ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
  1800. }
  1801. break;
  1802. }
  1803. case EM_REPLACESEL:
  1804. case WM_SETTEXT:
  1805. case WM_DEVMODECHANGE:
  1806. case WM_SETTINGCHANGE:
  1807. case WM_SETMESSAGESTRING: // MFC internal msg
  1808. // All these messages require the lParam to be converted from Unicode
  1809. // It is a full string, so lets treat it as such.
  1810. ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
  1811. break;
  1812. case WM_DDE_EXECUTE:
  1813. // wParam is the client window hWnd, lParam is the command LPTSTR.
  1814. // Only convert lParam if both client and server windows are Unicode
  1815. if(GetUnicodeWindowProp((HWND)lpMsg->wParam))
  1816. {
  1817. ar = GodotToAcpOnHeap((LPWSTR)(lpMsg->lParam), &(LPSTR)(MsgA.lParam));
  1818. }
  1819. break;
  1820. }
  1821. switch(mt)
  1822. {
  1823. case mtDispatchMessage:
  1824. RetVal=DispatchMessageA(&MsgA);
  1825. break;
  1826. case mtIsDialogMessage:
  1827. RetVal=(LRESULT)IsDialogMessageA(hDlg, &MsgA);
  1828. break;
  1829. case mtTranslateAccelerator:
  1830. RetVal = (LRESULT)TranslateAcceleratorA(hDlg, hAccTable, &MsgA);
  1831. break;
  1832. }
  1833. // If we used some heap memory then free it now
  1834. if(ar == arAlloc)
  1835. GodotHeapFree((LPSTR)(MsgA.lParam));
  1836. return(RetVal);
  1837. }