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.

3073 lines
88 KiB

  1. /**************************************************************************\
  2. * Module Name: ntstubs.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * client side API stubs
  7. *
  8. * History:
  9. * 03-19-95 JimA Created.
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define CLIENTSIDE 1
  14. #include <dbt.h>
  15. #include "ntsend.h"
  16. #include "cfgmgr32.h"
  17. #include "csrhlpr.h"
  18. WINUSERAPI
  19. BOOL
  20. WINAPI
  21. SetSysColors(
  22. int cElements,
  23. CONST INT * lpaElements,
  24. CONST COLORREF * lpaRgbValues)
  25. {
  26. return NtUserSetSysColors(cElements,
  27. lpaElements,
  28. lpaRgbValues,
  29. SSCF_NOTIFY | SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS);
  30. }
  31. HWND WOWFindWindow(
  32. LPCSTR pClassName,
  33. LPCSTR pWindowName)
  34. {
  35. return InternalFindWindowExA(NULL, NULL, pClassName, pWindowName, FW_16BIT);
  36. }
  37. #ifdef IMM_PER_LOGON
  38. VOID UpdatePerUserImmEnabling(
  39. VOID)
  40. {
  41. BOOL fRet = (BOOL)NtUserCallNoParam(SFI_UPDATEPERUSERIMMENABLING);
  42. if (fRet) {
  43. if (IS_IME_ENABLED()) {
  44. /*
  45. * hen ImmEnable flag is update and it gets enabled during
  46. * the last logon, we need to load Imm32.dll.
  47. */
  48. HMODULE hModule = GetModuleHandleW(L"imm32.dll");
  49. if (hModule == NULL) {
  50. LoadLibraryW(L"imm32.dll");
  51. }
  52. }
  53. }
  54. }
  55. #endif
  56. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, UpdatePerUserSystemParameters, HANDLE, hToken, DWORD, dwFlags)
  57. BOOL UpdatePerUserSystemParameters(
  58. HANDLE hToken,
  59. DWORD dwFlags)
  60. {
  61. TAGMSGF0(DBGTAG_KBD, "entering");
  62. BEGINCALL()
  63. if ((dwFlags & UPUSP_USERLOGGEDON) || (dwFlags & (UPUSP_POLICYCHANGE | UPUSP_REMOTESETTINGS)) == 0) {
  64. /*
  65. * This is the first logon, need to initialize
  66. * the input locale.
  67. */
  68. LANGID langidKbd;
  69. WCHAR wszKLName[KL_NAMELENGTH];
  70. UINT uKlFlags = KLF_ACTIVATE | KLF_RESET;
  71. #ifdef IMM_PER_LOGON
  72. /*
  73. * Update the per user portion of the system metrics.
  74. * Continues even if this update fails.
  75. */
  76. UpdatePerUserImmEnabling();
  77. #endif
  78. /*
  79. * Initialize IME hotkeys before loading keyboard
  80. * layouts.
  81. */
  82. CliImmInitializeHotKeys(ISHK_INITIALIZE, NULL);
  83. /*
  84. * Try to get the remote input locale first.
  85. */
  86. if (!GetRemoteKeyboardLayout(wszKLName, &langidKbd)) {
  87. /*
  88. * If this is not a remote connection,
  89. * let's handle the input locale substition.
  90. */
  91. uKlFlags |= KLF_SUBSTITUTE_OK;
  92. langidKbd = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  93. /*
  94. * Get the active keyboard layout from the registry.
  95. */
  96. GetActiveKeyboardName(wszKLName);
  97. }
  98. LoadKeyboardLayoutWorker(NULL, wszKLName, langidKbd, uKlFlags, TRUE);
  99. /*
  100. * Now load the remaining preload keyboard layouts.
  101. */
  102. LoadPreloadKeyboardLayouts();
  103. }
  104. /*
  105. * Only if not just a policy change.
  106. */
  107. if (dwFlags != UPUSP_POLICYCHANGE) {
  108. /*
  109. * FLush any MUI cach to be able to load strings latter for the new UIlangID.
  110. */
  111. LdrFlushAlternateResourceModules();
  112. }
  113. retval = (DWORD)NtUserUpdatePerUserSystemParameters(hToken, dwFlags);
  114. /*
  115. * Cause the wallpaper to be changed.
  116. */
  117. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, 0, 0);
  118. ERRORTRAP(0);
  119. ENDCALL(BOOL);
  120. }
  121. DWORD Event(
  122. PEVENT_PACKET pep)
  123. {
  124. BEGINCALL()
  125. CheckDDECritOut;
  126. retval = (DWORD)NtUserEvent(
  127. pep);
  128. ERRORTRAP(0);
  129. ENDCALL(DWORD);
  130. }
  131. LONG GetClassWOWWords(
  132. HINSTANCE hInstance,
  133. LPCTSTR pString)
  134. {
  135. IN_STRING strClassName;
  136. PCLS pcls;
  137. /*
  138. * Make sure cleanup will work successfully
  139. */
  140. strClassName.fAllocated = FALSE;
  141. BEGINCALL()
  142. FIRSTCOPYLPSTRW(&strClassName, pString);
  143. pcls = NtUserGetWOWClass(hInstance, strClassName.pstr);
  144. if (pcls == NULL) {
  145. MSGERRORCODE(ERROR_CLASS_DOES_NOT_EXIST);
  146. }
  147. pcls = (PCLS)((KPBYTE)pcls - GetClientInfo()->ulClientDelta);
  148. retval = _GetClassData(pcls, NULL, GCLP_WOWWORDS, TRUE);
  149. ERRORTRAP(0);
  150. CLEANUPLPSTRW(strClassName);
  151. ENDCALL(LONG);
  152. }
  153. /***************************************************************************\
  154. * InitTask
  155. *
  156. * Initialize a WOW task. This is the first call a WOW thread makes to user.
  157. * NtUserInitTask returns NTSTATUS because if the thread fails to convert
  158. * to a GUI thread, STATUS_INVALID_SYSTEM_SERVICE is returned.
  159. *
  160. * 11-03-95 JimA Modified to use NTSTATUS.
  161. \***************************************************************************/
  162. BOOL InitTask(
  163. UINT wVersion,
  164. DWORD dwAppCompatFlags,
  165. DWORD dwUserWOWCompatFlags,
  166. LPCSTR pszModName,
  167. LPCSTR pszBaseFileName,
  168. DWORD hTaskWow,
  169. DWORD dwHotkey,
  170. DWORD idTask,
  171. DWORD dwX,
  172. DWORD dwY,
  173. DWORD dwXSize,
  174. DWORD dwYSize)
  175. {
  176. IN_STRING strModName;
  177. IN_STRING strBaseFileName;
  178. NTSTATUS Status;
  179. /*
  180. * Make sure cleanup will work successfully
  181. */
  182. strModName.fAllocated = FALSE;
  183. strBaseFileName.fAllocated = FALSE;
  184. BEGINCALL()
  185. FIRSTCOPYLPSTRW(&strModName, pszModName);
  186. COPYLPSTRW(&strBaseFileName, pszBaseFileName);
  187. Status = NtUserInitTask(
  188. wVersion,
  189. dwAppCompatFlags,
  190. dwUserWOWCompatFlags,
  191. strModName.pstr,
  192. strBaseFileName.pstr,
  193. hTaskWow,
  194. dwHotkey,
  195. idTask,
  196. dwX,
  197. dwY,
  198. dwXSize,
  199. dwYSize);
  200. retval = (Status == STATUS_SUCCESS);
  201. CLEANUPLPSTRW(strModName);
  202. CLEANUPLPSTRW(strBaseFileName);
  203. ERRORTRAP(FALSE);
  204. ENDCALL(BOOL);
  205. }
  206. HANDLE ConvertMemHandle(
  207. HANDLE hData,
  208. UINT cbNULL)
  209. {
  210. UINT cbData;
  211. LPBYTE lpData;
  212. BEGINCALL()
  213. if (GlobalFlags(hData) == GMEM_INVALID_HANDLE) {
  214. RIPMSG0(RIP_WARNING, "ConvertMemHandle hMem is not valid");
  215. MSGERROR();
  216. }
  217. if (!(cbData = (UINT)GlobalSize(hData))) {
  218. MSGERROR();
  219. }
  220. USERGLOBALLOCK(hData, lpData);
  221. if (lpData == NULL) {
  222. MSGERROR();
  223. }
  224. /*
  225. * Make sure text formats are NULL terminated.
  226. */
  227. switch (cbNULL) {
  228. case 2:
  229. lpData[cbData - 2] = 0;
  230. // FALL THROUGH
  231. case 1:
  232. lpData[cbData - 1] = 0;
  233. }
  234. retval = (ULONG_PTR)NtUserConvertMemHandle(lpData, cbData);
  235. USERGLOBALUNLOCK(hData);
  236. ERRORTRAP(NULL);
  237. ENDCALL(HANDLE);
  238. }
  239. HANDLE CreateLocalMemHandle(
  240. HANDLE hMem)
  241. {
  242. UINT cbData;
  243. NTSTATUS Status;
  244. BEGINCALL()
  245. Status = NtUserCreateLocalMemHandle(hMem, NULL, 0, &cbData);
  246. if (Status != STATUS_BUFFER_TOO_SMALL) {
  247. RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure");
  248. MSGERROR();
  249. }
  250. if (!(retval = (ULONG_PTR)GlobalAlloc(GMEM_FIXED, cbData))) {
  251. MSGERROR();
  252. }
  253. Status = NtUserCreateLocalMemHandle(hMem, (LPBYTE)retval, cbData, NULL);
  254. if (!NT_SUCCESS(Status)) {
  255. RIPMSG0(RIP_WARNING, "__CreateLocalMemHandle server returned failure");
  256. UserGlobalFree((HANDLE)retval);
  257. MSGERROR();
  258. }
  259. ERRORTRAP(0);
  260. ENDCALL(HANDLE);
  261. }
  262. HHOOK _SetWindowsHookEx(
  263. HANDLE hmod,
  264. LPTSTR pszLib,
  265. DWORD idThread,
  266. int nFilterType,
  267. PROC pfnFilterProc,
  268. DWORD dwFlags)
  269. {
  270. IN_STRING strLib;
  271. /*
  272. * Make sure cleanup will work successfully
  273. */
  274. strLib.fAllocated = FALSE;
  275. BEGINCALL()
  276. FIRSTCOPYLPWSTROPT(&strLib, pszLib);
  277. retval = (ULONG_PTR)NtUserSetWindowsHookEx(
  278. hmod,
  279. strLib.pstr,
  280. idThread,
  281. nFilterType,
  282. pfnFilterProc,
  283. dwFlags);
  284. ERRORTRAP(0);
  285. CLEANUPLPWSTR(strLib);
  286. ENDCALL(HHOOK);
  287. }
  288. /***************************************************************************\
  289. * SetWinEventHook
  290. *
  291. * History:
  292. * 1996-09-23 IanJa Created
  293. \***************************************************************************/
  294. WINUSERAPI
  295. HWINEVENTHOOK
  296. WINAPI
  297. SetWinEventHook(
  298. DWORD eventMin,
  299. DWORD eventMax,
  300. HMODULE hmodWinEventProc, // Must pass this if global!
  301. WINEVENTPROC lpfnWinEventProc,
  302. DWORD idProcess, // Can be zero; all processes
  303. DWORD idThread, // Can be zero; all threads
  304. DWORD dwFlags)
  305. {
  306. UNICODE_STRING str;
  307. PUNICODE_STRING pstr;
  308. WCHAR awchLib[MAX_PATH];
  309. BEGINCALL()
  310. if ((dwFlags & WINEVENT_INCONTEXT) && (hmodWinEventProc != NULL)) {
  311. /*
  312. * If we're passing an hmod, we need to grab the file name of the
  313. * module while we're still on the client since module handles
  314. * are NOT global.
  315. */
  316. USHORT cb;
  317. cb = (USHORT)(sizeof(WCHAR) * GetModuleFileNameW(hmodWinEventProc, awchLib, sizeof(awchLib)/sizeof(WCHAR)));
  318. if (cb == 0) {
  319. /*
  320. * hmod is bogus - return NULL.
  321. */
  322. return NULL;
  323. }
  324. str.Buffer = awchLib;
  325. str.Length = cb - sizeof(UNICODE_NULL);
  326. str.MaximumLength = cb;
  327. pstr = &str;
  328. } else {
  329. pstr = NULL;
  330. }
  331. retval = (ULONG_PTR)NtUserSetWinEventHook(
  332. eventMin,
  333. eventMax,
  334. hmodWinEventProc,
  335. pstr,
  336. lpfnWinEventProc,
  337. idProcess,
  338. idThread,
  339. dwFlags);
  340. ERRORTRAP(0);
  341. ENDCALL(HWINEVENTHOOK);
  342. };
  343. FUNCLOGVOID4(LOG_GENERAL, WINAPI, NotifyWinEvent, DWORD, dwEvent, HWND, hwnd, LONG, idObject, LONG, idChild)
  344. WINUSERAPI
  345. VOID
  346. WINAPI
  347. NotifyWinEvent(
  348. DWORD dwEvent,
  349. HWND hwnd,
  350. LONG idObject,
  351. LONG idChild)
  352. {
  353. BEGINCALLVOID()
  354. if (FEVENTHOOKED(dwEvent)) {
  355. NtUserNotifyWinEvent(dwEvent, hwnd, idObject, idChild);
  356. }
  357. ERRORTRAPVOID();
  358. ENDCALLVOID();
  359. }
  360. /***************************************************************************\
  361. * RegisterUserApiHook
  362. *
  363. * History:
  364. * 03-Mar-2000 JerrySh Created.
  365. \***************************************************************************/
  366. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RegisterUserApiHook, HINSTANCE, hmod, INITUSERAPIHOOK, pfnUserApiHook)
  367. BOOL RegisterUserApiHook(
  368. HINSTANCE hmod,
  369. INITUSERAPIHOOK pfnUserApiHook)
  370. {
  371. WCHAR pwszLibFileName[MAX_PATH];
  372. ULONG_PTR offPfnProc;
  373. IN_STRING strLib;
  374. /*
  375. * If we're passing an hmod, we need to grab the file name of the
  376. * module while we're still on the client since module handles
  377. * are NOT global.
  378. */
  379. if (!GetModuleFileNameW(hmod, pwszLibFileName, ARRAY_SIZE(pwszLibFileName))) {
  380. return FALSE;
  381. }
  382. /*
  383. * Libraries are loaded at different linear addresses in different
  384. * process contexts. For this reason, we need to convert the window
  385. * proc address into an offset while setting the hook, and then convert
  386. * it back to a real per-process function pointer when calling a
  387. * hook. Do this by subtracting the 'hmod' (which is a pointer to the
  388. * linear and contiguous .exe header) from the function index.
  389. */
  390. offPfnProc = (ULONG_PTR)pfnUserApiHook - (ULONG_PTR)hmod;
  391. /*
  392. * Make sure cleanup will work successfully
  393. */
  394. strLib.fAllocated = FALSE;
  395. BEGINCALL()
  396. COPYLPWSTR(&strLib, pwszLibFileName);
  397. retval = (ULONG_PTR)NtUserRegisterUserApiHook(
  398. strLib.pstr,
  399. offPfnProc);
  400. ERRORTRAP(0);
  401. CLEANUPLPWSTR(strLib);
  402. ENDCALL(BOOL);
  403. }
  404. #ifdef MESSAGE_PUMP_HOOK
  405. /***************************************************************************\
  406. * ResetMessagePumpHook
  407. *
  408. * ResetMessagePumpHook() resets the MessagePumpHook function pointers
  409. * to the internal "real" implementations.
  410. *
  411. * History:
  412. * 12-13-2000 JStall Created
  413. \***************************************************************************/
  414. void ResetMessagePumpHook(MESSAGEPUMPHOOK * pwmh)
  415. {
  416. pwmh->cbSize = sizeof(MESSAGEPUMPHOOK);
  417. pwmh->pfnInternalGetMessage = NtUserRealInternalGetMessage;
  418. pwmh->pfnWaitMessageEx = NtUserRealWaitMessageEx;
  419. pwmh->pfnGetQueueStatus = RealGetQueueStatus;
  420. pwmh->pfnMsgWaitForMultipleObjectsEx
  421. = RealMsgWaitForMultipleObjectsEx;
  422. }
  423. /***************************************************************************\
  424. * RegisterMessagePumpHook
  425. *
  426. * RegisterMessagePumpHook() sets up MPH's on the current thread. If this is
  427. * the first thread to be initialized in the process, the process-wide
  428. * initialization is also performed. If a thread has already been
  429. * initialized with MPH's, its "ref-count" is incremented on the existing
  430. * MPH's.
  431. *
  432. * NOTE: Unlike UserApiHook's, we make a callback while holding a critical
  433. * section. This is because it is infinitely easier to synchronize this
  434. * inside USER32.DLL rather than allowing re-entrancy in the DLL. It is
  435. * designed after DllMain(), where the loader also has a lock that is
  436. * sychronized.
  437. *
  438. * NOTE: Under the current implementation of MPH's, only one set of MPH's
  439. * per process can be installed. Each process may have a different set of
  440. * WMH's.
  441. *
  442. * History:
  443. * 12-13-2000 JStall Created
  444. \***************************************************************************/
  445. BOOL RegisterMessagePumpHook(
  446. INITMESSAGEPUMPHOOK pfnInitMPH)
  447. {
  448. BOOL fInit = FALSE;
  449. BEGINCALL()
  450. retval = FALSE;
  451. RtlEnterCriticalSection(&gcsMPH);
  452. if (pfnInitMPH == NULL) {
  453. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "Need valid pfnInitMPH");
  454. goto errorexit;
  455. }
  456. if (gcLoadMPH == 0) {
  457. MESSAGEPUMPHOOK mphTemp;
  458. /*
  459. * First time we are initializing.
  460. */
  461. UserAssertMsg0(gpfnInitMPH == NULL, "MPH callback should not already be initialized");
  462. gpfnInitMPH = pfnInitMPH;
  463. ResetMessagePumpHook(&mphTemp);
  464. if (!(gpfnInitMPH)(UIAH_INITIALIZE, &mphTemp) || (mphTemp.cbSize == 0)) {
  465. goto errorexit;
  466. }
  467. CopyMemory(&gmph, &mphTemp, mphTemp.cbSize);
  468. fInit = TRUE;
  469. } else {
  470. if (gpfnInitMPH == pfnInitMPH) {
  471. /*
  472. * Initializing a second time with the same callback.
  473. */
  474. fInit = TRUE;
  475. }
  476. }
  477. if (fInit) {
  478. /*
  479. * Initialize MPH's on this thread.
  480. */
  481. if (NtUserCallNoParam(SFI__DOINITMESSAGEPUMPHOOK)) {
  482. if (gcLoadMPH++ == 0) {
  483. InterlockedExchange(&gfMessagePumpHook, TRUE);
  484. }
  485. retval = TRUE;
  486. }
  487. }
  488. ERRORTRAP(0);
  489. RtlLeaveCriticalSection(&gcsMPH);
  490. ENDCALL(BOOL);
  491. }
  492. /***************************************************************************\
  493. * UnregisterMessagePumpHook
  494. *
  495. * UnregisterMessagePumpHook() decrements the count of WMH's on the current
  496. * thread. When this count reaches 0, WMH's are uninstalled from the
  497. * current thread. When the global WMH count reaches 0, WMH's are uninstalled
  498. * from the entire process.
  499. *
  500. * NOTE: See RegisterMessagePumpHook() about use of the critical section.
  501. *
  502. * History:
  503. * 12-13-2000 JStall Created
  504. \***************************************************************************/
  505. BOOL UnregisterMessagePumpHook(
  506. VOID)
  507. {
  508. BEGINCALL()
  509. RtlEnterCriticalSection(&gcsMPH);
  510. if (gcLoadMPH <= 0) {
  511. RIPMSG0(RIP_ERROR, "UninitMessagePumpHook: Called without matching Init()");
  512. goto errorexit;
  513. }
  514. /*
  515. * Uninitialize this thread's WMH. When the reference count reaches 0, the
  516. * thread will no longer be hooked.
  517. */
  518. if (!NtUserCallNoParam(SFI__DOUNINITMESSAGEPUMPHOOK)) {
  519. goto errorexit;
  520. }
  521. if (--gcLoadMPH == 0) {
  522. /*
  523. * Final unload: make callback and reset
  524. */
  525. InterlockedExchange(&gfMessagePumpHook, FALSE);
  526. (gpfnInitMPH)(UIAH_UNINITIALIZE, NULL);
  527. ResetMessagePumpHook(&gmph);
  528. gpfnInitMPH = NULL;
  529. }
  530. retval = TRUE;
  531. ERRORTRAP(0);
  532. RtlLeaveCriticalSection(&gcsMPH);
  533. ENDCALL(BOOL);
  534. }
  535. #endif // MESSAGE_PUMP_HOOK
  536. /***************************************************************************\
  537. * ThunkedMenuItemInfo
  538. *
  539. * History:
  540. * 07-22-96 GerardoB - Added header and Fixed up for 5.0
  541. \***************************************************************************/
  542. BOOL ThunkedMenuItemInfo(
  543. HMENU hMenu,
  544. UINT nPosition,
  545. BOOL fByPosition,
  546. BOOL fInsert,
  547. LPMENUITEMINFOW lpmii,
  548. BOOL fAnsi)
  549. {
  550. MENUITEMINFOW mii;
  551. IN_STRING strItem;
  552. /*
  553. * Make sure cleanup will work successfully
  554. */
  555. strItem.fAllocated = FALSE;
  556. BEGINCALL()
  557. /*
  558. * Make a local copy so we can make changes
  559. */
  560. mii = *(LPMENUITEMINFO)(lpmii);
  561. strItem.pstr = NULL;
  562. if (mii.fMask & MIIM_BITMAP) {
  563. if (((HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem)) < HBMMENU_MAX) && IS_PTR(mii.hbmpItem)) {
  564. /*
  565. * Looks like the user was trying to insert one of the
  566. * HBMMENU_* bitmaps, but stuffed some data in the HIWORD.
  567. * We know the HIWORD data is invalid because the LOWORD
  568. * handle is below the GDI minimum.
  569. */
  570. RIPMSG1(RIP_WARNING, "Invalid HIWORD data (0x%04X) for HBMMENU_* bitmap.", HIWORD(HandleToUlong(mii.hbmpItem)));
  571. mii.hbmpItem = (HBITMAP)LOWORD(HandleToUlong(mii.hbmpItem));
  572. } else if (!IS_PTR(mii.hbmpItem) && mii.hbmpItem >= HBMMENU_MAX) {
  573. /*
  574. * The app is passing a 16-bit GDI handle. GDI handles this
  575. * on the client-side, but not on the kernel side. So
  576. * convert it to 32-bits. This fixes bug 201493 in
  577. * Macromedia Director.
  578. */
  579. HBITMAP hbmNew = GdiFixUpHandle(mii.hbmpItem);
  580. if (hbmNew) {
  581. RIPMSGF2(RIP_WARNING,
  582. "Fix 16-bit bitmap handle 0x%x to 0x%x",
  583. mii.hbmpItem,
  584. hbmNew);
  585. mii.hbmpItem = hbmNew;
  586. }
  587. }
  588. }
  589. if (mii.fMask & MIIM_STRING) {
  590. if (fAnsi) {
  591. FIRSTCOPYLPSTROPTW(&strItem, mii.dwTypeData);
  592. } else {
  593. FIRSTCOPYLPWSTROPT(&strItem, mii.dwTypeData);
  594. }
  595. }
  596. retval = (DWORD)NtUserThunkedMenuItemInfo(hMenu,
  597. nPosition,
  598. fByPosition,
  599. fInsert,
  600. &mii,
  601. strItem.pstr);
  602. ERRORTRAP(FALSE);
  603. CLEANUPLPSTRW(strItem);
  604. ENDCALL(BOOL);
  605. }
  606. /***************************************************************************\
  607. * DrawCaption
  608. *
  609. * History:
  610. * 16-April-2001 Mohamed Hooked API and created this wrapper.
  611. \***************************************************************************/
  612. FUNCLOG4(
  613. LOG_GENERAL,
  614. BOOL,
  615. DUMMYCALLINGTYPE,
  616. DrawCaption,
  617. HWND,
  618. hwnd,
  619. HDC,
  620. hdc,
  621. CONST RECT*,
  622. lprc,
  623. UINT,
  624. flags)
  625. BOOL DrawCaption(
  626. HWND hwnd,
  627. HDC hdc,
  628. CONST RECT *lprc,
  629. UINT flags)
  630. {
  631. BOOL bRet;
  632. BEGIN_USERAPIHOOK()
  633. bRet = guah.pfnDrawCaption(hwnd, hdc, lprc, flags);
  634. END_USERAPIHOOK()
  635. return bRet;
  636. }
  637. BOOL RealDrawCaption(
  638. HWND hwnd,
  639. HDC hdc,
  640. CONST RECT *lprc,
  641. UINT flags)
  642. {
  643. HDC hdcr;
  644. BEGINCALL()
  645. if (IsMetaFile(hdc)) {
  646. return FALSE;
  647. }
  648. hdcr = GdiConvertAndCheckDC(hdc);
  649. if (hdcr == (HDC)0) {
  650. return FALSE;
  651. }
  652. retval = (DWORD)NtUserDrawCaption(hwnd, hdcr, lprc, flags);
  653. ERRORTRAP(0);
  654. ENDCALL(BOOL);
  655. }
  656. FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetAsyncKeyState, int, vKey)
  657. SHORT GetAsyncKeyState(
  658. int vKey)
  659. {
  660. BEGINCALLCONNECT()
  661. /*
  662. * Asynchronous key state reports the PHYSICAL mouse button,
  663. * regardless of whether the buttons have been swapped or not.
  664. */
  665. if ((vKey == VK_RBUTTON || vKey == VK_LBUTTON) && SYSMET(SWAPBUTTON)) {
  666. vKey ^= (VK_RBUTTON ^ VK_LBUTTON);
  667. }
  668. /*
  669. * If this is one of the common keys, see if we can pull it out
  670. * of the cache.
  671. */
  672. if ((UINT)vKey < CVKASYNCKEYCACHE) {
  673. PCLIENTINFO pci = GetClientInfo();
  674. if ((pci->dwAsyncKeyCache == gpsi->dwAsyncKeyCache) &&
  675. !TestKeyRecentDownBit(pci->afAsyncKeyStateRecentDown, vKey)) {
  676. if (TestKeyDownBit(pci->afAsyncKeyState, vKey)) {
  677. retval = 0x8000;
  678. } else {
  679. retval = 0;
  680. }
  681. return (SHORT)retval;
  682. }
  683. }
  684. retval = (DWORD)NtUserGetAsyncKeyState(vKey);
  685. ERRORTRAP(0);
  686. ENDCALL(SHORT);
  687. }
  688. FUNCLOG1(LOG_GENERAL, SHORT, DUMMYCALLINGTYPE, GetKeyState, int, vKey)
  689. SHORT GetKeyState(
  690. int vKey)
  691. {
  692. BEGINCALLCONNECT()
  693. /*
  694. * If this is one of the common keys, see if we can pull it out
  695. * of the cache.
  696. */
  697. if ((UINT)vKey < CVKKEYCACHE) {
  698. PCLIENTINFO pci = GetClientInfo();
  699. if (pci->dwKeyCache == gpsi->dwKeyCache) {
  700. retval = 0;
  701. if (TestKeyToggleBit(pci->afKeyState, vKey))
  702. retval |= 0x0001;
  703. if (TestKeyDownBit(pci->afKeyState, vKey)) {
  704. /*
  705. * Used to be retval |= 0x8000.Fix for bug 28820; Ctrl-Enter
  706. * accelerator doesn't work on Nestscape Navigator Mail 2.0
  707. */
  708. retval |= 0xff80; // This is what 3.1 returned!!!!
  709. }
  710. return (SHORT)retval;
  711. }
  712. }
  713. retval = (DWORD)NtUserGetKeyState(
  714. vKey);
  715. ERRORTRAP(0);
  716. ENDCALL(SHORT);
  717. }
  718. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, OpenClipboard, HWND, hwnd)
  719. BOOL OpenClipboard(
  720. HWND hwnd)
  721. {
  722. BOOL fEmptyClient;
  723. BEGINCALL()
  724. retval = (DWORD)NtUserOpenClipboard(hwnd, &fEmptyClient);
  725. if (fEmptyClient)
  726. ClientEmptyClipboard();
  727. ERRORTRAP(0);
  728. ENDCALL(BOOL);
  729. }
  730. BOOL _PeekMessage(
  731. LPMSG pmsg,
  732. HWND hwnd,
  733. UINT wMsgFilterMin,
  734. UINT wMsgFilterMax,
  735. UINT wRemoveMsg,
  736. BOOL bAnsi)
  737. {
  738. BEGINCALL()
  739. if (bAnsi) {
  740. //
  741. // If we have pushed message for DBCS messaging, we should pass this one
  742. // to Apps at first...
  743. //
  744. GET_DBCS_MESSAGE_IF_EXIST(
  745. PeekMessage,pmsg,wMsgFilterMin,wMsgFilterMax,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE));
  746. }
  747. retval = (DWORD)NtUserPeekMessage(
  748. pmsg,
  749. hwnd,
  750. wMsgFilterMin,
  751. wMsgFilterMax,
  752. wRemoveMsg);
  753. if (retval) {
  754. // May have a bit more work to do if this MSG is for an ANSI app
  755. if (bAnsi) {
  756. if (RtlWCSMessageWParamCharToMB(pmsg->message, &(pmsg->wParam))) {
  757. WPARAM dwAnsi = pmsg->wParam;
  758. //
  759. // Build DBCS-ware wParam. (for EM_SETPASSWORDCHAR...)
  760. //
  761. BUILD_DBCS_MESSAGE_TO_CLIENTA_FROM_SERVER(
  762. pmsg,dwAnsi,TRUE,((wRemoveMsg & PM_REMOVE) ? TRUE:FALSE));
  763. } else {
  764. retval = 0;
  765. }
  766. } else {
  767. //
  768. // Only LOWORD of WPARAM is valid for WM_CHAR....
  769. // (Mask off DBCS messaging information.)
  770. //
  771. BUILD_DBCS_MESSAGE_TO_CLIENTW_FROM_SERVER(pmsg->message,pmsg->wParam);
  772. }
  773. }
  774. ExitPeekMessage:
  775. ERRORTRAP(0);
  776. ENDCALL(BOOL);
  777. }
  778. LONG_PTR _SetWindowLongPtr(
  779. HWND hwnd,
  780. int nIndex,
  781. LONG_PTR dwNewLong,
  782. BOOL bAnsi)
  783. {
  784. PWND pwnd;
  785. LONG_PTR dwOldLong;
  786. DWORD dwCPDType = 0;
  787. pwnd = ValidateHwnd(hwnd);
  788. if (pwnd == NULL)
  789. return 0;
  790. if (TestWF(pwnd, WFDIALOGWINDOW)) {
  791. switch (nIndex) {
  792. case DWLP_DLGPROC: // See similar case GWL_WNDPROC
  793. /*
  794. * Hide the window proc from other processes
  795. */
  796. if (!TestWindowProcess(pwnd)) {
  797. RIPERR1(ERROR_ACCESS_DENIED,
  798. RIP_WARNING,
  799. "Access denied to hwnd (%#lx) in _SetWindowLong",
  800. hwnd);
  801. return 0;
  802. }
  803. /*
  804. * Get the old window proc address
  805. */
  806. dwOldLong = (LONG_PTR)PDLG(pwnd)->lpfnDlg;
  807. /*
  808. * We always store the actual address in the wndproc; We only
  809. * give the CallProc handles to the application
  810. */
  811. UserAssert(!ISCPDTAG(dwOldLong));
  812. /*
  813. * May need to return a CallProc handle if there is an
  814. * Ansi/Unicode tranistion
  815. */
  816. if (bAnsi != ((PDLG(pwnd)->flags & DLGF_ANSI) ? TRUE : FALSE)) {
  817. dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
  818. }
  819. /*
  820. * If we detected a transition create a CallProc handle for
  821. * this type of transition and this wndproc (dwOldLong)
  822. */
  823. if (dwCPDType) {
  824. ULONG_PTR cpd;
  825. cpd = GetCPD(pwnd, dwCPDType | CPD_DIALOG, dwOldLong);
  826. if (cpd) {
  827. dwOldLong = cpd;
  828. } else {
  829. RIPMSGF0(RIP_WARNING,
  830. "[DWL_DLGPROC]: Unable to alloc CPD handle");
  831. }
  832. }
  833. /*
  834. * Convert a possible CallProc Handle into a real address.
  835. * The app may have kept the CallProc Handle from some
  836. * previous mixed GetClassinfo or SetWindowLong.
  837. *
  838. * WARNING bAnsi is modified here to represent real type of
  839. * proc rather than if SetWindowLongA or W was called
  840. */
  841. if (ISCPDTAG(dwNewLong)) {
  842. PCALLPROCDATA pCPD;
  843. if (pCPD = HMValidateHandleNoRip((HANDLE)dwNewLong, TYPE_CALLPROC)) {
  844. dwNewLong = KERNEL_ULONG_PTR_TO_ULONG_PTR(pCPD->pfnClientPrevious);
  845. bAnsi = pCPD->wType & CPD_UNICODE_TO_ANSI;
  846. }
  847. }
  848. /*
  849. * If an app 'unsubclasses' a server-side window proc we need to
  850. * restore everything so SendMessage and friends know that it's
  851. * a server-side proc again. Need to check against client side
  852. * stub addresses.
  853. */
  854. PDLG(pwnd)->lpfnDlg = (DLGPROC)dwNewLong;
  855. if (bAnsi) {
  856. PDLG(pwnd)->flags |= DLGF_ANSI;
  857. } else {
  858. PDLG(pwnd)->flags &= ~DLGF_ANSI;
  859. }
  860. return dwOldLong;
  861. case DWLP_USER:
  862. #ifdef BUILD_WOW6432
  863. // kernel has special handling of DWLP_USER
  864. nIndex = sizeof(KERNEL_LRESULT) + sizeof(KERNEL_PVOID);
  865. #endif
  866. case DWLP_MSGRESULT:
  867. break;
  868. default:
  869. if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) {
  870. RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
  871. return 0;
  872. }
  873. }
  874. }
  875. BEGINCALL()
  876. /*
  877. * If this is a listbox window and the listbox structure has
  878. * already been initialized, don't allow the app to override the
  879. * owner draw styles. We need to do this since Windows only
  880. * used the styles in creating the structure, but we also use
  881. * them to determine if strings need to be thunked.
  882. *
  883. */
  884. if (nIndex == GWL_STYLE &&
  885. GETFNID(pwnd) == FNID_LISTBOX &&
  886. ((PLBWND)pwnd)->pLBIV != NULL &&
  887. (!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) {
  888. #if DBG
  889. LONG_PTR dwDebugLong = dwNewLong;
  890. #endif
  891. dwNewLong &= ~(LBS_OWNERDRAWFIXED |
  892. LBS_OWNERDRAWVARIABLE |
  893. LBS_HASSTRINGS);
  894. dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED |
  895. LBS_OWNERDRAWVARIABLE |
  896. LBS_HASSTRINGS);
  897. #if DBG
  898. if (dwDebugLong != dwNewLong) {
  899. RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS.");
  900. }
  901. #endif
  902. }
  903. retval = (ULONG_PTR)NtUserSetWindowLongPtr(
  904. hwnd,
  905. nIndex,
  906. dwNewLong,
  907. bAnsi);
  908. ERRORTRAP(0);
  909. ENDCALL(LONG_PTR);
  910. }
  911. #ifdef _WIN64
  912. LONG _SetWindowLong(
  913. HWND hwnd,
  914. int nIndex,
  915. LONG dwNewLong,
  916. BOOL bAnsi)
  917. {
  918. PWND pwnd;
  919. pwnd = ValidateHwnd(hwnd);
  920. if (pwnd == NULL)
  921. return 0;
  922. if (TestWF(pwnd, WFDIALOGWINDOW)) {
  923. switch (nIndex) {
  924. case DWLP_DLGPROC: // See similar case GWLP_WNDPROC
  925. RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetWindowLong: invalid index %d", nIndex);
  926. return 0;
  927. case DWLP_MSGRESULT:
  928. case DWLP_USER:
  929. break;
  930. default:
  931. if (nIndex >= 0 && nIndex < DLGWINDOWEXTRA) {
  932. RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
  933. return 0;
  934. }
  935. }
  936. }
  937. BEGINCALL()
  938. /*
  939. * If this is a listbox window and the listbox structure has
  940. * already been initialized, don't allow the app to override the
  941. * owner draw styles. We need to do this since Windows only
  942. * used the styles in creating the structure, but we also use
  943. * them to determine if strings need to be thunked.
  944. *
  945. */
  946. if (nIndex == GWL_STYLE &&
  947. GETFNID(pwnd) == FNID_LISTBOX &&
  948. ((PLBWND)pwnd)->pLBIV != NULL &&
  949. (!TestWindowProcess(pwnd) || ((PLBWND)pwnd)->pLBIV->fInitialized)) {
  950. #if DBG
  951. LONG dwDebugLong = dwNewLong;
  952. #endif
  953. dwNewLong &= ~(LBS_OWNERDRAWFIXED |
  954. LBS_OWNERDRAWVARIABLE |
  955. LBS_HASSTRINGS);
  956. dwNewLong |= pwnd->style & (LBS_OWNERDRAWFIXED |
  957. LBS_OWNERDRAWVARIABLE |
  958. LBS_HASSTRINGS);
  959. #if DBG
  960. if (dwDebugLong != dwNewLong) {
  961. RIPMSG0(RIP_WARNING, "SetWindowLong can't change LBS_OWNERDRAW* or LBS_HASSTRINGS.");
  962. }
  963. #endif
  964. }
  965. retval = (DWORD)NtUserSetWindowLong(
  966. hwnd,
  967. nIndex,
  968. dwNewLong,
  969. bAnsi);
  970. ERRORTRAP(0);
  971. ENDCALL(LONG);
  972. }
  973. #endif
  974. BOOL TranslateMessageEx(
  975. CONST MSG *pmsg,
  976. UINT flags)
  977. {
  978. BEGINCALL()
  979. /*
  980. * Don't bother going over to the kernel if this isn't
  981. * key message.
  982. */
  983. switch (pmsg->message) {
  984. case WM_KEYDOWN:
  985. case WM_KEYUP:
  986. case WM_SYSKEYDOWN:
  987. case WM_SYSKEYUP:
  988. break;
  989. default:
  990. if (pmsg->message & RESERVED_MSG_BITS) {
  991. RIPERR1(ERROR_INVALID_PARAMETER,
  992. RIP_WARNING,
  993. "Invalid parameter \"pmsg->message\" (%ld) to TranslateMessageEx",
  994. pmsg->message);
  995. }
  996. MSGERROR();
  997. }
  998. retval = (DWORD)NtUserTranslateMessage(
  999. pmsg,
  1000. flags);
  1001. ERRORTRAP(0);
  1002. ENDCALL(BOOL);
  1003. }
  1004. BOOL TranslateMessage(
  1005. CONST MSG *pmsg)
  1006. {
  1007. //
  1008. // IME special key handling
  1009. //
  1010. if (LOWORD(pmsg->wParam) == VK_PROCESSKEY) {
  1011. BOOL fResult;
  1012. //
  1013. // This vkey should be processed by IME.
  1014. //
  1015. fResult = fpImmTranslateMessage(pmsg->hwnd,
  1016. pmsg->message,
  1017. pmsg->wParam,
  1018. pmsg->lParam);
  1019. if (fResult) {
  1020. return fResult;
  1021. }
  1022. }
  1023. return TranslateMessageEx(pmsg, 0);
  1024. }
  1025. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowRgn, HWND, hwnd, HRGN, hrgn, BOOL, bRedraw)
  1026. BOOL SetWindowRgn(
  1027. HWND hwnd,
  1028. HRGN hrgn,
  1029. BOOL bRedraw)
  1030. {
  1031. BOOL ret;
  1032. BEGIN_USERAPIHOOK()
  1033. ret = guah.pfnSetWindowRgn(hwnd, hrgn, bRedraw);
  1034. END_USERAPIHOOK()
  1035. return ret;
  1036. }
  1037. BOOL RealSetWindowRgn(
  1038. HWND hwnd,
  1039. HRGN hrgn,
  1040. BOOL bRedraw)
  1041. {
  1042. BEGINCALL()
  1043. retval = (DWORD)NtUserSetWindowRgn(
  1044. hwnd,
  1045. hrgn,
  1046. bRedraw);
  1047. if (retval) {
  1048. DeleteObject(hrgn);
  1049. }
  1050. ERRORTRAP(0);
  1051. ENDCALL(BOOL);
  1052. }
  1053. FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, InternalGetWindowText, HWND, hwnd, LPWSTR, pString, int, cchMaxCount)
  1054. BOOL InternalGetWindowText(
  1055. HWND hwnd,
  1056. LPWSTR pString,
  1057. int cchMaxCount)
  1058. {
  1059. BEGINCALL()
  1060. retval = (DWORD)NtUserInternalGetWindowText(
  1061. hwnd,
  1062. pString,
  1063. cchMaxCount);
  1064. if (!retval) {
  1065. *pString = (WCHAR)0;
  1066. }
  1067. ERRORTRAP(0);
  1068. ENDCALL(BOOL);
  1069. }
  1070. int ToUnicode(
  1071. UINT wVirtKey,
  1072. UINT wScanCode,
  1073. CONST BYTE *pKeyState,
  1074. LPWSTR pwszBuff,
  1075. int cchBuff,
  1076. UINT wFlags)
  1077. {
  1078. BEGINCALL()
  1079. retval = (DWORD)NtUserToUnicodeEx(
  1080. wVirtKey,
  1081. wScanCode,
  1082. pKeyState,
  1083. pwszBuff,
  1084. cchBuff,
  1085. wFlags,
  1086. (HKL)NULL);
  1087. if (!retval) {
  1088. *pwszBuff = L'\0';
  1089. }
  1090. ERRORTRAP(0);
  1091. ENDCALL(int);
  1092. }
  1093. int ToUnicodeEx(
  1094. UINT wVirtKey,
  1095. UINT wScanCode,
  1096. CONST BYTE *pKeyState,
  1097. LPWSTR pwszBuff,
  1098. int cchBuff,
  1099. UINT wFlags,
  1100. HKL hkl)
  1101. {
  1102. BEGINCALL()
  1103. retval = (DWORD)NtUserToUnicodeEx(
  1104. wVirtKey,
  1105. wScanCode,
  1106. pKeyState,
  1107. pwszBuff,
  1108. cchBuff,
  1109. wFlags,
  1110. hkl);
  1111. if (!retval) {
  1112. *pwszBuff = L'\0';
  1113. }
  1114. ERRORTRAP(0);
  1115. ENDCALL(int);
  1116. }
  1117. #if DBG
  1118. FUNCLOGVOID2(LOG_GENERAL, DUMMYCALLINGTYPE, DbgWin32HeapFail, DWORD, dwFlags, BOOL, bFail)
  1119. VOID DbgWin32HeapFail(
  1120. DWORD dwFlags,
  1121. BOOL bFail)
  1122. {
  1123. if ((dwFlags | WHF_VALID) != WHF_VALID) {
  1124. RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags);
  1125. return;
  1126. }
  1127. if (dwFlags & WHF_CSRSS) {
  1128. // Tell csr about it
  1129. CsrWin32HeapFail(dwFlags, bFail);
  1130. }
  1131. NtUserDbgWin32HeapFail(dwFlags, bFail);
  1132. }
  1133. FUNCLOG3(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, DbgWin32HeapStat, PDBGHEAPSTAT, phs, DWORD, dwLen, DWORD, dwFlags)
  1134. DWORD DbgWin32HeapStat(
  1135. PDBGHEAPSTAT phs,
  1136. DWORD dwLen,
  1137. DWORD dwFlags)
  1138. {
  1139. if ((dwFlags | WHF_VALID) != WHF_VALID) {
  1140. RIPMSG1(RIP_WARNING, "Invalid flags for DbgWin32HeapFail %x", dwFlags);
  1141. return 0;
  1142. }
  1143. if (dwFlags & WHF_CSRSS) {
  1144. return CsrWin32HeapStat(phs, dwLen);
  1145. } else if (dwFlags & WHF_DESKTOP) {
  1146. return NtUserDbgWin32HeapStat(phs, dwLen);
  1147. }
  1148. return 0;
  1149. }
  1150. #endif // DBG
  1151. FUNCLOG4(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetWindowStationUser, HWINSTA, hwinsta, PLUID, pluidUser, PSID, psidUser, DWORD, cbsidUser)
  1152. BOOL SetWindowStationUser(
  1153. HWINSTA hwinsta,
  1154. PLUID pluidUser,
  1155. PSID psidUser,
  1156. DWORD cbsidUser)
  1157. {
  1158. LUID luidNone = { 0, 0 };
  1159. BEGINCALL()
  1160. retval = (DWORD)NtUserSetWindowStationUser(hwinsta,
  1161. pluidUser,
  1162. psidUser,
  1163. cbsidUser);
  1164. /*
  1165. * Load global atoms if the logon succeeded
  1166. */
  1167. if (retval) {
  1168. if (!RtlEqualLuid(pluidUser,&luidNone)) {
  1169. /*
  1170. * Reset console and load Nls data.
  1171. */
  1172. Logon(TRUE);
  1173. } else {
  1174. /*
  1175. * Flush NLS cache.
  1176. */
  1177. Logon(FALSE);
  1178. }
  1179. retval = TRUE;
  1180. }
  1181. ERRORTRAP(0);
  1182. ENDCALL(BOOL);
  1183. }
  1184. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetSystemCursor, HCURSOR, hcur, DWORD, id)
  1185. BOOL SetSystemCursor(
  1186. HCURSOR hcur,
  1187. DWORD id)
  1188. {
  1189. BEGINCALL()
  1190. if (hcur == NULL) {
  1191. hcur = (HANDLE)LoadIcoCur(NULL,
  1192. MAKEINTRESOURCE(id),
  1193. RT_CURSOR,
  1194. 0,
  1195. 0,
  1196. LR_DEFAULTSIZE);
  1197. if (hcur == NULL)
  1198. MSGERROR();
  1199. }
  1200. retval = (DWORD)NtUserSetSystemCursor(hcur, id);
  1201. ERRORTRAP(0);
  1202. ENDCALL(BOOL);
  1203. }
  1204. HCURSOR FindExistingCursorIcon(
  1205. LPWSTR pszModName,
  1206. LPCWSTR pszResName,
  1207. PCURSORFIND pcfSearch)
  1208. {
  1209. IN_STRING strModName;
  1210. IN_STRING strResName;
  1211. /*
  1212. * Make sure cleanup will work successfully
  1213. */
  1214. strModName.fAllocated = FALSE;
  1215. strResName.fAllocated = FALSE;
  1216. BEGINCALL()
  1217. if (pszModName == NULL)
  1218. pszModName = szUSER32;
  1219. COPYLPWSTR(&strModName, pszModName);
  1220. COPYLPWSTRID(&strResName, pszResName);
  1221. retval = (ULONG_PTR)NtUserFindExistingCursorIcon(strModName.pstr,
  1222. strResName.pstr,
  1223. pcfSearch);
  1224. ERRORTRAP(0);
  1225. CLEANUPLPWSTR(strModName);
  1226. CLEANUPLPWSTR(strResName);
  1227. ENDCALL(HCURSOR);
  1228. }
  1229. BOOL _SetCursorIconData(
  1230. HCURSOR hCursor,
  1231. PCURSORDATA pcur)
  1232. {
  1233. IN_STRING strModName;
  1234. IN_STRING strResName;
  1235. /*
  1236. * Make sure cleanup will work successfully
  1237. */
  1238. strModName.fAllocated = FALSE;
  1239. strResName.fAllocated = FALSE;
  1240. BEGINCALL()
  1241. COPYLPWSTROPT(&strModName, KPWSTR_TO_PWSTR(pcur->lpModName));
  1242. COPYLPWSTRIDOPT(&strResName, KPWSTR_TO_PWSTR(pcur->lpName));
  1243. retval = (DWORD)NtUserSetCursorIconData(hCursor,
  1244. strModName.pstr,
  1245. strResName.pstr,
  1246. pcur);
  1247. ERRORTRAP(0);
  1248. CLEANUPLPWSTR(strModName);
  1249. CLEANUPLPWSTR(strResName);
  1250. ENDCALL(BOOL);
  1251. }
  1252. BOOL _DefSetText(
  1253. HWND hwnd,
  1254. LPCWSTR lpszText,
  1255. BOOL bAnsi)
  1256. {
  1257. LARGE_STRING str;
  1258. BEGINCALL()
  1259. if (lpszText) {
  1260. if (bAnsi) {
  1261. RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&str,
  1262. (LPSTR)lpszText, (UINT)-1);
  1263. } else {
  1264. RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&str,
  1265. lpszText, (UINT)-1);
  1266. }
  1267. }
  1268. retval = (DWORD)NtUserDefSetText(hwnd, lpszText ? &str : NULL);
  1269. ERRORTRAP(0);
  1270. ENDCALL(BOOL);
  1271. }
  1272. HWND _CreateWindowEx(
  1273. DWORD dwExStyle,
  1274. LPCTSTR pClassName,
  1275. LPCTSTR pWindowName,
  1276. DWORD dwStyle,
  1277. int x,
  1278. int y,
  1279. int nWidth,
  1280. int nHeight,
  1281. HWND hwndParent,
  1282. HMENU hmenu,
  1283. HANDLE hModule,
  1284. LPVOID pParam,
  1285. DWORD dwFlags)
  1286. {
  1287. LARGE_IN_STRING strClassName;
  1288. LARGE_STRING strWindowName;
  1289. PLARGE_STRING pstrClassName;
  1290. PLARGE_STRING pstrWindowName;
  1291. DWORD dwExpWinVerAndFlags;
  1292. /*
  1293. * Make sure cleanup will work successfully
  1294. */
  1295. strClassName.fAllocated = FALSE;
  1296. /*
  1297. * To be compatible with Chicago, we test the validity of
  1298. * the ExStyle bits and fail if any invalid bits are found.
  1299. * And for backward compatibilty with NT apps, we only fail for
  1300. * new apps (post NT 3.1).
  1301. */
  1302. // BOGUS
  1303. if (dwExStyle & 0x00000800L) {
  1304. dwExStyle |= WS_EX_TOOLWINDOW;
  1305. dwExStyle &= 0xfffff7ffL;
  1306. }
  1307. dwExpWinVerAndFlags = (DWORD)(WORD)GETEXPWINVER(hModule);
  1308. if ((dwExStyle & ~WS_EX_ALLVALID) && Is400Compat(dwExpWinVerAndFlags)) {
  1309. RIPMSG1(RIP_WARNING, "Invalid 5.1 ExStyle 0x%x", dwExStyle);
  1310. return NULL;
  1311. }
  1312. {
  1313. BOOL fMDIchild = FALSE;
  1314. MDICREATESTRUCT mdics;
  1315. HMENU hSysMenu;
  1316. BEGINCALL()
  1317. if ((fMDIchild = (BOOL)(dwExStyle & WS_EX_MDICHILD))) {
  1318. SHORTCREATE sc;
  1319. PWND pwndParent;
  1320. pwndParent = ValidateHwnd(hwndParent);
  1321. if (pwndParent == NULL || GETFNID(pwndParent) != FNID_MDICLIENT) {
  1322. RIPMSG0(RIP_WARNING, "Invalid parent for MDI child window");
  1323. MSGERROR();
  1324. }
  1325. mdics.lParam = (LPARAM)pParam;
  1326. pParam = &mdics;
  1327. mdics.x = sc.x = x;
  1328. mdics.y = sc.y = y;
  1329. mdics.cx = sc.cx = nWidth;
  1330. mdics.cy = sc.cy = nHeight;
  1331. mdics.style = sc.style = dwStyle;
  1332. mdics.hOwner = hModule;
  1333. mdics.szClass = pClassName;
  1334. mdics.szTitle = pWindowName;
  1335. if (!CreateMDIChild(&sc, &mdics, dwExpWinVerAndFlags, &hSysMenu, pwndParent))
  1336. MSGERROR();
  1337. x = sc.x;
  1338. y = sc.y;
  1339. nWidth = sc.cx;
  1340. nHeight = sc.cy;
  1341. dwStyle = sc.style;
  1342. hmenu = sc.hMenu;
  1343. }
  1344. /*
  1345. * Set up class and window name. If the window name is an
  1346. * ordinal, make it look like a string so the callback thunk
  1347. * will be able to ensure it is in the correct format.
  1348. */
  1349. pstrWindowName = NULL;
  1350. if (dwFlags & CW_FLAGS_ANSI) {
  1351. dwExStyle = dwExStyle | WS_EX_ANSICREATOR;
  1352. if (IS_PTR(pClassName)) {
  1353. RtlCaptureLargeAnsiString(&strClassName,
  1354. (PCHAR)pClassName, TRUE);
  1355. pstrClassName = (PLARGE_STRING)strClassName.pstr;
  1356. } else {
  1357. pstrClassName = (PLARGE_STRING)pClassName;
  1358. }
  1359. if (pWindowName != NULL) {
  1360. if (*(PBYTE)pWindowName == 0xff) {
  1361. strWindowName.bAnsi = TRUE;
  1362. strWindowName.Buffer = (PVOID)pWindowName;
  1363. strWindowName.Length = 3;
  1364. strWindowName.MaximumLength = 3;
  1365. } else {
  1366. RtlInitLargeAnsiString((PLARGE_ANSI_STRING)&strWindowName,
  1367. (LPSTR)pWindowName,
  1368. (UINT)-1);
  1369. }
  1370. pstrWindowName = &strWindowName;
  1371. }
  1372. } else {
  1373. if (IS_PTR(pClassName)) {
  1374. RtlInitLargeUnicodeString(
  1375. (PLARGE_UNICODE_STRING)&strClassName.strCapture,
  1376. pClassName, (UINT)-1);
  1377. pstrClassName = (PLARGE_STRING)&strClassName.strCapture;
  1378. } else {
  1379. pstrClassName = (PLARGE_STRING)pClassName;
  1380. }
  1381. if (pWindowName != NULL) {
  1382. if (pWindowName != NULL &&
  1383. *(PWORD)pWindowName == 0xffff) {
  1384. strWindowName.bAnsi = FALSE;
  1385. strWindowName.Buffer = (PVOID)pWindowName;
  1386. strWindowName.Length = 4;
  1387. strWindowName.MaximumLength = 4;
  1388. } else {
  1389. RtlInitLargeUnicodeString((PLARGE_UNICODE_STRING)&strWindowName,
  1390. pWindowName, (UINT)-1);
  1391. }
  1392. pstrWindowName = &strWindowName;
  1393. }
  1394. }
  1395. dwExpWinVerAndFlags |= (dwFlags & (CW_FLAGS_DIFFHMOD | CW_FLAGS_VERSIONCLASS));
  1396. retval = (ULONG_PTR)VerNtUserCreateWindowEx(
  1397. dwExStyle,
  1398. pstrClassName,
  1399. pstrWindowName,
  1400. dwStyle,
  1401. x,
  1402. y,
  1403. nWidth,
  1404. nHeight,
  1405. hwndParent,
  1406. hmenu,
  1407. hModule,
  1408. pParam,
  1409. dwExpWinVerAndFlags);
  1410. // If this is an MDI child, we need to do some more to complete the
  1411. // process of creating an MDI child.
  1412. if (retval && fMDIchild) {
  1413. MDICompleteChildCreation((HWND)retval, hSysMenu, ((dwStyle & WS_VISIBLE) != 0L), (BOOL)((dwStyle & WS_DISABLED)!= 0L));
  1414. }
  1415. ERRORTRAP(0);
  1416. CLEANUPLPSTRW(strClassName);
  1417. ENDCALL(HWND);
  1418. }
  1419. }
  1420. HKL _LoadKeyboardLayoutEx(
  1421. HANDLE hFile,
  1422. UINT offTable,
  1423. PKBDTABLE_MULTI_INTERNAL pKbdTableMulti,
  1424. HKL hkl,
  1425. LPCTSTR pwszKL,
  1426. UINT KbdInputLocale,
  1427. UINT Flags)
  1428. {
  1429. IN_STRING strKL;
  1430. /*
  1431. * Make sure cleanup will work successfully
  1432. */
  1433. strKL.fAllocated = FALSE;
  1434. BEGINCALL()
  1435. FIRSTCOPYLPWSTR(&strKL, pwszKL);
  1436. retval = (ULONG_PTR)NtUserLoadKeyboardLayoutEx(
  1437. hFile,
  1438. offTable,
  1439. pKbdTableMulti,
  1440. hkl,
  1441. strKL.pstr,
  1442. KbdInputLocale,
  1443. Flags);
  1444. ERRORTRAP(0);
  1445. CLEANUPLPWSTR(strKL);
  1446. ENDCALL(HKL);
  1447. }
  1448. FUNCLOGVOID5(LOG_GENERAL, DUMMYCALLINGTYPE, mouse_event, DWORD, dwFlags, DWORD, dx, DWORD, dy, DWORD, dwData, ULONG_PTR, dwExtraInfo)
  1449. VOID mouse_event(
  1450. DWORD dwFlags,
  1451. DWORD dx,
  1452. DWORD dy,
  1453. DWORD dwData,
  1454. ULONG_PTR dwExtraInfo)
  1455. {
  1456. INPUT ms;
  1457. BEGINCALLVOID()
  1458. ms.type = INPUT_MOUSE;
  1459. ms.mi.dwFlags = dwFlags;
  1460. ms.mi.dx = dx;
  1461. ms.mi.dy = dy;
  1462. ms.mi.mouseData = dwData;
  1463. ms.mi.time = 0;
  1464. ms.mi.dwExtraInfo = dwExtraInfo;
  1465. NtUserSendInput(1, &ms, sizeof(INPUT));
  1466. ENDCALLVOID()
  1467. }
  1468. FUNCLOGVOID4(LOG_GENERAL, DUMMYCALLINGTYPE, keybd_event, BYTE, bVk, BYTE, bScan, DWORD, dwFlags, ULONG_PTR, dwExtraInfo)
  1469. VOID keybd_event(
  1470. BYTE bVk,
  1471. BYTE bScan,
  1472. DWORD dwFlags,
  1473. ULONG_PTR dwExtraInfo)
  1474. {
  1475. INPUT kbd;
  1476. BEGINCALLVOID()
  1477. kbd.type = INPUT_KEYBOARD;
  1478. kbd.ki.dwFlags = dwFlags;
  1479. kbd.ki.wVk = bVk;
  1480. kbd.ki.wScan = bScan;
  1481. kbd.ki.time = 0;
  1482. kbd.ki.dwExtraInfo = dwExtraInfo;
  1483. NtUserSendInput(1, &kbd, sizeof(INPUT));
  1484. ENDCALLVOID()
  1485. }
  1486. /*
  1487. * Message thunks
  1488. */
  1489. MESSAGECALL(fnINWPARAMDBCSCHAR)
  1490. {
  1491. BEGINCALL()
  1492. /*
  1493. * The server always expects the characters to be unicode so
  1494. * if this was generated from an ANSI routine convert it to Unicode
  1495. */
  1496. if (bAnsi) {
  1497. /*
  1498. * Setup for DBCS Messaging..
  1499. */
  1500. BUILD_DBCS_MESSAGE_TO_SERVER_FROM_CLIENTA(msg,wParam,TRUE);
  1501. /*
  1502. * Convert DBCS/SBCS to Unicode...
  1503. */
  1504. RtlMBMessageWParamCharToWCS(msg, &wParam);
  1505. }
  1506. retval = (DWORD)NtUserMessageCall(
  1507. hwnd,
  1508. msg,
  1509. wParam,
  1510. lParam,
  1511. xParam,
  1512. xpfnProc,
  1513. bAnsi);
  1514. ERRORTRAP(0);
  1515. ENDCALL(DWORD);
  1516. }
  1517. MESSAGECALL(fnCOPYGLOBALDATA)
  1518. {
  1519. PBYTE pData;
  1520. BEGINCALL()
  1521. if (wParam == 0) {
  1522. MSGERROR();
  1523. }
  1524. USERGLOBALLOCK((HGLOBAL)lParam, pData);
  1525. if (pData == NULL) {
  1526. MSGERROR();
  1527. }
  1528. retval = NtUserMessageCall(
  1529. hwnd,
  1530. msg,
  1531. wParam,
  1532. (LPARAM)pData,
  1533. xParam,
  1534. xpfnProc,
  1535. bAnsi);
  1536. USERGLOBALUNLOCK((HGLOBAL)lParam);
  1537. UserGlobalFree((HGLOBAL)lParam);
  1538. ERRORTRAP(0);
  1539. ENDCALL(ULONG_PTR);
  1540. }
  1541. MESSAGECALL(fnINPAINTCLIPBRD)
  1542. {
  1543. LPPAINTSTRUCT lpps;
  1544. BEGINCALL()
  1545. USERGLOBALLOCK((HGLOBAL)lParam, lpps);
  1546. if (lpps) {
  1547. retval = (DWORD)NtUserMessageCall(
  1548. hwnd,
  1549. msg,
  1550. wParam,
  1551. (LPARAM)lpps,
  1552. xParam,
  1553. xpfnProc,
  1554. bAnsi);
  1555. USERGLOBALUNLOCK((HGLOBAL)lParam);
  1556. } else {
  1557. RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINPAINTCLIPBRD): USERGLOBALLOCK failed on %p!", lParam);
  1558. MSGERROR();
  1559. }
  1560. ERRORTRAP(0);
  1561. ENDCALL(DWORD);
  1562. }
  1563. MESSAGECALL(fnINSIZECLIPBRD)
  1564. {
  1565. LPRECT lprc;
  1566. BEGINCALL()
  1567. USERGLOBALLOCK((HGLOBAL)lParam, lprc);
  1568. if (lprc) {
  1569. retval = (DWORD)NtUserMessageCall(
  1570. hwnd,
  1571. msg,
  1572. wParam,
  1573. (LPARAM)lprc,
  1574. xParam,
  1575. xpfnProc,
  1576. bAnsi);
  1577. USERGLOBALUNLOCK((HGLOBAL)lParam);
  1578. } else {
  1579. RIPMSG1(RIP_WARNING, "MESSAGECALL(fnINSIZECLIPBRD): USERGLOBALLOCK failed on %p!", lParam);
  1580. MSGERROR();
  1581. }
  1582. ERRORTRAP(0);
  1583. ENDCALL(DWORD);
  1584. }
  1585. MESSAGECALL(fnINDEVICECHANGE)
  1586. {
  1587. struct _DEV_BROADCAST_HEADER *pHdr;
  1588. PDEV_BROADCAST_PORT_W pPortW = NULL;
  1589. PDEV_BROADCAST_PORT_A pPortA;
  1590. PDEV_BROADCAST_DEVICEINTERFACE_W pInterfaceW = NULL;
  1591. PDEV_BROADCAST_DEVICEINTERFACE_A pInterfaceA;
  1592. PDEV_BROADCAST_HANDLE pHandleW = NULL;
  1593. PDEV_BROADCAST_HANDLE pHandleA;
  1594. LPWSTR lpStr;
  1595. int iStr, iSize;
  1596. BEGINCALL()
  1597. if (!(wParam &0x8000) || !lParam || !bAnsi)
  1598. goto shipit;
  1599. pHdr = (struct _DEV_BROADCAST_HEADER *)lParam;
  1600. switch (pHdr->dbcd_devicetype) {
  1601. case DBT_DEVTYP_PORT:
  1602. pPortA = (PDEV_BROADCAST_PORT_A)lParam;
  1603. iStr = strlen(pPortA->dbcp_name);
  1604. iSize = FIELD_OFFSET(DEV_BROADCAST_PORT_W, dbcp_name) + sizeof(WCHAR)*(iStr+1);
  1605. pPortW = UserLocalAlloc(0, iSize);
  1606. if (pPortW == NULL)
  1607. return 0;
  1608. RtlCopyMemory(pPortW, pPortA, sizeof(DEV_BROADCAST_PORT_A));
  1609. lpStr = pPortW->dbcp_name;
  1610. if (iStr) {
  1611. MBToWCS(pPortA->dbcp_name, -1, &lpStr, iStr, FALSE);
  1612. lpStr[iStr] = 0;
  1613. } else {
  1614. lpStr[0] = 0;
  1615. }
  1616. pPortW->dbcp_size = iSize;
  1617. lParam = (LPARAM)pPortW;
  1618. bAnsi = FALSE;
  1619. break;
  1620. case DBT_DEVTYP_DEVICEINTERFACE:
  1621. pInterfaceA = (PDEV_BROADCAST_DEVICEINTERFACE_A)lParam;
  1622. iStr = strlen(pInterfaceA->dbcc_name);
  1623. iSize = FIELD_OFFSET(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name) + sizeof(WCHAR)*(iStr+1);
  1624. pInterfaceW = UserLocalAlloc(0, iSize);
  1625. if (pInterfaceW == NULL)
  1626. return 0;
  1627. RtlCopyMemory(pInterfaceW, pInterfaceA, sizeof(DEV_BROADCAST_DEVICEINTERFACE_A));
  1628. lpStr = pInterfaceW->dbcc_name;
  1629. if (iStr) {
  1630. MBToWCS(pInterfaceA->dbcc_name, -1, &lpStr, iStr, FALSE);
  1631. lpStr[iStr] = 0;
  1632. } else {
  1633. lpStr[0] = 0;
  1634. }
  1635. pInterfaceW->dbcc_size = iSize;
  1636. lParam = (LPARAM)pInterfaceW;
  1637. bAnsi = FALSE;
  1638. break;
  1639. case DBT_DEVTYP_HANDLE:
  1640. pHandleA = (PDEV_BROADCAST_HANDLE)lParam;
  1641. bAnsi = FALSE;
  1642. if ((wParam != DBT_CUSTOMEVENT) || (pHandleA->dbch_nameoffset < 0)) break;
  1643. iStr = strlen(pHandleA->dbch_data+pHandleA->dbch_nameoffset);
  1644. /*
  1645. * Calculate size of new structure with UNICODE string instead of Ansi string
  1646. */
  1647. iSize = FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset + sizeof(WCHAR)*(iStr+1);
  1648. /*
  1649. * Just in case there were an odd number of bytes in the non-text data
  1650. */
  1651. if (iSize & 1) iSize++;
  1652. pHandleW = UserLocalAlloc(0, iSize);
  1653. if (pHandleW == NULL)
  1654. return 0;
  1655. RtlCopyMemory(pHandleW, pHandleA, FIELD_OFFSET(DEV_BROADCAST_HANDLE, dbch_data)+ pHandleA->dbch_nameoffset);
  1656. /*
  1657. * Make sure this is even for the UNICODE string.
  1658. */
  1659. if (pHandleW->dbch_nameoffset & 1) pHandleW->dbch_nameoffset++;
  1660. lpStr = (LPWSTR)(pHandleW->dbch_data+pHandleW->dbch_nameoffset);
  1661. if (iStr) {
  1662. MBToWCS(pHandleA->dbch_data+pHandleA->dbch_nameoffset, -1,
  1663. &lpStr, iStr, FALSE);
  1664. }
  1665. lpStr[iStr] = 0;
  1666. pHandleW->dbch_size = iSize;
  1667. lParam = (LPARAM)pHandleW;
  1668. break;
  1669. }
  1670. shipit:
  1671. retval = (DWORD)NtUserMessageCall(
  1672. hwnd,
  1673. msg,
  1674. wParam,
  1675. lParam,
  1676. xParam,
  1677. xpfnProc,
  1678. bAnsi);
  1679. if (pPortW) UserLocalFree(pPortW);
  1680. if (pInterfaceW) UserLocalFree(pInterfaceW);
  1681. if (pHandleW) UserLocalFree(pHandleW);
  1682. ERRORTRAP(0);
  1683. ENDCALL(DWORD);
  1684. }
  1685. MESSAGECALL(fnIMECONTROL)
  1686. {
  1687. PVOID pvData = NULL;
  1688. LPARAM lData = lParam;
  1689. BEGINCALL()
  1690. /*
  1691. * The server always expects the characters to be unicode so
  1692. * if this was generated from an ANSI routine convert it to Unicode
  1693. */
  1694. if (bAnsi) {
  1695. switch (wParam) {
  1696. case IMC_GETCOMPOSITIONFONT:
  1697. case IMC_GETSOFTKBDFONT:
  1698. case IMC_SETCOMPOSITIONFONT:
  1699. pvData = UserLocalAlloc(0, sizeof(LOGFONTW));
  1700. if (pvData == NULL)
  1701. MSGERROR();
  1702. if (wParam == IMC_SETCOMPOSITIONFONT) {
  1703. // Later, we do A/W conversion based on thread hkl/CP.
  1704. CopyLogFontAtoW((PLOGFONTW)pvData, (PLOGFONTA)lParam);
  1705. }
  1706. lData = (LPARAM)pvData;
  1707. break;
  1708. case IMC_SETSOFTKBDDATA:
  1709. {
  1710. PSOFTKBDDATA pSoftKbdData;
  1711. PWORD pCodeA;
  1712. PWSTR pCodeW;
  1713. CHAR ch[3];
  1714. DWORD cbSize;
  1715. UINT uCount, i;
  1716. uCount = ((PSOFTKBDDATA)lParam)->uCount;
  1717. cbSize = FIELD_OFFSET(SOFTKBDDATA, wCode[0])
  1718. + uCount * sizeof(WORD) * 256;
  1719. pvData = UserLocalAlloc(0, cbSize);
  1720. if (pvData == NULL)
  1721. MSGERROR();
  1722. pSoftKbdData = (PSOFTKBDDATA)pvData;
  1723. pSoftKbdData->uCount = uCount;
  1724. ch[2] = (CHAR)'\0';
  1725. pCodeA = &((PSOFTKBDDATA)lParam)->wCode[0][0];
  1726. pCodeW = &pSoftKbdData->wCode[0][0];
  1727. i = uCount * 256;
  1728. while (i--) {
  1729. if (HIBYTE(*pCodeA)) {
  1730. ch[0] = (CHAR)HIBYTE(*pCodeA);
  1731. ch[1] = (CHAR)LOBYTE(*pCodeA);
  1732. } else {
  1733. ch[0] = (CHAR)LOBYTE(*pCodeA);
  1734. ch[1] = (CHAR)'\0';
  1735. }
  1736. MBToWCSEx(THREAD_CODEPAGE(), (LPSTR)&ch, -1, &pCodeW, 1, FALSE);
  1737. pCodeA++; pCodeW++;
  1738. }
  1739. lData = (LPARAM)pvData;
  1740. }
  1741. break;
  1742. default:
  1743. break;
  1744. }
  1745. }
  1746. retval = (DWORD)NtUserMessageCall(
  1747. hwnd,
  1748. msg,
  1749. wParam,
  1750. lData,
  1751. xParam,
  1752. xpfnProc,
  1753. bAnsi);
  1754. if (bAnsi) {
  1755. switch (wParam) {
  1756. case IMC_GETCOMPOSITIONFONT:
  1757. case IMC_GETSOFTKBDFONT:
  1758. CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData);
  1759. break;
  1760. default:
  1761. break;
  1762. }
  1763. }
  1764. if (pvData != NULL)
  1765. UserLocalFree(pvData);
  1766. ERRORTRAP(0);
  1767. ENDCALL(DWORD);
  1768. }
  1769. DWORD CalcCharacterPositionAtoW(
  1770. DWORD dwCharPosA,
  1771. LPSTR lpszCharStr,
  1772. DWORD dwCodePage)
  1773. {
  1774. DWORD dwCharPosW = 0;
  1775. while (dwCharPosA != 0) {
  1776. if (IsDBCSLeadByteEx(dwCodePage, *lpszCharStr)) {
  1777. if (dwCharPosA >= 2) {
  1778. dwCharPosA -= 2;
  1779. }
  1780. else {
  1781. dwCharPosA--;
  1782. }
  1783. lpszCharStr += 2;
  1784. }
  1785. else {
  1786. dwCharPosA--;
  1787. lpszCharStr++;
  1788. }
  1789. dwCharPosW++;
  1790. }
  1791. return dwCharPosW;
  1792. }
  1793. int UnicodeToMultiByteSize(DWORD dwCodePage, LPCWSTR pwstr)
  1794. {
  1795. char dummy[2], *lpszDummy = dummy;
  1796. return WCSToMBEx((WORD)dwCodePage, pwstr, 1, &lpszDummy, sizeof(WCHAR), FALSE);
  1797. }
  1798. DWORD CalcCharacterPositionWtoA(
  1799. DWORD dwCharPosW,
  1800. LPWSTR lpwszCharStr,
  1801. DWORD dwCodePage)
  1802. {
  1803. DWORD dwCharPosA = 0;
  1804. ULONG MultiByteSize;
  1805. while (dwCharPosW != 0) {
  1806. MultiByteSize = UnicodeToMultiByteSize(dwCodePage, lpwszCharStr);
  1807. if (MultiByteSize == 2) {
  1808. dwCharPosA += 2;
  1809. }
  1810. else {
  1811. dwCharPosA++;
  1812. }
  1813. dwCharPosW--;
  1814. lpwszCharStr++;
  1815. }
  1816. return dwCharPosA;
  1817. }
  1818. #ifdef LATER
  1819. DWORD WINAPI ImmGetReconvertTotalSize(DWORD dwSize, REQ_CALLER eCaller, BOOL bAnsiTarget)
  1820. {
  1821. if (dwSize < sizeof(RECONVERTSTRING)) {
  1822. return 0;
  1823. }
  1824. if (bAnsiTarget) {
  1825. dwSize -= sizeof(RECONVERTSTRING);
  1826. if (eCaller == FROM_IME) {
  1827. dwSize /= 2;
  1828. } else {
  1829. dwSize *= 2;
  1830. }
  1831. dwSize += sizeof(RECONVERTSTRING);
  1832. }
  1833. return dwSize;
  1834. }
  1835. FUNCLOG4(LOG_GENERAL, DWORD, WINAPI, ImmReconversionWorker, LPRECONVERTSTRING, lpRecTo, LPRECONVERTSTRING, lpRecFrom, BOOL, bToAnsi, DWORD, dwCodePage)
  1836. DWORD WINAPI ImmReconversionWorker(
  1837. LPRECONVERTSTRING lpRecTo,
  1838. LPRECONVERTSTRING lpRecFrom,
  1839. BOOL bToAnsi,
  1840. DWORD dwCodePage)
  1841. {
  1842. INT i;
  1843. DWORD dwSize = 0;
  1844. UserAssert(lpRecTo);
  1845. UserAssert(lpRecFrom);
  1846. if (lpRecFrom->dwVersion != 0 || lpRecTo->dwVersion != 0) {
  1847. RIPMSG0(RIP_WARNING, "ImmReconversionWorker: dwVersion in lpRecTo or lpRecFrom is incorrect.");
  1848. return 0;
  1849. }
  1850. // Note:
  1851. // In any IME related structures, use the following principal.
  1852. // 1) xxxStrOffset is an actual offset, i.e. byte count.
  1853. // 2) xxxStrLen is a number of characters, i.e. TCHAR count.
  1854. //
  1855. // CalcCharacterPositionXtoY() takes TCHAR count so that we
  1856. // need to adjust xxxStrOffset if it's being converted. But you
  1857. // should be careful, because the actual position of the string
  1858. // is always at something like (LPBYTE)lpStruc + lpStruc->dwStrOffset.
  1859. //
  1860. if (bToAnsi) {
  1861. // Convert W to A
  1862. lpRecTo->dwStrOffset = sizeof *lpRecTo;
  1863. i = WideCharToMultiByte(dwCodePage,
  1864. (DWORD)0,
  1865. (LPWSTR)((LPSTR)lpRecFrom + lpRecFrom->dwStrOffset), // src
  1866. (INT)lpRecFrom->dwStrLen,
  1867. (LPSTR)lpRecTo + lpRecTo->dwStrOffset, // dest
  1868. (INT)lpRecFrom->dwStrLen * DBCS_CHARSIZE,
  1869. (LPSTR)NULL,
  1870. (LPBOOL)NULL);
  1871. lpRecTo->dwCompStrOffset =
  1872. CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR),
  1873. (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
  1874. dwCodePage)
  1875. * sizeof(CHAR);
  1876. lpRecTo->dwCompStrLen =
  1877. (CalcCharacterPositionWtoA(lpRecFrom->dwCompStrOffset / sizeof(WCHAR) +
  1878. lpRecFrom->dwCompStrLen,
  1879. (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
  1880. dwCodePage)
  1881. * sizeof(CHAR))
  1882. - lpRecTo->dwCompStrOffset;
  1883. lpRecTo->dwTargetStrOffset =
  1884. CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR),
  1885. (LPWSTR)((LPBYTE)lpRecFrom +
  1886. lpRecFrom->dwStrOffset),
  1887. dwCodePage)
  1888. * sizeof(CHAR);
  1889. lpRecTo->dwTargetStrLen =
  1890. (CalcCharacterPositionWtoA(lpRecFrom->dwTargetStrOffset / sizeof(WCHAR) +
  1891. lpRecFrom->dwTargetStrLen,
  1892. (LPWSTR)((LPBYTE)lpRecFrom + lpRecFrom->dwStrOffset),
  1893. dwCodePage)
  1894. * sizeof(CHAR))
  1895. - lpRecTo->dwTargetStrOffset;
  1896. ((LPSTR)lpRecTo)[lpRecTo->dwStrOffset + i] = '\0';
  1897. lpRecTo->dwStrLen = i * sizeof(CHAR);
  1898. dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(CHAR));
  1899. } else {
  1900. // AtoW
  1901. lpRecTo->dwStrOffset = sizeof *lpRecTo;
  1902. i = MultiByteToWideChar(dwCodePage,
  1903. (DWORD)MB_PRECOMPOSED,
  1904. (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset, // src
  1905. (INT)lpRecFrom->dwStrLen,
  1906. (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset), // dest
  1907. (INT)lpRecFrom->dwStrLen);
  1908. lpRecTo->dwCompStrOffset =
  1909. CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset,
  1910. (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
  1911. dwCodePage) * sizeof(WCHAR);
  1912. lpRecTo->dwCompStrLen =
  1913. ((CalcCharacterPositionAtoW(lpRecFrom->dwCompStrOffset +
  1914. lpRecFrom->dwCompStrLen,
  1915. (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
  1916. dwCodePage) * sizeof(WCHAR))
  1917. - lpRecTo->dwCompStrOffset) / sizeof(WCHAR);
  1918. lpRecTo->dwTargetStrOffset =
  1919. CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset,
  1920. (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
  1921. dwCodePage) * sizeof(WCHAR);
  1922. lpRecTo->dwTargetStrLen =
  1923. ((CalcCharacterPositionAtoW(lpRecFrom->dwTargetStrOffset +
  1924. lpRecFrom->dwTargetStrLen,
  1925. (LPSTR)lpRecFrom + lpRecFrom->dwStrOffset,
  1926. dwCodePage) * sizeof(WCHAR))
  1927. - lpRecTo->dwTargetStrOffset) / sizeof(WCHAR);
  1928. lpRecTo->dwStrLen = i; // Length is TCHAR count.
  1929. if (lpRecTo->dwSize >= (DWORD)(lpRecTo->dwStrOffset + (i + 1)* sizeof(WCHAR))) {
  1930. LPWSTR lpW = (LPWSTR)((LPSTR)lpRecTo + lpRecTo->dwStrOffset);
  1931. lpW[i] = L'\0';
  1932. }
  1933. dwSize = sizeof(RECONVERTSTRING) + ((i + 1) * sizeof(WCHAR));
  1934. }
  1935. return dwSize;
  1936. }
  1937. #define GETCOMPOSITIONSTRING(hImc, index, buf, buflen) \
  1938. (bAnsi ? fpImmGetCompositionStringA : fpImmGetCompositionStringW)((hImc), (index), (buf), (buflen))
  1939. MESSAGECALL(fnIMEREQUEST)
  1940. {
  1941. PVOID pvData = NULL;
  1942. LPARAM lData = lParam;
  1943. BEGINCALL()
  1944. if (!IS_IME_ENABLED()) {
  1945. // If IME is not enabled, save time.
  1946. MSGERROR();
  1947. }
  1948. /*
  1949. * The server always expects the characters to be unicode so
  1950. * if this was generated from an ANSI routine convert it to Unicode
  1951. */
  1952. if (wParam == IMR_QUERYCHARPOSITION) {
  1953. //
  1954. // Store the UNICODE character count in PrivateIMECHARPOSITION.
  1955. //
  1956. // No need to save the original dwCharPos, since dwCharPositionA/W are not
  1957. // overwritten in the kernel.
  1958. //
  1959. if (bAnsi) {
  1960. ((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionW;
  1961. }
  1962. }
  1963. else if (bAnsi) {
  1964. switch (wParam) {
  1965. case IMR_COMPOSITIONFONT:
  1966. pvData = UserLocalAlloc(0, sizeof(LOGFONTW));
  1967. if (pvData == NULL)
  1968. MSGERROR();
  1969. lData = (LPARAM)pvData;
  1970. break;
  1971. case IMR_CONFIRMRECONVERTSTRING:
  1972. case IMR_RECONVERTSTRING:
  1973. case IMR_DOCUMENTFEED:
  1974. if ((LPVOID)lParam != NULL) {
  1975. // IME wants not only the buffer size but the real reconversion information
  1976. DWORD dwSize = ImmGetReconvertTotalSize(((LPRECONVERTSTRING)lParam)->dwSize, FROM_IME, FALSE);
  1977. LPRECONVERTSTRING lpReconv;
  1978. pvData = UserLocalAlloc(0, dwSize + sizeof(WCHAR));
  1979. if (pvData == NULL) {
  1980. RIPMSG0(RIP_WARNING, "fnIMEREQUEST: failed to allocate a buffer for reconversion.");
  1981. MSGERROR();
  1982. }
  1983. lpReconv = (LPRECONVERTSTRING)pvData;
  1984. // setup the information in the allocated structure
  1985. lpReconv->dwVersion = 0;
  1986. lpReconv->dwSize = dwSize;
  1987. //
  1988. // if it's confirmation message, we need to translate the contents
  1989. //
  1990. if (wParam == IMR_CONFIRMRECONVERTSTRING) {
  1991. ImmReconversionWorker(lpReconv, (LPRECONVERTSTRING)lParam, FALSE, CP_ACP);
  1992. }
  1993. }
  1994. break;
  1995. default:
  1996. break;
  1997. }
  1998. }
  1999. retval = (DWORD)NtUserMessageCall(
  2000. hwnd,
  2001. msg,
  2002. wParam,
  2003. lData,
  2004. xParam,
  2005. xpfnProc,
  2006. bAnsi);
  2007. if (bAnsi) {
  2008. switch (wParam) {
  2009. case IMR_COMPOSITIONFONT:
  2010. if (retval) {
  2011. CopyLogFontWtoA((PLOGFONTA)lParam, (PLOGFONTW)pvData);
  2012. }
  2013. break;
  2014. case IMR_QUERYCHARPOSITION:
  2015. ((LPIMECHARPOSITION)lParam)->dwCharPos = ((LPPrivateIMECHARPOSITION)lParam)->dwCharPositionA;
  2016. break;
  2017. case IMR_RECONVERTSTRING:
  2018. case IMR_DOCUMENTFEED:
  2019. //
  2020. // Note: by definition, we don't need back-conversion for IMR_CONFIRMRECONVERTSTRING
  2021. //
  2022. if (retval) {
  2023. // IME wants the buffer size
  2024. retval = ImmGetReconvertTotalSize((DWORD)retval, FROM_APP, FALSE);
  2025. if (retval < sizeof(RECONVERTSTRING)) {
  2026. RIPMSG2(RIP_WARNING, "WM_IME_REQUEST(%x): return value from application %d is invalid.", wParam, retval);
  2027. retval = 0;
  2028. } else if (lParam) {
  2029. // We need to perform the A/W conversion of the contents
  2030. if (!ImmReconversionWorker((LPRECONVERTSTRING)lParam, (LPRECONVERTSTRING)pvData, TRUE, CP_ACP)) {
  2031. MSGERROR();
  2032. }
  2033. }
  2034. }
  2035. break;
  2036. }
  2037. }
  2038. ERRORTRAP(0);
  2039. if (pvData != NULL)
  2040. UserLocalFree(pvData);
  2041. ENDCALL(DWORD);
  2042. }
  2043. #endif
  2044. MESSAGECALL(fnEMGETSEL)
  2045. {
  2046. PWND pwnd = ValidateHwnd(hwnd);
  2047. if (pwnd == NULL)
  2048. return 0;
  2049. BEGINCALL()
  2050. retval = (DWORD)NtUserMessageCall(
  2051. hwnd,
  2052. msg,
  2053. wParam,
  2054. lParam,
  2055. xParam,
  2056. xpfnProc,
  2057. bAnsi);
  2058. //
  2059. // temp for our beta...
  2060. //
  2061. // !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
  2062. //
  2063. // to reduce user <-> kernel mode transition...
  2064. //
  2065. if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
  2066. ULONG cchTextLength;
  2067. LONG lOriginalLengthW;
  2068. LONG lOriginalLengthL;
  2069. LONG wParamLocal;
  2070. LONG lParamLocal;
  2071. if (wParam) {
  2072. lOriginalLengthW = *(LONG *)wParam;
  2073. } else {
  2074. lOriginalLengthW = (LONG)(LOWORD(retval));
  2075. }
  2076. if (lParam) {
  2077. lOriginalLengthL = *(LONG *)lParam;
  2078. } else {
  2079. lOriginalLengthL = (LONG)(HIWORD(retval));
  2080. }
  2081. cchTextLength = (DWORD)NtUserMessageCall(
  2082. hwnd,
  2083. WM_GETTEXTLENGTH,
  2084. (WPARAM)0,
  2085. (LPARAM)0,
  2086. xParam,
  2087. xpfnProc,
  2088. bAnsi);
  2089. if (cchTextLength) {
  2090. PVOID pvString;
  2091. ULONG cbTextLength;
  2092. cchTextLength++;
  2093. if (!bAnsi) {
  2094. cbTextLength = cchTextLength * sizeof(WCHAR);
  2095. } else {
  2096. cbTextLength = cchTextLength;
  2097. }
  2098. pvString = UserLocalAlloc(0,cbTextLength);
  2099. if (pvString) {
  2100. retval = (DWORD)NtUserMessageCall(
  2101. hwnd,
  2102. WM_GETTEXT,
  2103. cchTextLength,
  2104. (LPARAM)pvString,
  2105. xParam,
  2106. xpfnProc,
  2107. bAnsi);
  2108. if (retval) {
  2109. if (bAnsi) {
  2110. /*
  2111. * ansiString/unicodeLenght -> ansiLength
  2112. */
  2113. CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal)
  2114. CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal);
  2115. } else {
  2116. /*
  2117. * unicodeString/ansiLenght -> unicodeLength
  2118. */
  2119. CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal);
  2120. CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal);
  2121. }
  2122. retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF));
  2123. if (wParam) {
  2124. *(LONG *)wParam = wParamLocal;
  2125. }
  2126. if (lParam) {
  2127. *(LONG *)lParam = lParamLocal;
  2128. }
  2129. } else {
  2130. UserLocalFree(pvString);
  2131. MSGERROR();
  2132. }
  2133. UserLocalFree(pvString);
  2134. } else {
  2135. MSGERROR();
  2136. }
  2137. } else {
  2138. MSGERROR();
  2139. }
  2140. }
  2141. ERRORTRAP(0);
  2142. ENDCALL(DWORD);
  2143. }
  2144. MESSAGECALL(fnEMSETSEL)
  2145. {
  2146. PWND pwnd = ValidateHwnd(hwnd);
  2147. if (pwnd == NULL) {
  2148. return 0;
  2149. }
  2150. BEGINCALL()
  2151. //
  2152. // temp for our beta...
  2153. //
  2154. // !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
  2155. //
  2156. // to reduce user <-> kernel mode transition...
  2157. //
  2158. if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
  2159. if (((LONG)wParam <= 0) && ((LONG)lParam <=0)) {
  2160. //
  2161. // if (wParam == 0 or wParam == -1)
  2162. // and
  2163. // (lParam == 0 or lParam == -1)
  2164. //
  2165. // In this case, we don't need to convert the value...
  2166. //
  2167. } else {
  2168. ULONG cchTextLength;
  2169. LONG lOriginalLengthW = (LONG)wParam;
  2170. LONG lOriginalLengthL = (LONG)lParam;
  2171. cchTextLength = (DWORD)NtUserMessageCall(
  2172. hwnd,
  2173. WM_GETTEXTLENGTH,
  2174. (WPARAM)0,
  2175. (LPARAM)0,
  2176. xParam,
  2177. xpfnProc,
  2178. bAnsi);
  2179. if (cchTextLength) {
  2180. PVOID pvString;
  2181. ULONG cbTextLength;
  2182. cchTextLength++;
  2183. if (!bAnsi) {
  2184. cbTextLength = cchTextLength * sizeof(WCHAR);
  2185. } else {
  2186. cbTextLength = cchTextLength;
  2187. }
  2188. pvString = UserLocalAlloc(0,cbTextLength);
  2189. if (pvString) {
  2190. retval = (DWORD)NtUserMessageCall(
  2191. hwnd,
  2192. WM_GETTEXT,
  2193. cchTextLength,
  2194. (LPARAM)pvString,
  2195. xParam,
  2196. xpfnProc,
  2197. bAnsi);
  2198. if (retval) {
  2199. if ((LONG)retval < lOriginalLengthW) {
  2200. lOriginalLengthW = (LONG)retval;
  2201. }
  2202. if ((LONG)retval < lOriginalLengthL) {
  2203. lOriginalLengthL = (LONG)retval;
  2204. }
  2205. if (bAnsi) {
  2206. if (lOriginalLengthW > 0) {
  2207. CalcUnicodeStringLengthA(pvString, lOriginalLengthW, &wParam);
  2208. }
  2209. if (lOriginalLengthL > 0) {
  2210. CalcUnicodeStringLengthA(pvString, lOriginalLengthL, &lParam);
  2211. }
  2212. } else {
  2213. if (lOriginalLengthW > 0) {
  2214. CalcAnsiStringLengthW(pvString, lOriginalLengthW, &wParam);
  2215. }
  2216. if (lOriginalLengthL > 0) {
  2217. CalcAnsiStringLengthW(pvString, lOriginalLengthL, &lParam);
  2218. }
  2219. }
  2220. } else {
  2221. UserLocalFree(pvString);
  2222. MSGERROR();
  2223. }
  2224. UserLocalFree(pvString);
  2225. } else {
  2226. MSGERROR();
  2227. }
  2228. } else {
  2229. MSGERROR();
  2230. }
  2231. }
  2232. }
  2233. retval = (DWORD)NtUserMessageCall(
  2234. hwnd,
  2235. msg,
  2236. wParam,
  2237. lParam,
  2238. xParam,
  2239. xpfnProc,
  2240. bAnsi);
  2241. ERRORTRAP(0);
  2242. ENDCALL(DWORD);
  2243. }
  2244. MESSAGECALL(fnCBGETEDITSEL)
  2245. {
  2246. PWND pwnd = ValidateHwnd(hwnd);
  2247. if (pwnd == NULL)
  2248. return 0;
  2249. BEGINCALL()
  2250. retval = (DWORD)NtUserMessageCall(
  2251. hwnd,
  2252. msg,
  2253. wParam,
  2254. lParam,
  2255. xParam,
  2256. xpfnProc,
  2257. bAnsi);
  2258. //
  2259. // temp for our beta...
  2260. //
  2261. // !!! THIS CODE SHOULD BE IN KERNEL MODE !!!
  2262. //
  2263. // to reduce user <-> kernel mode transition...
  2264. //
  2265. if (bAnsi != ((TestWF(pwnd, WFANSIPROC)) ? TRUE : FALSE)) {
  2266. ULONG cchTextLength;
  2267. LONG lOriginalLengthW = *(LONG *)wParam;
  2268. LONG lOriginalLengthL = *(LONG *)lParam;
  2269. LONG wParamLocal;
  2270. LONG lParamLocal;
  2271. if (wParam) {
  2272. lOriginalLengthW = *(LONG *)wParam;
  2273. } else {
  2274. lOriginalLengthW = (LONG)(LOWORD(retval));
  2275. }
  2276. if (lParam) {
  2277. lOriginalLengthL = *(LONG *)lParam;
  2278. } else {
  2279. lOriginalLengthL = (LONG)(HIWORD(retval));
  2280. }
  2281. cchTextLength = (DWORD)NtUserMessageCall(
  2282. hwnd,
  2283. WM_GETTEXTLENGTH,
  2284. (WPARAM)0,
  2285. (LPARAM)0,
  2286. xParam,
  2287. xpfnProc,
  2288. bAnsi);
  2289. if (cchTextLength) {
  2290. PVOID pvString;
  2291. ULONG cbTextLength;
  2292. cchTextLength++;
  2293. if (!bAnsi) {
  2294. cbTextLength = cchTextLength * sizeof(WCHAR);
  2295. } else {
  2296. cbTextLength = cchTextLength;
  2297. }
  2298. pvString = UserLocalAlloc(0,cbTextLength);
  2299. if (pvString) {
  2300. retval = (DWORD)NtUserMessageCall(
  2301. hwnd,
  2302. WM_GETTEXT,
  2303. cchTextLength,
  2304. (LPARAM)pvString,
  2305. xParam,
  2306. xpfnProc,
  2307. bAnsi);
  2308. if (retval) {
  2309. if (bAnsi) {
  2310. /*
  2311. * ansiString/unicodeLenght -> ansiLength
  2312. */
  2313. CalcAnsiStringLengthA(pvString, lOriginalLengthW, &wParamLocal);
  2314. CalcAnsiStringLengthA(pvString, lOriginalLengthL, &lParamLocal);
  2315. } else {
  2316. /*
  2317. * unicodeString/ansiLenght -> unicodeLength
  2318. */
  2319. CalcUnicodeStringLengthW(pvString, lOriginalLengthW, &wParamLocal);
  2320. CalcUnicodeStringLengthW(pvString, lOriginalLengthL, &lParamLocal);
  2321. }
  2322. retval = (DWORD)(((lParamLocal) << 16) | ((wParamLocal) & 0x0000FFFF));
  2323. if (wParam) {
  2324. *(LONG *)wParam = wParamLocal;
  2325. }
  2326. if (lParam) {
  2327. *(LONG *)lParam = lParamLocal;
  2328. }
  2329. } else {
  2330. UserLocalFree(pvString);
  2331. MSGERROR();
  2332. }
  2333. UserLocalFree(pvString);
  2334. } else {
  2335. MSGERROR();
  2336. }
  2337. } else {
  2338. MSGERROR();
  2339. }
  2340. }
  2341. ERRORTRAP(0);
  2342. ENDCALL(DWORD);
  2343. }
  2344. LONG BroadcastSystemMessageWorker(
  2345. DWORD dwFlags,
  2346. LPDWORD lpdwRecipients,
  2347. UINT message,
  2348. WPARAM wParam,
  2349. LPARAM lParam,
  2350. PBSMINFO pBSMInfo,
  2351. BOOL fAnsi)
  2352. {
  2353. DWORD dwRecipients;
  2354. /*
  2355. * Prevent apps from setting hi 16 bits so we can use them internally.
  2356. */
  2357. if (message & RESERVED_MSG_BITS) {
  2358. RIPERR1(ERROR_INVALID_PARAMETER,
  2359. RIP_WARNING,
  2360. "Invalid message 0x%x for BroadcastSystemMessage",
  2361. message);
  2362. return 0;
  2363. }
  2364. if (dwFlags & ~BSF_VALID) {
  2365. RIPERR1(ERROR_INVALID_PARAMETER,
  2366. RIP_WARNING,
  2367. "Invalid dwFlags 0x%x for BroadcastSystemMessage",
  2368. dwFlags);
  2369. return 0;
  2370. }
  2371. if ((dwFlags & (BSF_RETURNHDESK | BSF_LUID)) && pBSMInfo == NULL) {
  2372. RIPERR0(ERROR_INVALID_PARAMETER,
  2373. RIP_WARNING,
  2374. "Invalid BSF_RETURNHDESK or BSF_LUID is set and pBSMInfo is NULL for BroadcastSystemMessageEx");
  2375. return 0;
  2376. }
  2377. if (pBSMInfo != NULL && pBSMInfo->cbSize != sizeof(BSMINFO)) {
  2378. RIPERR1(ERROR_INVALID_PARAMETER,
  2379. RIP_WARNING,
  2380. "Invalid pBSMInfo->cbSize (%x) for BroadcastSystemMessageEx",
  2381. pBSMInfo->cbSize);
  2382. return 0;
  2383. }
  2384. //
  2385. // Check if the message number is in the private message range.
  2386. // If so, do not send it to Win4.0 windows.
  2387. // (This is required because apps like SimCity broadcast a message
  2388. // that has the value 0x500 and that confuses MsgSrvr's
  2389. // MSGSRVR_NOTIFY handler.
  2390. //
  2391. if (message >= WM_USER && message < 0xC000) {
  2392. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "invalid message (%x) for BroadcastSystemMessage", message);
  2393. return 0;
  2394. }
  2395. if (dwFlags & BSF_FORCEIFHUNG) {
  2396. dwFlags |= BSF_NOHANG;
  2397. }
  2398. //
  2399. // If BSF_QUERY or message has a pointer, it can not be posted.
  2400. //
  2401. if (dwFlags & BSF_QUERY) {
  2402. if (dwFlags & BSF_ASYNC) {
  2403. RIPMSGF0(RIP_WARNING, "BSF_QUERY can't be BSF_ASYNC");
  2404. }
  2405. dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags.
  2406. }
  2407. if (dwFlags & BSF_ASYNC) {
  2408. if (TESTSYNCONLYMESSAGE(message, wParam)) {
  2409. RIPERR0(ERROR_MESSAGE_SYNC_ONLY,
  2410. RIP_WARNING,
  2411. "BSM: Can't post messages with pointers");
  2412. dwFlags &= ~BSF_ASYNC; // Strip the BSF_ASYNC flags.
  2413. }
  2414. }
  2415. /*
  2416. * Let us find out who the intended recipients are.
  2417. */
  2418. if (lpdwRecipients != NULL) {
  2419. dwRecipients = *lpdwRecipients;
  2420. } else {
  2421. dwRecipients = BSM_ALLCOMPONENTS;
  2422. }
  2423. /*
  2424. * If they want all components, add the corresponding bits.
  2425. */
  2426. if ((dwRecipients & BSM_COMPONENTS) == BSM_ALLCOMPONENTS) {
  2427. dwRecipients |= (BSM_VXDS | BSM_NETDRIVER | BSM_INSTALLABLEDRIVERS |
  2428. BSM_APPLICATIONS);
  2429. }
  2430. if (dwRecipients & ~BSM_VALID) {
  2431. RIPERR1(ERROR_INVALID_PARAMETER,
  2432. RIP_WARNING,
  2433. "BSM: Invalid dwRecipients 0x%x",
  2434. dwRecipients);
  2435. return 0;
  2436. }
  2437. /*
  2438. * Does this need to be sent to all apps?
  2439. */
  2440. if (dwRecipients & BSM_APPLICATIONS) {
  2441. BROADCASTSYSTEMMSGPARAMS bsmParams;
  2442. LONG lret;
  2443. bsmParams.dwFlags = dwFlags;
  2444. bsmParams.dwRecipients = dwRecipients;
  2445. bsmParams.hwnd = NULL;
  2446. bsmParams.hdesk = NULL;
  2447. if (dwFlags & BSF_LUID) {
  2448. bsmParams.luid = pBSMInfo->luid;
  2449. }
  2450. lret = (LONG)CsSendMessage(GetDesktopWindow(), message, wParam, lParam,
  2451. (ULONG_PTR)&bsmParams, FNID_SENDMESSAGEBSM, fAnsi);
  2452. /*
  2453. * Give the caller back the recipients that actually receive the message.
  2454. */
  2455. if (lpdwRecipients != NULL) {
  2456. *lpdwRecipients = bsmParams.dwRecipients;
  2457. }
  2458. //
  2459. // If the query was denied, then return who denied it.
  2460. //
  2461. if (lret == 0 && (dwFlags & BSF_QUERY) && pBSMInfo != NULL) {
  2462. pBSMInfo->hwnd = bsmParams.hwnd;
  2463. pBSMInfo->hdesk = bsmParams.hdesk;
  2464. }
  2465. return lret;
  2466. }
  2467. return -1;
  2468. }
  2469. HDEVNOTIFY
  2470. RegisterDeviceNotificationWorker(
  2471. IN HANDLE hRecipient,
  2472. IN LPVOID NotificationFilter,
  2473. IN DWORD Flags)
  2474. {
  2475. HINSTANCE hLib;
  2476. FARPROC fpRegisterNotification;
  2477. PVOID Context = NULL;
  2478. HDEVNOTIFY notifyHandle = NULL;
  2479. CONFIGRET Status = CR_SUCCESS;
  2480. extern
  2481. CONFIGRET
  2482. CMP_RegisterNotification(IN HANDLE hRecipient,
  2483. IN LPBYTE NotificationFilter,
  2484. IN DWORD Flags,
  2485. OUT PVOID *Context);
  2486. //
  2487. // Load the config manager client dll and retrieve entry pts.
  2488. //
  2489. hLib = LoadLibrary(TEXT("SETUPAPI.DLL"));
  2490. if (hLib != NULL) {
  2491. fpRegisterNotification = GetProcAddress(hLib,
  2492. "CMP_RegisterNotification");
  2493. if (fpRegisterNotification != NULL) {
  2494. Status = (CONFIGRET)(*fpRegisterNotification)(hRecipient,
  2495. NotificationFilter,
  2496. Flags,
  2497. &Context);
  2498. }
  2499. FreeLibrary(hLib);
  2500. }
  2501. if (Status != CR_SUCCESS) {
  2502. /*
  2503. * Something went wrong, map the CR errors to a Win32 style error
  2504. * code.
  2505. */
  2506. switch (Status) {
  2507. case CR_INVALID_POINTER:
  2508. SetLastError(ERROR_INVALID_PARAMETER);
  2509. break;
  2510. case CR_INVALID_DATA:
  2511. SetLastError(ERROR_INVALID_DATA);
  2512. break;
  2513. case CR_OUT_OF_MEMORY:
  2514. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2515. break;
  2516. case CR_FAILURE:
  2517. default:
  2518. SetLastError(ERROR_SERVICE_SPECIFIC_ERROR);
  2519. break;
  2520. }
  2521. }
  2522. if (Context != NULL && (ULONG_PTR)Context != -1) {
  2523. notifyHandle = (HDEVNOTIFY)Context;
  2524. }
  2525. return notifyHandle;
  2526. }
  2527. BOOL
  2528. UnregisterDeviceNotification(
  2529. IN HDEVNOTIFY Handle)
  2530. {
  2531. HINSTANCE hLib;
  2532. FARPROC fpUnregisterNotification;
  2533. CONFIGRET crStatus = CR_SUCCESS;
  2534. extern
  2535. CONFIGRET
  2536. CMP_UnregisterNotification(IN ULONG Context);
  2537. /*
  2538. * Load the config manager client dll and retrieve entry pts.
  2539. */
  2540. hLib = LoadLibrary(TEXT("SETUPAPI.DLL"));
  2541. if (hLib != NULL) {
  2542. fpUnregisterNotification = GetProcAddress(hLib,
  2543. "CMP_UnregisterNotification");
  2544. if (fpUnregisterNotification != NULL) {
  2545. crStatus = (CONFIGRET)(*fpUnregisterNotification)((ULONG_PTR)Handle);
  2546. }
  2547. FreeLibrary(hLib);
  2548. }
  2549. if (crStatus != CR_SUCCESS) {
  2550. /*
  2551. * Something went wrong, map the CR errors to a Win32 style error
  2552. * code.
  2553. */
  2554. switch (crStatus) {
  2555. case CR_INVALID_POINTER:
  2556. SetLastError(ERROR_INVALID_PARAMETER);
  2557. break;
  2558. case CR_INVALID_DATA:
  2559. SetLastError(ERROR_INVALID_DATA);
  2560. break;
  2561. case CR_FAILURE:
  2562. default:
  2563. SetLastError(ERROR_SERVICE_SPECIFIC_ERROR);
  2564. break;
  2565. }
  2566. }
  2567. return (BOOL)(crStatus == CR_SUCCESS);
  2568. }