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.

2821 lines
84 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: clipbrd.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Clipboard code.
  7. *
  8. * History:
  9. * 18-Nov-1990 ScottLu Ported from Win3.
  10. * 18-Nov-1990 ScottLu Added revalidation code
  11. * 11-Feb-1991 JimA Added access checks
  12. * 20-Jun-1995 ChrisWil Merged Chicago functionality.
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #undef DUMMY_TEXT_HANDLE
  17. #define DUMMY_TEXT_HANDLE (HANDLE)0x0001 // must be first dummy
  18. #define DUMMY_DIB_HANDLE (HANDLE)0x0002
  19. #define DUMMY_METARENDER_HANDLE (HANDLE)0x0003
  20. #define DUMMY_METACLONE_HANDLE (HANDLE)0x0004
  21. #define DUMMY_MAX_HANDLE (HANDLE)0x0004 // must be last dummy
  22. #define PRIVATEFORMAT 0
  23. #define GDIFORMAT 1
  24. #define HANDLEFORMAT 2
  25. #define METAFILEFORMAT 3
  26. #define CCHFORMATNAME 256
  27. #define IsTextHandle(fmt, hdata) \
  28. (((hdata) != DUMMY_TEXT_HANDLE) && \
  29. (((fmt) == CF_TEXT) || ((fmt) == CF_OEMTEXT) || ((fmt) == CF_UNICODETEXT)))
  30. #define IsDibHandle(fmt, hdata) \
  31. (((fmt) == CF_DIB) && ((hdata) != DUMMY_DIB_HANDLE))
  32. #define IsMetaDummyHandle(hdata) \
  33. ((hdata == DUMMY_METACLONE_HANDLE) || (hdata == DUMMY_METARENDER_HANDLE))
  34. /**************************************************************************\
  35. * CheckClipboardAccess
  36. *
  37. * Perform access check on the clipboard. Special case CSRSS threads
  38. * so that console windows on multiple windowstations will have
  39. * the correct access.
  40. *
  41. * 04-Jul-1995 JimA Created
  42. \**************************************************************************/
  43. PWINDOWSTATION CheckClipboardAccess(
  44. VOID)
  45. {
  46. NTSTATUS Status;
  47. PWINDOWSTATION pwinsta;
  48. BOOL fUseDesktop;
  49. PTHREADINFO pti;
  50. pti = PtiCurrentShared();
  51. /*
  52. * CSR process use to have NULL pwinsta. Now that it's assigned to
  53. * the services windowstation we have to explicitly use the desktop
  54. * for checking the access.
  55. */
  56. fUseDesktop = (pti->TIF_flags & TIF_CSRSSTHREAD) ? TRUE : FALSE;
  57. Status = ReferenceWindowStation(PsGetCurrentThread(),
  58. NULL,
  59. WINSTA_ACCESSCLIPBOARD,
  60. &pwinsta,
  61. fUseDesktop);
  62. if (!NT_SUCCESS(Status)) {
  63. RIPNTERR0(Status, RIP_WARNING,"Access to clipboard denied.");
  64. return NULL;
  65. }
  66. return pwinsta;
  67. }
  68. /**************************************************************************\
  69. * ConvertMemHandle
  70. *
  71. * Converts data to a clipboard-memory-handle. This special handle
  72. * contains the size-of-data in the first DWORD. The second DWORD points
  73. * back to the block.
  74. *
  75. * History:
  76. \**************************************************************************/
  77. HANDLE _ConvertMemHandle(
  78. LPBYTE ccxlpData,
  79. UINT cbData)
  80. {
  81. PCLIPDATA pClipData;
  82. UINT cbObject;
  83. /*
  84. * Round up size to account for CLIPDATA structure padding on Win64.
  85. */
  86. cbObject = max(sizeof(CLIPDATA), FIELD_OFFSET(CLIPDATA, abData) + cbData);
  87. /*
  88. * Catch integer overflow
  89. */
  90. if (cbObject < cbData) {
  91. return NULL;
  92. }
  93. pClipData = HMAllocObject(NULL,
  94. NULL,
  95. TYPE_CLIPDATA,
  96. cbObject);
  97. if (pClipData == NULL) {
  98. return NULL;
  99. }
  100. pClipData->cbData = cbData;
  101. try {
  102. RtlCopyMemory(&pClipData->abData, ccxlpData, cbData);
  103. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  104. HMFreeObject(pClipData);
  105. return NULL;
  106. }
  107. return PtoHq(pClipData);
  108. }
  109. /***************************************************************************\
  110. * _OpenClipboard (API)
  111. *
  112. * External routine. Opens the clipboard for reading/writing, etc.
  113. *
  114. * History:
  115. * 18-Nov-1990 ScottLu Ported from Win3.
  116. * 11-Feb-1991 JimA Added access checks.
  117. \***************************************************************************/
  118. BOOL _OpenClipboard(
  119. PWND pwnd,
  120. LPBOOL lpfEmptyClient)
  121. {
  122. PTHREADINFO pti;
  123. PWINDOWSTATION pwinsta;
  124. CheckLock(pwnd);
  125. if (lpfEmptyClient != NULL) {
  126. *lpfEmptyClient = FALSE;
  127. }
  128. /*
  129. * If the window is already destroyed, then the clipboard might not get
  130. * disowned when the window is finally unlocked.
  131. */
  132. if (pwnd != NULL && TestWF(pwnd, WFDESTROYED)) {
  133. RIPERR1(ERROR_INVALID_PARAMETER,
  134. RIP_WARNING,
  135. "Destroyed pwnd 0x%p trying to open the clipboard",
  136. pwnd);
  137. return FALSE;
  138. }
  139. /*
  140. * Blow it off if the caller does not have the proper access rights
  141. */
  142. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  143. return FALSE;
  144. }
  145. pti = PtiCurrent();
  146. /*
  147. * If this thread already has the clipboard open, then there's no
  148. * need to proceed further.
  149. */
  150. if ((pwnd == pwinsta->spwndClipOpen) && (pti == pwinsta->ptiClipLock))
  151. return TRUE;
  152. if ((pwnd != pwinsta->spwndClipOpen) && (pwinsta->ptiClipLock != NULL)) {
  153. /*
  154. * Only rip if the current-thread doesn't have the clipboard open.
  155. */
  156. if (pti != pwinsta->ptiClipLock) {
  157. RIPMSG0(RIP_VERBOSE,
  158. "OpenClipboard already out by another thread");
  159. }
  160. return FALSE;
  161. }
  162. UserAssert(pwnd == NULL || !TestWF(pwnd, WFDESTROYED));
  163. Lock(&pwinsta->spwndClipOpen, pwnd);
  164. pwinsta->ptiClipLock = pti;
  165. /*
  166. * The client side clipboard cache needs to be emptied if this thread
  167. * doesn't own the data in the clipboard.
  168. * Note: We only empty the 16bit clipboard if a 32bit guy owns the
  169. * clipboard.
  170. * Harvard graphics uses a handle put into the clipboard
  171. * by another app, and it expects that handle to still be good after the
  172. * clipboard has opened and closed mutilple times
  173. * There may be a problem here if app A puts in format foo and app B opens
  174. * the clipboard for format foo and then closes it and opens it again
  175. * format foo client side handle may not be valid. We may need some
  176. * sort of uniqueness counter to tell if the client side handle is
  177. * in sync with the server and always call the server or put the data
  178. * in share memory with some semaphore.
  179. *
  180. * pwinsta->spwndClipOwner: window that last called EmptyClipboard
  181. * pwinsta->ptiClipLock : thread that currently has the clipboard open
  182. */
  183. if (lpfEmptyClient != NULL) {
  184. if (!(pti->TIF_flags & TIF_16BIT) ||
  185. (pti->ppi->iClipSerialNumber != pwinsta->iClipSerialNumber)) {
  186. *lpfEmptyClient = (pwinsta->spwndClipOwner == NULL) ||
  187. (pwinsta->ptiClipLock->ppi !=
  188. GETPTI(pwinsta->spwndClipOwner)->ppi);
  189. pti->ppi->iClipSerialNumber = pwinsta->iClipSerialNumber;
  190. }
  191. }
  192. return TRUE;
  193. }
  194. /***************************************************************************\
  195. * xxxDrawClipboard
  196. *
  197. * Tells the clipboard viewers to redraw.
  198. *
  199. * History:
  200. * 18-Nov-1990 ScottLu Ported from Win3.
  201. \***************************************************************************/
  202. VOID xxxDrawClipboard(
  203. PWINDOWSTATION pwinsta)
  204. {
  205. /*
  206. * This is what WSF_CLIPBOARDCHANGED is for - to tell us to update the
  207. * clipboard viewers.
  208. */
  209. pwinsta->dwWSF_Flags &= ~WSF_CLIPBOARDCHANGED;
  210. if (pwinsta->ptiDrawingClipboard == NULL && pwinsta->spwndClipViewer != NULL) {
  211. TL tlpwndClipViewer;
  212. /*
  213. * Send the message that causes clipboard viewers to redraw.
  214. * Remember that we're sending this message so we don't send
  215. * this message twice.
  216. */
  217. pwinsta->ptiDrawingClipboard = PtiCurrent();
  218. ThreadLockAlways(pwinsta->spwndClipViewer, &tlpwndClipViewer);
  219. if (!(PtiCurrent()->TIF_flags & TIF_16BIT)) {
  220. /*
  221. * Desynchronize 32 bit apps.
  222. */
  223. xxxSendNotifyMessage(pwinsta->spwndClipViewer,
  224. WM_DRAWCLIPBOARD,
  225. (WPARAM)HW(pwinsta->spwndClipOwner),
  226. 0L);
  227. } else {
  228. xxxSendMessage(pwinsta->spwndClipViewer,
  229. WM_DRAWCLIPBOARD,
  230. (WPARAM)HW(pwinsta->spwndClipOwner),
  231. 0L);
  232. }
  233. ThreadUnlock(&tlpwndClipViewer);
  234. pwinsta->ptiDrawingClipboard = NULL;
  235. }
  236. }
  237. /***************************************************************************\
  238. * PasteScreenPalette
  239. *
  240. * Creates temp palette with all colors of screen, and sticks it on
  241. * clipboard.
  242. *
  243. * 20-Jun-1995 ChrisWil Ported from Chicago.
  244. \***************************************************************************/
  245. VOID PasteScreenPalette(
  246. PWINDOWSTATION pwinsta)
  247. {
  248. int irgb;
  249. int crgbPal;
  250. LPLOGPALETTE lppal;
  251. HPALETTE hpal = NULL;
  252. int crgbFixed;
  253. UserAssert(TEST_PUSIF(PUSIF_PALETTEDISPLAY));
  254. /*
  255. * Use current state of screen.
  256. */
  257. crgbPal = GreGetDeviceCaps(gpDispInfo->hdcScreen, SIZEPALETTE);
  258. if (GreGetSystemPaletteUse(gpDispInfo->hdcScreen) == SYSPAL_STATIC) {
  259. crgbFixed = GreGetDeviceCaps(gpDispInfo->hdcScreen, NUMRESERVED) / 2;
  260. } else {
  261. crgbFixed = 1;
  262. }
  263. lppal = (LPLOGPALETTE)UserAllocPool(sizeof(LOGPALETTE) +
  264. (sizeof(PALETTEENTRY) * crgbPal),
  265. TAG_CLIPBOARD);
  266. if (lppal == NULL) {
  267. return;
  268. }
  269. lppal->palVersion = 0x300;
  270. lppal->palNumEntries = (WORD)crgbPal;
  271. if (GreGetSystemPaletteEntries(gpDispInfo->hdcScreen, 0, crgbPal, lppal->palPalEntry)) {
  272. crgbPal -= crgbFixed;
  273. for (irgb = crgbFixed; irgb < crgbPal; irgb++) {
  274. /*
  275. * Any non-system palette entries need to have PC_NOCOLLAPSE
  276. * flag set.
  277. */
  278. lppal->palPalEntry[irgb].peFlags = PC_NOCOLLAPSE;
  279. }
  280. hpal = GreCreatePalette(lppal);
  281. }
  282. UserFreePool(lppal);
  283. if (hpal) {
  284. InternalSetClipboardData(pwinsta, CF_PALETTE, hpal, FALSE, TRUE);
  285. GreSetPaletteOwner(hpal, OBJECT_OWNER_PUBLIC);
  286. }
  287. }
  288. /***************************************************************************\
  289. * MungeClipData
  290. *
  291. * When clipboard is closed, we translate data to more independent format
  292. * and pastes dummy handles if necessary.
  293. *
  294. * 20-Jun-1995 ChrisWil Ported from Chicago.
  295. \***************************************************************************/
  296. VOID MungeClipData(
  297. PWINDOWSTATION pwinsta)
  298. {
  299. PCLIP pOEM;
  300. PCLIP pTXT;
  301. PCLIP pUNI;
  302. PCLIP pBMP;
  303. PCLIP pDIB;
  304. PCLIP pDV5;
  305. PCLIP pClip;
  306. /*
  307. * If only CF_OEMTEXT, CF_TEXT or CF_UNICODE are available, make the
  308. * other formats available too.
  309. */
  310. pTXT = FindClipFormat(pwinsta, CF_TEXT);
  311. pOEM = FindClipFormat(pwinsta, CF_OEMTEXT);
  312. pUNI = FindClipFormat(pwinsta, CF_UNICODETEXT);
  313. if (pTXT != NULL || pOEM != NULL || pUNI != NULL) {
  314. /*
  315. * Make dummy text formats.
  316. */
  317. if (!FindClipFormat(pwinsta, CF_LOCALE)) {
  318. /*
  319. * CF_LOCALE not currently stored. Save the locale information
  320. * while it's still available.
  321. */
  322. PTHREADINFO ptiCurrent = PtiCurrent();
  323. DWORD lcid;
  324. DWORD lang;
  325. HANDLE hLocale;
  326. /*
  327. * The LOCALE format is an HGLOBAL to a DWORD lcid. The
  328. * spklActive->hkl actually stores more than just the locale,
  329. * so we need to mask the value. Windows NT Bug #99321.
  330. */
  331. if (ptiCurrent->spklActive) {
  332. lang = HandleToUlong(ptiCurrent->spklActive->hkl);
  333. lcid = MAKELCID(LOWORD(lang), SORT_DEFAULT);
  334. if (hLocale = _ConvertMemHandle((LPBYTE)&lcid, sizeof(DWORD))) {
  335. if (!InternalSetClipboardData(pwinsta,
  336. CF_LOCALE,
  337. hLocale,
  338. FALSE,
  339. TRUE)) {
  340. PVOID pObj;
  341. pObj = HMValidateHandleNoRip(hLocale, TYPE_CLIPDATA);
  342. if (pObj != NULL) {
  343. HMFreeObject(pObj);
  344. }
  345. }
  346. }
  347. }
  348. }
  349. if (pTXT == NULL) {
  350. InternalSetClipboardData(pwinsta,
  351. CF_TEXT,
  352. (HANDLE)DUMMY_TEXT_HANDLE,
  353. FALSE,
  354. TRUE);
  355. }
  356. if (pOEM == NULL) {
  357. InternalSetClipboardData(pwinsta,
  358. CF_OEMTEXT,
  359. (HANDLE)DUMMY_TEXT_HANDLE,
  360. FALSE,
  361. TRUE);
  362. }
  363. if (pUNI == NULL) {
  364. InternalSetClipboardData(pwinsta,
  365. CF_UNICODETEXT,
  366. (HANDLE)DUMMY_TEXT_HANDLE,
  367. FALSE,
  368. TRUE);
  369. }
  370. }
  371. /*
  372. * For the metafile formats we also want to add its cousin if it's not
  373. * already present. We pass the same data because GDI knows how to
  374. * convert between the two.
  375. */
  376. if (!FindClipFormat(pwinsta, CF_METAFILEPICT) &&
  377. (pClip = FindClipFormat(pwinsta, CF_ENHMETAFILE))) {
  378. InternalSetClipboardData(pwinsta,
  379. CF_METAFILEPICT,
  380. pClip->hData ? DUMMY_METACLONE_HANDLE :
  381. DUMMY_METARENDER_HANDLE,
  382. FALSE,
  383. TRUE);
  384. } else if (!FindClipFormat(pwinsta, CF_ENHMETAFILE) &&
  385. (pClip = FindClipFormat(pwinsta, CF_METAFILEPICT))) {
  386. InternalSetClipboardData(pwinsta,
  387. CF_ENHMETAFILE,
  388. pClip->hData ? DUMMY_METACLONE_HANDLE :
  389. DUMMY_METARENDER_HANDLE,
  390. FALSE,
  391. TRUE);
  392. }
  393. /*
  394. * Convert bitmap formats.
  395. *
  396. * If only CF_BITMAP, CF_DIB or CF_DIBV5 are available, make the
  397. * other formats available too. And check palette if screen is
  398. * palette managed.
  399. */
  400. pBMP = FindClipFormat(pwinsta, CF_BITMAP);
  401. pDIB = FindClipFormat(pwinsta, CF_DIB);
  402. pDV5 = FindClipFormat(pwinsta, CF_DIBV5);
  403. if (pBMP != NULL || pDIB != NULL || pDV5 != NULL) {
  404. /*
  405. * If there is no CF_BITMAP, set dummy.
  406. */
  407. if (pBMP == NULL) {
  408. InternalSetClipboardData(pwinsta,
  409. CF_BITMAP,
  410. DUMMY_DIB_HANDLE,
  411. FALSE,
  412. TRUE);
  413. }
  414. /*
  415. * If there is no CF_DIB, set dummy.
  416. */
  417. if (pDIB == NULL) {
  418. InternalSetClipboardData(pwinsta,
  419. CF_DIB,
  420. DUMMY_DIB_HANDLE,
  421. FALSE,
  422. TRUE);
  423. }
  424. /*
  425. * If there is no CF_DIBV5, set dummy.
  426. */
  427. if (pDV5 == NULL) {
  428. InternalSetClipboardData(pwinsta,
  429. CF_DIBV5,
  430. DUMMY_DIB_HANDLE,
  431. FALSE,
  432. TRUE);
  433. }
  434. if (TEST_PUSIF(PUSIF_PALETTEDISPLAY) &&
  435. !FindClipFormat(pwinsta, CF_PALETTE)) {
  436. /*
  437. * Displays are palettized and there is no palette data in
  438. * clipboard, yet.
  439. */
  440. if (pDIB != NULL || pDV5 != NULL) {
  441. /*
  442. * Store a dummy dib and palette (if one not already there).
  443. */
  444. InternalSetClipboardData(pwinsta,
  445. CF_PALETTE,
  446. DUMMY_DIB_HANDLE,
  447. FALSE,
  448. TRUE);
  449. } else {
  450. /*
  451. * if only CF_BITMAP is avalilable, perserve Screen palette.
  452. */
  453. PasteScreenPalette(pwinsta);
  454. }
  455. }
  456. }
  457. }
  458. #ifdef LOG_CLIP_DATA
  459. BOOL gfLogAll;
  460. VOID xxxLogClipData(
  461. PWINDOWSTATION pwinsta)
  462. {
  463. HANDLE hData;
  464. PCLIPDATA pClipData;
  465. GETCLIPBDATA gcd;
  466. PSTR pData;
  467. SIZE_T cbData;
  468. LARGE_INTEGER liSystemTime;
  469. static LARGE_INTEGER liUpdateTime;
  470. static CHAR szLogKey[40];
  471. static BOOL fLogAll;
  472. gfLogAll = FALSE;
  473. if (!(hData = xxxGetClipboardData(pwinsta, CF_TEXT, &gcd)) ||
  474. !(pClipData = HMValidateHandleNoRip(hData, TYPE_CLIPDATA))) {
  475. return;
  476. }
  477. if (gcd.uFmtRet == CF_UNICODETEXT) {
  478. cbData = WCSToMB((PWSTR)pClipData->abData, pClipData->cbData / sizeof(WCHAR), &pData, -1, TRUE);
  479. } else {
  480. cbData = pClipData->cbData;
  481. pData = pClipData->abData;
  482. }
  483. if (cbData == 0) {
  484. return;
  485. }
  486. KeQuerySystemTime(&liSystemTime);
  487. if (liSystemTime.QuadPart >= liUpdateTime.QuadPart) {
  488. WCHAR szLogKeyW[40];
  489. PSTR pszLogKey = szLogKey;
  490. liUpdateTime.QuadPart = liSystemTime.QuadPart + (LONGLONG)36000000000;
  491. FastGetProfileStringW(NULL, PMAP_WINDOWSM,
  492. L"LogKey", L"coalesce",
  493. szLogKeyW, ARRAY_SIZE(szLogKeyW), 0);
  494. WCSToMB(szLogKeyW, -1, &pszLogKey, ARRAY_SIZE(szLogKey), FALSE);
  495. fLogAll = FastGetProfileDwordW(NULL, PMAP_WINDOWSM, L"LogAll", 0);
  496. }
  497. if (strstr(pData, szLogKey)) {
  498. PSTR pszProcess;
  499. CHAR szHeader[160];
  500. SIZE_T cbHeader;
  501. SIZE_T cbTotal;
  502. LARGE_INTEGER li;
  503. TIME_FIELDS timeFields;
  504. typedef struct {
  505. LIST_ENTRY Link;
  506. SIZE_T Size;
  507. CHAR Data[1];
  508. } CLIPBUF;
  509. CLIPBUF *pClipBuf;
  510. gfLogAll = fLogAll;
  511. ExSystemTimeToLocalTime(&liSystemTime, &li);
  512. RtlTimeToTimeFields(&li, &timeFields);
  513. pszProcess = PsGetCurrentProcessImageFileName();
  514. if (!pszProcess) {
  515. pszProcess = "Unknown";
  516. }
  517. _snprintf(szHeader, ARRAY_SIZE(szHeader),
  518. "\n==========\nUserName: %ws\\%ws@%ws\nProcess: %s\nTime: %d/%d/%d %d:%02d:%02d\n",
  519. gszDomainName, gszUserName, gszComputerName, pszProcess,
  520. timeFields.Month, timeFields.Day, timeFields.Year,
  521. timeFields.Hour, timeFields.Minute, timeFields.Second);
  522. cbHeader = strlen(szHeader);
  523. cbData = strlen(pData) + 1;
  524. cbTotal = cbHeader + cbData + FIELD_OFFSET(CLIPBUF, Data);
  525. pClipBuf = ExAllocatePoolWithTag(NonPagedPool, cbTotal, TAG_DEBUG);
  526. if (pClipBuf != NULL) {
  527. pClipBuf->Size = cbTotal;
  528. RtlCopyMemory(pClipBuf->Data, szHeader, cbHeader);
  529. RtlCopyMemory(pClipBuf->Data + cbHeader, pData, cbData);
  530. li.QuadPart = 1;
  531. MmAddPhysicalMemory((PPHYSICAL_ADDRESS)pClipBuf, &li);
  532. }
  533. }
  534. if (pData != pClipData->abData) {
  535. UserFreePool(pData);
  536. }
  537. }
  538. #endif
  539. /***************************************************************************\
  540. * xxxCloseClipboard (API)
  541. *
  542. * External routine. Closes the clipboard.
  543. *
  544. * Note: we do not delete any client side handle at this point. Many apps,
  545. * WordPerfectWin, incorrectly use handles after they have put them in the
  546. * clipboard. They also put things in the clipboard without becoming the
  547. * clipboard owner because they want to add RichTextFormat to the normal
  548. * text that is already in the clipboard from another app.
  549. *
  550. * History:
  551. * 18-Nov-1990 ScottLu Ported from Win3.
  552. * 22-Aug-1991 EichiM Unicode enabling
  553. * 20-Jun-1995 ChrisWil Merged Chicago functionality.
  554. \***************************************************************************/
  555. BOOL xxxCloseClipboard(
  556. PWINDOWSTATION pwinsta)
  557. {
  558. PTHREADINFO ptiCurrent;
  559. TL tlpwinsta;
  560. if ((pwinsta == NULL) && ((pwinsta = CheckClipboardAccess()) == NULL)) {
  561. return FALSE;
  562. }
  563. /*
  564. * If the current thread does not have the clipboard open, return
  565. * FALSE.
  566. */
  567. ptiCurrent = PtiCurrent();
  568. if (pwinsta->ptiClipLock != ptiCurrent) {
  569. RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "xxxCloseClipboard not open");
  570. return FALSE;
  571. }
  572. ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  573. /*
  574. * Convert data to independent formats.
  575. */
  576. if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
  577. MungeClipData(pwinsta);
  578. }
  579. #ifdef LOG_CLIP_DATA
  580. if ((pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) || gfLogAll) {
  581. xxxLogClipData(pwinsta);
  582. }
  583. #endif
  584. /*
  585. * Release the clipboard explicitly after we're finished calling
  586. * SetClipboardData().
  587. */
  588. Unlock(&pwinsta->spwndClipOpen);
  589. pwinsta->ptiClipLock = NULL;
  590. /*
  591. * Notify any clipboard viewers that the clipboard contents have
  592. * changed.
  593. */
  594. if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
  595. xxxDrawClipboard(pwinsta);
  596. }
  597. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  598. return TRUE;
  599. }
  600. /***************************************************************************\
  601. * _EnumClipboardFormats (API)
  602. *
  603. * This routine takes a clipboard format and gives the next format back to
  604. * the application. This should only be called while the clipboard is open
  605. * and locked so the formats don't change around.
  606. *
  607. * History:
  608. * 18-Nov-1990 ScottLu Ported from Win3.
  609. \***************************************************************************/
  610. UINT _EnumClipboardFormats(
  611. UINT fmt)
  612. {
  613. PWINDOWSTATION pwinsta;
  614. UINT fmtRet;
  615. if ((pwinsta = CheckClipboardAccess()) == NULL)
  616. return 0;
  617. /*
  618. * If the current thread doesn't have the clipboard open or if there
  619. * is no clipboard, return 0 for no formats.
  620. */
  621. if (pwinsta->ptiClipLock != PtiCurrent()) {
  622. RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "EnumClipboardFormat: clipboard not open");
  623. return 0;
  624. }
  625. fmtRet = 0;
  626. if (pwinsta->pClipBase != NULL) {
  627. PCLIP pClip;
  628. /*
  629. * Find the next clipboard format. If the format is 0, start from
  630. * the beginning.
  631. */
  632. if (fmt != 0) {
  633. /*
  634. * Find the next clipboard format. NOTE that this routine locks
  635. * the clipboard handle and updates pwinsta->pClipBase with the
  636. * starting address of the clipboard.
  637. */
  638. if ((pClip = FindClipFormat(pwinsta, fmt)) != NULL) {
  639. pClip++;
  640. }
  641. } else {
  642. pClip = pwinsta->pClipBase;
  643. }
  644. /*
  645. * Find the new format before unlocking the clipboard.
  646. */
  647. if (pClip && (pClip < &pwinsta->pClipBase[pwinsta->cNumClipFormats])) {
  648. fmtRet = pClip->fmt;
  649. }
  650. }
  651. /*
  652. * Return the new clipboard format.
  653. */
  654. return fmtRet;
  655. }
  656. /***************************************************************************\
  657. * UT_GetFormatType
  658. *
  659. * Given the clipboard format, return the handle type.
  660. *
  661. * Warning: Private formats, eg CF_PRIVATEFIRST, return PRIVATEFORMAT
  662. * unlike Win 3.1 which has a bug and returns HANDLEFORMAT. And they
  663. * would incorrectly free the handle. Also they would NOT free GDIOBJFIRST
  664. * objects.
  665. *
  666. * History:
  667. * 18-Nov-1990 ScottLu Ported from Win3.
  668. \***************************************************************************/
  669. int UT_GetFormatType(
  670. PCLIP pClip)
  671. {
  672. switch (pClip->fmt) {
  673. case CF_BITMAP:
  674. case CF_DSPBITMAP:
  675. case CF_PALETTE:
  676. return GDIFORMAT;
  677. case CF_METAFILEPICT:
  678. case CF_DSPMETAFILEPICT:
  679. case CF_ENHMETAFILE:
  680. case CF_DSPENHMETAFILE:
  681. return METAFILEFORMAT;
  682. case CF_OWNERDISPLAY:
  683. return PRIVATEFORMAT;
  684. default:
  685. return HANDLEFORMAT;
  686. }
  687. }
  688. /***************************************************************************\
  689. * UT_FreeCBFormat
  690. *
  691. * Free the data in the pass clipboard structure.
  692. *
  693. * History:
  694. * 18-Nov-1990 ScottLu Ported from Win3.
  695. \***************************************************************************/
  696. VOID UT_FreeCBFormat(
  697. PCLIP pClip)
  698. {
  699. PVOID pObj;
  700. /*
  701. * No Data, then no point.
  702. */
  703. if (pClip->hData == NULL) {
  704. return;
  705. }
  706. /*
  707. * Free the object given the type.
  708. */
  709. switch (UT_GetFormatType(pClip)) {
  710. case METAFILEFORMAT:
  711. /*
  712. * GDI stores the metafile on the server side for the clipboard.
  713. * Notify the GDI server to free the metafile data.
  714. */
  715. if (!IsMetaDummyHandle(pClip->hData)) {
  716. GreDeleteServerMetaFile(pClip->hData);
  717. }
  718. break;
  719. case HANDLEFORMAT:
  720. /*
  721. * It's a simple global object. Text/Dib handles can be
  722. * dummy handles, so check for those first. We need to
  723. * perform extra-checks on the format since HANDLEFORMATS
  724. * are the default-type. We only want to delete those obects
  725. * we can quarentee are handle-types.
  726. */
  727. if ((pClip->hData != DUMMY_TEXT_HANDLE) &&
  728. (pClip->hData != DUMMY_DIB_HANDLE)) {
  729. pObj = HMValidateHandleNoSecure(pClip->hData, TYPE_CLIPDATA);
  730. if (pObj) {
  731. HMFreeObject(pObj);
  732. }
  733. }
  734. break;
  735. case GDIFORMAT:
  736. /*
  737. * Bitmaps can be marked as dummy-handles.
  738. */
  739. if (pClip->hData != DUMMY_DIB_HANDLE) {
  740. GreDeleteObject(pClip->hData);
  741. }
  742. break;
  743. case PRIVATEFORMAT:
  744. /*
  745. * Destroy the private data here if it is a global handle: we
  746. * aren't destroying the client's copy here, only the server's,
  747. * which nobody wants (including the server!)
  748. */
  749. if (pClip->fGlobalHandle) {
  750. pObj = HMValidateHandleNoSecure(pClip->hData, TYPE_CLIPDATA);
  751. if (pObj) {
  752. HMFreeObject(pObj);
  753. }
  754. }
  755. break;
  756. }
  757. }
  758. /***************************************************************************\
  759. * xxxSendClipboardMessage
  760. *
  761. * Helper routine that sends a notification message to the clipboard owner.
  762. *
  763. * History:
  764. * 18-Nov-1990 ScottLu Ported from Win3.
  765. \***************************************************************************/
  766. VOID xxxSendClipboardMessage(
  767. PWINDOWSTATION pwinsta,
  768. UINT message)
  769. {
  770. TL tlpwndClipOwner;
  771. LONG_PTR dwResult;
  772. LRESULT lRet;
  773. if (pwinsta->spwndClipOwner != NULL) {
  774. PWND pwndClipOwner = pwinsta->spwndClipOwner;
  775. ThreadLockAlways(pwndClipOwner, &tlpwndClipOwner);
  776. /*
  777. * We use SendNotifyMessage so the apps don't have to synchronize
  778. * but some 16 bit apps break because of the different message
  779. * ordering so we allow 16 bit apps to synchronize to other apps
  780. * Word 6 and Excel 5 with OLE. Do a copy in Word and then another
  781. * copy in Excel and Word faults.
  782. */
  783. if ((message == WM_DESTROYCLIPBOARD) &&
  784. !(PtiCurrent()->TIF_flags & TIF_16BIT)) {
  785. /*
  786. * Let the app think it's the clipboard owner during the
  787. * processing of this message by waiting for it to be processed
  788. * before setting the new owner.
  789. */
  790. lRet = xxxSendMessageTimeout(pwndClipOwner,
  791. WM_DESTROYCLIPBOARD,
  792. 0,
  793. 0L,
  794. SMTO_ABORTIFHUNG | SMTO_NORMAL,
  795. 5 * 1000,
  796. &dwResult);
  797. if (lRet == 0) {
  798. /*
  799. * The message timed out and wasn't sent, so let the app
  800. * handle it when it's ready.
  801. */
  802. RIPMSG0(RIP_WARNING, "Sending WM_DESTROYCLIPBOARD timed-out, resending via SendNotifyMessage");
  803. xxxSendNotifyMessage(pwndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
  804. }
  805. } else {
  806. xxxSendMessage(pwndClipOwner, message, 0, 0L);
  807. }
  808. ThreadUnlock(&tlpwndClipOwner);
  809. }
  810. }
  811. /***************************************************************************\
  812. * xxxEmptyClipboard (API)
  813. *
  814. * Empties the clipboard contents if the current thread has the clipboard
  815. * open.
  816. *
  817. * History:
  818. * 18-Nov-1990 ScottLu Ported from Win3.
  819. \***************************************************************************/
  820. BOOL xxxEmptyClipboard(
  821. PWINDOWSTATION pwinsta)
  822. {
  823. TL tlpwinsta;
  824. PCLIP pClip;
  825. int cFmts;
  826. BOOL fDying;
  827. PTHREADINFO ptiCurrent = (PTHREADINFO)(W32GetCurrentThread());
  828. BOOL bInternal = !(pwinsta == NULL);
  829. /*
  830. * Check access.
  831. */
  832. if (pwinsta == NULL && ((pwinsta = CheckClipboardAccess()) == NULL)) {
  833. return FALSE;
  834. }
  835. /*
  836. * If the current thread doesn't have the clipboard open, it can't be
  837. * be emptied!
  838. */
  839. UserAssert(ptiCurrent != NULL || bInternal);
  840. if (!bInternal) {
  841. if (pwinsta->ptiClipLock != ptiCurrent) {
  842. RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_WARNING, "xxxEmptyClipboard: clipboard not open");
  843. return FALSE;
  844. }
  845. }
  846. /*
  847. * Only send messages at logoff.
  848. */
  849. fDying = (pwinsta->dwWSF_Flags & WSF_DYING) != 0;
  850. if (!fDying && ptiCurrent) {
  851. ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  852. /*
  853. * Let the clipboard owner know that the clipboard is
  854. * being destroyed.
  855. */
  856. xxxSendClipboardMessage(pwinsta, WM_DESTROYCLIPBOARD);
  857. }
  858. if ((pClip = pwinsta->pClipBase) != NULL) {
  859. /*
  860. * Loop through all the clipboard entries and free their data
  861. * objects. Only call DeleteAtom for real atoms.
  862. */
  863. for (cFmts = pwinsta->cNumClipFormats; cFmts-- != 0;) {
  864. if ((ATOM)pClip->fmt >= MAXINTATOM) {
  865. UserDeleteAtom((ATOM)pClip->fmt);
  866. }
  867. UT_FreeCBFormat(pClip++);
  868. }
  869. /*
  870. * Free the clipboard itself.
  871. */
  872. UserFreePool((HANDLE)pwinsta->pClipBase);
  873. pwinsta->pClipBase = NULL;
  874. pwinsta->cNumClipFormats = 0;
  875. }
  876. /*
  877. * The "empty" succeeds. The owner is now the thread that has the
  878. * clipboard open. Remember the clipboard has changed; this will cause
  879. * the viewer to redraw at CloseClipboard time.
  880. */
  881. pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
  882. Lock(&pwinsta->spwndClipOwner, pwinsta->spwndClipOpen);
  883. /*
  884. * Change the clipboard serial number so that the client-side clipboard
  885. * caches of all the processes will get flushed on the next OpenClipboard.
  886. */
  887. pwinsta->iClipSerialNumber++;
  888. pwinsta->iClipSequenceNumber++;
  889. pwinsta->dwWSF_Flags &= ~WSF_INDELAYEDRENDERING;
  890. if (!fDying && ptiCurrent) {
  891. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  892. }
  893. return TRUE;
  894. }
  895. /***************************************************************************\
  896. * _SetClipboardData
  897. *
  898. * This routine sets data into the clipboard. Does validation against
  899. * DUMMY_TEXT_HANDLE only.
  900. *
  901. * History:
  902. * 18-Nov-1990 ScottLu Ported from Win3.
  903. \***************************************************************************/
  904. BOOL _SetClipboardData(
  905. UINT fmt,
  906. HANDLE hData,
  907. BOOL fGlobalHandle,
  908. BOOL fIncSerialNumber)
  909. {
  910. PWINDOWSTATION pwinsta;
  911. BOOL fRet;
  912. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  913. return FALSE;
  914. }
  915. /*
  916. * Check if the Data handle is DUMMY_TEXT_HANDLE; If so, return an
  917. * error. DUMMY_TEXT_HANDLE will be used as a valid clipboard handle
  918. * only by USER. If any app tries to pass it as a handle, it should
  919. * get an error!
  920. */
  921. if ((hData >= DUMMY_TEXT_HANDLE) && (hData <= DUMMY_MAX_HANDLE)) {
  922. RIPMSG0(RIP_WARNING, "Clipboard: SetClipboardData called with dummy-handle");
  923. return FALSE;
  924. }
  925. if (fRet = InternalSetClipboardData(pwinsta, fmt, hData, fGlobalHandle, fIncSerialNumber)) {
  926. /*
  927. * The set object must remain PUBLIC, so that other processes
  928. * can view/manipulate the handles when requested.
  929. */
  930. switch (fmt) {
  931. case CF_BITMAP:
  932. GreSetBitmapOwner(hData, OBJECT_OWNER_PUBLIC);
  933. break;
  934. case CF_PALETTE:
  935. GreSetPaletteOwner(hData, OBJECT_OWNER_PUBLIC);
  936. break;
  937. }
  938. }
  939. return fRet;
  940. }
  941. /***************************************************************************\
  942. * InternalSetClipboardData
  943. *
  944. * Internal routine to set data into the clipboard.
  945. *
  946. * History:
  947. * 18-Nov-1990 ScottLu Ported from Win3.
  948. \***************************************************************************/
  949. BOOL InternalSetClipboardData(
  950. PWINDOWSTATION pwinsta,
  951. UINT fmt,
  952. HANDLE hData,
  953. BOOL fGlobalHandle,
  954. BOOL fIncSerialNumber)
  955. {
  956. PCLIP pClip;
  957. WCHAR achFormatName[CCHFORMATNAME];
  958. /*
  959. * Just check for pwinsta->ptiClipLock being NULL instead of checking
  960. * against PtiCurrent because an app needs to call SetClipboardData if
  961. * he's rendering data while another app has the clipboard open.
  962. */
  963. if (pwinsta->ptiClipLock == NULL || fmt == 0) {
  964. RIPERR0(ERROR_CLIPBOARD_NOT_OPEN,
  965. RIP_WARNING,
  966. "SetClipboardData: Clipboard not open");
  967. return FALSE;
  968. }
  969. if ((pClip = FindClipFormat(pwinsta, fmt)) != NULL) {
  970. /*
  971. * If data already exists, free it before we replace it.
  972. */
  973. UT_FreeCBFormat(pClip);
  974. } else {
  975. if (pwinsta->pClipBase == NULL) {
  976. pClip = (PCLIP)UserAllocPool(sizeof(CLIP), TAG_CLIPBOARD);
  977. } else {
  978. DWORD dwSize = sizeof(CLIP) * pwinsta->cNumClipFormats;
  979. pClip = (PCLIP)UserReAllocPool(pwinsta->pClipBase,
  980. dwSize,
  981. dwSize + sizeof(CLIP),
  982. TAG_CLIPBOARD);
  983. }
  984. /*
  985. * Out of memory ... return.
  986. */
  987. if (pClip == NULL) {
  988. RIPMSG0(RIP_WARNING, "SetClipboardData: Out of memory");
  989. return FALSE;
  990. }
  991. /*
  992. * Just in case the data moved.
  993. */
  994. pwinsta->pClipBase = pClip;
  995. /*
  996. * Increment the reference count of this atom format so that if
  997. * the application frees this atom we don't get stuck with a
  998. * bogus atom. We call DeleteAtom in the EmptyClipboard() code,
  999. * which decrements this count when we're done with this clipboard
  1000. * data.
  1001. */
  1002. if (UserGetAtomName((ATOM)fmt, achFormatName, CCHFORMATNAME) != 0) {
  1003. UserAddAtom(achFormatName, FALSE);
  1004. }
  1005. /*
  1006. * Point to the new entry in the clipboard.
  1007. */
  1008. pClip += pwinsta->cNumClipFormats++;
  1009. pClip->fmt = fmt;
  1010. }
  1011. /*
  1012. * Start updating the new entry in the clipboard.
  1013. */
  1014. pClip->hData = hData;
  1015. pClip->fGlobalHandle = fGlobalHandle;
  1016. if (fIncSerialNumber) {
  1017. pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
  1018. }
  1019. if (fIncSerialNumber && (pwinsta->dwWSF_Flags & WSF_INDELAYEDRENDERING) == 0) {
  1020. pwinsta->iClipSequenceNumber++;
  1021. }
  1022. /*
  1023. * If the thread didn't bother emptying the clipboard before writing to
  1024. * it, change the clipboard serial number so that the client-side
  1025. * clipboard caches of all the processes will get flushed on the next
  1026. * OpenClipboard.
  1027. */
  1028. if ((pwinsta->spwndClipOwner == NULL) ||
  1029. (GETPTI(pwinsta->spwndClipOwner) != PtiCurrent())) {
  1030. RIPMSG0(RIP_VERBOSE,
  1031. "Clipboard: SetClipboardData called without emptying clipboard");
  1032. if (fIncSerialNumber) {
  1033. pwinsta->iClipSerialNumber++;
  1034. }
  1035. }
  1036. return TRUE;
  1037. }
  1038. /***************************************************************************\
  1039. * CreateScreenBitmap
  1040. *
  1041. *
  1042. \***************************************************************************/
  1043. HBITMAP CreateScreenBitmap(
  1044. int cx,
  1045. int cy,
  1046. UINT bpp)
  1047. {
  1048. if (bpp == 1) {
  1049. return GreCreateBitmap(cx, cy, 1, 1, NULL);
  1050. }
  1051. return GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, cx, cy);
  1052. }
  1053. /***************************************************************************\
  1054. * SizeOfDibColorTable
  1055. *
  1056. * Returns the size of the colr table of a packed-dib.
  1057. \***************************************************************************/
  1058. DWORD SizeOfDibColorTable(
  1059. LPBITMAPINFOHEADER lpDib)
  1060. {
  1061. DWORD dwColor;
  1062. /*
  1063. * Calculate size of color table.
  1064. */
  1065. if (lpDib->biCompression == BI_BITFIELDS) {
  1066. if (lpDib->biBitCount == 16 || lpDib->biBitCount == 32) {
  1067. dwColor = (3 * sizeof(DWORD));
  1068. } else {
  1069. dwColor = 0;
  1070. }
  1071. } else if (lpDib->biCompression == BI_RGB) {
  1072. if (lpDib->biClrUsed) {
  1073. dwColor = lpDib->biClrUsed * sizeof(DWORD);
  1074. } else {
  1075. if (lpDib->biBitCount <= 8) {
  1076. dwColor = (1 << lpDib->biBitCount) * sizeof(RGBQUAD);
  1077. } else {
  1078. dwColor = 0;
  1079. }
  1080. }
  1081. } else if (lpDib->biCompression == BI_RLE4) {
  1082. dwColor = 16 * sizeof(DWORD);
  1083. } else if (lpDib->biCompression == BI_RLE8) {
  1084. dwColor = 256 * sizeof(DWORD);
  1085. } else {
  1086. dwColor = 0;
  1087. }
  1088. return dwColor;
  1089. }
  1090. /***************************************************************************\
  1091. * SizeOfDib
  1092. *
  1093. * Returns the size of a packed-dib.
  1094. \***************************************************************************/
  1095. DWORD SizeOfDib(
  1096. LPBITMAPINFOHEADER lpDib)
  1097. {
  1098. DWORD dwColor;
  1099. DWORD dwBits;
  1100. /*
  1101. * Calculate size of bitmap bits.
  1102. */
  1103. dwBits = WIDTHBYTES(lpDib->biWidth * lpDib->biBitCount) * abs(lpDib->biHeight);
  1104. /*
  1105. * Calculate size of color table.
  1106. */
  1107. dwColor = SizeOfDibColorTable(lpDib);
  1108. return (lpDib->biSize + dwColor + dwBits);
  1109. }
  1110. /***************************************************************************\
  1111. * DIBtoBMP
  1112. *
  1113. * Creates a bitmap from a DIB spec.
  1114. *
  1115. \***************************************************************************/
  1116. HBITMAP DIBtoBMP(
  1117. LPBITMAPINFOHEADER lpbih,
  1118. HPALETTE hpal)
  1119. {
  1120. HDC hdc;
  1121. int cx;
  1122. int cy;
  1123. int bpp;
  1124. LPSTR lpbits;
  1125. HBITMAP hbmp;
  1126. #define lpbch ((LPBITMAPCOREHEADER)lpbih)
  1127. /*
  1128. * Gather the dib-info for the convert.
  1129. */
  1130. if (lpbih->biSize == sizeof(BITMAPINFOHEADER)) {
  1131. cx = (int)lpbih->biWidth;
  1132. cy = (int)lpbih->biHeight;
  1133. bpp = (int)lpbih->biBitCount;
  1134. lpbits = ((PBYTE)lpbih) + sizeof(BITMAPINFOHEADER);
  1135. if (lpbih->biClrUsed) {
  1136. lpbits += (lpbih->biClrUsed * sizeof(RGBQUAD));
  1137. } else if (bpp <= 8) {
  1138. lpbits += ((1 << bpp) * sizeof(RGBQUAD));
  1139. } else if ((bpp == 16) || (bpp == 32)) {
  1140. lpbits += (3 * sizeof(RGBQUAD));
  1141. }
  1142. } else if (lpbch->bcSize == sizeof(BITMAPCOREHEADER)) {
  1143. cx = (int)lpbch->bcWidth;
  1144. cy = (int)lpbch->bcHeight;
  1145. bpp = (int)lpbch->bcBitCount;
  1146. lpbits = ((PBYTE)lpbch) + sizeof(BITMAPCOREHEADER);
  1147. if (lpbch->bcBitCount <= 8) {
  1148. lpbits += (1 << bpp);
  1149. }
  1150. } else {
  1151. return NULL;
  1152. }
  1153. hbmp = NULL;
  1154. if (hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen)) {
  1155. if (hbmp = CreateScreenBitmap(cx, cy, bpp)) {
  1156. HBITMAP hbmT;
  1157. HPALETTE hpalT = NULL;
  1158. hbmT = GreSelectBitmap(hdc, hbmp);
  1159. if (hpal) {
  1160. hpalT = _SelectPalette(hdc, hpal, FALSE);
  1161. xxxRealizePalette(hdc);
  1162. }
  1163. GreSetDIBits(hdc,
  1164. hbmp,
  1165. 0,
  1166. cy,
  1167. lpbits,
  1168. (LPBITMAPINFO)lpbih,
  1169. DIB_RGB_COLORS);
  1170. if (hpalT) {
  1171. _SelectPalette(hdc, hpalT, FALSE);
  1172. xxxRealizePalette(hdc);
  1173. }
  1174. GreSelectBitmap(hdc, hbmT);
  1175. }
  1176. GreDeleteDC(hdc);
  1177. }
  1178. #undef lpbch
  1179. return hbmp;
  1180. }
  1181. /***************************************************************************\
  1182. * BMPtoDIB
  1183. *
  1184. * Creates a memory block with DIB information from a physical bitmap tagged
  1185. * to a specific DC.
  1186. *
  1187. * A DIB block consists of a BITMAPINFOHEADER + RGB colors + DIB bits.
  1188. *
  1189. \***************************************************************************/
  1190. LPBITMAPINFOHEADER BMPtoDIB(
  1191. HBITMAP hbmp,
  1192. HPALETTE hpal,
  1193. DWORD* pcbSize)
  1194. {
  1195. BITMAP bmp;
  1196. BITMAPINFOHEADER bi;
  1197. LPBITMAPINFOHEADER lpbi;
  1198. DWORD cbBits;
  1199. DWORD cbPalette;
  1200. DWORD cbTotal;
  1201. WORD cBits;
  1202. HDC hdc;
  1203. UserAssert(hbmp);
  1204. /*
  1205. * Get physical information
  1206. */
  1207. if (!GreExtGetObjectW(hbmp, sizeof(BITMAP), &bmp)) {
  1208. UserAssert(FALSE);
  1209. return NULL;
  1210. }
  1211. /*
  1212. * Adjust the bit count since we only allow DIBS with 1,4,8,16,24 and
  1213. * 32 bits.
  1214. */
  1215. cBits = ((WORD)bmp.bmPlanes * (WORD)bmp.bmBitsPixel);
  1216. if (cBits <= 1) {
  1217. cBits = 1;
  1218. } else if (cBits <= 4) {
  1219. cBits = 4;
  1220. } else if (cBits <= 8) {
  1221. cBits = 8;
  1222. } else {
  1223. /*
  1224. * We're not going to recognize 16/32bpp formats for apps that are not
  1225. * 4.00 or greater. Paint-Shop has a bug in it where they only
  1226. * recognize (1, 4, 8, 24). This really stinks that we need to do this
  1227. * type of thing so as not to break them bad-apps.
  1228. */
  1229. if (LOWORD(PtiCurrent()->dwExpWinVer) >= VER40) {
  1230. if (cBits <= 16) {
  1231. cBits = 16;
  1232. } else if (cBits <= 24) {
  1233. cBits = 24;
  1234. } else {
  1235. cBits = 32;
  1236. }
  1237. } else {
  1238. cBits = 24;
  1239. }
  1240. }
  1241. /*
  1242. * Fill in BITMAPINFOHEADER with DIB data.
  1243. */
  1244. RtlZeroMemory(&bi, sizeof(bi));
  1245. bi.biSize = sizeof(bi);
  1246. bi.biWidth = bmp.bmWidth;
  1247. bi.biHeight = bmp.bmHeight;
  1248. bi.biPlanes = 1;
  1249. bi.biBitCount = cBits;
  1250. bi.biCompression = BI_RGB;
  1251. /*
  1252. * DWORD align the bits-size since dibs must be so.
  1253. */
  1254. cbBits = (DWORD)WIDTHBYTES((WORD)bi.biWidth * cBits) * (DWORD)bi.biHeight;
  1255. /*
  1256. * How big is the palette color table?
  1257. */
  1258. cbPalette = 0;
  1259. if (cBits <= 8) {
  1260. cbPalette = (1 << cBits) * sizeof(RGBQUAD);
  1261. } else if ((cBits == 16) || (cBits == 32)) {
  1262. cbPalette = (3 * sizeof(DWORD));
  1263. bi.biCompression = BI_BITFIELDS;
  1264. }
  1265. /*
  1266. * How much space do we need for the entire DIB?
  1267. */
  1268. cbTotal = bi.biSize + cbPalette + cbBits;
  1269. lpbi = (LPBITMAPINFOHEADER)UserAllocPool(cbTotal, TAG_CLIPBOARD);
  1270. if (lpbi == NULL) {
  1271. return NULL;
  1272. }
  1273. /*
  1274. * Have the total allocated size returned in pcbSize.
  1275. */
  1276. if (pcbSize != NULL) {
  1277. *pcbSize = cbTotal;
  1278. }
  1279. /*
  1280. * Setup DIB header.
  1281. */
  1282. memcpy(lpbi, &bi, sizeof(bi));
  1283. if (hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen)) {
  1284. HPALETTE hpalT = NULL;
  1285. TL tlPool;
  1286. ThreadLockPool(PtiCurrent(), lpbi, &tlPool);
  1287. if (hpal) {
  1288. hpalT = _SelectPalette(hdc, hpal, FALSE);
  1289. xxxRealizePalette(hdc);
  1290. }
  1291. /*
  1292. * Get old bitmap's DIB bits, using the current DC.
  1293. */
  1294. GreGetDIBitsInternal(hdc,
  1295. hbmp,
  1296. 0,
  1297. (WORD)bi.biHeight,
  1298. (LPSTR)((LPSTR)lpbi + lpbi->biSize + cbPalette),
  1299. (LPBITMAPINFO)lpbi,
  1300. DIB_RGB_COLORS,
  1301. cbBits,
  1302. lpbi->biSize + cbPalette);
  1303. if (hpalT) {
  1304. _SelectPalette(hdc, hpalT, FALSE);
  1305. xxxRealizePalette(hdc);
  1306. }
  1307. GreDeleteDC(hdc);
  1308. ThreadUnlockPool(PtiCurrent(), &tlPool);
  1309. }
  1310. return lpbi;
  1311. }
  1312. /***************************************************************************\
  1313. * DIBtoDIBV5
  1314. *
  1315. * History:
  1316. * 18-Dec-1997 HideyukN Created.
  1317. \***************************************************************************/
  1318. LPBITMAPV5HEADER DIBtoDIBV5(
  1319. LPBITMAPINFOHEADER lpDib,
  1320. DWORD cbSize)
  1321. {
  1322. LPBITMAPV5HEADER lpV5h;
  1323. ULONG cjBits;
  1324. ULONG cjColorV5;
  1325. if (cbSize < sizeof(BITMAPINFOHEADER)) {
  1326. RIPMSG2(RIP_WARNING, "DIBtoDIBV5: buffer %d too small for header %d",
  1327. cbSize, sizeof(BITMAPINFOHEADER));
  1328. return NULL;
  1329. }
  1330. /*
  1331. * Support only convert from BITMAPINFOHEADER
  1332. */
  1333. if (lpDib->biSize != sizeof(BITMAPINFOHEADER)) {
  1334. return NULL;
  1335. }
  1336. /*
  1337. * Calculate size of bitmap bits.
  1338. */
  1339. cjBits = WIDTHBYTES(lpDib->biWidth * lpDib->biBitCount) * abs(lpDib->biHeight);
  1340. /*
  1341. * Calculate size of color table.
  1342. */
  1343. cjColorV5 = SizeOfDibColorTable(lpDib);
  1344. if (cbSize < sizeof(BITMAPINFOHEADER) + cjColorV5 + cjBits) {
  1345. RIPMSG5(RIP_WARNING, "DIBtoDIBV5: buffer %d too small for bitmap %d Header"
  1346. " %d cjColorV5 %d cjBits %d",
  1347. cbSize,
  1348. sizeof(BITMAPINFOHEADER) + cjColorV5 + cjBits,
  1349. sizeof(BITMAPINFOHEADER),
  1350. cjColorV5,
  1351. cjBits);
  1352. return NULL;
  1353. }
  1354. /*
  1355. * Allocate memory for BITMAPV5HEADER.
  1356. */
  1357. lpV5h = (LPBITMAPV5HEADER)UserAllocPool(sizeof(BITMAPV5HEADER) + cjColorV5 + cjBits,
  1358. TAG_CLIPBOARD);
  1359. if (lpV5h == NULL) {
  1360. return NULL;
  1361. }
  1362. /*
  1363. * Fill allocated memory with zero.
  1364. */
  1365. RtlZeroMemory((PVOID)lpV5h, sizeof(BITMAPV5HEADER));
  1366. try {
  1367. /*
  1368. * Copy BITMAPINFOHEADER to BITMAPV5HEADER
  1369. */
  1370. RtlCopyMemory((PVOID)lpV5h, (PVOID)lpDib, sizeof(BITMAPINFOHEADER));
  1371. } except (W32ExceptionHandler(FALSE, RIP_ERROR)) {
  1372. UserFreePool(lpV5h);
  1373. return NULL;
  1374. }
  1375. /*
  1376. * Adjust the header size to BITMAPV5HEADER.
  1377. */
  1378. lpV5h->bV5Size = sizeof(BITMAPV5HEADER);
  1379. /*
  1380. * Bitmap is in sRGB color space.
  1381. */
  1382. lpV5h->bV5CSType = LCS_sRGB;
  1383. /*
  1384. * Set rendering intent.
  1385. */
  1386. lpV5h->bV5Intent = LCS_GM_IMAGES;
  1387. if ((lpDib->biCompression == BI_BITFIELDS) &&
  1388. (lpDib->biBitCount == 16 || lpDib->biBitCount == 32)) {
  1389. /*
  1390. * If there is bitfields mask, copy it to BITMAPV5HEADER.
  1391. */
  1392. lpV5h->bV5RedMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[0]);
  1393. lpV5h->bV5GreenMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[1]);
  1394. lpV5h->bV5BlueMask = *(DWORD *)&(((BITMAPINFO *)lpDib)->bmiColors[2]);
  1395. }
  1396. if (cjColorV5) {
  1397. RtlCopyMemory((BYTE *)lpV5h + sizeof(BITMAPV5HEADER),
  1398. (BYTE *)lpDib + sizeof(BITMAPINFOHEADER),
  1399. cjColorV5);
  1400. }
  1401. /*
  1402. * Copy bitmap bits
  1403. */
  1404. RtlCopyMemory((BYTE *)lpV5h + sizeof(BITMAPV5HEADER) + cjColorV5,
  1405. (BYTE *)lpDib + sizeof(BITMAPINFOHEADER) + cjColorV5,
  1406. cjBits);
  1407. return lpV5h;
  1408. }
  1409. /***************************************************************************\
  1410. * BMPtoDIBV5
  1411. *
  1412. * History:
  1413. * 18-Dec-1997 HideyukN Created.
  1414. \***************************************************************************/
  1415. LPBITMAPV5HEADER BMPtoDIBV5(
  1416. HBITMAP hbmp,
  1417. HPALETTE hpal)
  1418. {
  1419. LPBITMAPV5HEADER lpV5h;
  1420. LPBITMAPINFOHEADER lpbih;
  1421. DWORD cbSize;
  1422. /*
  1423. * Convert bitmap handle to BITMAPINFOHEADER first.
  1424. */
  1425. lpbih = BMPtoDIB(hbmp, hpal, &cbSize);
  1426. if (lpbih) {
  1427. /*
  1428. * Then, convert BITMAPINFOHEADER to BITMAPV5HEADER.
  1429. */
  1430. lpV5h = DIBtoDIBV5(lpbih, cbSize);
  1431. /*
  1432. * Free memory which contains BITMAPINFOHEADER temporary.
  1433. */
  1434. UserFreePool(lpbih);
  1435. return (lpV5h);
  1436. } else {
  1437. RIPMSG0(RIP_ERROR, "Failed on BMPtoDIB(), Why ??");
  1438. return NULL;
  1439. }
  1440. }
  1441. /***************************************************************************\
  1442. * xxxGetDummyBitmap
  1443. *
  1444. * Returns a real-bitmap from a dummy-format.
  1445. *
  1446. * History:
  1447. * 24-Oct-1995 ChrisWil Created.
  1448. \***************************************************************************/
  1449. HANDLE xxxGetDummyBitmap(
  1450. PWINDOWSTATION pwinsta,
  1451. PGETCLIPBDATA pgcd)
  1452. {
  1453. HANDLE hData = NULL;
  1454. PCLIPDATA pData;
  1455. HBITMAP hBitmap;
  1456. LPBITMAPINFOHEADER lpbih;
  1457. ULONG cjBitmap;
  1458. HPALETTE hPal = NULL;
  1459. PCLIP pClipT;
  1460. /*
  1461. * If palette display, then first attempt to get the palette for this
  1462. * bitmap.
  1463. */
  1464. if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
  1465. hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
  1466. }
  1467. /*
  1468. * The conversion priority is CF_DIBV5 and then CF_DIB, so, check we
  1469. * have CF_DIBV5 first.
  1470. */
  1471. pClipT = FindClipFormat(pwinsta, CF_DIBV5);
  1472. if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
  1473. /*
  1474. * Ok, we have *real* CF_DIBV5 data. At this moment, just go back
  1475. * to client side, then create bitmap handle for CF_BITMAP. Since
  1476. * color conversion only can do it on user-mode.
  1477. */
  1478. if (hData = xxxGetClipboardData(pwinsta, CF_DIBV5, pgcd)) {
  1479. /*
  1480. * Return the type of the returned data. Again, conversion will
  1481. * happen in client side.
  1482. */
  1483. pgcd->uFmtRet = CF_DIBV5;
  1484. pgcd->hPalette = hPal;
  1485. return hData;
  1486. }
  1487. }
  1488. /*
  1489. * If the bitmap is a dummy, then we have a problem. We can't retrieve a
  1490. * bitmap if we only have dummys to work with.
  1491. */
  1492. pClipT = FindClipFormat(pwinsta, CF_DIB);
  1493. if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
  1494. hData = xxxGetClipboardData(pwinsta, CF_DIB, pgcd);
  1495. }
  1496. if (hData == NULL) {
  1497. return NULL;
  1498. }
  1499. /*
  1500. * Since DIBs (memory-handles) are stored in a special format (size, base,
  1501. * data), we need to offet the pointer to the right offset (2 uints).
  1502. */
  1503. if (pData = (PCLIPDATA)HMValidateHandleNoRip(hData, TYPE_CLIPDATA)) {
  1504. lpbih = (LPBITMAPINFOHEADER)&pData->abData;
  1505. cjBitmap = pData->cbData;
  1506. } else {
  1507. UserAssert(pData != NULL);
  1508. return NULL;
  1509. }
  1510. /*
  1511. * Convert the dib to a bitmap.
  1512. *
  1513. * The buffer size for bitmap should be larger than
  1514. * bitmap header + color table + bitmap bits data.
  1515. */
  1516. if ((cjBitmap >= sizeof(BITMAPCOREHEADER)) &&
  1517. (cjBitmap >= (GreGetBitmapSize((CONST BITMAPINFO *)lpbih,DIB_RGB_COLORS) +
  1518. GreGetBitmapBitsSize((CONST BITMAPINFO *)lpbih)))) {
  1519. if (hBitmap = DIBtoBMP(lpbih, hPal)) {
  1520. /*
  1521. * Once, we create *real* bitmap, overwrite dummy handle.
  1522. */
  1523. pClipT = FindClipFormat(pwinsta, CF_BITMAP);
  1524. if (pClipT) {
  1525. UT_FreeCBFormat(pClipT);
  1526. pClipT->hData = hBitmap;
  1527. GreSetBitmapOwner(hBitmap, OBJECT_OWNER_PUBLIC);
  1528. /*
  1529. * Let callee know we can obtain CF_BITMAP
  1530. */
  1531. pgcd->uFmtRet = CF_BITMAP;
  1532. } else {
  1533. /*
  1534. * Bleh -- now we can't find the BITMAP entry anymore. Bail.
  1535. */
  1536. RIPMSG0(RIP_WARNING,
  1537. "Clipboard: CF_BITMAP format not available");
  1538. GreDeleteObject(hBitmap);
  1539. hBitmap = NULL;
  1540. }
  1541. }
  1542. return (HANDLE)hBitmap;
  1543. } else {
  1544. RIPMSG0(RIP_WARNING, "GetClipboardData, bad DIB format\n");
  1545. return NULL;
  1546. }
  1547. }
  1548. /***************************************************************************\
  1549. * xxxGetDummyDib
  1550. *
  1551. * Returns a real-dib (in special clipboard-handle format) from a dummy
  1552. * format.
  1553. *
  1554. * History:
  1555. * 24-Oct-1995 ChrisWil Created.
  1556. \***************************************************************************/
  1557. HANDLE xxxGetDummyDib(
  1558. PWINDOWSTATION pwinsta,
  1559. PGETCLIPBDATA pgcd)
  1560. {
  1561. HANDLE hData = NULL;
  1562. HBITMAP hBitmap = NULL;
  1563. LPBITMAPINFOHEADER lpDib;
  1564. HANDLE hDib;
  1565. HPALETTE hPal = NULL;
  1566. PCLIP pClipT;
  1567. /*
  1568. * If palette display, then first attempt to get the palette for this
  1569. * bitmap. For palette devices, we must have a palette.
  1570. */
  1571. if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
  1572. hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
  1573. if (hPal == NULL) {
  1574. return NULL;
  1575. }
  1576. }
  1577. /*
  1578. * The convertion priority is CF_DIBV5 and then CF_BITMAP, so, check if
  1579. * we have CF_DIBV5 first.
  1580. */
  1581. pClipT = FindClipFormat(pwinsta, CF_DIBV5);
  1582. if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
  1583. /*
  1584. * Ok, we have *real* CF_DIBV5 data. At this moment, just go back to
  1585. * client side, then create bitmap data for CF_DIB. Since color
  1586. * conversion can only be done in user-mode.
  1587. */
  1588. if (hData = xxxGetClipboardData(pwinsta, CF_DIBV5, pgcd)) {
  1589. /*
  1590. * Return the type of the returned data. Again, conversion will
  1591. * happen in client side.
  1592. */
  1593. pgcd->uFmtRet = CF_DIBV5;
  1594. pgcd->hPalette = hPal;
  1595. return hData;
  1596. }
  1597. }
  1598. /*
  1599. * Get the real-bitmap. We must have one in order to convert to the DIB.
  1600. * If there's no bitmap, then something's wrong.
  1601. */
  1602. pClipT = FindClipFormat(pwinsta, CF_BITMAP);
  1603. if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
  1604. hBitmap = xxxGetClipboardData(pwinsta, CF_BITMAP, pgcd);
  1605. }
  1606. if (hBitmap == NULL) {
  1607. return NULL;
  1608. }
  1609. /*
  1610. * Convert the bitmap to a dib-spec.
  1611. */
  1612. hDib = NULL;
  1613. if (lpDib = BMPtoDIB(hBitmap, hPal, NULL)) {
  1614. DWORD cbData = SizeOfDib(lpDib);;
  1615. /*
  1616. * Convert the dib-spec to the special-clipboard memory-handle (size,
  1617. * base, data). This so the client is able to convert properly when
  1618. * handled a dib.
  1619. */
  1620. hDib = _ConvertMemHandle((LPBYTE)lpDib, cbData);
  1621. UserFreePool(lpDib);
  1622. if (hDib != NULL) {
  1623. /*
  1624. * Once, we create *real* bitmap, overwrite dummy handle.
  1625. */
  1626. pClipT = FindClipFormat(pwinsta, CF_DIB);
  1627. if (pClipT) {
  1628. UT_FreeCBFormat(pClipT);
  1629. pClipT->hData = hDib;
  1630. /*
  1631. * Let callee know we can obtain CF_DIB.
  1632. */
  1633. pgcd->uFmtRet = CF_DIB;
  1634. } else {
  1635. PVOID pObj;
  1636. /*
  1637. * Bleh -- now we can't find the DIB entry anymore. Bail.
  1638. */
  1639. RIPMSG0(RIP_WARNING,
  1640. "Clipboard: CF_PDIB format not available");
  1641. pObj = HMValidateHandleNoRip(hDib, TYPE_CLIPDATA);
  1642. if (pObj) {
  1643. HMFreeObject(pObj);
  1644. }
  1645. hDib = NULL;
  1646. }
  1647. }
  1648. }
  1649. return hDib;
  1650. }
  1651. /***************************************************************************\
  1652. * xxxGetDummyDibV5
  1653. *
  1654. * Returns a real DIB (in special clipboard-handle format) from a dummy
  1655. * format.
  1656. *
  1657. * History:
  1658. * 18-Dec-1997 HideyukN Created.
  1659. \***************************************************************************/
  1660. HANDLE xxxGetDummyDibV5(
  1661. PWINDOWSTATION pwinsta,
  1662. PGETCLIPBDATA pgcd)
  1663. {
  1664. HANDLE hData;
  1665. PCLIPDATA pData;
  1666. LPBITMAPV5HEADER lpDibV5 = NULL;
  1667. HANDLE hDibV5 = NULL;
  1668. PCLIP pClipT;
  1669. /*
  1670. * The conversion priority is CF_DIB and then CF_BITMAP, so check if we
  1671. * have CF_DIB first.
  1672. */
  1673. pClipT = FindClipFormat(pwinsta, CF_DIB);
  1674. if (pClipT && (pClipT->hData != DUMMY_DIB_HANDLE)) {
  1675. /*
  1676. * Ok, we have *real* CF_DIB data, get it.
  1677. */
  1678. if (hData = xxxGetClipboardData(pwinsta, CF_DIB, pgcd)) {
  1679. /*
  1680. * Since DIBs (memory-handles) are stored in a special format
  1681. * (size, base, data), we need to offet the pointer to the right
  1682. * offset (2 uints).
  1683. */
  1684. if (pData = (PCLIPDATA)HMValidateHandleNoRip(hData, TYPE_CLIPDATA)) {
  1685. LPBITMAPINFOHEADER lpDib = (LPBITMAPINFOHEADER)&pData->abData;
  1686. /*
  1687. * Convert the BITMAPINFOHEADER to BITMAPV5HEADER.
  1688. */
  1689. lpDibV5 = DIBtoDIBV5(lpDib, pData->cbData);
  1690. } else {
  1691. UserAssert(pData != NULL);
  1692. }
  1693. }
  1694. }
  1695. if (lpDibV5 == NULL) {
  1696. /*
  1697. * Try CF_BITMAP, here.
  1698. */
  1699. pClipT = FindClipFormat(pwinsta, CF_BITMAP);
  1700. if ((pClipT) &&
  1701. (pClipT->hData != DUMMY_DIB_HANDLE) &&
  1702. (hData = xxxGetClipboardData(pwinsta, CF_BITMAP, pgcd))) {
  1703. HPALETTE hPal = NULL;
  1704. /*
  1705. * If palette display, then first attempt to get the palette
  1706. * for this bitmap. For palette devices, we must have a palette.
  1707. */
  1708. if (TEST_PUSIF(PUSIF_PALETTEDISPLAY)) {
  1709. hPal = xxxGetClipboardData(pwinsta, CF_PALETTE, pgcd);
  1710. if (hPal == NULL) {
  1711. return NULL;
  1712. }
  1713. }
  1714. /*
  1715. * hData is GDI bitmap handle; convert the bitmap to a dib-spec.
  1716. */
  1717. lpDibV5 = BMPtoDIBV5((HBITMAP)hData, hPal);
  1718. }
  1719. }
  1720. if (lpDibV5 != NULL) {
  1721. DWORD cbData = SizeOfDib((LPBITMAPINFOHEADER)lpDibV5);
  1722. /*
  1723. * Convert the dib-spec to the special-clipboard memory-handle (size,
  1724. * base, data). This so the client is able to convert properly when
  1725. * handled a dib.
  1726. */
  1727. hDibV5 = _ConvertMemHandle((LPBYTE)lpDibV5, cbData);
  1728. UserFreePool(lpDibV5);
  1729. if (hDibV5 != NULL) {
  1730. /*
  1731. * Once, we create *real* bitmap, overwrite dummy handle.
  1732. */
  1733. pClipT = FindClipFormat(pwinsta, CF_DIBV5);
  1734. if (pClipT) {
  1735. UT_FreeCBFormat(pClipT);
  1736. pClipT->hData = hDibV5;
  1737. /*
  1738. * Let callee know we can obtain CF_DIBV5.
  1739. */
  1740. pgcd->uFmtRet = CF_DIBV5;
  1741. } else {
  1742. PVOID pObj;
  1743. /*
  1744. * Bleh -- now we can't find the DIB entry anymore. Bail.
  1745. */
  1746. RIPMSG0(RIP_WARNING,
  1747. "Clipboard: CF_DIBV5 format not available");
  1748. pObj = HMValidateHandleNoRip(hDibV5, TYPE_CLIPDATA);
  1749. if (pObj) {
  1750. HMFreeObject(pObj);
  1751. }
  1752. hDibV5 = NULL;
  1753. }
  1754. }
  1755. }
  1756. return hDibV5;
  1757. }
  1758. /***************************************************************************\
  1759. * CreateDIBPalette
  1760. *
  1761. * This creates a palette with PC_NOCOLLAPSE entries since we require the
  1762. * palette-entries and bitmap-indexes to map exactly. Otherwise, we could
  1763. * end up selecting a palette where a color collapses to an index not
  1764. * where the bitmap thinks it is. This would cause slower drawing since
  1765. * the Blt would go through color translation.
  1766. *
  1767. * History:
  1768. * 31-Jan-1992 MikeKe From win31
  1769. \***************************************************************************/
  1770. HPALETTE CreateDIBPalette(
  1771. LPBITMAPINFOHEADER pbmih,
  1772. UINT colors)
  1773. {
  1774. HPALETTE hpal;
  1775. if (colors != 0) {
  1776. int i;
  1777. BOOL fOldDIB = (pbmih->biSize == sizeof(BITMAPCOREHEADER));
  1778. RGBTRIPLE *pColorTable;
  1779. PLOGPALETTE plp;
  1780. /*
  1781. * Allocate memory for palette creation.
  1782. */
  1783. plp = (PLOGPALETTE)UserAllocPoolWithQuota(sizeof(LOGPALETTE) +
  1784. (sizeof(PALETTEENTRY) * 256),
  1785. TAG_CLIPBOARDPALETTE);
  1786. if (plp == NULL) {
  1787. return NULL;
  1788. }
  1789. pColorTable = (RGBTRIPLE *)((LPSTR)pbmih + (WORD)pbmih->biSize);
  1790. plp->palVersion = 0x300;
  1791. if (fOldDIB || (pbmih->biClrUsed == 0)) {
  1792. UserAssert(colors <= 0xFFFF);
  1793. plp->palNumEntries = (WORD)colors;
  1794. } else {
  1795. UserAssert(pbmih->biClrUsed <= 0xFFFF);
  1796. plp->palNumEntries = (WORD)pbmih->biClrUsed;
  1797. }
  1798. for (i = 0; i < (int)(plp->palNumEntries); i++) {
  1799. plp->palPalEntry[i].peRed = pColorTable->rgbtRed;
  1800. plp->palPalEntry[i].peGreen = pColorTable->rgbtGreen;
  1801. plp->palPalEntry[i].peBlue = pColorTable->rgbtBlue;
  1802. plp->palPalEntry[i].peFlags = (BYTE)PC_NOCOLLAPSE;
  1803. if (fOldDIB) {
  1804. pColorTable++;
  1805. } else {
  1806. pColorTable = (RGBTRIPLE *)((LPSTR)pColorTable+sizeof(RGBQUAD));
  1807. }
  1808. }
  1809. hpal = GreCreatePalette((LPLOGPALETTE)plp);
  1810. UserFreePool(plp);
  1811. } else {
  1812. hpal = GreCreateHalftonePalette(HDCBITS());
  1813. }
  1814. GreSetPaletteOwner(hpal, OBJECT_OWNER_PUBLIC);
  1815. return hpal;
  1816. }
  1817. /***************************************************************************\
  1818. * xxxGetDummyPalette
  1819. *
  1820. * Returns a real-palette from a dummy-format. Derives it from a real DIB.
  1821. *
  1822. * History:
  1823. * 24-Oct-1995 ChrisWil Created.
  1824. \***************************************************************************/
  1825. HANDLE xxxGetDummyPalette(
  1826. PWINDOWSTATION pwinsta,
  1827. PGETCLIPBDATA pgcd)
  1828. {
  1829. HANDLE hData;
  1830. PCLIPDATA pData;
  1831. LPBITMAPINFOHEADER lpbih;
  1832. HPALETTE hPal;
  1833. PCLIP pClipT;
  1834. /*
  1835. * Since CF_DIBV5 has higher priority than CF_DIB, look into CF_DIBV5
  1836. * first to find DIB palette.
  1837. */
  1838. UINT uFmt = CF_DIBV5;
  1839. if ((pClipT = FindClipFormat(pwinsta, uFmt)) != NULL) {
  1840. if (pClipT->hData != DUMMY_DIB_HANDLE) {
  1841. /*
  1842. * Ok, we have real CF_DIBV5, let extract palette from DIBV5.
  1843. */
  1844. } else {
  1845. /*
  1846. * Otherwise, try CF_DIB.
  1847. */
  1848. uFmt = CF_DIB;
  1849. /*
  1850. * If no DIB available or it's a dummy handle, bail since we
  1851. * must have a real DIB to derive the palette.
  1852. */
  1853. if ((pClipT = FindClipFormat(pwinsta, uFmt)) == NULL) {
  1854. return NULL;
  1855. }
  1856. if (pClipT->hData == DUMMY_DIB_HANDLE) {
  1857. return NULL;
  1858. }
  1859. }
  1860. }
  1861. /*
  1862. * Get the DIB by which we derive the palette. If the DIB comes back as a
  1863. * dummy, then there's something wrong. We must have a real dib at this
  1864. * point.
  1865. */
  1866. hData = (HANDLE)xxxGetClipboardData(pwinsta, uFmt, pgcd);
  1867. UserAssert(hData > DUMMY_MAX_HANDLE);
  1868. if (hData == NULL) {
  1869. return NULL;
  1870. }
  1871. /*
  1872. * Since DIBs (memory-handles) are stored in a special format (size, base,
  1873. * data), we need to offet the pointer to the right offset (2 uints).
  1874. */
  1875. if (pData = (PCLIPDATA)HMValidateHandle(hData, TYPE_CLIPDATA)) {
  1876. lpbih = (LPBITMAPINFOHEADER)&pData->abData;
  1877. } else {
  1878. UserAssert(pData != NULL);
  1879. return NULL;
  1880. }
  1881. if ((pClipT = FindClipFormat(pwinsta, CF_PALETTE)) == NULL) {
  1882. RIPMSG0(RIP_WARNING,
  1883. "Clipboard: CF_PALETTE format not available");
  1884. return NULL;
  1885. }
  1886. /*
  1887. * Note -- if CreateDIBPalette ever changes to leave the crit sect,
  1888. * we will need to move the above FindClipFormat to after the create
  1889. * call and deal with gracefully freeing hPal on failure. pClipT
  1890. * can change during callbacks.
  1891. */
  1892. hPal = CreateDIBPalette(lpbih, lpbih->biClrUsed);
  1893. if (hPal != NULL) {
  1894. UT_FreeCBFormat(pClipT);
  1895. pClipT->hData = hPal;
  1896. GreSetPaletteOwner(hPal, OBJECT_OWNER_PUBLIC);
  1897. }
  1898. return (HANDLE)hPal;
  1899. }
  1900. /***************************************************************************\
  1901. * xxxGetDummyText
  1902. *
  1903. * Returns a handle to text from a dummy-format.
  1904. *
  1905. * History:
  1906. * 24-Oct-1995 ChrisWil Created.
  1907. \***************************************************************************/
  1908. HANDLE xxxGetDummyText(
  1909. PWINDOWSTATION pwinsta,
  1910. UINT fmt,
  1911. PGETCLIPBDATA pgcd)
  1912. {
  1913. HANDLE hText;
  1914. PCLIP pClipT;
  1915. UINT uFmtMain;
  1916. UINT uFmtAlt;
  1917. BOOL bMain = TRUE;
  1918. /*
  1919. * Get the handle of the other text format available.
  1920. */
  1921. switch (fmt) {
  1922. case CF_TEXT:
  1923. uFmtMain = CF_UNICODETEXT;
  1924. uFmtAlt = CF_OEMTEXT;
  1925. goto GetRealText;
  1926. case CF_OEMTEXT:
  1927. uFmtMain = CF_UNICODETEXT;
  1928. uFmtAlt = CF_TEXT;
  1929. goto GetRealText;
  1930. case CF_UNICODETEXT:
  1931. uFmtMain = CF_TEXT;
  1932. uFmtAlt = CF_OEMTEXT;
  1933. GetRealText:
  1934. if ((pClipT = FindClipFormat(pwinsta, uFmtMain)) == NULL) {
  1935. return NULL;
  1936. }
  1937. if (pClipT->hData != DUMMY_TEXT_HANDLE) {
  1938. if (xxxGetClipboardData(pwinsta, uFmtMain, pgcd)) {
  1939. break;
  1940. }
  1941. return NULL;
  1942. }
  1943. if ((pClipT = FindClipFormat(pwinsta, uFmtAlt)) == NULL) {
  1944. return NULL;
  1945. }
  1946. if (pClipT->hData != DUMMY_TEXT_HANDLE) {
  1947. bMain = FALSE;
  1948. if (xxxGetClipboardData(pwinsta, uFmtAlt, pgcd)) {
  1949. break;
  1950. }
  1951. }
  1952. /*
  1953. * Fall through to return a dummy handle.
  1954. */
  1955. default:
  1956. return NULL;
  1957. }
  1958. /*
  1959. * Since xxxGetClipboardData leaves the critsect, we need to reacquire
  1960. * pClipT.
  1961. */
  1962. pClipT = FindClipFormat(pwinsta, bMain ? uFmtMain : uFmtAlt);
  1963. if (pClipT == NULL) {
  1964. RIPMSG1(RIP_WARNING,
  1965. "Clipboard: GetDummyText, format 0x%x not available",
  1966. bMain ? uFmtMain : uFmtAlt);
  1967. return NULL;
  1968. }
  1969. /*
  1970. * Return the type of the returned data.
  1971. */
  1972. pgcd->uFmtRet = pClipT->fmt;
  1973. hText = pClipT->hData;
  1974. /*
  1975. * Set the locale, since the text will need to be converted to another
  1976. * format.
  1977. */
  1978. if (pClipT = FindClipFormat(pwinsta, CF_LOCALE)) {
  1979. pgcd->hLocale = pClipT->hData;
  1980. } else {
  1981. pgcd->hLocale = NULL;
  1982. }
  1983. return hText;
  1984. }
  1985. /***************************************************************************\
  1986. * xxxGetRenderData
  1987. *
  1988. * Returns a handle to delayed rendered data. This requires a call to the
  1989. * client to supply the data. This causes us to regenerate our pointer to
  1990. * pClip.
  1991. *
  1992. * History:
  1993. * 24-Oct-1995 ChrisWil Created.
  1994. \***************************************************************************/
  1995. HANDLE xxxGetRenderData(
  1996. PWINDOWSTATION pwinsta,
  1997. UINT fmt)
  1998. {
  1999. BOOL fClipboardChangedOld;
  2000. TL tlpwndClipOwner;
  2001. PCLIP pClip;
  2002. DWORD_PTR lpdwResult;
  2003. /*
  2004. * If the handle is NULL, the data is delay rendered. This means we send
  2005. * a message to the current clipboard owner and have it render the data
  2006. * for us.
  2007. */
  2008. if (pwinsta->spwndClipOwner != NULL) {
  2009. BOOL fSucceeded;
  2010. /*
  2011. * Preserve the WSF_CLIPBOARDCHANGED flag before SendMessage and
  2012. * restore the flag later. Thus we ignore the changes done to the
  2013. * WSF_CLIPBOARDCHANGED flag by apps while rendering data in the
  2014. * delayed rendering scheme. This avoids clipboard viewers from
  2015. * painting twice.
  2016. */
  2017. fClipboardChangedOld = (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) != 0;
  2018. SET_FLAG(pwinsta->dwWSF_Flags, WSF_INDELAYEDRENDERING);
  2019. ThreadLockAlways(pwinsta->spwndClipOwner, &tlpwndClipOwner);
  2020. if (!xxxSendMessageTimeout(pwinsta->spwndClipOwner,
  2021. WM_RENDERFORMAT,
  2022. fmt,
  2023. 0L,
  2024. SMTO_ABORTIFHUNG,
  2025. CB_DELAYRENDER_TIMEOUT,
  2026. &lpdwResult)) {
  2027. fSucceeded = FALSE;
  2028. } else {
  2029. fSucceeded = TRUE;
  2030. }
  2031. ThreadUnlock(&tlpwndClipOwner);
  2032. SET_OR_CLEAR_FLAG(pwinsta->dwWSF_Flags, WSF_CLIPBOARDCHANGED, fClipboardChangedOld);
  2033. CLEAR_FLAG(pwinsta->dwWSF_Flags, WSF_INDELAYEDRENDERING);
  2034. if (!fSucceeded) {
  2035. return NULL;
  2036. }
  2037. }
  2038. if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
  2039. RIPMSGF1(RIP_WARNING,
  2040. "Meta Render/Clone format 0x%x not available", fmt);
  2041. return NULL;
  2042. }
  2043. /*
  2044. * We should have the handle now since it has been rendered.
  2045. */
  2046. return pClip->hData;
  2047. }
  2048. /***************************************************************************\
  2049. * xxxGetClipboardData (API)
  2050. *
  2051. * Grabs a particular data object out of the clipboard.
  2052. *
  2053. * History:
  2054. * 18-Nov-1990 ScottLu Ported from Win3.
  2055. * 20-Aug-1991 EichiM UNICODE enabling
  2056. \***************************************************************************/
  2057. HANDLE xxxGetClipboardData(
  2058. PWINDOWSTATION pwinsta,
  2059. UINT fmt,
  2060. PGETCLIPBDATA pgcd)
  2061. {
  2062. PCLIP pClip;
  2063. HANDLE hData;
  2064. /*
  2065. * Check the clipboard owner.
  2066. */
  2067. if (pwinsta->ptiClipLock != PtiCurrent()) {
  2068. RIPERR0(ERROR_CLIPBOARD_NOT_OPEN, RIP_VERBOSE, "GetClipboardData: clipboard not open");
  2069. return NULL;
  2070. }
  2071. /*
  2072. * Make sure the format is available.
  2073. */
  2074. if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
  2075. RIPMSG1(RIP_VERBOSE, "Clipboard: Requested format 0x%lX not available", fmt);
  2076. return NULL;
  2077. }
  2078. /*
  2079. * If this is a DUMMY_META*_HANDLE it means that the other metafile
  2080. * format was set in as a delay render format and we should ask for that
  2081. * format to get the metafile because the app has not told us they know
  2082. * about this format.
  2083. */
  2084. if (IsMetaDummyHandle(pClip->hData)) {
  2085. if (fmt == CF_ENHMETAFILE) {
  2086. fmt = CF_METAFILEPICT;
  2087. } else if (fmt == CF_METAFILEPICT) {
  2088. fmt = CF_ENHMETAFILE;
  2089. } else {
  2090. RIPMSG0(RIP_WARNING,
  2091. "Clipboard: Meta Render/Clone expects a metafile type");
  2092. }
  2093. if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
  2094. RIPMSG1(RIP_WARNING,
  2095. "Clipboard: Meta Render/Clone format 0x%x not available", fmt);
  2096. return NULL;
  2097. }
  2098. }
  2099. /*
  2100. * This is the data we're returning, unless it's a dummy or render handle.
  2101. */
  2102. hData = pClip->hData;
  2103. /*
  2104. * We are dealing with non-handles. Retrieve the real data through these
  2105. * inline-routines. NOTE: These make recursive calls to
  2106. * xxxGetClipboardData(), so care must be taken to assure the pClip is
  2107. * pointing to what we think it's pointing to.
  2108. */
  2109. if (hData == NULL || hData == DUMMY_METARENDER_HANDLE) {
  2110. hData = xxxGetRenderData(pwinsta, fmt);
  2111. } else if (hData == DUMMY_DIB_HANDLE) {
  2112. switch (fmt) {
  2113. case CF_DIB:
  2114. hData = xxxGetDummyDib(pwinsta, pgcd);
  2115. break;
  2116. case CF_DIBV5:
  2117. hData = xxxGetDummyDibV5(pwinsta, pgcd);
  2118. break;
  2119. case CF_BITMAP:
  2120. hData = xxxGetDummyBitmap(pwinsta, pgcd);
  2121. break;
  2122. case CF_PALETTE:
  2123. hData = xxxGetDummyPalette(pwinsta, pgcd);
  2124. break;
  2125. }
  2126. } else if (hData == DUMMY_TEXT_HANDLE) {
  2127. hData = xxxGetDummyText(pwinsta, fmt, pgcd);
  2128. } else {
  2129. /*
  2130. * This path took no callbacks, so we know pClip is OK.
  2131. */
  2132. if (pgcd) {
  2133. pgcd->fGlobalHandle = pClip->fGlobalHandle;
  2134. }
  2135. return hData;
  2136. }
  2137. /*
  2138. * The callbacks for dummy handle resolution have possibly invalidated
  2139. * pClip -- recreate it.
  2140. */
  2141. if ((pClip = FindClipFormat(pwinsta, fmt)) == NULL) {
  2142. RIPMSG1(RIP_VERBOSE, "Clipboard: Requested format 0x%x not available", fmt);
  2143. return NULL;
  2144. }
  2145. /*
  2146. * Return if this is a global-handle.
  2147. */
  2148. if (pgcd) {
  2149. pgcd->fGlobalHandle = pClip->fGlobalHandle;
  2150. }
  2151. return hData;
  2152. }
  2153. /***************************************************************************\
  2154. * FindClipFormat
  2155. *
  2156. * Finds a particular clipboard format in the clipboard, returns a pointer
  2157. * to it, or NULL. If a pointer is found, on return the clipboard is locked
  2158. * and pwinsta->pClipBase has been updated to point to the beginning of the
  2159. * clipboard.
  2160. *
  2161. * History:
  2162. * 18-Nov-1990 ScottLu Ported from Win3.
  2163. \***************************************************************************/
  2164. PCLIP FindClipFormat(
  2165. PWINDOWSTATION pwinsta,
  2166. UINT format)
  2167. {
  2168. PCLIP pClip;
  2169. int iFmt;
  2170. if (format != 0 && ((pClip = pwinsta->pClipBase) != NULL)) {
  2171. for (iFmt = pwinsta->cNumClipFormats; iFmt-- != 0;) {
  2172. if (pClip->fmt == format) {
  2173. return pClip;
  2174. }
  2175. pClip++;
  2176. }
  2177. }
  2178. return NULL;
  2179. }
  2180. /***************************************************************************\
  2181. * _GetPriorityClipboardFormat (API)
  2182. *
  2183. * This api allows an application to look for any one of a range of
  2184. * clipboard formats in a predefined search order.
  2185. *
  2186. * History:
  2187. * 18-Nov-1990 ScottLu Ported from Win3.
  2188. * 11-Feb-1991 JimA Added access checks.
  2189. \***************************************************************************/
  2190. int _GetPriorityClipboardFormat(
  2191. PUINT lpPriorityList,
  2192. int cfmts)
  2193. {
  2194. PWINDOWSTATION pwinsta;
  2195. PCLIP pClip;
  2196. int iFmt;
  2197. UINT fmt;
  2198. /*
  2199. * Blow it off if the caller does not have the proper access rights.
  2200. */
  2201. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  2202. return 0;
  2203. }
  2204. /*
  2205. * If there is no clipboard or no objects in the clipboard, return 0.
  2206. */
  2207. if (pwinsta->cNumClipFormats == 0 || pwinsta->pClipBase == NULL) {
  2208. return 0;
  2209. }
  2210. /*
  2211. * Look through the list for any of the formats in lpPriorityList.
  2212. */
  2213. while (cfmts-- > 0) {
  2214. fmt = *lpPriorityList;
  2215. if (fmt != 0) {
  2216. pClip = pwinsta->pClipBase;
  2217. for (iFmt = pwinsta->cNumClipFormats; iFmt-- != 0; pClip++) {
  2218. if (pClip->fmt == fmt) {
  2219. return fmt;
  2220. }
  2221. }
  2222. }
  2223. lpPriorityList++;
  2224. }
  2225. /*
  2226. * There is no matching format, so return -1.
  2227. */
  2228. return -1;
  2229. }
  2230. /***************************************************************************\
  2231. * xxxSetClipboardViewer (API)
  2232. *
  2233. * Sets the clipboard viewer window.
  2234. *
  2235. * History:
  2236. * 18-Nov-1990 ScottLu Ported from Win3.
  2237. * 11-Feb-1991 JimA Added access checks.
  2238. \***************************************************************************/
  2239. PWND xxxSetClipboardViewer(
  2240. PWND pwndClipViewerNew)
  2241. {
  2242. TL tlpwinsta;
  2243. PWINDOWSTATION pwinsta;
  2244. HWND hwndClipViewerOld;
  2245. PTHREADINFO ptiCurrent;
  2246. CheckLock(pwndClipViewerNew);
  2247. /*
  2248. * Do not let a destroyed window be locked into the winsta. See
  2249. * _OpenClipboard for more details.
  2250. */
  2251. if (pwndClipViewerNew != NULL && TestWF(pwndClipViewerNew, WFDESTROYED)) {
  2252. RIPERR1(ERROR_INVALID_PARAMETER,
  2253. RIP_WARNING,
  2254. "Destroyed pwnd 0x%p trying to become clipboard viewer",
  2255. pwndClipViewerNew);
  2256. return NULL;
  2257. }
  2258. /*
  2259. * Blow it off if the caller does not have the proper access rights. The
  2260. * NULL return really doesn't indicate an error but the supposed viewer
  2261. * will never receive any clipboard messages, so it shouldn't cause any
  2262. * problems.
  2263. */
  2264. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  2265. return NULL;
  2266. }
  2267. ptiCurrent = PtiCurrent();
  2268. ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  2269. hwndClipViewerOld = HW(pwinsta->spwndClipViewer);
  2270. Lock(&pwinsta->spwndClipViewer, pwndClipViewerNew);
  2271. xxxDrawClipboard(pwinsta);
  2272. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  2273. if (hwndClipViewerOld != NULL) {
  2274. return RevalidateHwnd(hwndClipViewerOld);
  2275. }
  2276. return NULL;
  2277. }
  2278. /***************************************************************************\
  2279. * xxxChangeClipboardChain (API)
  2280. *
  2281. * Changes the clipboard viewer chain.
  2282. *
  2283. * History:
  2284. * 18-Nov-1990 ScottLu Ported from Win3.
  2285. * 11-Feb-1991 JimA Added access checks.
  2286. \***************************************************************************/
  2287. BOOL xxxChangeClipboardChain(
  2288. PWND pwndRemove,
  2289. PWND pwndNewNext)
  2290. {
  2291. TL tlpwinsta;
  2292. PWINDOWSTATION pwinsta;
  2293. BOOL result;
  2294. TL tlpwndClipViewer;
  2295. PTHREADINFO ptiCurrent;
  2296. CheckLock(pwndRemove);
  2297. CheckLock(pwndNewNext);
  2298. /*
  2299. * Blow it off if the caller does not have the proper access rights.
  2300. */
  2301. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  2302. return FALSE;
  2303. }
  2304. /*
  2305. * pwndRemove should be this thread's window, pwndNewNext will either be
  2306. * NULL or another thread's window.
  2307. */
  2308. ptiCurrent = PtiCurrent();
  2309. if (GETPTI(pwndRemove) != ptiCurrent) {
  2310. RIPMSG0(RIP_WARNING,
  2311. "Clipboard: ChangeClipboardChain will not remove cross threads");
  2312. return FALSE;
  2313. }
  2314. if (pwinsta->spwndClipViewer == NULL) {
  2315. RIPMSG0(RIP_WARNING, "Clipboard: ChangeClipboardChain has no viewer window");
  2316. return FALSE;
  2317. }
  2318. ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  2319. if (pwndRemove == pwinsta->spwndClipViewer) {
  2320. Lock(&pwinsta->spwndClipViewer, pwndNewNext);
  2321. result = TRUE;
  2322. } else {
  2323. ThreadLockAlways(pwinsta->spwndClipViewer, &tlpwndClipViewer);
  2324. result = (BOOL)xxxSendMessage(pwinsta->spwndClipViewer,
  2325. WM_CHANGECBCHAIN,
  2326. (WPARAM)HW(pwndRemove),
  2327. (LPARAM)HW(pwndNewNext));
  2328. ThreadUnlock(&tlpwndClipViewer);
  2329. }
  2330. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  2331. return result;
  2332. }
  2333. /***************************************************************************\
  2334. * xxxDisownClipboard
  2335. *
  2336. * Disowns the clipboard so someone else can grab it.
  2337. *
  2338. * pwndClipOwner is the pwnd that is the reason for disowning the clipboard
  2339. * when that window is deleted.
  2340. *
  2341. * History:
  2342. * 18-Jun-1991 DarrinM Ported from Win3.
  2343. \***************************************************************************/
  2344. VOID xxxDisownClipboard(
  2345. PWND pwndClipOwner)
  2346. {
  2347. TL tlpwinsta;
  2348. PWINDOWSTATION pwinsta;
  2349. int iFmt;
  2350. int cFmts;
  2351. PCLIP pClip;
  2352. PCLIP pClipOut;
  2353. BOOL fKeepDummyHandle;
  2354. PTHREADINFO ptiCurrent;
  2355. if ((pwinsta = CheckClipboardAccess()) == NULL) {
  2356. return;
  2357. }
  2358. ptiCurrent = PtiCurrent();
  2359. ThreadLockWinSta(ptiCurrent, pwinsta, &tlpwinsta);
  2360. xxxSendClipboardMessage(pwinsta, WM_RENDERALLFORMATS);
  2361. pClipOut = pClip = pwinsta->pClipBase;
  2362. fKeepDummyHandle = FALSE;
  2363. for (cFmts = 0, iFmt = pwinsta->cNumClipFormats; iFmt-- != 0;) {
  2364. /*
  2365. * We have to remove the Dummy handles also if the corresponding
  2366. * valid handles are NULL; We should not remove the dummy handles if
  2367. * the corresponding valid handles are not NULL. The following code
  2368. * assumes that only one dummy handle is possible and that can appear
  2369. * only after the corresponding valid handle in the pClip linked list.
  2370. */
  2371. if (pClip->hData != NULL) {
  2372. if ((pClip->hData != DUMMY_TEXT_HANDLE) ||
  2373. ((pClip->hData == DUMMY_TEXT_HANDLE) && fKeepDummyHandle)) {
  2374. cFmts++;
  2375. *pClipOut++ = *pClip;
  2376. if (IsTextHandle(pClip->fmt, pClip->hData)) {
  2377. fKeepDummyHandle = TRUE;
  2378. }
  2379. }
  2380. }
  2381. pClip++;
  2382. }
  2383. /*
  2384. * Unlock the clipboard owner if the owner is still the window we were
  2385. * cleaning up for.
  2386. */
  2387. if (pwndClipOwner == pwinsta->spwndClipOwner) {
  2388. Unlock(&pwinsta->spwndClipOwner);
  2389. } else {
  2390. RIPMSGF2(RIP_WARNING,
  2391. "pwndClipOwner changed from 0x%p to 0x%p",
  2392. pwndClipOwner,
  2393. pwinsta->spwndClipOwner);
  2394. }
  2395. /*
  2396. * If number of formats changed, redraw.
  2397. */
  2398. if (cFmts != pwinsta->cNumClipFormats) {
  2399. pwinsta->dwWSF_Flags |= WSF_CLIPBOARDCHANGED;
  2400. pwinsta->iClipSequenceNumber++;
  2401. }
  2402. pwinsta->cNumClipFormats = cFmts;
  2403. /*
  2404. * If anything changed, redraw, and make sure the data type munging is
  2405. * done. Else we will lose them when xxxDrawClipboard clears the
  2406. * WSF_CLIPBOARDCHANGED flag.
  2407. */
  2408. if (pwinsta->dwWSF_Flags & WSF_CLIPBOARDCHANGED) {
  2409. xxxDrawClipboard(pwinsta);
  2410. MungeClipData(pwinsta);
  2411. }
  2412. ThreadUnlockWinSta(ptiCurrent, &tlpwinsta);
  2413. }
  2414. /***************************************************************************\
  2415. * ForceEmptyClipboard
  2416. *
  2417. * We're logging off. Force the clipboard contents to go away.
  2418. *
  2419. * 23-Jul-1992 ScottLu Created.
  2420. \***************************************************************************/
  2421. VOID ForceEmptyClipboard(
  2422. PWINDOWSTATION pwinsta)
  2423. {
  2424. /*
  2425. * This will be NULL for a non-GUI thread.
  2426. */
  2427. pwinsta->ptiClipLock = ((PTHREADINFO)(W32GetCurrentThread()));
  2428. Unlock(&pwinsta->spwndClipOwner);
  2429. Unlock(&pwinsta->spwndClipViewer);
  2430. Unlock(&pwinsta->spwndClipOpen);
  2431. xxxEmptyClipboard(pwinsta);
  2432. /*
  2433. * If the windowstation is dying, don't bother closing the clipboard.
  2434. */
  2435. if (!(pwinsta->dwWSF_Flags & WSF_DYING)) {
  2436. xxxCloseClipboard(pwinsta);
  2437. }
  2438. }