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.

569 lines
17 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: classc.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains
  7. *
  8. * History:
  9. * 15-Dec-1993 JohnC Pulled functions from user\server.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /*
  14. * These arrays are used by GetClassWord/Long.
  15. */
  16. // !!! can't we get rid of this and just special case GCW_ATOM
  17. CONST BYTE afClassDWord[] = {
  18. FIELD_SIZE(CLS, spicnSm), // GCL_HICONSM (-34)
  19. 0,
  20. FIELD_SIZE(CLS, atomNVClassName), // GCW_ATOM (-32)
  21. 0,
  22. 0,
  23. 0,
  24. 0,
  25. 0,
  26. FIELD_SIZE(CLS, style), // GCL_STYLE (-26)
  27. 0,
  28. FIELD_SIZE(CLS, lpfnWndProc), // GCL_WNDPROC (-24)
  29. 0,
  30. 0,
  31. 0,
  32. FIELD_SIZE(CLS, cbclsExtra), // GCL_CBCLSEXTRA (-20)
  33. 0,
  34. FIELD_SIZE(CLS, cbwndExtra), // GCL_CBWNDEXTRA (-18)
  35. 0,
  36. FIELD_SIZE(CLS, hModule), // GCL_HMODULE (-16)
  37. 0,
  38. FIELD_SIZE(CLS, spicn), // GCL_HICON (-14)
  39. 0,
  40. FIELD_SIZE(CLS, spcur), // GCL_HCURSOR (-12)
  41. 0,
  42. FIELD_SIZE(CLS, hbrBackground), // GCL_HBRBACKGROUND (-10)
  43. 0,
  44. FIELD_SIZE(CLS, lpszMenuName) // GCL_HMENUNAME (-8)
  45. };
  46. CONST BYTE aiClassOffset[] = {
  47. FIELD_OFFSET(CLS, spicnSm), // GCL_HICONSM
  48. 0,
  49. FIELD_OFFSET(CLS, atomNVClassName), // GCW_ATOM
  50. 0,
  51. 0,
  52. 0,
  53. 0,
  54. 0,
  55. FIELD_OFFSET(CLS, style), // GCL_STYLE
  56. 0,
  57. FIELD_OFFSET(CLS, lpfnWndProc), // GCL_WNDPROC
  58. 0,
  59. 0,
  60. 0,
  61. FIELD_OFFSET(CLS, cbclsExtra), // GCL_CBCLSEXTRA
  62. 0,
  63. FIELD_OFFSET(CLS, cbwndExtra), // GCL_CBWNDEXTRA
  64. 0,
  65. FIELD_OFFSET(CLS, hModule), // GCL_HMODULE
  66. 0,
  67. FIELD_OFFSET(CLS, spicn), // GCL_HICON
  68. 0,
  69. FIELD_OFFSET(CLS, spcur), // GCL_HCURSOR
  70. 0,
  71. FIELD_OFFSET(CLS, hbrBackground), // GCL_HBRBACKGROUND
  72. 0,
  73. FIELD_OFFSET(CLS, lpszMenuName) // GCL_MENUNAME
  74. };
  75. /*
  76. * INDEX_OFFSET must refer to the first entry of afClassDWord[]
  77. */
  78. #define INDEX_OFFSET GCLP_HICONSM
  79. /***************************************************************************\
  80. * GetClassData
  81. *
  82. * GetClassWord and GetClassLong are now identical routines because they both
  83. * can return DWORDs. This single routine performs the work for them both
  84. * by using two arrays; afClassDWord to determine whether the result should be
  85. * a UINT or a DWORD, and aiClassOffset to find the correct offset into the
  86. * CLS structure for a given GCL_ or GCL_ index.
  87. *
  88. * History:
  89. * 11-19-90 darrinm Wrote.
  90. \***************************************************************************/
  91. ULONG_PTR _GetClassData(
  92. PCLS pcls,
  93. PWND pwnd, // used for transition to kernel-mode for GCL_WNDPROC
  94. int index,
  95. BOOL bAnsi)
  96. {
  97. KERNEL_ULONG_PTR dwData;
  98. DWORD dwCPDType = 0;
  99. index -= INDEX_OFFSET;
  100. if (index < 0) {
  101. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  102. return 0;
  103. }
  104. UserAssert(index >= 0);
  105. UserAssert(index < sizeof(afClassDWord));
  106. UserAssert(sizeof(afClassDWord) == sizeof(aiClassOffset));
  107. if (afClassDWord[index] == sizeof(DWORD)) {
  108. dwData = *(KPDWORD)(((KPBYTE)pcls) + aiClassOffset[index]);
  109. } else if (afClassDWord[index] == sizeof(KERNEL_ULONG_PTR)) {
  110. dwData = *(KPKERNEL_ULONG_PTR)(((KPBYTE)pcls) + aiClassOffset[index]);
  111. } else {
  112. dwData = (DWORD)*(KPWORD)(((KPBYTE)pcls) + aiClassOffset[index]);
  113. }
  114. index += INDEX_OFFSET;
  115. /*
  116. * If we're returning an icon or cursor handle, do the reverse
  117. * mapping here.
  118. */
  119. switch(index) {
  120. case GCLP_MENUNAME:
  121. if (IS_PTR(pcls->lpszMenuName)) {
  122. /*
  123. * The Menu Name is a real string: return the client-side address.
  124. * (If the class was registered by another app this returns an
  125. * address in that app's addr. space, but it's the best we can do)
  126. */
  127. dwData = bAnsi ?
  128. (ULONG_PTR)pcls->lpszClientAnsiMenuName :
  129. (ULONG_PTR)pcls->lpszClientUnicodeMenuName;
  130. }
  131. break;
  132. case GCLP_HICON:
  133. case GCLP_HCURSOR:
  134. case GCLP_HICONSM:
  135. /*
  136. * We have to go to the kernel to convert the pcursor to a handle because
  137. * cursors are allocated out of POOL, which is not accessable from the client.
  138. */
  139. if (dwData) {
  140. dwData = NtUserCallHwndParam(PtoH(pwnd), index, SFI_GETCLASSICOCUR);
  141. }
  142. break;
  143. case GCLP_WNDPROC:
  144. {
  145. /*
  146. * Always return the client wndproc in case this is a server
  147. * window class.
  148. */
  149. if (pcls->CSF_flags & CSF_SERVERSIDEPROC) {
  150. dwData = MapServerToClientPfn(dwData, bAnsi);
  151. } else {
  152. KERNEL_ULONG_PTR dwT = dwData;
  153. dwData = MapClientNeuterToClientPfn(pcls, dwT, bAnsi);
  154. /*
  155. * If the client mapping didn't change the window proc then see if
  156. * we need a callproc handle.
  157. */
  158. if (dwData == dwT) {
  159. /*
  160. * Need to return a CallProc handle if there is an Ansi/Unicode mismatch
  161. */
  162. if (bAnsi != !!(pcls->CSF_flags & CSF_ANSIPROC)) {
  163. dwCPDType |= bAnsi ? CPD_ANSI_TO_UNICODE : CPD_UNICODE_TO_ANSI;
  164. }
  165. }
  166. }
  167. if (dwCPDType) {
  168. ULONG_PTR dwCPD;
  169. dwCPD = GetCPD(pwnd, dwCPDType | CPD_WNDTOCLS, KERNEL_ULONG_PTR_TO_ULONG_PTR(dwData));
  170. if (dwCPD) {
  171. dwData = dwCPD;
  172. } else {
  173. RIPMSG0(RIP_WARNING, "GetClassLong unable to alloc CPD returning handle\n");
  174. }
  175. }
  176. }
  177. break;
  178. case GCL_CBCLSEXTRA:
  179. if ((pcls->CSF_flags & CSF_WOWCLASS) && (pcls->CSF_flags & CSF_WOWEXTRA)) {
  180. /*
  181. * The 16-bit app changed its Extra bytes value. Return the changed
  182. * value. FritzS
  183. */
  184. return PWCFromPCLS(pcls)->iClsExtra;
  185. }
  186. else
  187. return pcls->cbclsExtra;
  188. break;
  189. /*
  190. * WOW uses a pointer straight into the class structure.
  191. */
  192. case GCLP_WOWWORDS:
  193. if (pcls->CSF_flags & CSF_WOWCLASS) {
  194. return ((ULONG_PTR)PWCFromPCLS(pcls));
  195. } else
  196. return 0;
  197. case GCL_STYLE:
  198. dwData &= CS_VALID;
  199. break;
  200. }
  201. return KERNEL_ULONG_PTR_TO_ULONG_PTR(dwData);
  202. }
  203. /***************************************************************************\
  204. * _GetClassLong (API)
  205. *
  206. * Return a class long. Positive index values return application class longs
  207. * while negative index values return system class longs. The negative
  208. * indices are published in WINDOWS.H.
  209. *
  210. * History:
  211. * 10-16-90 darrinm Wrote.
  212. \***************************************************************************/
  213. ULONG_PTR _GetClassLongPtr(
  214. PWND pwnd,
  215. int index,
  216. BOOL bAnsi)
  217. {
  218. PCLS pcls = REBASEALWAYS(pwnd, pcls);
  219. if (index < 0) {
  220. return _GetClassData(pcls, pwnd, index, bAnsi);
  221. } else {
  222. if ((UINT)index + sizeof(ULONG_PTR) > (UINT)pcls->cbclsExtra) {
  223. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  224. return 0;
  225. } else {
  226. ULONG_PTR UNALIGNED * KPTR_MODIFIER pudw;
  227. pudw = (ULONG_PTR UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pcls + 1) + index);
  228. return *pudw;
  229. }
  230. }
  231. }
  232. #ifdef _WIN64
  233. DWORD _GetClassLong(
  234. PWND pwnd,
  235. int index,
  236. BOOL bAnsi)
  237. {
  238. PCLS pcls = REBASEALWAYS(pwnd, pcls);
  239. if (index < 0) {
  240. if (index < INDEX_OFFSET || afClassDWord[index - INDEX_OFFSET] > sizeof(DWORD)) {
  241. RIPERR1(ERROR_INVALID_INDEX, RIP_WARNING, "GetClassLong: invalid index %d", index);
  242. return 0;
  243. }
  244. return (DWORD)_GetClassData(pcls, pwnd, index, bAnsi);
  245. } else {
  246. if ((UINT)index + sizeof(DWORD) > (UINT)pcls->cbclsExtra) {
  247. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  248. return 0;
  249. } else {
  250. DWORD UNALIGNED * KPTR_MODIFIER pudw;
  251. pudw = (DWORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pcls + 1) + index);
  252. return *pudw;
  253. }
  254. }
  255. }
  256. #endif
  257. /***************************************************************************\
  258. * GetClassWord (API)
  259. *
  260. * Return a class word. Positive index values return application class words
  261. * while negative index values return system class words. The negative
  262. * indices are published in WINDOWS.H.
  263. *
  264. * History:
  265. * 10-16-90 darrinm Wrote.
  266. \***************************************************************************/
  267. FUNCLOG2(LOG_GENERAL, WORD, DUMMYCALLINGTYPE, GetClassWord, HWND, hwnd, int, index)
  268. WORD GetClassWord(
  269. HWND hwnd,
  270. int index)
  271. {
  272. PWND pwnd;
  273. PCLS pclsClient;
  274. pwnd = ValidateHwnd(hwnd);
  275. if (pwnd == NULL)
  276. return 0;
  277. pclsClient = (PCLS)REBASEALWAYS(pwnd, pcls);
  278. try {
  279. if (index == GCW_ATOM) {
  280. return (WORD)_GetClassData(pclsClient, pwnd, index, FALSE);
  281. } else {
  282. if ((index < 0) || ((UINT)index + sizeof(WORD) > (UINT)pclsClient->cbclsExtra)) {
  283. RIPERR0(ERROR_INVALID_INDEX, RIP_VERBOSE, "");
  284. return 0;
  285. } else {
  286. WORD UNALIGNED * KPTR_MODIFIER puw;
  287. puw = (WORD UNALIGNED * KPTR_MODIFIER)((KPBYTE)(pclsClient + 1) + index);
  288. return *puw;
  289. }
  290. }
  291. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  292. RIPERR1(ERROR_INVALID_WINDOW_HANDLE,
  293. RIP_WARNING,
  294. "Window %x no longer valid",
  295. hwnd);
  296. return 0;
  297. }
  298. }
  299. /***************************************************************************\
  300. * VersionRegisterClass
  301. *
  302. * Tries to register a versioned class by loading calling a
  303. * predefined entry point in the DLL lpzDllName in the specified activation context.
  304. *
  305. * History:
  306. * 10-16-01 msadek Wrote.
  307. \***************************************************************************/
  308. BOOL VersionRegisterClass(
  309. LPWSTR lpzClassName,
  310. LPWSTR lpzDllName,
  311. PACTIVATION_CONTEXT lpActivationContext,
  312. HMODULE *phModule)
  313. {
  314. BOOL bRet = FALSE;
  315. HMODULE hDllMod = NULL;
  316. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame),
  317. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  318. RtlActivateActivationContextUnsafeFast(&ActivationFrame, lpActivationContext);
  319. __try {
  320. /*
  321. * Try to register it, by loading its DLL. Notice that this DLL
  322. * will never get unloaded unless we failed to create the window.
  323. * but once we created a window by loading this DLL will never free it.
  324. */
  325. PREGISTERCLASSNAMEW pRegisterClassNameW = NULL;
  326. if ((hDllMod = LoadLibraryW(lpzDllName)) &&
  327. (pRegisterClassNameW = (PREGISTERCLASSNAMEW)GetProcAddress(hDllMod, "RegisterClassNameW"))) {
  328. if (IS_PTR(lpzClassName)) {
  329. bRet = (*pRegisterClassNameW)(lpzClassName);
  330. } else {
  331. UNICODE_STRING UnicodeClassName;
  332. WCHAR Buffer[MAX_ATOM_LEN];
  333. UnicodeClassName.MaximumLength = (USHORT)(MAX_ATOM_LEN * sizeof(WCHAR));
  334. UnicodeClassName.Buffer = Buffer;
  335. if (NtUserGetAtomName((ATOM)lpzClassName, &UnicodeClassName)) {
  336. bRet = (*pRegisterClassNameW)(Buffer);
  337. }
  338. }
  339. }
  340. } __finally {
  341. RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
  342. }
  343. if (!bRet && hDllMod != NULL) {
  344. FREE_LIBRARY_SAVE_ERROR(hDllMod);
  345. } else if (phModule) {
  346. *phModule = hDllMod;
  347. }
  348. return bRet;
  349. }
  350. /***************************************************************************\
  351. * ClassNameToVersion
  352. *
  353. * Map class name to class name+version.
  354. * lpClassName : Class name to be mapped, it may be ANSI, Unicode or an Atom.
  355. * pClassVerName : Buffer to receive the class name+version.
  356. * lpDllName : if it is not NULL it will point to the DLL owns this class
  357. name.
  358. * bIsANSI : True of lpClassName is ANSI, FALSE if it is Unicode.
  359. *
  360. * Return: If it succeed it returns lpClassName or lpClassName.
  361. * if it failed it returns NULL.
  362. *
  363. * History:
  364. * 08-01-00 MHamid Wrote.
  365. \***************************************************************************/
  366. LPWSTR
  367. ClassNameToVersion(
  368. LPCWSTR lpClassName,
  369. LPWSTR pClassVerName,
  370. LPWSTR *lpDllName,
  371. PACTIVATION_CONTEXT* lppActivationContext,
  372. BOOL bIsANSI
  373. )
  374. {
  375. int cbSrc;
  376. int cbDst;
  377. UNICODE_STRING UnicodeClassName;
  378. ACTIVATION_CONTEXT_SECTION_KEYED_DATA acskd;
  379. ACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION UNALIGNED * pRedirEntry;
  380. LPWSTR lpClassNameRet;
  381. LPWSTR pwstr;
  382. ULONG strLength;
  383. LPWSTR Buffer;
  384. NTSTATUS Status;
  385. acskd.ActivationContext = NULL;
  386. if (lppActivationContext != NULL) {
  387. *lppActivationContext = NULL;
  388. }
  389. /*
  390. * Allocate local buffer.
  391. */
  392. Buffer = UserLocalAlloc(0, MAX_ATOM_LEN * sizeof(WCHAR));
  393. if (Buffer == NULL) {
  394. return NULL;
  395. }
  396. /*
  397. * Capture lpClassName into a local buffer.
  398. */
  399. if (IS_PTR(lpClassName)) {
  400. /*
  401. * lpClassName is string.
  402. */
  403. if (bIsANSI) {
  404. /*
  405. * it is ANSI then convert it to unicode.
  406. */
  407. cbSrc = strlen((LPSTR)lpClassName) + 1;
  408. RtlMultiByteToUnicodeN(Buffer,
  409. MAX_ATOM_LEN * sizeof(WCHAR), &cbDst,
  410. (LPSTR)lpClassName, cbSrc);
  411. } else {
  412. /*
  413. * It is already unicode, then just copy it.
  414. */
  415. cbSrc = min (wcslen(lpClassName) + 1, MAX_ATOM_LEN);
  416. cbSrc *= sizeof(WCHAR);
  417. RtlCopyMemory(Buffer, lpClassName, cbSrc);
  418. }
  419. /*
  420. * Build the UNICODE_STRING
  421. */
  422. RtlInitUnicodeString(&UnicodeClassName, Buffer);
  423. } else {
  424. /*
  425. * lpClassName is an atom, get its name and build the UNICODE_STRING
  426. */
  427. UnicodeClassName.MaximumLength = (USHORT)(MAX_ATOM_LEN * sizeof(WCHAR));
  428. UnicodeClassName.Buffer = Buffer;
  429. UnicodeClassName.Length = (USHORT)NtUserGetAtomName((ATOM)lpClassName, &UnicodeClassName) * sizeof(WCHAR);
  430. if (!UnicodeClassName.Length) {
  431. lpClassNameRet = NULL;
  432. goto Free_Buffer;
  433. }
  434. }
  435. /*
  436. * Call Fusion to map the class name.
  437. */
  438. RtlZeroMemory(&acskd, sizeof(acskd));
  439. acskd.Size = sizeof(acskd);
  440. Status = RtlFindActivationContextSectionString(
  441. FIND_ACTIVATION_CONTEXT_SECTION_KEY_RETURN_ACTIVATION_CONTEXT,
  442. NULL,
  443. ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
  444. &UnicodeClassName,
  445. &acskd);
  446. /*
  447. * If there is no Activation Section we will use the plain class name.
  448. */
  449. if ((Status == STATUS_SXS_SECTION_NOT_FOUND) ||
  450. (Status == STATUS_SXS_KEY_NOT_FOUND)) {
  451. lpClassNameRet = (LPWSTR)lpClassName;
  452. goto Free_Buffer;
  453. }
  454. /*
  455. * Case of failure return NULL.
  456. */
  457. if (!NT_SUCCESS(Status) ||
  458. acskd.DataFormatVersion != ACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION_FORMAT_WHISTLER) {
  459. lpClassNameRet = NULL;
  460. goto Free_Buffer;
  461. }
  462. pRedirEntry = (PACTIVATION_CONTEXT_DATA_WINDOW_CLASS_REDIRECTION) acskd.Data;
  463. UserAssert(pRedirEntry);
  464. pwstr = (LPWSTR)(((ULONG_PTR) pRedirEntry) + pRedirEntry->VersionSpecificClassNameOffset);
  465. strLength = pRedirEntry->VersionSpecificClassNameLength + sizeof(WCHAR);
  466. if (lpDllName) {
  467. *lpDllName = (LPWSTR)(((ULONG_PTR) acskd.SectionBase) + pRedirEntry->DllNameOffset);
  468. }
  469. UserAssert(pwstr);
  470. UserAssert(strLength <= MAX_ATOM_LEN * sizeof(WCHAR));
  471. /*
  472. * if the call is ANSI then convert the class name+version to ANSI string.
  473. */
  474. if (bIsANSI) {
  475. RtlUnicodeToMultiByteN((LPSTR)pClassVerName,
  476. MAX_ATOM_LEN, &cbDst,
  477. pwstr, strLength);
  478. } else {
  479. /*
  480. * if it is unicode then just copy the class name+version to the caller's buffer.
  481. */
  482. RtlCopyMemory(pClassVerName, pwstr, strLength);
  483. }
  484. /*
  485. * And return it.
  486. */
  487. lpClassNameRet = pClassVerName;
  488. if (lppActivationContext != NULL) {
  489. *lppActivationContext = acskd.ActivationContext;
  490. acskd.ActivationContext = NULL;
  491. }
  492. Free_Buffer:
  493. /*
  494. * Don't forget to free the local memory.
  495. */
  496. UserLocalFree(Buffer);
  497. if (acskd.ActivationContext != NULL) {
  498. RtlReleaseActivationContext(acskd.ActivationContext);
  499. acskd.ActivationContext = NULL;
  500. }
  501. return lpClassNameRet;
  502. }