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.

610 lines
19 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: acons.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains code for dealing with animated icons/cursors.
  7. *
  8. * History:
  9. * 10-02-91 DarrinM Created.
  10. * 07-30-92 DarrinM Unicodized.
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /***************************************************************************\
  15. * zzzSetSystemCursor (API)
  16. *
  17. * Replace a system (aka 'public') cursor with a user provided one. The new
  18. * cursor is pulled from a file (.CUR, .ICO, or .ANI) specified in WIN.INI.
  19. *
  20. * History:
  21. * 12/26/1991 DarrinM Created.
  22. * 08/04/1992 DarrinM Recreated.
  23. * 10/14/1995 SanfordS Win95 support.
  24. \***************************************************************************/
  25. BOOL zzzSetSystemCursor(
  26. PCURSOR pcur,
  27. DWORD id)
  28. {
  29. int i;
  30. if (!CheckWinstaWriteAttributesAccess()) {
  31. return FALSE;
  32. }
  33. UserAssert(pcur);
  34. /*
  35. * Check if this cursor is one of the replaceable ones.
  36. */
  37. for (i = 0; i < COCR_CONFIGURABLE; i++) {
  38. if (gasyscur[i].Id == (WORD)id) {
  39. break;
  40. }
  41. }
  42. /*
  43. * Not replaceable, bail out.
  44. */
  45. if (i == COCR_CONFIGURABLE) {
  46. RIPMSG1(RIP_WARNING, "_SetSystemCursor: called with bad id 0x%x", id);
  47. return FALSE;
  48. }
  49. return zzzSetSystemImage(pcur, gasyscur[i].spcur);
  50. }
  51. /***********************************************************************\
  52. * zzzSetSystemImage
  53. *
  54. * Places the contents of pcur into pcurSys and destroys pcur.
  55. *
  56. * 10/14/1995 Created SanfordS
  57. \***********************************************************************/
  58. BOOL zzzSetSystemImage(
  59. PCURSOR pcur,
  60. PCURSOR pcurSys)
  61. {
  62. #define CBCOPY (max(sizeof(CURSOR), sizeof(ACON)) - FIELD_OFFSET(CURSOR, CI_COPYSTART))
  63. #define pacon ((PACON)pcur)
  64. char cbT[CBCOPY];
  65. UINT CURSORF_flags;
  66. UserAssert(pcurSys);
  67. if (pcurSys == pcur) {
  68. return TRUE;
  69. }
  70. /*
  71. * All ssytem images being replaced should have ordinal names
  72. * and reference the USER module and be unowned.
  73. */
  74. UserAssert(!IS_PTR(pcurSys->strName.Buffer));
  75. UserAssert(pcurSys->atomModName == atomUSER32);
  76. /*
  77. * if pcur was an acon, transfer frame ownerships to pcurSys.
  78. */
  79. UserAssert(pcurSys->head.ppi == NULL);
  80. if (pcur->CURSORF_flags & CURSORF_ACON && pcur->head.ppi != NULL) {
  81. int i;
  82. PHE phe = HMPheFromObject(pcurSys);
  83. PTHREADINFO ptiOwner = ((PPROCESSINFO)phe->pOwner)->ptiList;
  84. for (i = 0; i < pacon->cpcur; i++) {
  85. HMChangeOwnerProcess(pacon->aspcur[i], ptiOwner);
  86. pacon->aspcur[i]->head.ppi = NULL;
  87. }
  88. }
  89. /*
  90. * If this assert fails, the CURSOR and ACON structures were changed
  91. * incorrectly - read the comments in user.h and wingdi.w around
  92. * tagCURSOR, tagACON, and CURSINFO.
  93. */
  94. UserAssert(FIELD_OFFSET(CURSOR, CI_FIRST) == FIELD_OFFSET(ACON, CI_FIRST));
  95. /*
  96. * swap everything starting from CI_COPYSTART.
  97. */
  98. RtlCopyMemory(cbT, &pcur->CI_COPYSTART, CBCOPY);
  99. RtlCopyMemory(&pcur->CI_COPYSTART, &pcurSys->CI_COPYSTART, CBCOPY);
  100. RtlCopyMemory(&pcurSys->CI_COPYSTART, cbT, CBCOPY);
  101. /*
  102. * Swap the CURSORF_ACON flags since they go with the swapped data.
  103. */
  104. CURSORF_flags = pcur->CURSORF_flags & CURSORF_ACON;
  105. pcur->CURSORF_flags =
  106. (pcur->CURSORF_flags & ~CURSORF_ACON) |
  107. (pcurSys->CURSORF_flags & CURSORF_ACON);
  108. pcurSys->CURSORF_flags =
  109. (pcurSys->CURSORF_flags & ~CURSORF_ACON) | CURSORF_flags;
  110. /*
  111. * If we swapped acons into pcur, then we need to change the ownerhsip to
  112. * make sure they can get destroyed.
  113. */
  114. if (pcur->CURSORF_flags & CURSORF_ACON) {
  115. int i;
  116. PTHREADINFO ptiCurrent = PtiCurrent();
  117. for (i = 0; i < pacon->cpcur; i++) {
  118. HMChangeOwnerProcess(pacon->aspcur[i], ptiCurrent);
  119. }
  120. }
  121. /*
  122. * Use THREADCLEANUP so system cursors are not destroyed.
  123. */
  124. _DestroyCursor(pcur, CURSOR_THREADCLEANUP);
  125. /*
  126. * If the current logical cursor is changing then force the current physical
  127. * cursor to change.
  128. */
  129. if (gpcurLogCurrent == pcurSys) {
  130. gpcurLogCurrent = NULL;
  131. gpcurPhysCurrent = NULL;
  132. zzzUpdateCursorImage();
  133. }
  134. /*
  135. * Mark the cursor as a system cursor that can be shadowed by GDI.
  136. */
  137. pcurSys->CURSORF_flags |= CURSORF_SYSTEM;
  138. return TRUE;
  139. #undef pacon
  140. #undef CBCOPY
  141. }
  142. /***************************************************************************\
  143. * _GetCursorFrameInfo (API)
  144. *
  145. * Example usage:
  146. *
  147. * hcur = _GetCursorFrameInfo(hacon, NULL, 4, &ccur);
  148. * hcur = _GetCursorFrameInfo(NULL, IDC_NORMAL, 0, &ccur); // get device's arrow
  149. *
  150. * History:
  151. * 08-05-92 DarrinM Created.
  152. \***************************************************************************/
  153. PCURSOR _GetCursorFrameInfo(
  154. PCURSOR pcur,
  155. int iFrame,
  156. PJIF pjifRate,
  157. LPINT pccur)
  158. {
  159. /*
  160. * If this is only a single cursor (not an ACON) just return it and
  161. * a frame count of 1.
  162. */
  163. if (!(pcur->CURSORF_flags & CURSORF_ACON)) {
  164. *pccur = 1;
  165. *pjifRate = 0;
  166. return pcur;
  167. }
  168. /*
  169. * Return the useful cursor information for the specified frame
  170. * of the ACON.
  171. */
  172. #define pacon ((PACON)pcur)
  173. if (iFrame < 0 || iFrame >= pacon->cicur) {
  174. return NULL;
  175. }
  176. *pccur = pacon->cicur;
  177. *pjifRate = pacon->ajifRate[iFrame];
  178. return pacon->aspcur[pacon->aicur[iFrame]];
  179. #undef pacon
  180. }
  181. /***************************************************************************\
  182. * DestroyAniIcon
  183. *
  184. * Free all the individual cursors that make up the frames of an animated
  185. * icon.
  186. *
  187. * WARNING: DestroyAniIcon assumes that all fields that an ACON shares with
  188. * a cursor will be freed by some cursor code (probably the cursor function
  189. * that calls this one).
  190. *
  191. * History:
  192. * 08-04-92 DarrinM Created.
  193. \***************************************************************************/
  194. BOOL DestroyAniIcon(
  195. PACON pacon)
  196. {
  197. int i;
  198. PCURSOR pcur;
  199. for (i = 0; i < pacon->cpcur; i++) {
  200. UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME);
  201. /*
  202. * This should not be a public acon; if it is, unlock won't be able
  203. * to destroy it. If destroy a public icon, ownership must be called
  204. * before calling this function (see zzzSetSystemImage).
  205. */
  206. UserAssert(GETPPI(pacon->aspcur[i]) != NULL);
  207. pcur = Unlock(&pacon->aspcur[i]);
  208. if (pcur != NULL) {
  209. _DestroyCursor(pcur, CURSOR_ALWAYSDESTROY);
  210. }
  211. }
  212. UserFreePool(pacon->aspcur);
  213. return TRUE;
  214. }
  215. /***********************************************************************\
  216. * LinkCursor
  217. *
  218. * Links unlinked cursor into the apropriate icon cache IFF its the
  219. * type of cursor that needs to be in the cache.
  220. *
  221. * Note that changing ownership if cursor objects needs to keep this
  222. * cache linking in mind. The unlink routine in
  223. * DestroyEmptyCursorObject() will handle public cursor objects made
  224. * local but that is all.
  225. *
  226. * 10/18/1995 Created SanfordS
  227. \***********************************************************************/
  228. VOID LinkCursor(
  229. PCURSOR pcur)
  230. {
  231. /*
  232. * Should never try to link twice!
  233. */
  234. UserAssert(!(pcur->CURSORF_flags & CURSORF_LINKED));
  235. /*
  236. * We don't cache acon frames because they all belong to the
  237. * root acon object.
  238. *
  239. * We don't cache process owned objects that are not LRSHARED
  240. * either.
  241. */
  242. if (!(pcur->CURSORF_flags & CURSORF_ACONFRAME)) {
  243. PPROCESSINFO ppi = pcur->head.ppi;
  244. if (ppi == NULL) {
  245. /*
  246. * Public cache object.
  247. */
  248. pcur->pcurNext = gpcurFirst;
  249. gpcurFirst = pcur;
  250. pcur->CURSORF_flags |= CURSORF_LINKED;
  251. } else if (pcur->CURSORF_flags & CURSORF_LRSHARED) {
  252. /*
  253. * Private cache LR_SHARED object.
  254. */
  255. pcur->pcurNext = ppi->pCursorCache;
  256. ppi->pCursorCache = pcur;
  257. pcur->CURSORF_flags |= CURSORF_LINKED;
  258. }
  259. }
  260. }
  261. /***************************************************************************\
  262. * ProcessAlphaBitmap
  263. *
  264. * Examines the source bitmap to see if it supports and uses an alpha
  265. * channel. If it does, a new DIB section is created that contains a
  266. * premultiplied copy of the data from the source bitmap.
  267. *
  268. * If the source bitmap is not capable of supporting, or simply doesn't use,
  269. * an alpha channel, the return value is NULL.
  270. *
  271. * If an error occurs, the return value is NULL.
  272. *
  273. * 8/10/2000 Created DwayneN
  274. \***************************************************************************/
  275. HBITMAP ProcessAlphaBitmap(
  276. HBITMAP hbmSource)
  277. {
  278. BITMAP bmp;
  279. BITMAPINFO bi;
  280. HBITMAP hbmAlpha;
  281. RGBQUAD * pAlphaBitmapBits;
  282. DWORD cPixels;
  283. DWORD i;
  284. RGBQUAD pixel;
  285. BOOL fAlphaChannel;
  286. /*
  287. * There are several code paths that end up calling us with a NULL
  288. * hbmSource. This is fine, in that it simply indicates that there
  289. * is no alpha channel.
  290. */
  291. if (hbmSource == NULL) {
  292. return NULL;
  293. }
  294. if (GreExtGetObjectW(hbmSource, sizeof(BITMAP), &bmp) == 0) {
  295. return NULL;
  296. }
  297. /*
  298. * Only single plane, 32bpp bitmaps can even contain an alpha channel.
  299. */
  300. if (bmp.bmPlanes != 1 ||
  301. bmp.bmBitsPixel != 32) {
  302. return NULL;
  303. }
  304. /*
  305. * Allocate room to hold the source bitmap's bits for examination.
  306. * We actually allocate a DIB - that will be passed out if the
  307. * source bitmap does indeed contain an alpha channel.
  308. */
  309. RtlZeroMemory(&bi, sizeof(bi));
  310. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  311. bi.bmiHeader.biWidth = bmp.bmWidth;
  312. bi.bmiHeader.biHeight = bmp.bmHeight;
  313. bi.bmiHeader.biPlanes = 1;
  314. bi.bmiHeader.biBitCount = 32;
  315. bi.bmiHeader.biCompression = BI_RGB;
  316. hbmAlpha = GreCreateDIBitmapReal(gpDispInfo->hdcScreen,
  317. 0,
  318. NULL,
  319. (LPBITMAPINFO)&bi,
  320. DIB_RGB_COLORS,
  321. sizeof(bi),
  322. 0,
  323. NULL,
  324. 0,
  325. NULL,
  326. 0,
  327. 0,
  328. &pAlphaBitmapBits);
  329. if (NULL != hbmAlpha) {
  330. /*
  331. * Set up the header again in case it was tweaked by GreCreateDIBitmapReal.
  332. */
  333. RtlZeroMemory(&bi, sizeof(bi));
  334. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  335. bi.bmiHeader.biWidth = bmp.bmWidth;
  336. bi.bmiHeader.biHeight = bmp.bmHeight;
  337. bi.bmiHeader.biPlanes = 1;
  338. bi.bmiHeader.biBitCount = 32;
  339. bi.bmiHeader.biCompression = BI_RGB;
  340. /*
  341. * Copy the bitmap data from the source bitmap into our alpha DIB.
  342. */
  343. if (0 == GreGetDIBitsInternal(gpDispInfo->hdcScreen,
  344. hbmSource,
  345. 0,
  346. bi.bmiHeader.biHeight,
  347. (LPBYTE) pAlphaBitmapBits,
  348. (LPBITMAPINFO)&bi,
  349. DIB_RGB_COLORS,
  350. BITMAPWIDTHSIZE(bi.bmiHeader.biWidth, bi.bmiHeader.biHeight,1,32),
  351. bi.bmiHeader.biSize)) {
  352. GreDeleteObject(hbmAlpha);
  353. return NULL;
  354. }
  355. /*
  356. * We need to examine the source bitmap to see if it contains an alpha
  357. * channel. This is simply a heuristic since there is no format difference
  358. * between 32bpp 888 RGB image and 32bpp 8888 ARGB image. What we do is look
  359. * for any non-0 alpha/reserved values. If all alpha/reserved values are 0,
  360. * then the image would be 100% invisible if blitted with alpha - which is
  361. * almost cerainly not the desired result. So we assume such bitmaps are
  362. * 32bpp non-alpha.
  363. */
  364. cPixels = bi.bmiHeader.biWidth * bi.bmiHeader.biHeight;
  365. fAlphaChannel = FALSE;
  366. for (i = 0; i < cPixels; i++) {
  367. if (pAlphaBitmapBits[i].rgbReserved != 0)
  368. {
  369. fAlphaChannel = TRUE;
  370. break;
  371. }
  372. }
  373. if (fAlphaChannel == FALSE) {
  374. GreDeleteObject(hbmAlpha);
  375. return NULL;
  376. }
  377. /*
  378. * The source bitmap appears to use an alpha channel. Spin through our
  379. * copy of the bits and premultiply them. This is a necessary step to
  380. * prepare an alpha bitmap for use by GDI.
  381. */
  382. for (i=0; i < cPixels; i++) {
  383. pixel = pAlphaBitmapBits[i];
  384. pAlphaBitmapBits[i].rgbRed = (pixel.rgbRed * pixel.rgbReserved) / 0xFF;
  385. pAlphaBitmapBits[i].rgbGreen = (pixel.rgbGreen * pixel.rgbReserved) / 0xFF;
  386. pAlphaBitmapBits[i].rgbBlue = (pixel.rgbBlue * pixel.rgbReserved) / 0xFF;
  387. }
  388. }
  389. return hbmAlpha;
  390. }
  391. /***************************************************************************\
  392. * _SetCursorIconData
  393. *
  394. * Initializes empty cursor/icons. Note that the string buffers and
  395. * pcurData are not captured. If a fault occurs in this routine,
  396. * all allocated memory will be freed when the cursors are destroyed.
  397. *
  398. * Critical side effect: If this function fails, the bitmaps must NOT
  399. * have been made public. (See CreateIconIndirect()).
  400. *
  401. * History:
  402. * 12-01-94 JimA Created.
  403. \***************************************************************************/
  404. BOOL _SetCursorIconData(
  405. PCURSOR pcur,
  406. PUNICODE_STRING cczpstrModName,
  407. PUNICODE_STRING cczpstrName,
  408. PCURSORDATA pcurData,
  409. DWORD cbData)
  410. {
  411. #define pacon ((PACON)pcur)
  412. int i;
  413. #if DBG
  414. BOOL fSuccess;
  415. #endif
  416. pcur->CURSORF_flags |= pcurData->CURSORF_flags;
  417. pcur->rt = pcurData->rt;
  418. if (pcurData->CURSORF_flags & CURSORF_ACON) {
  419. UserAssert(pacon->aspcur == NULL);
  420. RtlCopyMemory(&pacon->cpcur,
  421. &pcurData->cpcur,
  422. sizeof(ACON) - FIELD_OFFSET(ACON, cpcur));
  423. } else {
  424. RtlCopyMemory(&pcur->CI_COPYSTART,
  425. &pcurData->CI_COPYSTART,
  426. sizeof(CURSOR) - FIELD_OFFSET(CURSOR, CI_COPYSTART));
  427. }
  428. /*
  429. * Save name of the cursor resource
  430. */
  431. if (cczpstrName->Length != 0){
  432. /*
  433. * AllocateUnicodeString guards access to src Buffer with
  434. * a try block.
  435. */
  436. if (!AllocateUnicodeString(&pcur->strName, cczpstrName))
  437. return FALSE;
  438. } else {
  439. pcur->strName = *cczpstrName;
  440. }
  441. /*
  442. * Save the module name
  443. */
  444. if (cczpstrModName->Buffer) {
  445. /*
  446. * UserAddAtom guards access to the string with a try block.
  447. */
  448. pcur->atomModName = UserAddAtom(cczpstrModName->Buffer, FALSE);
  449. if (pcur->atomModName == 0) {
  450. return FALSE;
  451. }
  452. }
  453. if (pcur->CURSORF_flags & CURSORF_ACON) {
  454. /*
  455. * Stash away animated icon info.
  456. */
  457. pacon = (PACON)pcur;
  458. pacon->aspcur = UserAllocPool(cbData, TAG_CURSOR);
  459. if (pacon->aspcur == NULL)
  460. return FALSE;
  461. /*
  462. * Copy the handle array. Do this in a try/except so the
  463. * buffer will be freed if pcurData goes away. Even though
  464. * cursor destruction would free the array, a fault will
  465. * leave the contents in an undetermined state and cause
  466. * problems during cursor destruction.
  467. */
  468. try {
  469. RtlCopyMemory(pacon->aspcur, pcurData->aspcur, cbData);
  470. pacon->aicur = (DWORD *)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->aicur);
  471. pacon->ajifRate = (PJIF)((PBYTE)pacon->aspcur + (ULONG_PTR)pcurData->ajifRate);
  472. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  473. UserFreePool(pacon->aspcur);
  474. pacon->aspcur = NULL;
  475. return FALSE;
  476. }
  477. /*
  478. * Convert handles into pointers and lock them in.
  479. */
  480. for (i = 0; i < pacon->cpcur; i++) {
  481. PCURSOR pcurT;
  482. pcurT = (PCURSOR) HMValidateHandle(pacon->aspcur[i], TYPE_CURSOR);
  483. if (pcurT) {
  484. pacon->aspcur[i] = NULL;
  485. Lock(&pacon->aspcur[i], pcurT);
  486. } else {
  487. while (--i >= 0) {
  488. Unlock(&pacon->aspcur[i]);
  489. }
  490. UserFreePool(pacon->aspcur);
  491. pacon->aspcur = NULL;
  492. RIPMSG0(RIP_WARNING, "SetCursorIconData: invalid cursor handle for animated cursor");
  493. return FALSE;
  494. }
  495. }
  496. } else {
  497. PW32PROCESS W32Process = W32GetCurrentProcess();
  498. /*
  499. * If the icon's color bitmap has an alpha channel, pre-process it
  500. * and cache it in our hbmUserAlpha field.
  501. */
  502. pcur->hbmUserAlpha = ProcessAlphaBitmap(pcur->hbmColor);
  503. /*
  504. * Make the cursor and its bitmaps public - LAST THING!
  505. */
  506. UserAssert(pcur->hbmMask);
  507. UserAssert(pcur->cx);
  508. UserAssert(pcur->cy);
  509. /*
  510. * Make the cursor public so that it can be shared across processes.
  511. * Charge the curson to this very process GDI quota even if it's public.
  512. */
  513. #if DBG
  514. fSuccess =
  515. #endif
  516. GreSetBitmapOwner(pcur->hbmMask, OBJECT_OWNER_PUBLIC);
  517. UserAssert(fSuccess);
  518. GreIncQuotaCount(W32Process);
  519. if (pcur->hbmColor) {
  520. #if DBG
  521. fSuccess =
  522. #endif
  523. GreSetBitmapOwner(pcur->hbmColor, OBJECT_OWNER_PUBLIC);
  524. UserAssert(fSuccess);
  525. GreIncQuotaCount(W32Process);
  526. }
  527. if (pcur->hbmUserAlpha != NULL) {
  528. #if DBG
  529. fSuccess =
  530. #endif
  531. GreSetBitmapOwner(pcur->hbmUserAlpha, OBJECT_OWNER_PUBLIC);
  532. UserAssert(fSuccess);
  533. GreIncQuotaCount(W32Process);
  534. }
  535. }
  536. LinkCursor(pcur);
  537. return TRUE;
  538. #undef pacon
  539. }