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.

1844 lines
54 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: class.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains RegisterClass and the related window class management
  7. * functions.
  8. *
  9. * History:
  10. * 10-16-90 DarrinM Ported functions from Win 3.0 sources.
  11. * 02-01-91 mikeke Added Revalidation code (None)
  12. * 04-08-91 DarrinM C-S-ized and removed global/public class support.
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * These arrays are used by Get/SetClassWord/Long.
  18. *
  19. * INDEX_OFFSET must refer to the first entry of afClassDWord[]
  20. */
  21. #define INDEX_OFFSET GCLP_HICONSM
  22. CONST BYTE afClassDWord[-INDEX_OFFSET] = {
  23. FIELD_SIZE(CLS, spicnSm), // GCL_HICONSM (-34)
  24. 0,
  25. FIELD_SIZE(CLS, atomNVClassName), // GCW_ATOM (-32)
  26. 0,
  27. 0,
  28. 0,
  29. 0,
  30. 0,
  31. FIELD_SIZE(CLS, style), // GCL_STYLE (-26)
  32. 0,
  33. FIELD_SIZE(CLS, lpfnWndProc), // GCL_WNDPROC (-24)
  34. 0,
  35. 0,
  36. 0,
  37. FIELD_SIZE(CLS, cbclsExtra), // GCL_CBCLSEXTRA (-20)
  38. 0,
  39. FIELD_SIZE(CLS, cbwndExtra), // GCL_CBWNDEXTRA (-18)
  40. 0,
  41. FIELD_SIZE(CLS, hModule), // GCL_HMODULE (-16)
  42. 0,
  43. FIELD_SIZE(CLS, spicn), // GCL_HICON (-14)
  44. 0,
  45. FIELD_SIZE(CLS, spcur), // GCL_HCURSOR (-12)
  46. 0,
  47. FIELD_SIZE(CLS, hbrBackground), // GCL_HBRBACKGROUND (-10)
  48. 0,
  49. FIELD_SIZE(CLS, lpszMenuName), // GCL_HMENUNAME (-8)
  50. 0,
  51. 0,
  52. 0,
  53. 0,
  54. 0,
  55. 0,
  56. 0
  57. };
  58. CONST BYTE aiClassOffset[-INDEX_OFFSET] = {
  59. FIELD_OFFSET(CLS, spicnSm), // GCL_HICONSM
  60. 0,
  61. FIELD_OFFSET(CLS, atomNVClassName), // GCW_ATOM
  62. 0,
  63. 0,
  64. 0,
  65. 0,
  66. 0,
  67. FIELD_OFFSET(CLS, style), // GCL_STYLE
  68. 0,
  69. FIELD_OFFSET(CLS, lpfnWndProc), // GCL_WNDPROC
  70. 0,
  71. 0,
  72. 0,
  73. FIELD_OFFSET(CLS, cbclsExtra), // GCL_CBCLSEXTRA
  74. 0,
  75. FIELD_OFFSET(CLS, cbwndExtra), // GCL_CBWNDEXTRA
  76. 0,
  77. FIELD_OFFSET(CLS, hModule), // GCL_HMODULE
  78. 0,
  79. FIELD_OFFSET(CLS, spicn), // GCL_HICON
  80. 0,
  81. FIELD_OFFSET(CLS, spcur), // GCL_HCURSOR
  82. 0,
  83. FIELD_OFFSET(CLS, hbrBackground), // GCL_HBRBACKGROUND
  84. 0,
  85. FIELD_OFFSET(CLS, lpszMenuName), // GCL_MENUNAME
  86. 0,
  87. 0,
  88. 0,
  89. 0,
  90. 0,
  91. 0,
  92. 0
  93. };
  94. /***************************************************************************\
  95. * _RegisterClassEx (API)
  96. *
  97. * This stub calls InternalRegisterClass to do its work and then does some
  98. * additional work to save a pointer to the client-side menu name string.
  99. * The menu string is returned by _GetClassInfo so the client can fix up
  100. * a valid entry for the WNDCLASS lpszMenuName field.
  101. *
  102. * History:
  103. * 04-26-91 DarrinM Created.
  104. \***************************************************************************/
  105. ATOM _RegisterClassEx(
  106. LPWNDCLASSVEREX cczpwc,
  107. PCLSMENUNAME pcmn,
  108. WORD fnid,
  109. DWORD dwFlags,
  110. LPDWORD pdwWOW)
  111. {
  112. PCLS pcls;
  113. PTHREADINFO ptiCurrent = PtiCurrent();
  114. /*
  115. * NOTE -- lpszClassName and lpszMenuName in the wndclass may be client-side
  116. * pointers. Use of those fields must be protected in try blocks.
  117. */
  118. /*
  119. * Convert a possible CallProc Handle into a real address. They may
  120. * have kept the CallProc Handle from some previous mixed GetClassinfo
  121. * or SetWindowLong.
  122. */
  123. if (ISCPDTAG(cczpwc->lpfnWndProc)) {
  124. PCALLPROCDATA pCPD;
  125. if (pCPD = HMValidateHandleNoRip((HANDLE)cczpwc->lpfnWndProc, TYPE_CALLPROC)) {
  126. cczpwc->lpfnWndProc = (WNDPROC)pCPD->pfnClientPrevious;
  127. }
  128. }
  129. pcls = InternalRegisterClassEx(cczpwc, fnid, dwFlags | ((ptiCurrent->TIF_flags & TIF_16BIT)? CSF_WOWCLASS : 0));
  130. if (pcls != NULL) {
  131. pcls->lpszClientUnicodeMenuName = pcmn->pwszClientUnicodeMenuName;
  132. pcls->lpszClientAnsiMenuName = pcmn->pszClientAnsiMenuName;
  133. /*
  134. * copy 5 WOW dwords.
  135. */
  136. if (pdwWOW && (ptiCurrent->TIF_flags & TIF_16BIT)) {
  137. RtlCopyMemory (PWCFromPCLS(pcls), pdwWOW, sizeof(WC));
  138. }
  139. if ((ptiCurrent->TIF_flags & TIF_16BIT) && ptiCurrent->ptdb) {
  140. pcls->hTaskWow = ptiCurrent->ptdb->hTaskWow;
  141. } else {
  142. pcls->hTaskWow = 0;
  143. }
  144. /*
  145. * For some (presumably good) reason Win 3.1 changed RegisterClass
  146. * to return the classes classname atom.
  147. */
  148. return pcls->atomNVClassName;
  149. } else {
  150. return 0;
  151. }
  152. }
  153. /***************************************************************************\
  154. * ClassAlloc
  155. * ClassFree
  156. *
  157. * Generic allocation routines that discriminate between desktop heap
  158. * and pool.
  159. *
  160. * History:
  161. * 08-07-95 JimA Created
  162. \***************************************************************************/
  163. PVOID ClassAlloc(
  164. PDESKTOP pdesk,
  165. DWORD cbAlloc,
  166. ULONG tag)
  167. {
  168. PVOID pvalloc;
  169. if (pdesk) {
  170. /*
  171. * NTRAID#NTBUG9-411175-2001/06/06-jasonsch.
  172. */
  173. pvalloc = DesktopAllocAlways(pdesk, cbAlloc, tag);
  174. } else {
  175. pvalloc = UserAllocPoolWithQuotaZInit(cbAlloc, TAG_CLASS);
  176. }
  177. return pvalloc;
  178. }
  179. VOID ClassFree(
  180. PDESKTOP pdesk,
  181. PVOID pvfree)
  182. {
  183. if (pdesk != NULL) {
  184. DesktopFree(pdesk, pvfree);
  185. } else {
  186. UserFreePool(pvfree);
  187. }
  188. }
  189. /***************************************************************************\
  190. * ValidateAndLockCursor
  191. *
  192. * Win95 comaptible validation
  193. *
  194. * History:
  195. * 12-19-95 GerardoB Created
  196. \***************************************************************************/
  197. BOOL ValidateAndLockCursor(
  198. PCURSOR *ppcursor,
  199. BOOL fIs40Compat)
  200. {
  201. PCURSOR pcur;
  202. if (*ppcursor == NULL) {
  203. return TRUE;
  204. }
  205. pcur = HMValidateHandleNoSecure(*ppcursor, TYPE_CURSOR);
  206. if (pcur == NULL) {
  207. RIPMSGF1(RIP_WARNING,
  208. "Invalid Cursor or Icon: 0x%p",
  209. *ppcursor);
  210. if (fIs40Compat) {
  211. RIPERR0(ERROR_INVALID_PARAMETER,
  212. RIP_VERBOSE,
  213. "RegisterClass: Invalid Parameter");
  214. return FALSE;
  215. }
  216. }
  217. *ppcursor = NULL;
  218. Lock(ppcursor, pcur);
  219. return TRUE;
  220. }
  221. /***************************************************************************\
  222. * InternalRegisterClass
  223. *
  224. * This API is called by applications or the system to register private or
  225. * global (public) window classes. If a class with the same name already
  226. * exists the call will fail, except in the special case where an application
  227. * registers a private class with the same name as a global class. In this
  228. * case the private class supercedes the global class for that application.
  229. *
  230. * History:
  231. * 10-15-90 DarrinM Ported from Win 3.0 sources.
  232. \***************************************************************************/
  233. PCLS InternalRegisterClassEx(
  234. LPWNDCLASSVEREX cczlpwndcls,
  235. WORD fnid,
  236. DWORD CSF_flags)
  237. {
  238. BOOL fIs40Compat;
  239. ULONG_PTR dwT;
  240. PCLS pcls;
  241. LPWSTR pszT1;
  242. ATOM atomT;
  243. PTHREADINFO ptiCurrent;
  244. HANDLE hModule;
  245. PDESKTOP pdesk;
  246. ULONG cch;
  247. UNICODE_STRING UString;
  248. ANSI_STRING AString;
  249. /*
  250. * NOTE -- lpszClassName and lpszMenuName in the wndclass may be client-side
  251. * pointers. Use of those fields must be protected in try blocks.
  252. */
  253. CheckCritIn();
  254. ptiCurrent = PtiCurrent();
  255. /*
  256. * Don't allow 4.0 apps to register a class using hModuleWin
  257. * LATER GerardoB: Our client side classes use hmodUser (USER32) while
  258. * our server side classes use hWinInstance (WIN32K). We should change
  259. * CreateThreadInfo and LW_RegisterWindows so all classes use hModUser.
  260. */
  261. hModule = cczlpwndcls->hInstance;
  262. if (!(CSF_flags & (CSF_SYSTEMCLASS | CSF_SERVERSIDEPROC))
  263. && (hModule == hModuleWin)
  264. && (LOWORD(ptiCurrent->dwExpWinVer) >= VER40)) {
  265. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "InternalRegisterClassEx: Invalid hInstance (Cannot use system's hInstance)");
  266. return NULL;
  267. }
  268. /*
  269. * As of NT 4.0 we no longer honor CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW
  270. */
  271. if (cczlpwndcls->style & (CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW)) {
  272. RIPMSG0(RIP_VERBOSE, "CS_BYTEALIGNCLIENT and CS_BYTEALIGNWINDOW styles no longer honored.");
  273. }
  274. /*
  275. * Does this class exist as a private class? If so, fail.
  276. */
  277. atomT = FindClassAtom(cczlpwndcls->lpszClassNameVer);
  278. if (atomT != 0 && !(CSF_flags & CSF_SERVERSIDEPROC)) {
  279. /*
  280. * First check private classes. If already exists, return error.
  281. */
  282. if (_InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPrivateList,
  283. hModule) != NULL) {
  284. RIPERR1(ERROR_CLASS_ALREADY_EXISTS, RIP_VERBOSE, "RegisterClass: Class already exists %lx", (DWORD)atomT);
  285. return NULL;
  286. }
  287. /*
  288. * Now only check public classes if CS_GLOBALCLASS is set. If it
  289. * isn't set, then this will allow an application to re-register
  290. * a private class to take precedence over a public class.
  291. */
  292. if (cczlpwndcls->style & CS_GLOBALCLASS) {
  293. if (_InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPublicList, NULL) != NULL) {
  294. RIPERR0(ERROR_CLASS_ALREADY_EXISTS, RIP_VERBOSE, "RegisterClass: Global Class already exists");
  295. return NULL;
  296. }
  297. }
  298. }
  299. /*
  300. * Alloc space for the class.
  301. */
  302. if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) {
  303. pdesk = NULL;
  304. } else {
  305. pdesk = ptiCurrent->rpdesk;
  306. }
  307. pcls = (PCLS)ClassAlloc(pdesk, sizeof(CLS) + cczlpwndcls->cbClsExtra + (CSF_flags & CSF_WOWCLASS ? sizeof(WC):0), DTAG_CLASS);
  308. if (pcls == NULL) {
  309. return NULL;
  310. }
  311. LockDesktop(&pcls->rpdeskParent, pdesk, LDL_CLS_DESKPARENT1, (ULONG_PTR)pcls);
  312. pcls->pclsBase = pcls;
  313. /*
  314. * Copy over the shared part of the class structure.
  315. */
  316. UserAssert(FIELD_OFFSET(WNDCLASSEX, style) == FIELD_OFFSET(COMMON_WNDCLASS, style));
  317. RtlCopyMemory(&pcls->style, &(cczlpwndcls->style),
  318. sizeof(COMMON_WNDCLASS) - FIELD_OFFSET(COMMON_WNDCLASS, style));
  319. /*
  320. * Copy CSF_SERVERSIDEPROC, CSF_ANSIPROC (etc.) flags
  321. */
  322. pcls->CSF_flags = LOWORD(CSF_flags);
  323. pcls->fnid = fnid;
  324. if (fnid) {
  325. CBFNID(fnid) = (WORD)(pcls->cbwndExtra + sizeof(WND));
  326. #ifndef LAZY_CLASS_INIT
  327. if (!(pcls->CSF_flags & CSF_SERVERSIDEPROC) && ptiCurrent->pClientInfo != NULL) {
  328. /*
  329. * Clear the bit so new threads in this process
  330. * won't bother to reregister the client-side USER classes.
  331. */
  332. try {
  333. ptiCurrent->pClientInfo->CI_flags &= ~CI_REGISTERCLASSES;
  334. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  335. goto ValidateError1;
  336. }
  337. }
  338. #endif
  339. }
  340. /*
  341. * If this wndproc happens to be a client wndproc stub for a server
  342. * wndproc, then remember the server wndproc! This should be rare: why
  343. * would an application re-register a class that isn't "subclassed"?
  344. */
  345. if (!(pcls->CSF_flags & CSF_SERVERSIDEPROC)) {
  346. dwT = MapClientToServerPfn((ULONG_PTR)pcls->lpfnWndProc);
  347. if (dwT != 0) {
  348. pcls->CSF_flags |= CSF_SERVERSIDEPROC;
  349. pcls->CSF_flags &= ~CSF_ANSIPROC;
  350. pcls->lpfnWndProc = (WNDPROC_PWND)dwT;
  351. }
  352. }
  353. /*
  354. * Win95 compatible validation.
  355. *
  356. * hbrBackground was validated by GDI in the client side
  357. * NULL hInstances are mapped to GetModuleHandle(NULL) in the client
  358. * side
  359. */
  360. fIs40Compat = (CSF_flags & CSF_WIN40COMPAT) != 0;
  361. if (!ValidateAndLockCursor(&pcls->spcur, fIs40Compat)) {
  362. goto ValidateError1;
  363. }
  364. if (!ValidateAndLockCursor(&pcls->spicn, fIs40Compat)) {
  365. goto ValidateError2;
  366. }
  367. if (!ValidateAndLockCursor(&pcls->spicnSm, fIs40Compat)) {
  368. goto ValidateError3;
  369. }
  370. /*
  371. * Add the class name to the atom table.
  372. */
  373. if (IS_PTR(cczlpwndcls->lpszClassName)) {
  374. atomT = UserAddAtom(cczlpwndcls->lpszClassName, FALSE);
  375. } else {
  376. atomT = PTR_TO_ID(cczlpwndcls->lpszClassName);
  377. }
  378. if (atomT == 0) {
  379. goto AtomError1;
  380. }
  381. pcls->atomNVClassName = atomT;
  382. if (IS_PTR(cczlpwndcls->lpszClassNameVer)) {
  383. atomT = UserAddAtom(cczlpwndcls->lpszClassNameVer, FALSE);
  384. } else {
  385. atomT = PTR_TO_ID(cczlpwndcls->lpszClassNameVer);
  386. }
  387. if (atomT == 0) {
  388. goto AtomError2;
  389. }
  390. pcls->atomClassName = atomT;
  391. /*
  392. * Make an ANSI version of the class name to optimize
  393. * GetClassNameA for WOW.
  394. */
  395. if (IS_PTR(cczlpwndcls->lpszClassName)) {
  396. try {
  397. RtlInitUnicodeString(&UString, cczlpwndcls->lpszClassName);
  398. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  399. goto MemError2;
  400. }
  401. #ifdef FE_SB // InternalRegisterClassEx()
  402. cch = UString.Length + 1;
  403. #else
  404. cch = UString.Length / sizeof(WCHAR) + 1;
  405. #endif // FE_SB
  406. } else {
  407. cch = 7; // 1 char for '#', 5 for '65536'.
  408. }
  409. /*
  410. * Allocate the ANSI name buffer and convert the unicode name
  411. * to ANSI.
  412. */
  413. pcls->lpszAnsiClassName = (LPSTR)ClassAlloc(pdesk, cch, DTAG_TEXT);
  414. if (pcls->lpszAnsiClassName == NULL) {
  415. goto MemError2;
  416. }
  417. /*
  418. * Form the ANSI class name.
  419. */
  420. if (IS_PTR(cczlpwndcls->lpszClassName)) {
  421. /*
  422. * Class name is a string.
  423. */
  424. AString.Length = 0;
  425. AString.MaximumLength = (USHORT)cch;
  426. AString.Buffer = pcls->lpszAnsiClassName;
  427. try {
  428. RtlUnicodeStringToAnsiString(&AString, &UString, FALSE);
  429. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  430. goto MemError3;
  431. }
  432. } else {
  433. /*
  434. * Class name is an integer atom.
  435. */
  436. pcls->lpszAnsiClassName[0] = L'#';
  437. RtlIntegerToChar(PTR_TO_ID(cczlpwndcls->lpszClassName), 10, cch - 1,
  438. &pcls->lpszAnsiClassName[1]);
  439. }
  440. /*
  441. * Make local copy of menu name.
  442. */
  443. pszT1 = pcls->lpszMenuName;
  444. if (pszT1 != NULL) {
  445. if (IS_PTR(pszT1)) {
  446. try {
  447. RtlInitUnicodeString(&UString, pszT1);
  448. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  449. goto MemError3;
  450. }
  451. if (UString.Length == 0) {
  452. /*
  453. * app passed an empty string for the name
  454. */
  455. pcls->lpszMenuName = NULL;
  456. } else {
  457. UNICODE_STRING strMenuName;
  458. /*
  459. * Alloc space for the Menu Name.
  460. */
  461. if (!AllocateUnicodeString(&strMenuName, &UString)) {
  462. /*
  463. * The unlock call is delayed after the free such that if this is
  464. * the last reference on the desktop, the desktop heap is not
  465. * destroyed before we free the objects.
  466. */
  467. PDESKTOP rpdesk;
  468. MemError3:
  469. ClassFree(pdesk, pcls->lpszAnsiClassName);
  470. MemError2:
  471. UserDeleteAtom(pcls->atomClassName);
  472. AtomError2:
  473. UserDeleteAtom(pcls->atomNVClassName);
  474. AtomError1:
  475. Unlock(&pcls->spicnSm);
  476. ValidateError3:
  477. Unlock(&pcls->spicn);
  478. ValidateError2:
  479. Unlock(&pcls->spcur);
  480. ValidateError1:
  481. rpdesk = pcls->rpdeskParent;
  482. pcls->rpdeskParent = NULL;
  483. ClassFree(pdesk, pcls);
  484. /*
  485. * NOTE: Using pobj after freeing the object is not a
  486. * problem because UnlockDesktop uses the value for
  487. * tracking and doesn't dereference the pointer. If this
  488. * ever changes we'll get a BC.
  489. */
  490. UnlockDesktop(&rpdesk, LDU_CLS_DESKPARENT1, (ULONG_PTR)pcls);
  491. return NULL;
  492. }
  493. pcls->lpszMenuName = strMenuName.Buffer;
  494. }
  495. }
  496. }
  497. if ((CSF_flags & CSF_SERVERSIDEPROC) || (pcls->style & CS_GLOBALCLASS)) {
  498. if (pcls->CSF_flags & CSF_SYSTEMCLASS) {
  499. pcls->pclsNext = gpclsList;
  500. gpclsList = pcls;
  501. } else {
  502. pcls->pclsNext = ptiCurrent->ppi->pclsPublicList;
  503. ptiCurrent->ppi->pclsPublicList = pcls;
  504. }
  505. } else {
  506. pcls->pclsNext = ptiCurrent->ppi->pclsPrivateList;
  507. ptiCurrent->ppi->pclsPrivateList = pcls;
  508. }
  509. return pcls;
  510. }
  511. /***************************************************************************\
  512. * _UnregisterClass (API)
  513. *
  514. * This API function is used to unregister a window class previously
  515. * registered by the Application.
  516. *
  517. * Returns:
  518. * TRUE if successful.
  519. * FALSE otherwise.
  520. *
  521. * NOTE:
  522. * 1. The class name must have been registered earlier by this client
  523. * through RegisterClass().
  524. * 2. The class name should not be one of the predefined control classes.
  525. * 3. All windows created with this class must be destroyed before calling
  526. * this function.
  527. *
  528. * History:
  529. * 10-15-90 DarrinM Ported from Win 3.0 sources.
  530. * 03-09-94 BradG Fixed bug when ATOM was passed in
  531. \***************************************************************************/
  532. BOOL _UnregisterClass(
  533. LPCWSTR ccxlpszClassName,
  534. HANDLE hModule,
  535. PCLSMENUNAME pcmn)
  536. {
  537. ATOM atomT;
  538. PPCLS ppcls;
  539. PTHREADINFO ptiCurrent;
  540. CheckCritIn();
  541. ptiCurrent = PtiCurrent();
  542. /*
  543. * Check whether the given ClassName is already registered by the
  544. * Application with the given handle.
  545. * Return error, if either the Class does not exist or it does not
  546. * belong to the calling process.
  547. */
  548. /*
  549. * bradg (3/9/95) - Must first check to see if an ATOM has been passed
  550. */
  551. atomT = FindClassAtom(ccxlpszClassName);
  552. ppcls = _InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPrivateList, hModule);
  553. if (ppcls == NULL) {
  554. /*
  555. * Maybe this is a public class.
  556. */
  557. ppcls = _InnerGetClassPtr(atomT, &ptiCurrent->ppi->pclsPublicList, NULL);
  558. if (ppcls == NULL) {
  559. RIPERR1(ERROR_CLASS_DOES_NOT_EXIST, RIP_WARNING, "UnregisterClass: Class does not exist; atom=%lX", (DWORD)atomT);
  560. return FALSE;
  561. }
  562. }
  563. /*
  564. * If any windows created with this class still exist return an error.
  565. */
  566. if ((*ppcls)->cWndReferenceCount != 0) {
  567. RIPERR0(ERROR_CLASS_HAS_WINDOWS, RIP_WARNING, "UnregisterClass: Class still has window");
  568. return FALSE;
  569. }
  570. /*
  571. * Return client side pointers for cleanup
  572. */
  573. pcmn->pszClientAnsiMenuName = (*ppcls)->lpszClientAnsiMenuName;
  574. pcmn->pwszClientUnicodeMenuName = (*ppcls)->lpszClientUnicodeMenuName;
  575. pcmn->pusMenuName = NULL;
  576. /*
  577. * Release the Window class and related information.
  578. */
  579. DestroyClass(ppcls);
  580. return TRUE;
  581. }
  582. PCLS _GetWOWClass(
  583. HANDLE hModule,
  584. LPCWSTR ccxlpszClassName)
  585. {
  586. PCLS pcls;
  587. PPCLS ppcls = NULL;
  588. ATOM atomT;
  589. PTHREADINFO ptiCurrent;
  590. CheckCritInShared();
  591. ptiCurrent = PtiCurrentShared();
  592. /*
  593. * Is this class registered as a private class?
  594. */
  595. atomT = UserFindAtom(ccxlpszClassName);
  596. if (atomT != 0) {
  597. ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hModule);
  598. }
  599. if (ppcls == NULL) {
  600. RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, "");
  601. return NULL;
  602. }
  603. pcls = *ppcls;
  604. if (ptiCurrent->rpdesk != pcls->rpdeskParent) {
  605. pcls = pcls->pclsClone;
  606. while (pcls != NULL) {
  607. if (ptiCurrent->rpdesk == pcls->rpdeskParent) {
  608. goto Done;
  609. }
  610. pcls = pcls->pclsNext;
  611. }
  612. RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, "");
  613. return NULL;
  614. }
  615. Done:
  616. return pcls;
  617. }
  618. /***************************************************************************\
  619. * GetClassInfo (API)
  620. *
  621. * This function checks if the given class name is registered already. If the
  622. * class is not found, it returns 0; If the class is found, then all the
  623. * relevant information from the CLS structure is copied into the WNDCLASS
  624. * structure pointed to by the lpWndCls argument. If successful, it returns
  625. * the class name atom
  626. *
  627. * NOTE: hmod was used to distinguish between different task's public classes.
  628. * Now that public classes are gone, hmod isn't used anymore. We just search
  629. * the applications private class for a match and if none is found we search
  630. * the system classes.
  631. *
  632. * History:
  633. * 10-15-90 DarrinM Ported from Win 3.0 sources.
  634. * 04-08-91 DarrinM Removed public classes.
  635. * 04-26-91 DarrinM Streamlined to work with the client-side API.
  636. * 03-09-95 BradG Fixed bug when ATOM was passed in.
  637. \***************************************************************************/
  638. ATOM _GetClassInfoEx(
  639. HANDLE hModule,
  640. LPCWSTR ccxlpszClassName,
  641. LPWNDCLASSEX pwc,
  642. LPWSTR *ppszMenuName,
  643. BOOL bAnsi)
  644. {
  645. PCLS pcls;
  646. PPCLS ppcls;
  647. ATOM atomT;
  648. PTHREADINFO ptiCurrent;
  649. DWORD dwCPDType = 0;
  650. CheckCritIn();
  651. ptiCurrent = PtiCurrent();
  652. /*
  653. * These are done first so if we don't find the class, and therefore
  654. * fail, the return thank won't try to copy back these (nonexistant)
  655. * strings.
  656. */
  657. pwc->lpszMenuName = NULL;
  658. pwc->lpszClassName = NULL;
  659. /*
  660. * Must first check to see if an ATOM has been passed.
  661. */
  662. atomT = FindClassAtom(ccxlpszClassName);
  663. /*
  664. * Windows 3.1 does not perform the class search with
  665. * a null hModule. If an application supplies a NULL
  666. * hModule, they search on hModuleWin instead.
  667. */
  668. if (hModule == NULL) {
  669. hModule = hModClient;
  670. }
  671. ppcls = GetClassPtr(atomT, ptiCurrent->ppi, hModule);
  672. if (ppcls == NULL) {
  673. RIPERR0(ERROR_CLASS_DOES_NOT_EXIST, RIP_VERBOSE, "GetClassInfo: Class does not exist");
  674. return 0;
  675. }
  676. pcls = *ppcls;
  677. /*
  678. * Copy all the fields common to CLS and WNDCLASS structures except
  679. * the lpszMenuName and lpszClassName which will be filled in by the
  680. * client-side piece of GetClassInfo.
  681. */
  682. /*
  683. * Return public bits only.
  684. */
  685. pwc->style = pcls->style & CS_VALID;
  686. /*
  687. * Corel Depth 6.0 calls GetClassInfo (COMBOBOX) and registers a class
  688. * using the same name and style bits. This works OK on Win95 because
  689. * their "system" (combo, edit, etc) classes are not CS_GLOBALCLASS.
  690. * So we've got to mask this bit out for our classes.
  691. */
  692. /*
  693. * Bug 17998. If the app is 32bit and WinVer is less than 4.0 don't mask
  694. * out the CS_GLOBALCLASS bit.
  695. */
  696. if ((pcls->fnid != 0) &&
  697. ((LOWORD(ptiCurrent->dwExpWinVer) >= VER40) || (ptiCurrent->TIF_flags & TIF_16BIT)) ) {
  698. pwc->style &= ~CS_GLOBALCLASS;
  699. }
  700. pwc->cbClsExtra = pcls->cbclsExtra;
  701. pwc->cbWndExtra = pcls->cbwndExtra;
  702. /*
  703. * Stop 32-bit apps from inadvertantly using hModuleWin as their hInstance
  704. * when they register a window class.
  705. */
  706. if (LOWORD(ptiCurrent->dwExpWinVer) >= VER40) {
  707. /*
  708. * This is actually, Win95 behavior -- the USER.EXE hModule gets thunked
  709. * to NULL on the way out of the 16->32 bit thunk. Note -- if we ever
  710. * need to support 16-bit 4.0 apps (shudder), this may need to change.
  711. */
  712. if (hModule == hModClient) {
  713. pwc->hInstance = NULL;
  714. } else {
  715. pwc->hInstance = hModule;
  716. }
  717. } else {
  718. /*
  719. * Win NT 3.1/3.51 returned the hInstance from the class. Note that this
  720. * is incompatible with Win 3.1. WoW has hacks for 16-bit apps.
  721. */
  722. if ((pcls->hModule == hModuleWin) || (pcls->hModule == hModClient)) {
  723. pwc->hInstance = hModClient;
  724. } else {
  725. pwc->hInstance = pcls->hModule;
  726. }
  727. }
  728. pwc->hIcon = PtoH(pcls->spicn);
  729. pwc->hCursor = PtoH(pcls->spcur);
  730. pwc->hbrBackground = pcls->hbrBackground;
  731. /*
  732. * Need to hide the small icon if it's USER created.
  733. */
  734. if (pcls->spicnSm && (pcls->spicnSm->CURSORF_flags & CURSORF_SECRET)) {
  735. pwc->hIconSm = NULL;
  736. } else {
  737. pwc->hIconSm = PtoH(pcls->spicnSm);
  738. }
  739. /*
  740. * If its a server proc then map it to a client proc. If not we may have
  741. * to create a CPD.
  742. */
  743. if (pcls->CSF_flags & CSF_SERVERSIDEPROC) {
  744. pwc->lpfnWndProc =
  745. (WNDPROC)MapServerToClientPfn((ULONG_PTR)pcls->lpfnWndProc, bAnsi);
  746. } else {
  747. pwc->lpfnWndProc = (WNDPROC)MapClientNeuterToClientPfn(pcls, 0, bAnsi);
  748. /*
  749. * If the client mapping didn't change the window proc then see if
  750. * we need a callproc handle.
  751. */
  752. if (pwc->lpfnWndProc == (WNDPROC)pcls->lpfnWndProc) {
  753. /*
  754. * Need to return a CallProc handle if there is an Ansi/Unicode mismatch
  755. */
  756. if (bAnsi != !!(pcls->CSF_flags & CSF_ANSIPROC)) {
  757. dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
  758. }
  759. }
  760. }
  761. if (dwCPDType) {
  762. ULONG_PTR dwCPD;
  763. dwCPD = GetCPD(pcls, dwCPDType | CPD_CLASS, (ULONG_PTR)pwc->lpfnWndProc);
  764. if (dwCPD) {
  765. pwc->lpfnWndProc = (WNDPROC)dwCPD;
  766. } else {
  767. RIPMSG0(RIP_WARNING, "GetClassInfo unable to alloc CPD returning handle");
  768. }
  769. }
  770. /*
  771. * Return the stashed pointer to the client-side menu name string.
  772. */
  773. if (bAnsi) {
  774. *ppszMenuName = (LPWSTR)pcls->lpszClientAnsiMenuName;
  775. } else {
  776. *ppszMenuName = pcls->lpszClientUnicodeMenuName;
  777. }
  778. return pcls->atomNVClassName;
  779. }
  780. /***************************************************************************\
  781. * _SetClassWord (API)
  782. *
  783. * Set a class word. Positive index values set application class words
  784. * while negative index values set system class words. The negative
  785. * indices are published in WINDOWS.H.
  786. *
  787. * History:
  788. * 10-16-90 darrinm Wrote.
  789. \***************************************************************************/
  790. WORD _SetClassWord(
  791. PWND pwnd,
  792. int index,
  793. WORD value)
  794. {
  795. WORD wOld;
  796. WORD UNALIGNED *pw;
  797. PCLS pcls;
  798. CheckCritIn();
  799. if (GETPTI(pwnd)->ppi != PpiCurrent()) {
  800. RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassWord: different process: index 0x%lx", index);
  801. return 0;
  802. }
  803. pcls = pwnd->pcls->pclsBase;
  804. if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pcls->cbclsExtra)) {
  805. RIPERR1(ERROR_INVALID_INDEX,
  806. RIP_WARNING,
  807. "SetClassWord: invalid index 0x%x", index);
  808. return 0;
  809. } else {
  810. pw = (WORD UNALIGNED *)((BYTE *)(pcls + 1) + index);
  811. wOld = *pw;
  812. *pw = value;
  813. pcls = pcls->pclsClone;
  814. while (pcls != NULL) {
  815. pw = (WORD UNALIGNED *)((BYTE *)(pcls + 1) + index);
  816. *pw = value;
  817. pcls = pcls->pclsNext;
  818. }
  819. return wOld;
  820. }
  821. }
  822. /***************************************************************************\
  823. * xxxSetClassLong (API)
  824. *
  825. * Set a class long. Positive index values set application class longs
  826. * while negative index values set system class longs. The negative
  827. * indices are published in WINDOWS.H.
  828. *
  829. * History:
  830. * 10-16-90 darrinm Wrote.
  831. \***************************************************************************/
  832. ULONG_PTR xxxSetClassLongPtr(
  833. PWND pwnd,
  834. int index,
  835. ULONG_PTR value,
  836. BOOL bAnsi)
  837. {
  838. ULONG_PTR dwOld;
  839. PCLS pcls;
  840. CheckLock(pwnd);
  841. CheckCritIn();
  842. if (GETPTI(pwnd)->ppi != PpiCurrent()) {
  843. RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassLongPtr: different process: index 0x%lx", index);
  844. return 0;
  845. }
  846. if (index < 0) {
  847. return xxxSetClassData(pwnd, index, value, bAnsi);
  848. } else {
  849. pcls = pwnd->pcls->pclsBase;
  850. if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pcls->cbclsExtra) {
  851. RIPERR1(ERROR_INVALID_INDEX,
  852. RIP_WARNING,
  853. "SetClassLongPtr: invalid index 0x%x", index);
  854. return 0;
  855. } else {
  856. ULONG_PTR UNALIGNED *pudw;
  857. pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pcls + 1) + index);
  858. dwOld = *pudw;
  859. *pudw = value;
  860. pcls = pcls->pclsClone;
  861. while (pcls != NULL) {
  862. pudw = (ULONG_PTR UNALIGNED *)((BYTE *)(pcls + 1) + index);
  863. *pudw = value;
  864. pcls = pcls->pclsNext;
  865. }
  866. return dwOld;
  867. }
  868. }
  869. }
  870. #ifdef _WIN64
  871. DWORD xxxSetClassLong(
  872. PWND pwnd,
  873. int index,
  874. DWORD value,
  875. BOOL bAnsi)
  876. {
  877. DWORD dwOld;
  878. PCLS pcls;
  879. CheckLock(pwnd);
  880. CheckCritIn();
  881. if (GETPTI(pwnd)->ppi != PpiCurrent()) {
  882. RIPERR1(ERROR_ACCESS_DENIED, RIP_WARNING, "SetClassLong: different process: index 0x%lx", index);
  883. return 0;
  884. }
  885. if (index < 0) {
  886. if (index < INDEX_OFFSET || afClassDWord[index - INDEX_OFFSET] > sizeof(DWORD)) {
  887. RIPERR1(ERROR_INVALID_INDEX,
  888. RIP_WARNING,
  889. "SetClassLong: invalid index 0x%x", index);
  890. return 0;
  891. }
  892. return (DWORD)xxxSetClassData(pwnd, index, value, bAnsi);
  893. } else {
  894. pcls = pwnd->pcls->pclsBase;
  895. if ((UINT)index + sizeof(DWORD) > (UINT)pcls->cbclsExtra) {
  896. RIPERR1(ERROR_INVALID_INDEX,
  897. RIP_WARNING,
  898. "SetClassLong: invalid index 0x%x", index);
  899. return 0;
  900. } else {
  901. DWORD UNALIGNED *pudw;
  902. pudw = (DWORD UNALIGNED *)((BYTE *)(pcls + 1) + index);
  903. dwOld = *pudw;
  904. *pudw = value;
  905. pcls = pcls->pclsClone;
  906. while (pcls != NULL) {
  907. pudw = (DWORD UNALIGNED *)((BYTE *)(pcls + 1) + index);
  908. *pudw = value;
  909. pcls = pcls->pclsNext;
  910. }
  911. return dwOld;
  912. }
  913. }
  914. }
  915. #endif
  916. PPCLS _InnerGetClassPtr(
  917. ATOM atom,
  918. PPCLS ppcls,
  919. HANDLE hModule)
  920. {
  921. if (atom == 0)
  922. return NULL;
  923. while (*ppcls != NULL) {
  924. if ((*ppcls)->atomClassName == atom &&
  925. (hModule == NULL || HIWORD((ULONG_PTR)(*ppcls)->hModule) == HIWORD((ULONG_PTR)hModule)) &&
  926. !((*ppcls)->CSF_flags & CSF_WOWDEFERDESTROY)) {
  927. return ppcls;
  928. }
  929. ppcls = (PPCLS)*ppcls;
  930. }
  931. return NULL;
  932. }
  933. /***************************************************************************\
  934. * GetClassPtr
  935. *
  936. * Note: This returns a "pointer-to-PCLS" and not "PCLS".
  937. *
  938. * Scan the passed-in class list for the specified class. Return NULL if
  939. * the class isn't in the list.
  940. *
  941. * History:
  942. * 10-16-90 darrinm Ported this puppy.
  943. * 04-08-91 DarrinM Rewrote to remove global classes.
  944. * 08-14-92 FritzS Changed check to HIWORD only to allow Wow apps to
  945. * share window classes between instances of an app.
  946. (For Wow apps, HiWord of hInstance is 16-bit module,
  947. and LoWord is 16-bit hInstance
  948. \***************************************************************************/
  949. PPCLS GetClassPtr(
  950. ATOM atom,
  951. PPROCESSINFO ppi,
  952. HANDLE hModule)
  953. {
  954. PPCLS ppcls;
  955. /*
  956. * First search public then private then usersrv registered classes
  957. */
  958. ppcls = _InnerGetClassPtr(atom, &ppi->pclsPrivateList, hModule);
  959. if (ppcls)
  960. return ppcls;
  961. ppcls = _InnerGetClassPtr(atom, &ppi->pclsPublicList, NULL);
  962. if (ppcls)
  963. return ppcls;
  964. /*
  965. * Next seach public and private classes and override hmodule;
  966. * some apps (bunny) do a GetClassInfo(dialog) and RegisterClass
  967. * and only change the wndproc which set the hmodule to be just
  968. * like usersrv created it even though it is in the app's public
  969. * or private class list
  970. */
  971. /*
  972. * Later -- since we are no longer returning hModuleWin to any app,
  973. * we may only need to check for hModClient. Check this out.
  974. * FritzS
  975. */
  976. ppcls = _InnerGetClassPtr(atom, &ppi->pclsPrivateList, hModClient);
  977. if (ppcls)
  978. return ppcls;
  979. ppcls = _InnerGetClassPtr(atom, &ppi->pclsPublicList, hModClient);
  980. if (ppcls)
  981. return ppcls;
  982. /*
  983. * Search the system class list
  984. */
  985. ppcls = _InnerGetClassPtr(atom, &gpclsList, NULL);
  986. return ppcls;
  987. }
  988. /***************************************************************************\
  989. * UnlockAndFreeCPDs -
  990. *
  991. * Safe way to unlock and free a linked list of CPDs. Need to do it this
  992. * way in case the Thread's objects have already been marked for destruction.
  993. *
  994. * History 2/10/95 SanfordS Created
  995. \***************************************************************************/
  996. VOID UnlockAndFreeCPDs(
  997. PCALLPROCDATA *ppCPD)
  998. {
  999. PCALLPROCDATA pCPD;
  1000. while ((pCPD = *ppCPD) != NULL) {
  1001. /*
  1002. * Unlink the CPD from the list.
  1003. */
  1004. *ppCPD = pCPD->spcpdNext;
  1005. pCPD->spcpdNext = NULL;
  1006. /*
  1007. * Mark it for destruction.
  1008. */
  1009. if (!HMIsMarkDestroy(pCPD)) {
  1010. HMMarkObjectDestroy(pCPD);
  1011. }
  1012. /*
  1013. * Unlock it and it will be destroyed.
  1014. */
  1015. Unlock(&pCPD);
  1016. }
  1017. }
  1018. /***************************************************************************\
  1019. * DestroyClassBrush
  1020. *
  1021. * Destroy the brush of the class if it's a brush, it's not a system
  1022. * brush and no other class is using it
  1023. *
  1024. * History:
  1025. * 4-10-96 CLupu Created
  1026. \***************************************************************************/
  1027. void DestroyClassBrush(
  1028. PCLS pcls)
  1029. {
  1030. PPROCESSINFO ppi = PpiCurrent();
  1031. PCLS pclsWalk;
  1032. int nInd;
  1033. BOOL bRet;
  1034. /*
  1035. * Return if it's not a real brush
  1036. */
  1037. if (pcls->hbrBackground <= (HBRUSH)(COLOR_MAX))
  1038. return;
  1039. /*
  1040. * Don't delete the system brushes
  1041. */
  1042. for (nInd = 0; nInd < COLOR_MAX; nInd++) {
  1043. if (pcls->hbrBackground == SYSHBRUSH(nInd))
  1044. return;
  1045. }
  1046. /*
  1047. * Walk the process public public list
  1048. */
  1049. pclsWalk = ppi->pclsPublicList;
  1050. while (pclsWalk) {
  1051. if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground)
  1052. return;
  1053. pclsWalk = pclsWalk->pclsNext;
  1054. }
  1055. /*
  1056. * Walk the process private class list
  1057. */
  1058. pclsWalk = ppi->pclsPrivateList;
  1059. while (pclsWalk) {
  1060. if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground)
  1061. return;
  1062. pclsWalk = pclsWalk->pclsNext;
  1063. }
  1064. /*
  1065. * Finaly walk the system class list
  1066. */
  1067. pclsWalk = gpclsList;
  1068. while (pclsWalk) {
  1069. if (pclsWalk != pcls && pclsWalk->hbrBackground == pcls->hbrBackground)
  1070. return;
  1071. pclsWalk = pclsWalk->pclsNext;
  1072. }
  1073. bRet = GreDeleteObject(pcls->hbrBackground);
  1074. #if DBG
  1075. if (!bRet)
  1076. RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING,
  1077. "DestroyClassBrush: failed to destroy brush %#p", pcls->hbrBackground);
  1078. #endif
  1079. }
  1080. /***************************************************************************\
  1081. * DestroyClass
  1082. *
  1083. * Delete the window class. First, destroy any DCs that are attached to the
  1084. * class. Then delete classname atom. Then free the other stuff that was
  1085. * allocated when the class was registered and unlink the class from the
  1086. * master class list.
  1087. *
  1088. * History:
  1089. * 10-16-90 darrinm Ported this puppy.
  1090. \***************************************************************************/
  1091. VOID DestroyClass(
  1092. PPCLS ppcls)
  1093. {
  1094. PPCLS ppclsClone;
  1095. PCLS pcls;
  1096. PDESKTOP rpdesk;
  1097. pcls = *ppcls;
  1098. UserAssert(pcls->cWndReferenceCount == 0);
  1099. /*
  1100. * If this is a base class, destroy all clones before deleting
  1101. * stuff.
  1102. */
  1103. if (pcls == pcls->pclsBase) {
  1104. ppclsClone = &pcls->pclsClone;
  1105. while (*ppclsClone != NULL) {
  1106. DestroyClass(ppclsClone);
  1107. }
  1108. UserDeleteAtom(pcls->atomClassName);
  1109. UserDeleteAtom(pcls->atomNVClassName);
  1110. /*
  1111. * No freeing if it's an integer resource.
  1112. */
  1113. if (IS_PTR(pcls->lpszMenuName)) {
  1114. UserFreePool(pcls->lpszMenuName);
  1115. }
  1116. /*
  1117. * Free up the class dc if there is one.
  1118. */
  1119. if (pcls->pdce != NULL)
  1120. DestroyCacheDC(NULL, pcls->pdce->hdc);
  1121. /*
  1122. * Delete the hBrBackground brush if nobody else is
  1123. * using it.
  1124. */
  1125. DestroyClassBrush(pcls);
  1126. }
  1127. /*
  1128. * If we created the small icon delete it
  1129. */
  1130. DestroyClassSmIcon(pcls);
  1131. /*
  1132. * Unlock cursor and icon
  1133. */
  1134. Unlock(&pcls->spicn);
  1135. Unlock(&pcls->spicnSm);
  1136. Unlock(&pcls->spcur);
  1137. /*
  1138. * Free any CallProcData objects associated with this class
  1139. */
  1140. if (pcls->spcpdFirst) {
  1141. UnlockAndFreeCPDs(&pcls->spcpdFirst);
  1142. }
  1143. /*
  1144. * Point the previous guy at the guy we currently point to.
  1145. */
  1146. *ppcls = pcls->pclsNext;
  1147. /*
  1148. * The unlock call is delayed after the free such that if this is
  1149. * the last reference on the desktop, the desktop heap is not
  1150. * destroyed before we free the objects.
  1151. */
  1152. rpdesk = pcls->rpdeskParent;
  1153. pcls->rpdeskParent = NULL;
  1154. ClassFree(rpdesk, pcls->lpszAnsiClassName);
  1155. ClassFree(rpdesk, pcls);
  1156. /*
  1157. * NOTE: Using pobj after freeing the object is not a problem because
  1158. * UnlockDesktop uses the value for tracking and doesn't dereference
  1159. * the pointer. If this ever changes we'll get a BC.
  1160. */
  1161. UnlockDesktop(&rpdesk, LDU_CLS_DESKPARENT2, (ULONG_PTR)pcls);
  1162. }
  1163. /***************************************************************************\
  1164. * GetClassIcoCur
  1165. *
  1166. * Returns the pwnd's class icon/cursor. This is called by _GetClassData
  1167. * from the client side because PCURSORs are allocated from POOL (so the
  1168. * client cannot do PtoH on them). NtUserCallHwndParam does the PtoH translation
  1169. *
  1170. * History:
  1171. * 11-19-90 darrinm Wrote.
  1172. \***************************************************************************/
  1173. PCURSOR GetClassIcoCur(
  1174. PWND pwnd,
  1175. int index)
  1176. {
  1177. PCLS pcls = pwnd->pcls;
  1178. PCURSOR pcur;
  1179. switch (index) {
  1180. case GCLP_HICON:
  1181. pcur = pcls->spicn;
  1182. break;
  1183. case GCLP_HCURSOR:
  1184. pcur = pcls->spcur;
  1185. break;
  1186. case GCLP_HICONSM:
  1187. pcur = pcls->spicnSm;
  1188. break;
  1189. default:
  1190. RIPMSG2(RIP_WARNING,
  1191. "GetWndIcoCur: Invalid index: 0x%x pwnd: 0x%p",
  1192. index,
  1193. pwnd);
  1194. pcur = NULL;
  1195. }
  1196. return pcur;
  1197. }
  1198. /***************************************************************************\
  1199. * xxxSetClassCursor
  1200. *
  1201. * History:
  1202. \***************************************************************************/
  1203. ULONG_PTR xxxSetClassCursor(
  1204. PWND pwnd,
  1205. PCLS pcls,
  1206. DWORD index,
  1207. ULONG_PTR dwData)
  1208. {
  1209. ULONG_PTR dwOld;
  1210. CheckLock(pwnd);
  1211. if ((HANDLE)dwData != NULL) {
  1212. dwData = (ULONG_PTR)HMValidateHandle((HANDLE)dwData, TYPE_CURSOR);
  1213. if ((PVOID)dwData == NULL) {
  1214. if (index == GCLP_HICON || index == GCLP_HICONSM) {
  1215. RIPERR0(ERROR_INVALID_ICON_HANDLE, RIP_WARNING, "SetClassData: invalid icon");
  1216. } else {
  1217. RIPERR0(ERROR_INVALID_CURSOR_HANDLE, RIP_WARNING, "SetClassData: invalid cursor");
  1218. }
  1219. }
  1220. }
  1221. /*
  1222. * Handle the locking issue.
  1223. */
  1224. pcls = pcls->pclsBase;
  1225. switch (index) {
  1226. case GCLP_HICON:
  1227. case GCLP_HICONSM:
  1228. dwOld = (ULONG_PTR)xxxSetClassIcon(pwnd, pcls, (PCURSOR)dwData, index);
  1229. break;
  1230. case GCLP_HCURSOR:
  1231. dwOld = (ULONG_PTR)Lock(&pcls->spcur, dwData);
  1232. break;
  1233. }
  1234. /*
  1235. * Now set it for each clone class.
  1236. */
  1237. pcls = pcls->pclsClone;
  1238. while (pcls != NULL) {
  1239. switch(index) {
  1240. case GCLP_HICON:
  1241. case GCLP_HICONSM:
  1242. xxxSetClassIcon(pwnd, pcls, (PCURSOR)dwData, index);
  1243. break;
  1244. case GCLP_HCURSOR:
  1245. Lock(&pcls->spcur, dwData);
  1246. break;
  1247. }
  1248. pcls = pcls->pclsNext;
  1249. }
  1250. return (ULONG_PTR)PtoH((PVOID)dwOld);
  1251. }
  1252. /***************************************************************************\
  1253. * SetClassData
  1254. *
  1255. * SetClassWord and SetClassLong are now identical routines because they both
  1256. * can return DWORDs. This single routine performs the work for them both
  1257. * by using two arrays; afClassDWord to determine whether the result should be
  1258. * a WORD or a DWORD, and aiClassOffset to find the correct offset into the
  1259. * CLS structure for a given GCL_ or GCL_ index.
  1260. *
  1261. * History:
  1262. * 11-19-90 darrinm Wrote.
  1263. \***************************************************************************/
  1264. ULONG_PTR xxxSetClassData(
  1265. PWND pwnd,
  1266. int index,
  1267. ULONG_PTR dwData,
  1268. BOOL bAnsi)
  1269. {
  1270. PCLS pcls = pwnd->pcls;
  1271. BYTE *pb;
  1272. ULONG_PTR dwT;
  1273. ULONG_PTR dwOld;
  1274. DWORD dwCPDType = 0;
  1275. PCLSMENUNAME pcmn;
  1276. UNICODE_STRING strMenuName, UString;
  1277. CheckLock(pwnd);
  1278. switch(index) {
  1279. case GCLP_WNDPROC:
  1280. /*
  1281. * If the application (client) subclasses a class that has a server -
  1282. * side window proc we must return a client side proc stub that it
  1283. * can call.
  1284. */
  1285. if (pcls->CSF_flags & CSF_SERVERSIDEPROC) {
  1286. dwOld = MapServerToClientPfn((ULONG_PTR)pcls->lpfnWndProc, bAnsi);
  1287. pcls->CSF_flags &= ~CSF_SERVERSIDEPROC;
  1288. UserAssert(!(pcls->CSF_flags & CSF_ANSIPROC));
  1289. if (bAnsi) {
  1290. pcls->CSF_flags |= CSF_ANSIPROC;
  1291. }
  1292. } else {
  1293. dwOld = MapClientNeuterToClientPfn(pcls, 0, bAnsi);
  1294. /*
  1295. * If the client mapping didn't change the window proc then see if
  1296. * we need a callproc handle.
  1297. */
  1298. if (dwOld == (ULONG_PTR)pcls->lpfnWndProc) {
  1299. /*
  1300. * Need to return a CallProc handle if there is an Ansi/Unicode mismatch
  1301. */
  1302. if (bAnsi != !!(pcls->CSF_flags & CSF_ANSIPROC)) {
  1303. dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
  1304. }
  1305. }
  1306. }
  1307. if (dwCPDType) {
  1308. ULONG_PTR dwCPD;
  1309. dwCPD = GetCPD(pcls, dwCPDType | CPD_CLASS, dwOld);
  1310. if (dwCPD) {
  1311. dwOld = dwCPD;
  1312. } else {
  1313. RIPMSG0(RIP_WARNING, "GetClassLong unable to alloc CPD returning handle");
  1314. }
  1315. }
  1316. /*
  1317. * Convert a possible CallProc Handle into a real address. They may
  1318. * have kept the CallProc Handle from some previous mixed GetClassinfo
  1319. * or SetWindowLong.
  1320. */
  1321. if (ISCPDTAG(dwData)) {
  1322. PCALLPROCDATA pCPD;
  1323. if (pCPD = HMValidateHandleNoRip((HANDLE)dwData, TYPE_CALLPROC)) {
  1324. dwData = pCPD->pfnClientPrevious;
  1325. }
  1326. }
  1327. /*
  1328. * If an app 'unsubclasses' a server-side window proc we need to
  1329. * restore everything so SendMessage and friends know that it's
  1330. * a server-side proc again. Need to check against client side
  1331. * stub addresses.
  1332. */
  1333. pcls->lpfnWndProc = (WNDPROC_PWND)dwData;
  1334. if ((dwT = MapClientToServerPfn(dwData)) != 0) {
  1335. pcls->lpfnWndProc = (WNDPROC_PWND)dwT;
  1336. pcls->CSF_flags |= CSF_SERVERSIDEPROC;
  1337. pcls->CSF_flags &= ~CSF_ANSIPROC;
  1338. } else {
  1339. if (bAnsi) {
  1340. pcls->CSF_flags |= CSF_ANSIPROC;
  1341. } else {
  1342. pcls->CSF_flags &= ~CSF_ANSIPROC;
  1343. }
  1344. }
  1345. if (pcls->CSF_flags & CSF_WOWCLASS) {
  1346. PWC pwc = PWCFromPCLS(pcls);
  1347. pwc->hMod16 = (pcls->CSF_flags & CSF_SERVERSIDEPROC) ? 0 : xxxClientWOWGetProcModule(pcls->lpfnWndProc);
  1348. }
  1349. return dwOld;
  1350. break;
  1351. case GCLP_HICON:
  1352. case GCLP_HICONSM:
  1353. case GCLP_HCURSOR:
  1354. return xxxSetClassCursor(pwnd, pcls, index, dwData);
  1355. break;
  1356. case GCL_WOWMENUNAME:
  1357. if (pcls->CSF_flags & CSF_WOWCLASS) {
  1358. PWCFromPCLS(pcls)->vpszMenu = (DWORD)dwData;
  1359. } else {
  1360. UserAssert(FALSE);
  1361. }
  1362. break;
  1363. case GCL_CBCLSEXTRA:
  1364. if (pcls->CSF_flags & CSF_WOWCLASS) {
  1365. /*
  1366. * yes -- we can do this for WOW classes only.
  1367. */
  1368. if (pcls->CSF_flags & CSF_WOWEXTRA) {
  1369. dwOld = PWCFromPCLS(pcls)->iClsExtra;
  1370. PWCFromPCLS(pcls)->iClsExtra = LOWORD(dwData);
  1371. return dwOld;
  1372. } else {
  1373. PWCFromPCLS(pcls)->iClsExtra = LOWORD(dwData);
  1374. pcls->CSF_flags |= CSF_WOWEXTRA;
  1375. return pcls->cbclsExtra;
  1376. }
  1377. }
  1378. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Attempt to change cbClsExtra");
  1379. break;
  1380. case GCLP_MENUNAME:
  1381. pcmn = (PCLSMENUNAME) dwData;
  1382. /*
  1383. * pcmn->pusMenuName->Buffer is a client-side address.
  1384. */
  1385. dwOld = (ULONG_PTR) pcls->lpszMenuName;
  1386. /* Is it a string? */
  1387. if (IS_PTR(pcmn->pusMenuName->Buffer)) {
  1388. try {
  1389. RtlInitUnicodeString(&UString, pcmn->pusMenuName->Buffer);
  1390. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  1391. break;
  1392. }
  1393. /* Empty String? */
  1394. if (UString.Length == 0) {
  1395. pcls->lpszMenuName = NULL;
  1396. } else {
  1397. /* Make a copy of the string */
  1398. if (!AllocateUnicodeString(&strMenuName, &UString)) {
  1399. RIPMSG0(RIP_WARNING, "xxxSetClassData: GCL_MENUNAME AllocateUnicodeString failed");
  1400. break;
  1401. }
  1402. pcls->lpszMenuName = strMenuName.Buffer;
  1403. }
  1404. } else {
  1405. /* Just copy the id */
  1406. pcls->lpszMenuName = pcmn->pusMenuName->Buffer;
  1407. }
  1408. /* Don't return the kernel side pointer */
  1409. pcmn->pusMenuName = NULL;
  1410. /* Free old string, if any */
  1411. if (IS_PTR(dwOld)) {
  1412. UserFreePool((PVOID)dwOld);
  1413. }
  1414. /* Return client side pointers */
  1415. dwOld = (ULONG_PTR) pcls->lpszClientAnsiMenuName;
  1416. pcls->lpszClientAnsiMenuName = pcmn->pszClientAnsiMenuName;
  1417. pcmn->pszClientAnsiMenuName = (LPSTR)dwOld;
  1418. dwOld = (ULONG_PTR) pcls->lpszClientUnicodeMenuName;
  1419. pcls->lpszClientUnicodeMenuName = pcmn->pwszClientUnicodeMenuName;
  1420. pcmn->pwszClientUnicodeMenuName = (LPWSTR)dwOld;
  1421. return (bAnsi ? (ULONG_PTR) pcmn->pszClientAnsiMenuName : (ULONG_PTR) pcmn->pwszClientUnicodeMenuName);
  1422. default:
  1423. /*
  1424. * All other indexes go here...
  1425. */
  1426. index -= INDEX_OFFSET;
  1427. /*
  1428. * Only let valid indices go through; if aiClassOffset is zero
  1429. * then we have no mapping for this negative index so it must
  1430. * be a bogus index.
  1431. */
  1432. if ((index < 0) || (aiClassOffset[index] == 0)) {
  1433. RIPERR1(ERROR_INVALID_INDEX,
  1434. RIP_WARNING,
  1435. "SetClassLong: invalid index 0x%x", index);
  1436. return 0;
  1437. }
  1438. pcls = pcls->pclsBase;
  1439. pb = ((BYTE *)pcls) + aiClassOffset[index];
  1440. if (afClassDWord[index] == sizeof(DWORD)) {
  1441. dwOld = *(DWORD *)pb;
  1442. *(DWORD *)pb = (DWORD)dwData;
  1443. } else if (afClassDWord[index] == sizeof(ULONG_PTR)) {
  1444. dwOld = *(ULONG_PTR *)pb;
  1445. *(ULONG_PTR *)pb = dwData;
  1446. } else {
  1447. dwOld = (DWORD)*(WORD *)pb;
  1448. *(WORD *)pb = (WORD)dwData;
  1449. }
  1450. pcls = pcls->pclsClone;
  1451. while (pcls != NULL) {
  1452. pb = ((BYTE *)pcls) + aiClassOffset[index];
  1453. if (afClassDWord[index] == sizeof(DWORD)) {
  1454. dwOld = *(DWORD *)pb;
  1455. *(DWORD *)pb = (DWORD)dwData;
  1456. } else if (afClassDWord[index] == sizeof(ULONG_PTR)) {
  1457. dwOld = *(ULONG_PTR *)pb;
  1458. *(ULONG_PTR *)pb = dwData;
  1459. } else {
  1460. dwOld = (DWORD)*(WORD *)pb;
  1461. *(WORD *)pb = (WORD)dwData;
  1462. }
  1463. pcls = pcls->pclsNext;
  1464. }
  1465. return dwOld;
  1466. }
  1467. return 0;
  1468. }
  1469. /***************************************************************************\
  1470. * ReferenceClass
  1471. *
  1472. * Clones the class if it is a different desktop than the new window and
  1473. * increments the class window count(s).
  1474. *
  1475. * History:
  1476. * 12-11-93 JimA Created.
  1477. \***************************************************************************/
  1478. BOOL ReferenceClass(
  1479. PCLS pcls,
  1480. PWND pwnd)
  1481. {
  1482. DWORD cbName;
  1483. PCLS pclsClone;
  1484. PDESKTOP pdesk;
  1485. /*
  1486. * If the window is on the same desktop as the base class, just
  1487. * increment the window count.
  1488. */
  1489. if (pcls->rpdeskParent == pwnd->head.rpdesk) {
  1490. pcls->cWndReferenceCount++;
  1491. return TRUE;
  1492. }
  1493. /*
  1494. * The window is not on the base desktop. Try to find a cloned
  1495. * class.
  1496. */
  1497. for (pclsClone = pcls->pclsClone; pclsClone != NULL;
  1498. pclsClone = pclsClone->pclsNext) {
  1499. if (pclsClone->rpdeskParent == pwnd->head.rpdesk) {
  1500. break;
  1501. }
  1502. }
  1503. /*
  1504. * If we can't find one, clone the base class.
  1505. */
  1506. if (pclsClone == NULL) {
  1507. pdesk = pwnd->head.rpdesk;
  1508. pclsClone = ClassAlloc(pdesk, sizeof(CLS) + pcls->cbclsExtra + (pcls->CSF_flags & CSF_WOWCLASS ?sizeof(WC):0), DTAG_CLASS);
  1509. if (pclsClone == NULL) {
  1510. RIPMSG0(RIP_WARNING, "ReferenceClass: Failed Clone-Class Allocation");
  1511. return FALSE;
  1512. }
  1513. RtlCopyMemory(pclsClone, pcls, sizeof(CLS) + pcls->cbclsExtra + (pcls->CSF_flags & CSF_WOWCLASS?sizeof(WC):0));
  1514. cbName = strlen(pcls->lpszAnsiClassName) + 1;
  1515. pclsClone->lpszAnsiClassName = ClassAlloc(pdesk, cbName, DTAG_TEXT);
  1516. if (pclsClone->lpszAnsiClassName == NULL) {
  1517. ClassFree(pdesk, pclsClone);
  1518. RIPMSG0(RIP_WARNING, "ReferenceClass: No Clone Class Name");
  1519. return FALSE;
  1520. }
  1521. /*
  1522. * Everything has been allocated, now lock everything down.
  1523. * NULL pointers in clone to prevent Lock() from incorrectly
  1524. * decrementing object reference count
  1525. */
  1526. pclsClone->rpdeskParent = NULL;
  1527. LockDesktop(&pclsClone->rpdeskParent, pdesk,
  1528. LDL_CLS_DESKPARENT2, (ULONG_PTR)pclsClone);
  1529. pclsClone->pclsNext = pcls->pclsClone;
  1530. pclsClone->pclsClone = NULL;
  1531. pcls->pclsClone = pclsClone;
  1532. RtlCopyMemory(pclsClone->lpszAnsiClassName, pcls->lpszAnsiClassName, cbName);
  1533. pclsClone->spicn = pclsClone->spicnSm = pclsClone->spcur = NULL;
  1534. Lock(&pclsClone->spicn, pcls->spicn);
  1535. Lock(&pclsClone->spicnSm, pcls->spicnSm);
  1536. Lock(&pclsClone->spcur, pcls->spcur);
  1537. pclsClone->spcpdFirst = NULL;
  1538. pclsClone->cWndReferenceCount = 0;
  1539. }
  1540. /*
  1541. * Increment reference counts.
  1542. */
  1543. pcls->cWndReferenceCount++;
  1544. pclsClone->cWndReferenceCount++;
  1545. pwnd->pcls = pclsClone;
  1546. return TRUE;
  1547. }
  1548. /***************************************************************************\
  1549. * DereferenceClass
  1550. *
  1551. * Decrements the class window count in the base class. If it's the
  1552. * last window of a clone class, destroy the clone.
  1553. *
  1554. * History:
  1555. * 12-11-93 JimA Created.
  1556. \***************************************************************************/
  1557. VOID DereferenceClass(
  1558. PWND pwnd)
  1559. {
  1560. PCLS pcls = pwnd->pcls;
  1561. PPCLS ppcls;
  1562. UserAssert(pcls->cWndReferenceCount >= 1);
  1563. pwnd->pcls = NULL;
  1564. pcls->cWndReferenceCount--;
  1565. if (pcls != pcls->pclsBase) {
  1566. UserAssert(pcls->pclsBase->cWndReferenceCount >= 1);
  1567. pcls->pclsBase->cWndReferenceCount--;
  1568. if (pcls->cWndReferenceCount == 0) {
  1569. ppcls = &pcls->pclsBase->pclsClone;
  1570. while ((*ppcls) != pcls)
  1571. ppcls = &(*ppcls)->pclsNext;
  1572. UserAssert(ppcls);
  1573. DestroyClass(ppcls);
  1574. }
  1575. }
  1576. }
  1577. /***************************************************************************\
  1578. * DestroyProcessesClasses
  1579. *
  1580. * History:
  1581. * 04-07-91 DarrinM Created.
  1582. \***************************************************************************/
  1583. VOID DestroyProcessesClasses(
  1584. PPROCESSINFO ppi)
  1585. {
  1586. PPCLS ppcls;
  1587. /*
  1588. * Destroy the private classes first
  1589. */
  1590. ppcls = &(ppi->pclsPrivateList);
  1591. while (*ppcls != NULL) {
  1592. DestroyClass(ppcls);
  1593. }
  1594. /*
  1595. * Then the cloned public classes
  1596. */
  1597. ppcls = &(ppi->pclsPublicList);
  1598. while (*ppcls != NULL) {
  1599. DestroyClass(ppcls);
  1600. }
  1601. }