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.

1011 lines
32 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: getset.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains window manager information routines
  7. *
  8. * History:
  9. * 22-Oct-1990 MikeHar Ported functions from Win 3.0 sources.
  10. * 13-Feb-1991 MikeKe Added Revalidation code (None)
  11. * 08-Feb-1991 IanJa Unicode/ANSI aware and neutral
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. /****************************************************************************\
  16. * DefSetText
  17. *
  18. * Processes WM_SETTEXT messages by text-alloc'ing a string in the alternate
  19. * ds and setting 'hwnd->hName' to it's handle.
  20. *
  21. * History:
  22. * 23-Oct-1990 MikeHar Ported from Windows.
  23. * 09-Nov-1990 DarrinM Cleanup.
  24. \****************************************************************************/
  25. BOOL DefSetText(
  26. PWND pwnd,
  27. PLARGE_STRING cczpstr)
  28. {
  29. /*
  30. * Note -- string buffer may be on client side.
  31. */
  32. PDESKTOP pdesk;
  33. DWORD cbString;
  34. BOOL fTranslateOk;
  35. if (pwnd->head.rpdesk == NULL || cczpstr == NULL || cczpstr->Buffer == NULL) {
  36. pwnd->strName.Length = 0;
  37. return TRUE;
  38. }
  39. /*
  40. * Capture the new window name
  41. */
  42. if (cczpstr->bAnsi)
  43. cbString = (cczpstr->Length + 1) * sizeof(WCHAR);
  44. else
  45. cbString = cczpstr->Length + sizeof(WCHAR);
  46. /*
  47. * If the current buffer is not large enough,
  48. * reallocate it.
  49. */
  50. pdesk = pwnd->head.rpdesk;
  51. if (pwnd->strName.MaximumLength < cbString) {
  52. if (pwnd->strName.Buffer != NULL)
  53. DesktopFree(pdesk, pwnd->strName.Buffer);
  54. pwnd->strName.Buffer = (LPWSTR)DesktopAlloc(pdesk, cbString, DTAG_TEXT);
  55. pwnd->strName.Length = 0;
  56. if (pwnd->strName.Buffer == NULL) {
  57. pwnd->strName.MaximumLength = 0;
  58. return FALSE;
  59. }
  60. pwnd->strName.MaximumLength = cbString;
  61. }
  62. fTranslateOk = TRUE;
  63. if (cczpstr->Length != 0) {
  64. try {
  65. if (!cczpstr->bAnsi) {
  66. RtlCopyMemory(pwnd->strName.Buffer, cczpstr->Buffer, cbString);
  67. } else {
  68. LPCSTR ccxpszAnsi = (LPCSTR)cczpstr->Buffer;
  69. fTranslateOk = NT_SUCCESS(RtlMultiByteToUnicodeN(pwnd->strName.Buffer,
  70. cbString, &cbString,
  71. (LPSTR)ccxpszAnsi, cbString / sizeof(WCHAR)));
  72. }
  73. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  74. pwnd->strName.Length = 0;
  75. return FALSE;
  76. }
  77. }
  78. if (fTranslateOk) {
  79. pwnd->strName.Length = cbString - sizeof(WCHAR);
  80. return TRUE;
  81. } else {
  82. pwnd->strName.Length = 0;
  83. return FALSE;
  84. }
  85. }
  86. /***************************************************************************\
  87. * FCallerOk
  88. *
  89. * Ensures that no client stomps on server windows.
  90. *
  91. * 04-Feb-1992 ScottLu Created.
  92. \***************************************************************************/
  93. BOOL FCallerOk(
  94. PWND pwnd)
  95. {
  96. PTHREADINFO pti = PtiCurrent();
  97. if ((GETPTI(pwnd)->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) &&
  98. !(pti->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD))) {
  99. return FALSE;
  100. }
  101. if (PsGetThreadProcessId(GETPTI(pwnd)->pEThread) == gpidLogon &&
  102. PsGetThreadProcessId(pti->pEThread) != gpidLogon) {
  103. return FALSE;
  104. }
  105. return TRUE;
  106. }
  107. /***************************************************************************\
  108. * _SetWindowWord (supports SetWindowWordA/W API)
  109. *
  110. * Set a window word. Positive index values set application window words
  111. * while negative index values set system window words. The negative
  112. * indices are published in WINDOWS.H.
  113. *
  114. * History:
  115. * 26-Nov-1990 DarrinM Wrote.
  116. \***************************************************************************/
  117. WORD _SetWindowWord(
  118. PWND pwnd,
  119. int index,
  120. WORD value)
  121. {
  122. WORD wOld;
  123. /*
  124. * Don't allow setting of words belonging to a system thread if the
  125. * caller is not a system thread. Same goes for winlogon.
  126. */
  127. if (!FCallerOk(pwnd)) {
  128. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  129. return 0;
  130. }
  131. /*
  132. * Applications can not set a WORD into a dialog Proc or any of the
  133. * non-public reserved bytes in DLGWINDOWEXTRA (usersrv stores pointers
  134. * there).
  135. */
  136. if (TestWF(pwnd, WFDIALOGWINDOW)) {
  137. if (((index >= DWLP_DLGPROC) && (index < DWLP_MSGRESULT)) ||
  138. ((index > DWLP_USER+sizeof(LONG_PTR)-sizeof(WORD)) && (index < DLGWINDOWEXTRA))) {
  139. RIPERR3(ERROR_INVALID_INDEX, RIP_WARNING,
  140. "SetWindowWord: Trying to set WORD of a windowproc pwnd=(%#p) index=(%ld) fnid (%lX)",
  141. pwnd, index, (DWORD)pwnd->fnid);
  142. return 0;
  143. } else {
  144. /*
  145. * If this is really a dialog and not some other server class
  146. * where usersrv has stored some data (Windows Compuserve -
  147. * wincim - does this) then store the data now that we have
  148. * verified the index limits.
  149. */
  150. if (GETFNID(pwnd) == FNID_DIALOG) {
  151. goto DoSetWord;
  152. }
  153. }
  154. }
  155. if (index == GWLP_USERDATA) {
  156. wOld = (WORD)pwnd->dwUserData;
  157. pwnd->dwUserData = MAKELONG(value, HIWORD(pwnd->dwUserData));
  158. return wOld;
  159. }
  160. // fix for RedShift, they call SetWindowWord
  161. // tn play with the low word of the style dword
  162. if (index == GWL_STYLE) {
  163. wOld = (WORD)pwnd->style;
  164. pwnd->style = MAKELONG(value, HIWORD(pwnd->style));
  165. return wOld;
  166. }
  167. if (GETFNID(pwnd) != 0) {
  168. if (index >= 0 &&
  169. (index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
  170. switch (GETFNID(pwnd)) {
  171. case FNID_MDICLIENT:
  172. if (index == 0)
  173. break;
  174. goto DoDefault;
  175. case FNID_BUTTON:
  176. /*
  177. * CorelDraw, Direct Access 1.0 and WordPerfect 6.0 do a
  178. * get/set on the first button window word. Allow this
  179. * for compatibility.
  180. */
  181. if (index == 0) {
  182. /*
  183. * Since we now use a lookaside buffer for the control's
  184. * private data, we need to indirect into this structure.
  185. */
  186. PBUTN pbutn = ((PBUTNWND)pwnd)->pbutn;
  187. if (!pbutn || (LONG_PTR)pbutn == (LONG_PTR)-1) {
  188. return 0;
  189. } else {
  190. try {
  191. wOld = (WORD)ProbeAndReadUlong(&pbutn->buttonState);
  192. pbutn->buttonState = value;
  193. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  194. wOld = 0;
  195. }
  196. return wOld;
  197. }
  198. }
  199. goto DoDefault;
  200. default:
  201. DoDefault:
  202. RIPERR3(ERROR_INVALID_INDEX,
  203. RIP_WARNING,
  204. "SetWindowWord: Trying to set private server data pwnd=(%#p) index=(%ld) fnid (%lX)",
  205. pwnd, index, (DWORD)pwnd->fnid);
  206. return 0;
  207. break;
  208. }
  209. }
  210. }
  211. DoSetWord:
  212. if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pwnd->cbwndExtra)) {
  213. RIPERR0(ERROR_INVALID_INDEX, RIP_WARNING,"SetWindowWord Fails because of invalid index");
  214. return 0;
  215. } else {
  216. WORD UNALIGNED *pw;
  217. pw = (WORD UNALIGNED *)((BYTE *)(pwnd + 1) + index);
  218. wOld = *pw;
  219. *pw = value;
  220. return (WORD)wOld;
  221. }
  222. }
  223. /***************************************************************************\
  224. * xxxSetWindowLong (API)
  225. *
  226. * Set a window long. Positive index values set application window longs
  227. * while negative index values set system window longs. The negative
  228. * indices are published in WINDOWS.H.
  229. *
  230. * History:
  231. * 26-Nov-1990 DarrinM Wrote.
  232. \***************************************************************************/
  233. ULONG_PTR xxxSetWindowLongPtr(
  234. PWND pwnd,
  235. int index,
  236. ULONG_PTR dwData,
  237. BOOL bAnsi)
  238. {
  239. ULONG_PTR dwOld;
  240. /*
  241. * The only case that leaves the critical section is where
  242. * xxxSetWindowData is called, which ensures that the window is locked.
  243. * This saves us some locks.
  244. *
  245. * Don't allow setting of words belonging to a system thread if the
  246. * caller is not a system thread. Same goes for winlogon.
  247. */
  248. if (!FCallerOk(pwnd)) {
  249. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  250. return 0;
  251. }
  252. /*
  253. * If it's a dialog window, only a few indices are permitted.
  254. */
  255. if (GETFNID(pwnd) != 0) {
  256. if (TestWF(pwnd, WFDIALOGWINDOW)) {
  257. switch (index) {
  258. case DWLP_MSGRESULT:
  259. dwOld = (ULONG_PTR)((PDIALOG)(pwnd))->resultWP;
  260. ((PDIALOG)(pwnd))->resultWP = (LONG_PTR)dwData;
  261. return dwOld;
  262. case DWLP_USER:
  263. dwOld = (ULONG_PTR)((PDIALOG)(pwnd))->unused;
  264. ((PDIALOG)(pwnd))->unused = (LONG_PTR)dwData;
  265. return dwOld;
  266. default:
  267. if (index >= 0 && index < DLGWINDOWEXTRA) {
  268. RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
  269. return 0;
  270. }
  271. }
  272. } else {
  273. if (index >= 0 && index < (int)(CBFNID(pwnd->fnid)-sizeof(WND))) {
  274. switch (GETFNID(pwnd)) {
  275. case FNID_BUTTON:
  276. case FNID_COMBOBOX:
  277. case FNID_COMBOLISTBOX:
  278. case FNID_DIALOG:
  279. case FNID_LISTBOX:
  280. case FNID_STATIC:
  281. case FNID_EDIT:
  282. #ifdef FE_IME
  283. case FNID_IME:
  284. #endif
  285. /*
  286. * Allow the 0 index for controls to be set if it's
  287. * still NULL or the window is being destroyed. This
  288. * is where controls store their private data.
  289. */
  290. if (index == 0) {
  291. dwOld = *((PULONG_PTR)(pwnd + 1));
  292. if (dwOld == 0 || TestWF(pwnd, WFDESTROYED))
  293. goto SetData;
  294. }
  295. break;
  296. case FNID_MDICLIENT:
  297. /*
  298. * Allow the 0 index (which is reserved) to be set/get.
  299. * Quattro Pro 1.0 uses this index!
  300. *
  301. * Allow the 4 index to be set if it's still NULL or
  302. * the window is being destroyed. This is where we
  303. * store our private data.
  304. */
  305. #ifndef _WIN64
  306. if (index == 0) {
  307. goto SetData;
  308. }
  309. #endif
  310. if (index == GWLP_MDIDATA) {
  311. dwOld = *((PULONG_PTR)(pwnd + 1));
  312. if (dwOld == 0 || TestWF(pwnd, WFDESTROYED))
  313. goto SetData;
  314. }
  315. break;
  316. }
  317. RIPERR3(ERROR_INVALID_INDEX,
  318. RIP_WARNING,
  319. "SetWindowLongPtr: Trying to set private server data pwnd=(%#p) index=(%ld) FNID=(%lX)",
  320. pwnd, index, (DWORD)pwnd->fnid);
  321. return 0;
  322. }
  323. }
  324. }
  325. if (index < 0) {
  326. return xxxSetWindowData(pwnd, index, dwData, bAnsi);
  327. } else {
  328. if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pwnd->cbwndExtra) {
  329. RIPERR3(ERROR_INVALID_INDEX,
  330. RIP_WARNING,
  331. "SetWindowLongPtr: Index %d too big for cbWndExtra %d on pwnd %#p",
  332. index, pwnd->cbwndExtra, pwnd);
  333. return 0;
  334. } else {
  335. ULONG_PTR UNALIGNED *pudw;
  336. SetData:
  337. pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pwnd + 1) + index);
  338. dwOld = *pudw;
  339. *pudw = dwData;
  340. return dwOld;
  341. }
  342. }
  343. }
  344. #ifdef _WIN64
  345. DWORD xxxSetWindowLong(
  346. PWND pwnd,
  347. int index,
  348. DWORD dwData,
  349. BOOL bAnsi)
  350. {
  351. DWORD dwOld;
  352. /*
  353. * The only case that leaves the critical section is where we call
  354. * xxxSetWindowData, which checks that the window is locked. This saves
  355. * us some locks.
  356. *
  357. * Don't allow setting of words belonging to a system thread if the
  358. * caller is not a system thread. Same goes for winlogon.
  359. */
  360. if (!FCallerOk(pwnd)) {
  361. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  362. return 0;
  363. }
  364. /*
  365. * If it's a dialog window, only a few indices are permitted.
  366. */
  367. if (GETFNID(pwnd) != 0) {
  368. if (TestWF(pwnd, WFDIALOGWINDOW)) {
  369. switch (index) {
  370. case DWLP_MSGRESULT:
  371. dwOld = (DWORD)((PDIALOG)(pwnd))->resultWP;
  372. ((PDIALOG)(pwnd))->resultWP = (long)dwData;
  373. return dwOld;
  374. case DWLP_USER:
  375. dwOld = (DWORD)((PDIALOG)(pwnd))->unused;
  376. ((PDIALOG)(pwnd))->unused = (long)dwData;
  377. return dwOld;
  378. default:
  379. if (index >= 0 && index < DLGWINDOWEXTRA) {
  380. RIPERR0(ERROR_PRIVATE_DIALOG_INDEX, RIP_VERBOSE, "");
  381. return 0;
  382. }
  383. }
  384. } else {
  385. if (index >= 0 &&
  386. (index < (int)(CBFNID(pwnd->fnid)-sizeof(WND)))) {
  387. switch (GETFNID(pwnd)) {
  388. case FNID_MDICLIENT:
  389. /*
  390. * Allow the 0 index (which is reserved) to be set/get.
  391. * Quattro Pro 1.0 uses this index!
  392. */
  393. if (index == 0) {
  394. goto SetData;
  395. }
  396. /*
  397. * Allow the 4 index to be set if it's still NULL or
  398. * the window is being destroyed. This is where we
  399. * store our private data.
  400. */
  401. if (index == GWLP_MDIDATA) {
  402. dwOld = *((PDWORD)(pwnd + 1));
  403. if (dwOld == 0 || TestWF(pwnd, WFDESTROYED))
  404. goto SetData;
  405. }
  406. break;
  407. }
  408. RIPERR3(ERROR_INVALID_INDEX,
  409. RIP_WARNING,
  410. "SetWindowLong: Trying to set private server data pwnd=(%#p) index=(%ld) FNID=(%lX)",
  411. pwnd, index, (DWORD)pwnd->fnid);
  412. return 0;
  413. }
  414. }
  415. }
  416. if (index < 0) {
  417. if ((index != GWL_STYLE) && (index != GWL_EXSTYLE) && (index != GWL_ID) && (index != GWLP_USERDATA)) {
  418. RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "SetWindowLong: invalid index %d", index);
  419. return 0;
  420. }
  421. return (DWORD)xxxSetWindowData(pwnd, index, dwData, bAnsi);
  422. } else {
  423. if ((UINT)index + sizeof(DWORD) > (UINT)pwnd->cbwndExtra) {
  424. RIPERR3(ERROR_INVALID_INDEX,
  425. RIP_WARNING,
  426. "SetWindowLong: Index %d too big for cbWndExtra %d on pwnd %#p",
  427. index, pwnd->cbwndExtra, pwnd);
  428. return 0;
  429. } else {
  430. DWORD UNALIGNED *pudw;
  431. SetData:
  432. pudw = (DWORD UNALIGNED *)((BYTE *)(pwnd + 1) + index);
  433. dwOld = *pudw;
  434. *pudw = dwData;
  435. return dwOld;
  436. }
  437. }
  438. }
  439. #endif
  440. /***************************************************************************\
  441. * xxxHandleOwnerSwitch
  442. *
  443. \***************************************************************************/
  444. VOID xxxHandleOwnerSwitch(
  445. PWND pwnd,
  446. PWND pwndNewParent,
  447. PWND pwndOldParent)
  448. {
  449. CheckLock(pwnd);
  450. CheckLock(pwndNewParent);
  451. CheckLock(pwndOldParent);
  452. if (pwndOldParent != NULL && GETPTI(pwndOldParent) != GETPTI(pwnd)) {
  453. /*
  454. * See if it needs to be unattached.
  455. */
  456. if (pwndNewParent == NULL ||
  457. GETPTI(pwndNewParent) == GETPTI(pwnd) ||
  458. GETPTI(pwndNewParent) != GETPTI(pwndOldParent)) {
  459. zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndOldParent), FALSE);
  460. }
  461. }
  462. /*
  463. * See if it needs to be attached.
  464. */
  465. if (pwndNewParent != NULL &&
  466. GETPTI(pwndNewParent) != GETPTI(pwnd) &&
  467. (pwndOldParent == NULL ||
  468. GETPTI(pwndNewParent) != GETPTI(pwndOldParent))) {
  469. zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndNewParent), TRUE);
  470. }
  471. /*
  472. * Post hook messages for tray-windows.
  473. */
  474. if (IsTrayWindow(pwnd)) {
  475. HWND hwnd = PtoH(pwnd);
  476. /*
  477. * If we're setting the owner and it's changing from owned to
  478. * unowned or vice-versa, notify the tray.
  479. */
  480. if (pwndOldParent != NULL && pwndNewParent == NULL) {
  481. xxxCallHook(HSHELL_WINDOWCREATED,
  482. (WPARAM)hwnd,
  483. (LONG)0,
  484. WH_SHELL);
  485. PostShellHookMessages(HSHELL_WINDOWCREATED, (LPARAM)hwnd);
  486. } else if (pwndOldParent == NULL && pwndNewParent != NULL) {
  487. xxxCallHook(HSHELL_WINDOWDESTROYED,
  488. (WPARAM)hwnd,
  489. (LONG)0,
  490. WH_SHELL);
  491. PostShellHookMessages(HSHELL_WINDOWDESTROYED, (LPARAM)hwnd);
  492. }
  493. }
  494. }
  495. /***************************************************************************\
  496. * xxxSetWindowData
  497. *
  498. * SetWindowWord and ServerSetWindowLong are now identical routines because they
  499. * both can return DWORDs. This single routine performs the work for them both.
  500. *
  501. * History:
  502. * 26-Nov-1990 DarrinM Wrote.
  503. \***************************************************************************/
  504. ULONG_PTR xxxSetWindowData(
  505. PWND pwnd,
  506. int index,
  507. ULONG_PTR dwData,
  508. BOOL bAnsi)
  509. {
  510. ULONG_PTR dwT;
  511. ULONG_PTR dwOld;
  512. PMENU pmenu;
  513. PWND *ppwnd;
  514. PWND pwndNewParent;
  515. PWND pwndOldParent;
  516. BOOL fTopOwner;
  517. TL tlpwndOld;
  518. TL tlpwndNew;
  519. DWORD dwCPDType = 0;
  520. CheckLock(pwnd);
  521. UserAssert(IsWinEventNotifyDeferredOK());
  522. switch (index) {
  523. case GWLP_USERDATA:
  524. dwOld = pwnd->dwUserData;
  525. pwnd->dwUserData = dwData;
  526. break;
  527. case GWL_EXSTYLE:
  528. case GWL_STYLE:
  529. dwOld = xxxSetWindowStyle(pwnd, index, (DWORD)dwData);
  530. break;
  531. case GWLP_ID:
  532. /*
  533. * Win95 does a TestWF(pwnd, WFCHILD) here, but we'll do the same
  534. * check we do everywhere else or it'll cause us trouble.
  535. */
  536. if (TestwndChild(pwnd)) {
  537. /*
  538. * pwnd->spmenu is an id in this case.
  539. */
  540. dwOld = (ULONG_PTR)pwnd->spmenu;
  541. pwnd->spmenu = (struct tagMENU *)dwData;
  542. } else {
  543. dwOld = 0;
  544. if (pwnd->spmenu != NULL)
  545. dwOld = (ULONG_PTR)PtoH(pwnd->spmenu);
  546. if (dwData == 0) {
  547. UnlockWndMenu(pwnd, &pwnd->spmenu);
  548. } else {
  549. pmenu = ValidateHmenu((HANDLE)dwData);
  550. if (pmenu != NULL) {
  551. LockWndMenu(pwnd, &pwnd->spmenu, pmenu);
  552. } else {
  553. /*
  554. * Menu is invalid, so don't set a new one!
  555. */
  556. dwOld = 0;
  557. }
  558. }
  559. }
  560. break;
  561. case GWLP_HINSTANCE:
  562. dwOld = (ULONG_PTR)pwnd->hModule;
  563. pwnd->hModule = (HANDLE)dwData;
  564. break;
  565. case GWLP_WNDPROC: // See similar case DWLP_DLGPROC
  566. /*
  567. * Hide the window proc from other processes
  568. */
  569. if (PpiCurrent() != GETPTI(pwnd)->ppi) {
  570. RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING,
  571. "SetWindowLong: Window owned by another process %#p", pwnd);
  572. return 0;
  573. }
  574. /*
  575. * If the window has been zombized by a DestroyWindow but is still
  576. * around because the window was locked don't let anyone change
  577. * the window proc from DefWindowProc!
  578. *
  579. * !!! LATER long term move this test into the ValidateHWND; kind of
  580. * !!! LATER close to shipping for that
  581. */
  582. if (pwnd->fnid & FNID_DELETED_BIT) {
  583. UserAssert(pwnd->lpfnWndProc == xxxDefWindowProc);
  584. RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING,
  585. "SetWindowLong: Window is a zombie %#p", pwnd);
  586. return 0;
  587. }
  588. /*
  589. * If the application (client) subclasses a window that has a server -
  590. * side window proc we must return an address that the client can call:
  591. * this client-side wndproc expectes Unicode or ANSI depending on bAnsi
  592. */
  593. if (TestWF(pwnd, WFSERVERSIDEPROC)) {
  594. dwOld = MapServerToClientPfn((ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
  595. /*
  596. * If we don't have a client side address (like for the DDEMLMon
  597. * window) then blow off the subclassing.
  598. */
  599. if (dwOld == 0) {
  600. RIPMSG0(RIP_WARNING, "SetWindowLong: subclass server only window");
  601. return(0);
  602. }
  603. ClrWF(pwnd, WFSERVERSIDEPROC);
  604. } else {
  605. /*
  606. * Keep edit control behavior compatible with NT 3.51.
  607. */
  608. if (GETFNID(pwnd) == FNID_EDIT) {
  609. dwOld = (ULONG_PTR)MapKernelClientFnToClientFn(pwnd->lpfnWndProc);
  610. goto CheckAnsiUnicodeMismatch;
  611. } else {
  612. dwOld = MapClientNeuterToClientPfn(pwnd->pcls, (ULONG_PTR)pwnd->lpfnWndProc, bAnsi);
  613. }
  614. /*
  615. * If the client mapping didn't change the window proc then see if
  616. * we need a callproc handle.
  617. */
  618. if (dwOld == (ULONG_PTR)pwnd->lpfnWndProc) {
  619. CheckAnsiUnicodeMismatch:
  620. /*
  621. * May need to return a CallProc handle if there is an Ansi/Unicode mismatch
  622. */
  623. if (bAnsi != (TestWF(pwnd, WFANSIPROC) ? TRUE : FALSE)) {
  624. dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
  625. }
  626. }
  627. UserAssert(!ISCPDTAG(dwOld));
  628. if (dwCPDType) {
  629. ULONG_PTR cpd;
  630. cpd = GetCPD(pwnd, dwCPDType | CPD_WND, dwOld);
  631. if (cpd) {
  632. dwOld = cpd;
  633. } else {
  634. RIPMSG0(RIP_WARNING, "SetWindowLong unable to alloc CPD returning handle\n");
  635. }
  636. }
  637. }
  638. /*
  639. * Convert a possible CallProc Handle into a real address. They may
  640. * have kept the CallProc Handle from some previous mixed GetClassinfo
  641. * or SetWindowLong.
  642. *
  643. * WARNING bAnsi is modified here to represent real type of
  644. * proc rather than if SetWindowLongA or W was called
  645. *
  646. */
  647. if (ISCPDTAG(dwData)) {
  648. PCALLPROCDATA pCPD;
  649. if (pCPD = HMValidateHandleNoRip((HANDLE)dwData, TYPE_CALLPROC)) {
  650. dwData = pCPD->pfnClientPrevious;
  651. bAnsi = pCPD->wType & CPD_UNICODE_TO_ANSI;
  652. }
  653. }
  654. /*
  655. * If an app 'unsubclasses' a server-side window proc we need to
  656. * restore everything so SendMessage and friends know that it's
  657. * a server-side proc again. Need to check against client side
  658. * stub addresses.
  659. */
  660. if ((dwT = MapClientToServerPfn(dwData)) != 0) {
  661. pwnd->lpfnWndProc = (WNDPROC_PWND)dwT;
  662. SetWF(pwnd, WFSERVERSIDEPROC);
  663. ClrWF(pwnd, WFANSIPROC);
  664. } else {
  665. pwnd->lpfnWndProc = (WNDPROC_PWND)MapClientNeuterToClientPfn(pwnd->pcls, dwData, bAnsi);
  666. if (bAnsi) {
  667. SetWF(pwnd, WFANSIPROC);
  668. } else {
  669. ClrWF(pwnd, WFANSIPROC);
  670. }
  671. pwnd->hMod16 = xxxClientWOWGetProcModule(pwnd->lpfnWndProc);
  672. }
  673. break;
  674. case GWLP_HWNDPARENT:
  675. /*
  676. * Special case for pre-1.1 versions of Windows
  677. * Set/GetWindowWord(GWW_HWNDPARENT) needs to be mapped
  678. * to the hwndOwner for top level windows.
  679. */
  680. fTopOwner = FALSE;
  681. if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) {
  682. ppwnd = &pwnd->spwndOwner;
  683. fTopOwner = TRUE;
  684. } else {
  685. ppwnd = &pwnd->spwndParent;
  686. }
  687. /*
  688. * If we're a topmost, then we're only changing the owner
  689. * relationship. Otherwise, we are doing a relinking of the
  690. * parent/child relationship.
  691. */
  692. pwndOldParent = *ppwnd;
  693. pwndNewParent = ValidateHwnd((HWND)dwData);
  694. if (pwndNewParent == NULL && dwData) {
  695. RIPERR1(ERROR_INVALID_PARAMETER,
  696. RIP_WARNING,
  697. "Set GWL_HWNDPARENT, invalid hwndParent 0x%p",
  698. dwData);
  699. return 0;
  700. }
  701. dwOld = (ULONG_PTR)HW(*ppwnd);
  702. ThreadLock(pwndNewParent, &tlpwndNew);
  703. if (fTopOwner) {
  704. ThreadLock(pwndOldParent, &tlpwndOld);
  705. xxxHandleOwnerSwitch(pwnd, pwndNewParent, pwndOldParent);
  706. if (ValidateOwnerDepth(pwnd, pwndNewParent)) {
  707. /*
  708. * Set the owner.
  709. */
  710. if (pwndNewParent) {
  711. Lock(ppwnd, pwndNewParent);
  712. } else {
  713. Unlock(ppwnd);
  714. }
  715. } else {
  716. /*
  717. * Undo the switch and set last error.
  718. */
  719. xxxHandleOwnerSwitch(pwnd, pwndOldParent, pwndNewParent);
  720. RIPERR0(ERROR_INVALID_PARAMETER, RIP_ERROR, "Detected loop in owner chain");
  721. dwOld = 0;
  722. }
  723. ThreadUnlock(&tlpwndOld);
  724. } else {
  725. if (!xxxSetParent(pwnd, pwndNewParent)) {
  726. dwOld = 0;
  727. }
  728. }
  729. ThreadUnlock(&tlpwndNew);
  730. break;
  731. default:
  732. RIPERR1(ERROR_INVALID_INDEX,
  733. RIP_WARNING,
  734. "SetWindowLong: Invalid index 0x%x",
  735. index);
  736. return 0;
  737. }
  738. return dwOld;
  739. }
  740. /***************************************************************************\
  741. * FindPCPD
  742. *
  743. * Searches the list of CallProcData's associated with window to see if
  744. * one already exists representing this transition. CPD can be re-used
  745. * and aren't deleted until a window or thread dies
  746. *
  747. *
  748. * 04-Feb-1993 JohnC Created.
  749. \***************************************************************************/
  750. PCALLPROCDATA FindPCPD(
  751. PCALLPROCDATA pCPD,
  752. ULONG_PTR dwClientPrevious,
  753. WORD wCPDType)
  754. {
  755. while (pCPD) {
  756. if ((pCPD->pfnClientPrevious == dwClientPrevious) &&
  757. (pCPD->wType == wCPDType))
  758. return pCPD;
  759. pCPD = pCPD->spcpdNext;
  760. }
  761. return NULL;
  762. }
  763. /***************************************************************************\
  764. * GetCPD
  765. *
  766. * Searches the list of CallProcData's associated with a class or window
  767. * (if the class is not provided). If one already exists representing this
  768. * transition it is returned or else a new CPD is created
  769. *
  770. * 04-Feb-1993 JohnC Created.
  771. \***************************************************************************/
  772. ULONG_PTR GetCPD(
  773. PVOID pWndOrCls,
  774. DWORD CPDOption,
  775. ULONG_PTR dwProc32)
  776. {
  777. PCALLPROCDATA pCPD;
  778. PCLS pcls;
  779. #if DBG
  780. BOOL bAnsiProc;
  781. #endif
  782. PTHREADINFO ptiCurrent;
  783. if (CPDOption & (CPD_WND | CPD_DIALOG)) {
  784. UserAssert(!(CPDOption & (CPD_CLASS | CPD_WNDTOCLS)));
  785. pcls = ((PWND)pWndOrCls)->pcls;
  786. #if DBG
  787. if (CPDOption & CPD_WND) {
  788. bAnsiProc = !!(TestWF(pWndOrCls, WFANSIPROC));
  789. } else {
  790. /*
  791. * We'll assume the client-side dialog box code knows what it's
  792. * doing, since we can't check it from here.
  793. */
  794. bAnsiProc = !!(CPDOption & CPD_UNICODE_TO_ANSI);
  795. }
  796. #endif
  797. } else {
  798. UserAssert(CPDOption & (CPD_CLASS | CPD_WNDTOCLS));
  799. if (CPDOption & CPD_WNDTOCLS) {
  800. pcls = ((PWND)pWndOrCls)->pcls;
  801. } else {
  802. pcls = pWndOrCls;
  803. }
  804. #if DBG
  805. bAnsiProc = !!(pcls->CSF_flags & CSF_ANSIPROC);
  806. #endif
  807. }
  808. #if DBG
  809. /*
  810. * We should never have a CallProc handle as the calling address.
  811. */
  812. UserAssert(!ISCPDTAG(dwProc32));
  813. if (CPDOption & CPD_UNICODE_TO_ANSI) {
  814. UserAssert(bAnsiProc);
  815. } else if (CPDOption & CPD_ANSI_TO_UNICODE) {
  816. UserAssert(!bAnsiProc);
  817. }
  818. #endif
  819. /*
  820. * See if we already have a CallProc Handle that represents this
  821. * transition
  822. */
  823. pCPD = FindPCPD(pcls->spcpdFirst, dwProc32, (WORD)CPDOption);
  824. if (pCPD) {
  825. return MAKE_CPDHANDLE(PtoH(pCPD));
  826. }
  827. CheckCritIn();
  828. ptiCurrent = PtiCurrent();
  829. pCPD = HMAllocObject(ptiCurrent,
  830. ptiCurrent->rpdesk,
  831. TYPE_CALLPROC,
  832. sizeof(CALLPROCDATA));
  833. if (pCPD == NULL) {
  834. RIPMSG0(RIP_WARNING, "GetCPD unable to alloc CALLPROCDATA\n");
  835. return 0;
  836. }
  837. /*
  838. * Link in the new CallProcData to the class list.
  839. * Note -- these pointers are locked because WOWCleanup can come in
  840. * and delete objects, so we need to keep the pointers locked.
  841. */
  842. Lock(&pCPD->spcpdNext, pcls->spcpdFirst);
  843. Lock(&pcls->spcpdFirst, pCPD);
  844. /*
  845. * Initialize the CPD
  846. */
  847. pCPD->pfnClientPrevious = dwProc32;
  848. pCPD->wType = (WORD)CPDOption;
  849. return MAKE_CPDHANDLE(PtoH(pCPD));
  850. }
  851. /***************************************************************************\
  852. * MapClientToServerPfn
  853. *
  854. * Checks to see if a dword is a client wndproc stub to a server wndproc.
  855. * If it is, this returns the associated server side wndproc. If it isn't
  856. * this returns 0.
  857. *
  858. * 13-Jan-1992 ScottLu Created.
  859. \***************************************************************************/
  860. ULONG_PTR MapClientToServerPfn(
  861. ULONG_PTR dw)
  862. {
  863. ULONG_PTR *pdw;
  864. int i;
  865. pdw = (ULONG_PTR *)&gpsi->apfnClientW;
  866. for (i = FNID_WNDPROCSTART; i <= FNID_WNDPROCEND; i++, pdw++) {
  867. if (*pdw == dw) {
  868. return (ULONG_PTR)STOCID(i);
  869. }
  870. }
  871. pdw = (ULONG_PTR *)&gpsi->apfnClientA;
  872. for (i = FNID_WNDPROCSTART; i <= FNID_WNDPROCEND; i++, pdw++) {
  873. if (*pdw == dw) {
  874. return (ULONG_PTR)STOCID(i);
  875. }
  876. }
  877. return 0;
  878. }
  879. #if DBG
  880. ULONG DBGGetWindowLong(
  881. PWND pwnd,
  882. int index)
  883. {
  884. UserAssert(index >= 0);
  885. UserAssert((UINT)index + sizeof(DWORD) <= (UINT)pwnd->cbwndExtra);
  886. return __GetWindowLong(pwnd, index);
  887. }
  888. ULONG_PTR DBGGetWindowLongPtr(
  889. PWND pwnd,
  890. int index)
  891. {
  892. UserAssert(index >= 0);
  893. UserAssert((UINT)index + sizeof(ULONG_PTR) <= (UINT)pwnd->cbwndExtra);
  894. return __GetWindowLongPtr(pwnd, index);
  895. }
  896. #endif