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.

2374 lines
62 KiB

  1. /*****************************************************************************
  2. C L I P B O O K D I S P L A Y
  3. Name: clipdsp.c
  4. Date: 21-Jan-1994
  5. Creator: Unknown
  6. Description:
  7. This module handles the drawing of the clipbook displays.
  8. *****************************************************************************/
  9. #define WIN31
  10. #include <windows.h>
  11. #include <strsafe.h>
  12. #include "common.h"
  13. #include "clipbook.h"
  14. #include "clpbkrc.h"
  15. #include "clipbrd.h"
  16. #include "clipdsp.h"
  17. #include "debugout.h"
  18. #include "cvutil.h"
  19. #define ifmtMax (sizeof(rgfmt)/sizeof(WORD))
  20. static MFENUMPROC lpEnumMetaProc;
  21. BOOL fOwnerDisplay;
  22. HBRUSH hbrBackground;
  23. HMENU hDispMenu;
  24. /* The scroll information for OWNER display is to be preserved, whenever
  25. * the display changes between OWNER and NON-OWNER; The following globals
  26. * are used to save and restore the scroll info.
  27. */
  28. // winball: since only the Clipboard window supports owner display,
  29. // this info is not replicated for each MDI child...
  30. int OwnVerMin;
  31. int OwnVerMax;
  32. int OwnHorMin;
  33. int OwnHorMax;
  34. int OwnVerPos;
  35. int OwnHorPos;
  36. /* Defines priority order for show format */
  37. WORD rgfmt[] = {
  38. CF_OWNERDISPLAY,
  39. CF_UNICODETEXT,
  40. CF_TEXT,
  41. CF_OEMTEXT,
  42. CF_ENHMETAFILE,
  43. CF_METAFILEPICT,
  44. CF_DIB,
  45. CF_BITMAP,
  46. CF_DSPTEXT,
  47. CF_DSPBITMAP,
  48. CF_DSPMETAFILEPICT,
  49. CF_DSPENHMETAFILE,
  50. CF_PALETTE,
  51. CF_RIFF,
  52. CF_WAVE,
  53. CF_PENDATA,
  54. CF_SYLK,
  55. CF_DIF,
  56. CF_TIFF,
  57. CF_LOCALE
  58. };
  59. void ShowString( HWND, HDC, WORD);
  60. /*
  61. * MyOpenClipBoard
  62. */
  63. BOOL MyOpenClipboard(
  64. HWND hWnd)
  65. {
  66. HDC hDC;
  67. RECT Rect;
  68. if( VOpenClipboard( GETMDIINFO(hWnd)->pVClpbrd, hWnd ))
  69. return(TRUE);
  70. PERROR(TEXT("MyOpenClipboard fail\r\n"));
  71. /* Some app forgot to close the clipboard */
  72. hDC = GetDC(hWnd);
  73. GetClientRect(hWnd, (LPRECT)&Rect);
  74. FillRect(hDC, (LPRECT)&Rect, hbrBackground);
  75. ShowString( hWnd, hDC, IDS_ALREADYOPEN);
  76. ReleaseDC(hWnd, hDC);
  77. return(FALSE);
  78. }
  79. /*
  80. * SetCharDimensions
  81. */
  82. void SetCharDimensions(
  83. HWND hWnd,
  84. HFONT hFont)
  85. {
  86. register HDC hdc;
  87. TEXTMETRIC tm;
  88. PMDIINFO pMDI;
  89. pMDI = GETMDIINFO(hWnd);
  90. if (pMDI)
  91. {
  92. hdc = GetDC(hWnd);
  93. SelectObject(hdc, hFont);
  94. GetTextMetrics(hdc, (LPTEXTMETRIC)&tm);
  95. ReleaseDC(hWnd, hdc);
  96. pMDI->cxChar = (WORD)tm.tmAveCharWidth;
  97. pMDI->cxMaxCharWidth = (WORD)tm.tmMaxCharWidth;
  98. pMDI->cyLine = (WORD)(tm.tmHeight + tm.tmExternalLeading);
  99. pMDI->cxMargin = pMDI->cxChar / 2;
  100. pMDI->cyMargin = pMDI->cyLine / 4;
  101. }
  102. }
  103. /*
  104. * ChangeCharDimensions
  105. */
  106. void ChangeCharDimensions(
  107. HWND hwnd,
  108. UINT wOldFormat,
  109. UINT wNewFormat)
  110. {
  111. /* Check if the font has changed. */
  112. if (wOldFormat == CF_OEMTEXT)
  113. {
  114. if (wNewFormat != CF_OEMTEXT) // Select default system font sizes
  115. SetCharDimensions(hwnd, GetStockObject ( SYSTEM_FONT ) );
  116. }
  117. else if (wNewFormat == CF_OEMTEXT) // Select OEM font sizes
  118. SetCharDimensions(hwnd, GetStockObject ( OEM_FIXED_FONT ) );
  119. }
  120. /*
  121. * ClipbrdVScroll
  122. *
  123. * Scroll contents of window vertically, according to action code in wParam.
  124. */
  125. void ClipbrdVScroll (
  126. HWND hwnd,
  127. WORD wParam,
  128. WORD wThumb)
  129. {
  130. int cyWindow;
  131. long dyScroll;
  132. long cyScrollT;
  133. long dyScrollAbs;
  134. long cyPartialChar;
  135. PMDIINFO pMDI;
  136. pMDI = GETMDIINFO(hwnd);
  137. if (pMDI)
  138. {
  139. /* Ensure that all the bits are valid first, before scrolling them */
  140. UpdateWindow(hwnd);
  141. cyScrollT = pMDI->cyScrollNow;
  142. cyWindow = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
  143. /* Compute scroll results as an effect on cyScrollNow */
  144. switch (wParam)
  145. {
  146. case SB_LINEUP:
  147. cyScrollT -= pMDI->cyLine;
  148. break;
  149. case SB_LINEDOWN:
  150. cyScrollT += pMDI->cyLine;
  151. break;
  152. case SB_THUMBPOSITION:
  153. cyScrollT = (LONG)(((LONG)wThumb * pMDI->cyScrollLast) / VPOSLAST);
  154. break;
  155. case SB_PAGEUP:
  156. case SB_PAGEDOWN:
  157. {
  158. int cyPageScroll;
  159. cyPageScroll = cyWindow - pMDI->cyLine;
  160. if (cyPageScroll < (int)(pMDI->cyLine))
  161. cyPageScroll = pMDI->cyLine;
  162. cyScrollT += (wParam == SB_PAGEUP) ? -cyPageScroll : cyPageScroll;
  163. break;
  164. }
  165. default:
  166. return;
  167. }
  168. if ((cyScrollT < 0) || (pMDI->cyScrollLast <= 0))
  169. cyScrollT = 0;
  170. else if (cyScrollT > pMDI->cyScrollLast)
  171. cyScrollT = pMDI->cyScrollLast;
  172. else if (cyPartialChar = cyScrollT % pMDI->cyLine)
  173. {
  174. /* Round to the nearest character increment. */
  175. if (cyPartialChar > ((int)(pMDI->cyLine) >> 1))
  176. cyScrollT += pMDI->cyLine;
  177. cyScrollT -= cyPartialChar;
  178. }
  179. dyScroll = pMDI->cyScrollNow - cyScrollT;
  180. if (dyScroll > 0)
  181. dyScrollAbs = dyScroll;
  182. else if (dyScroll < 0)
  183. dyScrollAbs = -dyScroll;
  184. else
  185. return; /* Scrolling has no effect here. */
  186. pMDI->cyScrollNow = cyScrollT;
  187. if (dyScrollAbs >= pMDI->rcWindow.bottom - pMDI->rcWindow.top)
  188. /* ScrollWindow does not handle this case */
  189. InvalidateRect(hwnd, (LPRECT)&(pMDI->rcWindow), TRUE);
  190. else
  191. ScrollWindow(hwnd, 0,(int)dyScroll, &(pMDI->rcWindow), &(pMDI->rcWindow));
  192. UpdateWindow(hwnd);
  193. SetScrollPos (pMDI->hwndVscroll,
  194. SB_CTL,
  195. (pMDI->cyScrollLast <= 0) ?
  196. 0 :
  197. (int)((cyScrollT * (DWORD)VPOSLAST) / pMDI->cyScrollLast),
  198. TRUE);
  199. }
  200. }
  201. /*
  202. * ClipbrdHScroll
  203. *
  204. * Scroll contents of window horizontally, according to op code in wParam.
  205. */
  206. void ClipbrdHScroll (
  207. HWND hwnd,
  208. WORD wParam,
  209. WORD wThumb)
  210. {
  211. register int dxScroll;
  212. register int cxScrollT;
  213. int cxWindow;
  214. int dxScrollAbs;
  215. int cxPartialChar;
  216. PMDIINFO pMDI;
  217. pMDI = GETMDIINFO(hwnd);
  218. if (pMDI)
  219. {
  220. cxScrollT = pMDI->cxScrollNow;
  221. cxWindow = pMDI->rcWindow.right - pMDI->rcWindow.left;
  222. /* Compute scroll results as an effect on cxScrollNow */
  223. switch (wParam)
  224. {
  225. case SB_LINEUP:
  226. cxScrollT -= pMDI->cxChar;
  227. break;
  228. case SB_LINEDOWN:
  229. cxScrollT += pMDI->cxChar;
  230. break;
  231. case SB_THUMBPOSITION:
  232. cxScrollT = (int)(((LONG)wThumb * (LONG)pMDI->cxScrollLast) / HPOSLAST);
  233. break;
  234. case SB_PAGEUP:
  235. case SB_PAGEDOWN:
  236. {
  237. int cxPageScroll;
  238. cxPageScroll = cxWindow - pMDI->cxChar;
  239. if (cxPageScroll < (int)(pMDI->cxChar))
  240. cxPageScroll = pMDI->cxChar;
  241. cxScrollT += (wParam == SB_PAGEUP) ? -cxPageScroll : cxPageScroll;
  242. break;
  243. }
  244. default:
  245. return;
  246. }
  247. if ((cxScrollT < 0) || (pMDI->cxScrollLast <= 0))
  248. cxScrollT = 0;
  249. else if (cxScrollT > pMDI->cxScrollLast)
  250. cxScrollT = pMDI->cxScrollLast;
  251. else if (cxPartialChar = cxScrollT % pMDI->cxChar)
  252. { /* Round to the nearest character increment */
  253. if (cxPartialChar > ((int)(pMDI->cxChar) >> 1))
  254. cxScrollT += pMDI->cxChar;
  255. cxScrollT -= cxPartialChar;
  256. }
  257. /* Now we have a good cxScrollT value */
  258. dxScroll = pMDI->cxScrollNow - cxScrollT;
  259. if (dxScroll > 0)
  260. dxScrollAbs = dxScroll;
  261. else if (dxScroll < 0)
  262. dxScrollAbs = -dxScroll;
  263. else
  264. return; /* Scrolling has no effect here. */
  265. pMDI->cxScrollNow = cxScrollT;
  266. if (dxScrollAbs >= pMDI->rcWindow.right - pMDI->rcWindow.left)
  267. /* ScrollWindow does not handle this case */
  268. InvalidateRect( hwnd, (LPRECT) &(pMDI->rcWindow), TRUE );
  269. else
  270. ScrollWindow(hwnd, dxScroll, 0, (LPRECT)&(pMDI->rcWindow),
  271. (LPRECT)&(pMDI->rcWindow));
  272. UpdateWindow(hwnd);
  273. SetScrollPos (pMDI->hwndHscroll,
  274. SB_CTL,
  275. (pMDI->cxScrollLast <= 0) ?
  276. 0 :
  277. (int)(((DWORD)cxScrollT * (DWORD)HPOSLAST) / (DWORD)(pMDI->cxScrollLast)),
  278. TRUE);
  279. }
  280. }
  281. /*
  282. * DibPaletteSize
  283. */
  284. int DibPaletteSize(
  285. LPBITMAPINFOHEADER lpbi)
  286. {
  287. register int bits;
  288. register int nRet;
  289. /* With the new format headers, the size of the palette is in biClrUsed
  290. * else is dependent on bits per pixel.
  291. */
  292. if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  293. {
  294. if (lpbi->biClrUsed != 0)
  295. {
  296. nRet = lpbi->biClrUsed * sizeof(RGBQUAD);
  297. }
  298. else
  299. {
  300. bits = lpbi->biBitCount;
  301. if (24 == bits)
  302. {
  303. nRet = 0;
  304. }
  305. else if (16 == bits || 32 == bits)
  306. {
  307. nRet = 3 * sizeof(DWORD);
  308. }
  309. else
  310. {
  311. nRet = (1 << bits) * sizeof(RGBQUAD);
  312. }
  313. }
  314. }
  315. else
  316. {
  317. bits = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  318. nRet = (bits == 24) ? 0 : (1 << bits) * sizeof(RGBTRIPLE);
  319. }
  320. return(nRet);
  321. }
  322. /*
  323. * DibGetInfo
  324. */
  325. void DibGetInfo(
  326. HANDLE hdib,
  327. LPBITMAP pbm)
  328. {
  329. LPBITMAPINFOHEADER lpbi;
  330. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  331. if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  332. {
  333. pbm->bmWidth = (int)lpbi->biWidth;
  334. pbm->bmHeight = (int)lpbi->biHeight;
  335. }
  336. else
  337. {
  338. pbm->bmWidth = (int)((LPBITMAPCOREHEADER)lpbi)->bcWidth;
  339. pbm->bmHeight = (int)((LPBITMAPCOREHEADER)lpbi)->bcHeight;
  340. }
  341. GlobalUnlock(hdib);
  342. }
  343. /*
  344. * DrawDib
  345. */
  346. BOOL DrawDib(
  347. HWND hwnd,
  348. HDC hdc,
  349. int x0,
  350. int y0,
  351. HANDLE hdib)
  352. {
  353. LPBITMAPINFOHEADER lpbi;
  354. BITMAP bm;
  355. LPSTR lpBits;
  356. BOOL fOK = FALSE;
  357. if (hdib)
  358. {
  359. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  360. if (lpbi)
  361. {
  362. DibGetInfo(hdib, (LPBITMAP)&bm);
  363. lpBits = (LPSTR)lpbi + (WORD)lpbi->biSize + DibPaletteSize(lpbi);
  364. SetDIBitsToDevice (hdc,
  365. x0,
  366. y0,
  367. bm.bmWidth,
  368. bm.bmHeight,
  369. 0,
  370. 0,
  371. 0,
  372. bm.bmHeight,
  373. lpBits,
  374. (LPBITMAPINFO)lpbi,
  375. DIB_RGB_COLORS);
  376. GlobalUnlock(hdib);
  377. fOK = TRUE;
  378. }
  379. }
  380. return(fOK);
  381. }
  382. /*
  383. * FShowDIBitmap
  384. */
  385. BOOL FShowDIBitmap (
  386. HWND hwnd,
  387. register HDC hdc,
  388. PRECT prc,
  389. HANDLE hdib, //Bitmap in DIB format
  390. int cxScroll,
  391. int cyScroll)
  392. {
  393. BITMAP bm;
  394. PMDIINFO pMDI;
  395. pMDI = GETMDIINFO(hwnd);
  396. if (pMDI)
  397. {
  398. DibGetInfo(hdib, (LPBITMAP)&bm);
  399. // If window's been resized, determine maximum scroll positions.
  400. if (pMDI->cyScrollLast == -1)
  401. {
  402. /* Compute last scroll offset into bitmap */
  403. pMDI->cyScrollLast = bm.bmHeight -
  404. (pMDI->rcWindow.bottom - pMDI->rcWindow.top);
  405. if (pMDI->cyScrollLast < 0)
  406. {
  407. pMDI->cyScrollLast = 0;
  408. }
  409. }
  410. if (pMDI->cxScrollLast == -1)
  411. {
  412. /* Compute last scroll offset into bitmap */
  413. pMDI->cxScrollLast = bm.bmWidth -
  414. (pMDI->rcWindow.right - pMDI->rcWindow.left);
  415. if (pMDI->cxScrollLast < 0)
  416. {
  417. pMDI->cxScrollLast = 0;
  418. }
  419. }
  420. }
  421. SaveDC(hdc);
  422. IntersectClipRect (hdc, prc->left, prc->top, prc->right, prc->bottom);
  423. SetViewportOrgEx (hdc,prc->left - cxScroll, prc->top - cyScroll,NULL);
  424. DrawDib (hwnd, hdc, 0, 0, hdib);
  425. RestoreDC(hdc, -1);
  426. return(TRUE);
  427. }
  428. /*
  429. * FShowBitmap
  430. */
  431. BOOL FShowBitmap (
  432. HWND hwnd,
  433. HDC hdc,
  434. register PRECT prc,
  435. HBITMAP hbm,
  436. int cxScroll,
  437. int cyScroll)
  438. {
  439. register HDC hMemDC;
  440. BITMAP bitmap;
  441. int cxBlt, cyBlt;
  442. int cxRect, cyRect;
  443. PMDIINFO pMDI;
  444. pMDI = GETMDIINFO(hwnd);
  445. if ((hMemDC = CreateCompatibleDC(hdc)) == NULL)
  446. return(FALSE);
  447. if (!SelectObject(hMemDC, (HBITMAP)hbm))
  448. {
  449. DeleteDC(hMemDC);
  450. ShowString( hwnd, hdc, IDS_BADBMPFMT );
  451. return TRUE;
  452. }
  453. GetObject((HBITMAP)hbm, sizeof(BITMAP), (LPSTR)&bitmap);
  454. if (pMDI->cyScrollLast == -1)
  455. {
  456. /* Compute last scroll offset into bitmap */
  457. pMDI->cyScrollLast = bitmap.bmHeight - (pMDI->rcWindow.bottom - pMDI->rcWindow.top);
  458. if (pMDI->cyScrollLast < 0)
  459. pMDI->cyScrollLast = 0;
  460. }
  461. if ( pMDI->cxScrollLast == -1)
  462. {
  463. /* Compute last scroll offset into bitmap */
  464. pMDI->cxScrollLast = bitmap.bmWidth - (pMDI->rcWindow.right - pMDI->rcWindow.left);
  465. if ( pMDI->cxScrollLast < 0)
  466. pMDI->cxScrollLast = 0;
  467. }
  468. cxRect = prc->right - prc->left;
  469. cyRect = prc->bottom - prc->top;
  470. cxBlt = min(cxRect, bitmap.bmWidth - cxScroll);
  471. cyBlt = min(cyRect, bitmap.bmHeight - cyScroll);
  472. BitBlt (hdc,
  473. prc->left,
  474. prc->top,
  475. cxBlt,
  476. cyBlt,
  477. hMemDC,
  478. cxScroll,
  479. cyScroll, /* X,Y offset into source DC */
  480. SRCCOPY);
  481. DeleteDC(hMemDC);
  482. return(TRUE);
  483. }
  484. #define DXPAL (pMDI->cyLine)
  485. #define DYPAL (pMDI->cyLine)
  486. ////////////////////////////////////////////////////////////////////////////
  487. //
  488. // FShowPalette()
  489. //
  490. // Parameters:
  491. // hwnd - The wMDI child we're drawing in.
  492. // hdc - DC for the window.
  493. // prc - Rectangle to draw.
  494. // hpal - The palette to display.
  495. // cxScroll, cyScroll - Scroll position in pels OF PRC. NOT OF THE WINDOW.
  496. // Derive window scroll position by doing a cxScroll -= pMDI->cxScrollNow
  497. //
  498. ////////////////////////////////////////////////////////////////////////////
  499. BOOL FShowPalette(
  500. HWND hwnd,
  501. register HDC hdc,
  502. register PRECT prc,
  503. HPALETTE hpal,
  504. int cxScroll,
  505. int cyScroll)
  506. {
  507. int n;
  508. int x, y;
  509. int nx, ny;
  510. int nNumEntries;
  511. RECT rc;
  512. HBRUSH hbr;
  513. PMDIINFO pMDI;
  514. BOOL fOK = FALSE;
  515. TCHAR achHex[] = TEXT("0123456789ABCDEF");
  516. int nFirstLineDrawn;
  517. PINFO(TEXT("Palette: (%d,%d-%d,%d),cx %d, cy %d\r\n"),
  518. prc->left, prc->top, prc->right, prc->bottom, cxScroll, cyScroll);
  519. pMDI = GETMDIINFO(hwnd);
  520. if (hpal)
  521. {
  522. // Correct cyScroll to show window's scroll position, not prc's.
  523. cyScroll -= prc->top - pMDI->rcWindow.top;
  524. PINFO(TEXT("Corrected cyScroll %d\r\n"), cyScroll);
  525. // GetObject does not return an int-- it returns a USHORT. Thus,
  526. // we zero out nNumEntries before getobjecting the palette.
  527. nNumEntries = 0;
  528. GetObject(hpal, sizeof(int), (LPSTR)&nNumEntries);
  529. // Figure how many boxes across and tall the array of color boxes
  530. // is
  531. nx = ((pMDI->rcWindow.right - pMDI->rcWindow.left) / DXPAL);
  532. if (nx == 0)
  533. {
  534. nx = 1;
  535. }
  536. ny = (nNumEntries + nx - 1) / nx;
  537. PINFO(TEXT("%d entries, %d by %d array\r\n"), nNumEntries, nx, ny);
  538. // If the window's been resized, we have to tell it how far you
  539. // can scroll off to the right and down.
  540. if ( pMDI->cyScrollLast == -1)
  541. {
  542. pMDI->cyScrollLast = ny * DYPAL - // Height of palette minus
  543. pMDI->rcWindow.bottom - pMDI->rcWindow.top + // height of window plus
  544. DYPAL; // one palette entry height.
  545. if ( pMDI->cyScrollLast < 0)
  546. {
  547. pMDI->cyScrollLast = 0;
  548. }
  549. PINFO(TEXT("Last allowed scroll: %d\r\n"), pMDI->cyScrollLast);
  550. }
  551. if ( pMDI->cxScrollLast == -1)
  552. {
  553. /* Can't scroll palettes horizontally. */
  554. pMDI->cxScrollLast = 0;
  555. }
  556. SaveDC(hdc);
  557. IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  558. SetWindowOrgEx(hdc, -pMDI->rcWindow.left, -pMDI->rcWindow.top, NULL);
  559. // Set up the x and y positions of the first palette entry to draw
  560. // and figure out which palette entry IS the first that needs drawing.
  561. x = 0;
  562. nFirstLineDrawn = (cyScroll + prc->top - pMDI->rcWindow.top)/ DYPAL;
  563. n = nx * nFirstLineDrawn;
  564. y = DYPAL * nFirstLineDrawn - cyScroll;
  565. PINFO(TEXT("First entry %d at %d, %d\r\n"), n, x, y);
  566. // While n < number of entries and the current entry isn't off the bottom
  567. // of the window
  568. while (n < nNumEntries && y < prc->bottom)
  569. {
  570. // Figure out a DXPAL by DYPAL rect going down/right from x,y
  571. rc.left = x;
  572. rc.top = y;
  573. rc.right = rc.left + DXPAL;
  574. rc.bottom = rc.top + DYPAL;
  575. // PINFO(TEXT("(%d,%d) "), rc.left, rc.top);
  576. // Draw a black box with the appropriate color inside.
  577. if (RectVisible(hdc, &rc))
  578. {
  579. // PINFO(TEXT("<"));
  580. // If you change this one to zero, you get a text display of
  581. // the palette indices-- I used it to debug the draw code, 'cause
  582. // it's near impossible, when you've got little colored
  583. // squares, to figure out just which color is on the bottom of THAT
  584. // square THERE, the one that was scrolled halfway off the bottom
  585. // of the window, and you just scrolled it on. ("Well, it's sorta
  586. // purple... of course, this entire palette is sorta purple..")
  587. #if 1
  588. InflateRect(&rc, -1, -1);
  589. FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
  590. InflateRect(&rc, -1, -1);
  591. hbr = CreateSolidBrush(PALETTEINDEX(n));
  592. FillRect(hdc, &rc, hbr);
  593. DeleteObject(hbr);
  594. #else
  595. SetBkMode(hdc, TRANSPARENT);
  596. TextOut(hdc, rc.left + 2, rc.top + 2, &achHex[(n / 16)&0x0f], 1);
  597. TextOut(hdc, (rc.left + rc.right) / 2, rc.top + 2,
  598. &achHex[n & 0x0f], 1);
  599. #endif
  600. }
  601. // Go to next entry and advance x to the next position, "word
  602. // wrapping" to next line if we need to
  603. n++;
  604. x += DXPAL;
  605. if (0 == n % nx)
  606. {
  607. x = 0;
  608. y += DYPAL;
  609. PINFO(TEXT("Wrap at %d\r\n"), n);
  610. }
  611. }
  612. RestoreDC(hdc, -1);
  613. fOK = TRUE;
  614. }
  615. else
  616. {
  617. PERROR(TEXT("Bad palette!\r\n"));
  618. }
  619. return(fOK);
  620. }
  621. /*
  622. * PxlConvert
  623. *
  624. * Return the # of pixels spanned by 'val', a measurement in coordinates
  625. * appropriate to mapping mode mm. 'pxlDeviceRes' gives the resolution
  626. * of the device in pixels, along the axis of 'val'. 'milDeviceRes' gives
  627. * the same resolution measurement, but in millimeters.
  628. */
  629. int PxlConvert(
  630. int mm,
  631. int val,
  632. int pxlDeviceRes,
  633. int milDeviceRes)
  634. {
  635. register WORD wMult = 1;
  636. register WORD wDiv = 1;
  637. DWORD ulPxl;
  638. DWORD ulDenom;
  639. DWORD ulMaxInt = 0x7FFF;
  640. if (milDeviceRes == 0)
  641. {
  642. /* to make sure we don't get divide-by-0 */
  643. return(0);
  644. }
  645. switch (mm)
  646. {
  647. case MM_LOMETRIC:
  648. wDiv = 10;
  649. break;
  650. case MM_HIMETRIC:
  651. wDiv = 100;
  652. break;
  653. case MM_TWIPS:
  654. wMult = 254;
  655. wDiv = 14400;
  656. break;
  657. case MM_LOENGLISH:
  658. wMult = 2540;
  659. wDiv = 10000;
  660. break;
  661. case MM_HIENGLISH:
  662. wMult = 254;
  663. wDiv = 10000;
  664. break;
  665. case MM_TEXT:
  666. return(val);
  667. case MM_ISOTROPIC:
  668. case MM_ANISOTROPIC:
  669. /* These picture types have no original size */
  670. default:
  671. return(0);
  672. }
  673. /* Add denominator - 1 to numerator, to avoid roundoff */
  674. ulDenom = (DWORD)wDiv * (DWORD)milDeviceRes;
  675. ulPxl = (((DWORD)((DWORD)wMult * (DWORD)val * (DWORD)pxlDeviceRes)) + ulDenom - 1) / ulDenom;
  676. return((ulPxl > ulMaxInt) ? 0 : (int)ulPxl);
  677. }
  678. /*
  679. * FShowEnhMetaFile
  680. *
  681. * Display an enhanced metafile in the specified rectangle.
  682. */
  683. BOOL FShowEnhMetaFile(
  684. HWND hwnd,
  685. register HDC hdc,
  686. register PRECT prc,
  687. HANDLE hemf,
  688. int cxScroll,
  689. int cyScroll)
  690. {
  691. int cxBitmap;
  692. int cyBitmap;
  693. RECT rcWindow;
  694. int f = FALSE;
  695. PMDIINFO pMDI;
  696. pMDI = GETMDIINFO(hwnd);
  697. if (pMDI)
  698. {
  699. /* Not scrollable. Resize these into the given rect. */
  700. pMDI->cyScrollLast = 0;
  701. pMDI->cxScrollLast = 0;
  702. cxBitmap = pMDI->rcWindow.right - pMDI->rcWindow.left;
  703. cyBitmap = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
  704. /* We make the "viewport" to be an area the same size as the
  705. * clipboard object, and set the origin and clip region so as
  706. * to show the area we want. Note that the viewport may well be
  707. * bigger than the window.
  708. */
  709. SetMapMode(hdc, MM_TEXT);
  710. rcWindow.left = prc->left - cxScroll;
  711. rcWindow.top = prc->top - cyScroll;
  712. rcWindow.right = rcWindow.left + cxBitmap;
  713. rcWindow.bottom = rcWindow.top + cyBitmap;
  714. f = PlayEnhMetaFile (hdc, hemf, &rcWindow);
  715. // Always return TRUE. PlayEnhMetaFile() can return
  716. // FALSE even when the metafile can be displayed
  717. // properly. Things such as printer escap can cause
  718. // the call to return FALSE when painting to screen
  719. // but the image will be displayed fine.
  720. //
  721. // We return TRUE so we don't blank the display and
  722. // put "Clipbook can't display..." message.
  723. }
  724. return TRUE;
  725. }
  726. /*
  727. * EnumMetafileProc
  728. *
  729. * Metafile record play callback function used to work around problem
  730. * with non active MDI children playing a metafile that causes a foreground
  731. * palette selection
  732. */
  733. BOOL CALLBACK EnumMetafileProc (
  734. HDC hdc,
  735. HANDLETABLE FAR *lpht,
  736. METARECORD FAR *lpmr,
  737. int cObj,
  738. LPARAM lParam )
  739. {
  740. if ( lpmr->rdFunction == META_SELECTPALETTE )
  741. {
  742. return SelectPalette ( hdc, lpht[(lpmr->rdParm[0])].objectHandle[0],
  743. TRUE ) != NULL;
  744. }
  745. else
  746. {
  747. PlayMetaFileRecord ( hdc, lpht, lpmr, cObj );
  748. return TRUE;
  749. }
  750. }
  751. /*
  752. * FShowMetaFilePict
  753. *
  754. * Display a metafile in the specified rectangle.
  755. */
  756. BOOL FShowMetaFilePict(
  757. HWND hwnd,
  758. register HDC hdc,
  759. register PRECT prc,
  760. HANDLE hmfp,
  761. int cxScroll,
  762. int cyScroll)
  763. {
  764. int level;
  765. int cxBitmap;
  766. int cyBitmap;
  767. int f = FALSE;
  768. LPMETAFILEPICT lpmfp;
  769. PMDIINFO pMDI;
  770. pMDI = GETMDIINFO(hwnd);
  771. if (pMDI)
  772. {
  773. if ((lpmfp = (LPMETAFILEPICT)GlobalLock( hmfp )) != NULL)
  774. {
  775. METAFILEPICT mfp;
  776. mfp = *lpmfp;
  777. GlobalUnlock( hmfp );
  778. if ((level = SaveDC( hdc )) != 0)
  779. {
  780. /* Compute size of picture to be displayed */
  781. switch (mfp.mm)
  782. {
  783. case MM_ISOTROPIC:
  784. case MM_ANISOTROPIC:
  785. /* Not scrollable. Resize these into the given rect. */
  786. pMDI->cyScrollLast = 0;
  787. pMDI->cxScrollLast = 0;
  788. cxBitmap = pMDI->rcWindow.right - pMDI->rcWindow.left;
  789. cyBitmap = pMDI->rcWindow.bottom - pMDI->rcWindow.top;
  790. break;
  791. default:
  792. cxBitmap = PxlConvert(mfp.mm, mfp.xExt, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, HORZSIZE));
  793. cyBitmap = PxlConvert(mfp.mm, mfp.yExt, GetDeviceCaps(hdc, VERTRES), GetDeviceCaps(hdc, VERTSIZE));
  794. if (!cxBitmap || !cyBitmap)
  795. {
  796. goto NoDisplay;
  797. }
  798. if ( pMDI->cxScrollLast == -1)
  799. {
  800. pMDI->cxScrollLast =
  801. cxBitmap - (pMDI->rcWindow.right - pMDI->rcWindow.left);
  802. if ( pMDI->cxScrollLast < 0)
  803. {
  804. pMDI->cxScrollLast = 0;
  805. }
  806. }
  807. if (pMDI->cyScrollLast == -1)
  808. {
  809. pMDI->cyScrollLast =
  810. cyBitmap - (pMDI->rcWindow.bottom - pMDI->rcWindow.top);
  811. if (pMDI->cyScrollLast < 0)
  812. {
  813. pMDI->cyScrollLast = 0;
  814. }
  815. }
  816. break;
  817. }
  818. /* We make the "viewport" to be an area the same size as the
  819. * clipboard object, and set the origin and clip region so as
  820. * to show the area we want. Note that the viewport may well be
  821. * bigger than the window.
  822. */
  823. SetMapMode(hdc, mfp.mm);
  824. SetViewportOrgEx(hdc, prc->left - cxScroll, prc->top - cyScroll, NULL);
  825. switch (mfp.mm)
  826. {
  827. case MM_ISOTROPIC:
  828. if (mfp.xExt && mfp.yExt)
  829. {
  830. // So we get the correct shape rectangle when
  831. // SetViewportExt gets called.
  832. //
  833. SetWindowExtEx(hdc, mfp.xExt, mfp.yExt, NULL);
  834. }
  835. // FALL THRU
  836. case MM_ANISOTROPIC:
  837. SetViewportExtEx(hdc, cxBitmap, cyBitmap, NULL);
  838. break;
  839. }
  840. /* Since we may have scrolled, force brushes to align */
  841. SetBrushOrgEx(hdc, cxScroll - prc->left, cyScroll - prc->top, NULL);
  842. f = EnumMetaFile(hdc, mfp.hMF, EnumMetafileProc, 0L );
  843. FreeProcInstance ( (FARPROC) lpEnumMetaProc );
  844. NoDisplay:
  845. RestoreDC(hdc, level);
  846. }
  847. }
  848. }
  849. return(f);
  850. }
  851. /*
  852. * ShowString
  853. *
  854. * Blank rcWindow and show the string on the top line of the client area
  855. */
  856. void ShowString(
  857. HWND hwnd,
  858. HDC hdc,
  859. WORD id)
  860. {
  861. TCHAR szBuffer[BUFFERLEN];
  862. LPTSTR pszBuffer = szBuffer;
  863. INT iBufferSize = BUFFERLEN;
  864. INT iStringLen;
  865. /* Cancel any scrolling effects. */
  866. GETMDIINFO(hwnd)->cyScrollNow = 0;
  867. GETMDIINFO(hwnd)->cxScrollNow = 0;
  868. iStringLen = LoadString(hInst, id, pszBuffer, BUFFERLEN);
  869. // Is the buffer completely filled out?
  870. // We need a bigger one if yes.
  871. while (iStringLen == BUFFERLEN -1)
  872. {
  873. if (pszBuffer != szBuffer && pszBuffer)
  874. LocalFree (pszBuffer);
  875. iBufferSize *= 2;
  876. pszBuffer = LocalAlloc (LPTR, iBufferSize);
  877. if (!pszBuffer)
  878. goto done;
  879. iStringLen = LoadString (hInst, id, pszBuffer, iBufferSize);
  880. }
  881. FillRect (hdc, &(GETMDIINFO(hwnd)->rcWindow), hbrBackground);
  882. DrawText (hdc, pszBuffer, -1, &(GETMDIINFO(hwnd)->rcWindow),
  883. DT_CENTER | DT_WORDBREAK | DT_TOP);
  884. done:
  885. if (pszBuffer != szBuffer && pszBuffer)
  886. LocalFree (pszBuffer);
  887. }
  888. /*
  889. * CchLineA
  890. *
  891. *
  892. * Determine the # of characters in one display line's worth of lpch.
  893. * lpch is assumed to be an ansi string.
  894. *
  895. * Return the following:
  896. * HI WORD: # of chars to display (excludes CR, LF; will not
  897. * exceed cchLine)
  898. * LO WORD: offset of start of next line in lpch; If the current line
  899. * is NULL terminated, this contains offset to the NULL char;
  900. * In RgchBuf: characters to display
  901. *
  902. * Expands Tabs
  903. *
  904. * Accepts any of the following as valid end-of-line terminators:
  905. * CR, LF, CR-LF, LF-CR, NULL
  906. * Callers may test for having reached NULL by (lpch[LOWORD] == '\0')
  907. */
  908. LONG CchLineA(
  909. PMDIINFO pMDI,
  910. HDC hDC,
  911. CHAR rgchBuf[],
  912. CHAR FAR *lpch,
  913. INT cchLine,
  914. WORD wWidth)
  915. {
  916. CHAR ch;
  917. CHAR *pch = rgchBuf;
  918. register INT cchIn = 0;
  919. register INT cchOut = 0;
  920. INT iMinNoOfChars;
  921. SIZE size;
  922. INT iTextWidth = 0;
  923. iMinNoOfChars = wWidth / pMDI->cxMaxCharWidth;
  924. while (cchOut < cchLine)
  925. {
  926. switch (ch = *(lpch + (DWORD)cchIn++))
  927. {
  928. case '\0':
  929. /* cchIn is already incremented; So, it is pointing to
  930. * a character beyond the NULL; So, decrement it.
  931. */
  932. cchIn--;
  933. goto DoubleBreak;
  934. case '\015': /* CR */
  935. case '\012': /* LF */
  936. if ((lpch[cchIn] == '\015') || (lpch[cchIn] == '\012'))
  937. cchIn++;
  938. goto DoubleBreak;
  939. case '\011': /* TAB */
  940. {
  941. INT cchT = 8 - (cchOut % 8);
  942. /* Check if the width has exceeded or the total
  943. * number of characters has exceeded
  944. */
  945. if (((WORD)(iTextWidth + cchT * pMDI->cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
  946. /* Tab causes wrap to next line */
  947. goto DoubleBreak;
  948. while (cchT--)
  949. rgchBuf[cchOut++] = ' ';
  950. break;
  951. }
  952. default:
  953. rgchBuf[cchOut++] = ch;
  954. if( IsDBCSLeadByte(ch) )
  955. rgchBuf[cchOut++] = *(lpch + (DWORD)cchIn++);
  956. break;
  957. }
  958. /* Check if the width has been exceeded. */
  959. if (cchOut >= iMinNoOfChars)
  960. {
  961. GetTextExtentPointA(hDC, rgchBuf, cchOut, (LPSIZE)&size);
  962. iTextWidth = size.cx;
  963. if ((WORD)iTextWidth == wWidth)
  964. break;
  965. else if((WORD)iTextWidth > wWidth)
  966. {
  967. if (IsDBCSLeadByte(ch))
  968. {
  969. cchOut--;
  970. cchIn--;
  971. }
  972. cchOut--;
  973. cchIn--;
  974. break;
  975. }
  976. iMinNoOfChars += (wWidth - iTextWidth) / pMDI->cxMaxCharWidth;
  977. }
  978. }
  979. DoubleBreak:
  980. return(MAKELONG(cchIn, cchOut));
  981. }
  982. /*--------------------------------------------------------------------------*/
  983. /* */
  984. /* CchLineW() - */
  985. /* */
  986. /*--------------------------------------------------------------------------*/
  987. /*Same as previous function but takes unicode strings.
  988. */
  989. LONG CchLineW(
  990. PMDIINFO pMDI,
  991. HDC hDC,
  992. WCHAR rgchBuf[],
  993. WCHAR FAR *lpch,
  994. INT cchLine,
  995. WORD wWidth)
  996. {
  997. register INT cchIn = 0;
  998. register INT cchOut = 0;
  999. WCHAR ch;
  1000. WCHAR *pch = rgchBuf;
  1001. INT iMinNoOfChars;
  1002. INT iTextWidth = 0;
  1003. SIZE size;
  1004. iMinNoOfChars = wWidth / pMDI->cxMaxCharWidth;
  1005. while (cchOut < cchLine)
  1006. {
  1007. switch (ch = *(lpch + (DWORD)cchIn++))
  1008. {
  1009. case L'\0':
  1010. /* cchIn is already incremented; So, it is pointing to
  1011. * a character beyond the NULL; So, decrement it.
  1012. */
  1013. cchIn--;
  1014. goto DoubleBreak;
  1015. case L'\015': /* CR */
  1016. case L'\012': /* LF */
  1017. if ((lpch[cchIn] == L'\015') || (lpch[cchIn] == L'\012'))
  1018. cchIn++;
  1019. goto DoubleBreak;
  1020. case L'\011': /* TAB */
  1021. {
  1022. INT cchT = 8 - (cchOut % 8);
  1023. /* Check if the width has exceeded or the total
  1024. * number of characters has exceeded
  1025. */
  1026. if (((WORD)(iTextWidth + cchT * pMDI->cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
  1027. /* Tab causes wrap to next line */
  1028. goto DoubleBreak;
  1029. while (cchT--)
  1030. rgchBuf[cchOut++] = L' ';
  1031. break;
  1032. }
  1033. default:
  1034. rgchBuf[cchOut++] = ch;
  1035. break;
  1036. }
  1037. /* Check if the width has been exceeded. */
  1038. if (cchOut >= iMinNoOfChars)
  1039. {
  1040. GetTextExtentPointW(hDC, rgchBuf, cchOut, &size);
  1041. iTextWidth = size.cx;
  1042. if ((WORD)iTextWidth == wWidth)
  1043. break;
  1044. else if((WORD)iTextWidth > wWidth)
  1045. {
  1046. cchOut--;
  1047. cchIn--;
  1048. break;
  1049. }
  1050. iMinNoOfChars += (wWidth - iTextWidth) / pMDI->cxMaxCharWidth;
  1051. }
  1052. }
  1053. DoubleBreak:
  1054. return(MAKELONG(cchIn, cchOut));
  1055. }
  1056. #define cchLineMax 200
  1057. /*--------------------------------------------------------------------------*/
  1058. /* */
  1059. /* ShowText() - */
  1060. /* */
  1061. /*--------------------------------------------------------------------------*/
  1062. void ShowText(
  1063. HWND hwnd,
  1064. register HDC hdc,
  1065. PRECT prc,
  1066. HANDLE h,
  1067. INT cyScroll,
  1068. BOOL fUnicode)
  1069. {
  1070. CHAR FAR *lpch;
  1071. INT yT;
  1072. INT cLine;
  1073. INT cLineAllText = 0;
  1074. RECT rc;
  1075. INT yLine;
  1076. INT iLineFirstShow;
  1077. WORD wLen;
  1078. WORD wWidth;
  1079. CHAR rgch[cchLineMax*sizeof(WCHAR)];
  1080. PMDIINFO pMDI;
  1081. pMDI= GETMDIINFO(hwnd);
  1082. rc = *prc;
  1083. /* Expand repaint rectangle as necessary to hold an exact number of
  1084. * lines and start on an even line boundary. This is because we may
  1085. * get arbitrarily weird repaint rectangles when popups are moved.
  1086. * Scrolling repaint areas should require no adjustment.
  1087. */
  1088. rc.top -= (rc.top - pMDI->rcWindow.top) % pMDI->cyLine;
  1089. /* If expanding the repaint rectangle to the next line expands it */
  1090. /* beyond the bottom of my window, contract it one line. */
  1091. if ((yT = (rc.bottom - rc.top) % pMDI->cyLine) != 0)
  1092. if ((rc.bottom += pMDI->cyLine - yT) > pMDI->rcWindow.bottom)
  1093. rc.bottom -= pMDI->cyLine;
  1094. if (rc.bottom <= rc.top)
  1095. return;
  1096. if (((wWidth = (WORD)(pMDI->rcWindow.right - pMDI->rcWindow.left)) <= 0) ||
  1097. ((cLine = (rc.bottom - rc.top) / pMDI->cyLine) <= 0) ||
  1098. (NULL == (lpch = (LPSTR)GlobalLock(h))) )
  1099. {
  1100. /* Bad Rectangle or Bad Text Handle */
  1101. ShowString(hwnd, hdc, IDS_ERROR);
  1102. return;
  1103. }
  1104. /* Advance lpch to point at the text for the first line to show. */
  1105. iLineFirstShow = cyScroll / pMDI->cyLine;
  1106. /* Advance lpch to point at text for that line. */
  1107. if (!fUnicode)
  1108. while ((*lpch) && (iLineFirstShow--))
  1109. {
  1110. lpch += LOWORD(CchLineA(pMDI,hdc, rgch, lpch, cchLineMax, wWidth));
  1111. cLineAllText++;
  1112. }
  1113. else
  1114. while ((*((WCHAR *)lpch)) && (iLineFirstShow--))
  1115. {
  1116. lpch += ((LOWORD(CchLineW(pMDI, hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch,
  1117. cchLineMax, wWidth)))*sizeof(WCHAR));
  1118. cLineAllText++;
  1119. }
  1120. /* Display string, line by line */
  1121. yLine = rc.top;
  1122. while (cLine--)
  1123. {
  1124. LONG lT;
  1125. if (!fUnicode)
  1126. {
  1127. lT = CchLineA(pMDI, hdc, rgch, lpch, cchLineMax, wWidth);
  1128. }
  1129. else
  1130. {
  1131. lT = CchLineW(pMDI, hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth);
  1132. }
  1133. wLen = LOWORD(lT);
  1134. if (!fUnicode)
  1135. {
  1136. TextOutA(hdc, rc.left, yLine, (LPSTR) rgch, HIWORD(lT));
  1137. lpch += wLen;
  1138. }
  1139. else
  1140. {
  1141. if (!TextOutW(hdc, rc.left, yLine, (LPCWSTR) rgch, HIWORD(lT)))
  1142. {
  1143. GetLastError();
  1144. }
  1145. lpch += (wLen * sizeof(WCHAR));
  1146. }
  1147. yLine += pMDI->cyLine;
  1148. cLineAllText++;
  1149. if ((!fUnicode && (*lpch == 0)) || (fUnicode && (*((WCHAR *)lpch) == L'\0')))
  1150. {
  1151. break;
  1152. }
  1153. }
  1154. if (pMDI->cxScrollLast == -1)
  1155. {
  1156. /* We don't use horiz scroll for text */
  1157. pMDI->cxScrollLast = 0;
  1158. }
  1159. if (pMDI->cyScrollLast == -1)
  1160. {
  1161. INT cLineInRcWindow;
  1162. /* Validate y-size of text in clipboard. */
  1163. /* Adjust rcWindow dimensions for text display */
  1164. cLineInRcWindow = (pMDI->rcWindow.bottom - pMDI->rcWindow.top) / pMDI->cyLine;
  1165. do {
  1166. if (!fUnicode)
  1167. {
  1168. lpch += LOWORD(CchLineA(pMDI, hdc, rgch, lpch, cchLineMax, wWidth));
  1169. }
  1170. else
  1171. {
  1172. lpch += ((LOWORD(CchLineW(pMDI, hdc, (WCHAR *)rgch,
  1173. (WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
  1174. }
  1175. cLineAllText++;
  1176. }
  1177. while ((!fUnicode && (*lpch != 0)) || (fUnicode && ((*lpch != 0) || (*(lpch+1) != 0))));
  1178. pMDI->cyScrollLast = (cLineAllText - cLineInRcWindow) * pMDI->cyLine;
  1179. if (pMDI->cyScrollLast < 0)
  1180. {
  1181. pMDI->cyScrollLast = 0;
  1182. }
  1183. /* Restrict rcWindow so that it holds an exact # of text lines */
  1184. pMDI->rcWindow.bottom = pMDI->rcWindow.top + (cLineInRcWindow * pMDI->cyLine);
  1185. }
  1186. GlobalUnlock(h);
  1187. }
  1188. /*
  1189. * SendOwnerMessage
  1190. */
  1191. void SendOwnerMessage(
  1192. UINT message,
  1193. WPARAM wParam,
  1194. LPARAM lParam)
  1195. {
  1196. register HWND hwndOwner;
  1197. /* Send a message to the clipboard owner, if there is one */
  1198. hwndOwner = GetClipboardOwner();
  1199. if (hwndOwner != NULL)
  1200. SendMessage(hwndOwner, message, wParam, lParam);
  1201. }
  1202. /*
  1203. * SendOwnerSizeMessage
  1204. *
  1205. * Send WM_SIZECLIPBOARD message to clipboard owner.
  1206. * wParam is a handle to the clipboard window
  1207. * LOWORD(lParam) is a handle to the passed rect
  1208. */
  1209. void SendOwnerSizeMessage (
  1210. HWND hwnd,
  1211. int left,
  1212. int top,
  1213. int right,
  1214. int bottom)
  1215. {
  1216. register HANDLE hrc;
  1217. LPRECT lprc;
  1218. if ((hrc = GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER, (LONG)sizeof(RECT))) != NULL )
  1219. {
  1220. if ((lprc = (LPRECT)GlobalLock(hrc)) != NULL )
  1221. {
  1222. lprc->top = top;
  1223. lprc->bottom = bottom;
  1224. lprc->left = left;
  1225. lprc->right = right;
  1226. GlobalUnlock(hrc);
  1227. SendOwnerMessage(WM_SIZECLIPBOARD, (WPARAM)hwnd, (LPARAM)hrc);
  1228. }
  1229. GlobalFree(hrc);
  1230. }
  1231. }
  1232. /*
  1233. * GetBestFormat
  1234. *
  1235. * This routine decides which one of the existing formats is to be
  1236. * displayed in the viewer.
  1237. */
  1238. UINT GetBestFormat(
  1239. HWND hwnd,
  1240. UINT wFormat)
  1241. {
  1242. register WORD cFmt;
  1243. register WORD *pfmt;
  1244. // PINFO(TEXT("GBFormat %d\r\n"), wFormat);
  1245. if (wFormat == CBM_AUTO)
  1246. {
  1247. for (cFmt=ifmtMax, pfmt=&rgfmt[0]; cFmt--; pfmt++)
  1248. {
  1249. // PINFO(TEXT("Looking at # %d, (%d)\r\n"), cFmt, *pfmt);
  1250. if ( VIsClipboardFormatAvailable( GETMDIINFO(hwnd)->pVClpbrd, *pfmt ))
  1251. {
  1252. return(*pfmt);
  1253. }
  1254. }
  1255. return(0);
  1256. }
  1257. return(wFormat);
  1258. }
  1259. /*
  1260. * GetClipboardName
  1261. */
  1262. void GetClipboardName (
  1263. register int fmt,
  1264. LPTSTR szName,
  1265. register int iSize)
  1266. {
  1267. LPTSTR lprgch;
  1268. HANDLE hrgch;
  1269. *szName = '\0';
  1270. /* Get global memory that everyone can get to */
  1271. if ((hrgch = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)(iSize + 1))) == NULL)
  1272. {
  1273. PERROR(TEXT("GetClipboardName: alloc failure\n\r"));
  1274. return;
  1275. }
  1276. if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
  1277. goto ExitPoint;
  1278. switch (fmt)
  1279. {
  1280. // These are all of the formats we have know the names of.
  1281. case CF_RIFF:
  1282. case CF_WAVE:
  1283. case CF_PENDATA:
  1284. case CF_SYLK:
  1285. case CF_DIF:
  1286. case CF_TIFF:
  1287. case CF_TEXT:
  1288. case CF_UNICODETEXT:
  1289. case CF_OEMTEXT:
  1290. case CF_DSPTEXT:
  1291. case CF_LOCALE:
  1292. case CF_BITMAP:
  1293. case CF_DIB:
  1294. case CF_PALETTE:
  1295. case CF_DSPBITMAP:
  1296. case CF_METAFILEPICT:
  1297. case CF_DSPMETAFILEPICT:
  1298. case CF_ENHMETAFILE:
  1299. case CF_DSPENHMETAFILE:
  1300. case CF_HDROP:
  1301. LoadString(hInst, fmt, lprgch, iSize);
  1302. break;
  1303. case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
  1304. *lprgch = '\0';
  1305. SendOwnerMessage(WM_ASKCBFORMATNAME, (WPARAM)iSize, (LPARAM)(LPSTR)lprgch);
  1306. if (!*lprgch)
  1307. LoadString(hInst, fmt, lprgch, iSize);
  1308. break;
  1309. default:
  1310. *lprgch = '\0';
  1311. GetClipboardFormatName(fmt, lprgch, iSize);
  1312. break;
  1313. }
  1314. StringCchCopy(szName, iSize, lprgch);
  1315. GlobalUnlock(hrgch);
  1316. ExitPoint:
  1317. GlobalFree(hrgch);
  1318. }
  1319. /*
  1320. * GetClipboardMenuName
  1321. */
  1322. void GetClipboardMenuName (
  1323. register int fmt,
  1324. LPTSTR szName,
  1325. register int iSize)
  1326. {
  1327. LPTSTR lprgch;
  1328. HANDLE hrgch;
  1329. *szName = '\0';
  1330. /* Get global memory that everyone can get to */
  1331. if ((hrgch = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)(iSize + 1))) == NULL)
  1332. {
  1333. PERROR(TEXT("GetClipboardName: alloc failure\n\r"));
  1334. return;
  1335. }
  1336. if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
  1337. goto ExitPoint;
  1338. switch (fmt)
  1339. {
  1340. // These are all of the formats we have know the names of.
  1341. case CF_RIFF:
  1342. case CF_WAVE:
  1343. case CF_PENDATA:
  1344. case CF_SYLK:
  1345. case CF_DIF:
  1346. case CF_TIFF:
  1347. case CF_TEXT:
  1348. case CF_UNICODETEXT:
  1349. case CF_OEMTEXT:
  1350. case CF_DSPTEXT:
  1351. case CF_BITMAP:
  1352. case CF_DIB:
  1353. case CF_PALETTE:
  1354. case CF_DSPBITMAP:
  1355. case CF_METAFILEPICT:
  1356. case CF_DSPMETAFILEPICT:
  1357. case CF_ENHMETAFILE:
  1358. case CF_DSPENHMETAFILE:
  1359. case CF_HDROP:
  1360. case CF_LOCALE:
  1361. LoadString(hInst, fmt+MNDELTA, lprgch, iSize);
  1362. break;
  1363. case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
  1364. *lprgch = '\0';
  1365. SendOwnerMessage(WM_ASKCBFORMATNAME, (WPARAM)iSize, (LPARAM)(LPSTR)lprgch);
  1366. if (!*lprgch)
  1367. LoadString(hInst, CF_MN_OWNERDISPLAY, lprgch, iSize);
  1368. break;
  1369. default:
  1370. GetClipboardFormatName(fmt, lprgch, iSize);
  1371. break;
  1372. }
  1373. StringCchCopy(szName, iSize, lprgch);
  1374. GlobalUnlock(hrgch);
  1375. ExitPoint:
  1376. GlobalFree(hrgch);
  1377. }
  1378. /*
  1379. * DrawFormat
  1380. *
  1381. * Parameters:
  1382. * hdc - the hdc to draw in.
  1383. * prc - The rectangle to paint
  1384. * cxScroll - The scroll position of the window.
  1385. * cyScroll - The scroll position OF THE PAINT RECTANGLE. NOT THE WINDOW.
  1386. * (Gawd. Who DESIGNED this?) Measured in pels.
  1387. * BestFormat - The format to draw.
  1388. * hwndMDI - The window we're drawing in.
  1389. *
  1390. */
  1391. void DrawFormat(
  1392. register HDC hdc,
  1393. PRECT prc,
  1394. int cxScroll,
  1395. int cyScroll,
  1396. WORD BestFormat,
  1397. HWND hwndMDI)
  1398. {
  1399. register HANDLE h;
  1400. HFONT hFont;
  1401. int fOK = TRUE;
  1402. WORD wFormat = 0;
  1403. PMDIINFO pMDI;
  1404. pMDI = GETMDIINFO(hwndMDI);
  1405. PINFO(TEXT("DrawFormat: (%d, %d), %d"), cxScroll, cyScroll, BestFormat);
  1406. if (hwndMDI == hwndClpbrd && pMDI->pVClpbrd)
  1407. {
  1408. PERROR(TEXT("Clipboard window shouldn't have vClp!\r\n"));
  1409. }
  1410. /* If "Auto" is chosen and only data in unrecognised formats is
  1411. * available, then display "Can't display data in this format".
  1412. */
  1413. if ((BestFormat == 0) &&
  1414. VCountClipboardFormats( pMDI->pVClpbrd ))
  1415. {
  1416. if ((wFormat = (WORD)RegisterClipboardFormat(TEXT("FileName"))) &&
  1417. VIsClipboardFormatAvailable(pMDI->pVClpbrd, wFormat))
  1418. {
  1419. BestFormat = CF_TEXT;
  1420. }
  1421. else
  1422. {
  1423. PINFO(TEXT("no displayable format\n\r"));
  1424. ShowString( hwndMDI, hdc, IDS_CANTDISPLAY);
  1425. return;
  1426. }
  1427. }
  1428. PINFO(TEXT("format %x\n\r"), BestFormat);
  1429. h = VGetClipboardData( pMDI->pVClpbrd, wFormat ? wFormat : BestFormat );
  1430. if ( h != NULL)
  1431. {
  1432. PINFO(TEXT("Got format %x from VGetClipboardData\n\r"), BestFormat );
  1433. switch (BestFormat)
  1434. {
  1435. case CF_DSPTEXT:
  1436. case CF_TEXT:
  1437. ShowText( hwndMDI, hdc, prc, h, cyScroll, FALSE);
  1438. break;
  1439. case CF_UNICODETEXT:
  1440. hFont = SelectObject(hdc, hfontUni);
  1441. ShowText(hwndMDI, hdc, prc, h, cyScroll, TRUE);
  1442. SelectObject(hdc, hFont);
  1443. break;
  1444. case CF_OEMTEXT:
  1445. hFont = SelectObject(hdc, GetStockObject ( OEM_FIXED_FONT ) );
  1446. ShowText(hwndMDI, hdc, prc, h, cyScroll, FALSE);
  1447. SelectObject(hdc, hFont);
  1448. break;
  1449. case CF_DSPBITMAP:
  1450. case CF_BITMAP:
  1451. fOK = FShowBitmap( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
  1452. break;
  1453. case CF_DIB:
  1454. fOK = FShowDIBitmap( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
  1455. break;
  1456. case CF_PALETTE:
  1457. fOK = FShowPalette( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
  1458. break;
  1459. case CF_WAVE:
  1460. case CF_RIFF:
  1461. case CF_PENDATA:
  1462. case CF_DIF:
  1463. case CF_SYLK:
  1464. case CF_TIFF:
  1465. case CF_LOCALE:
  1466. ShowString( hwndMDI, hdc, IDS_BINARY);
  1467. break;
  1468. case CF_DSPMETAFILEPICT:
  1469. case CF_METAFILEPICT:
  1470. fOK = FShowMetaFilePict( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
  1471. break;
  1472. case CF_DSPENHMETAFILE:
  1473. case CF_ENHMETAFILE:
  1474. fOK = FShowEnhMetaFile( hwndMDI, hdc, prc, h, cxScroll, cyScroll);
  1475. break;
  1476. default:
  1477. ShowString( hwndMDI, hdc, IDS_BINARY);
  1478. break;
  1479. }
  1480. // Disable scroll bars that don't work
  1481. EnableWindow(pMDI->hwndVscroll, pMDI->cyScrollLast > 1 ? TRUE : FALSE);
  1482. EnableWindow(pMDI->hwndHscroll, pMDI->cxScrollLast > 1 ? TRUE : FALSE);
  1483. }
  1484. else
  1485. {
  1486. PERROR(TEXT("VGetClpDta fail\r\n"));
  1487. }
  1488. /* Check if the Data was not rendered by the application */
  1489. if ((h == NULL) &&
  1490. VCountClipboardFormats( pMDI->pVClpbrd ))
  1491. {
  1492. ShowString( hwndMDI, hdc, IDS_NOTRENDERED);
  1493. }
  1494. else
  1495. {
  1496. /* If we are unable to display the data, display "<Error>" */
  1497. if (!fOK)
  1498. {
  1499. ShowString( hwndMDI, hdc, IDS_ERROR);
  1500. }
  1501. }
  1502. }
  1503. /*
  1504. * DrawStuff
  1505. *
  1506. * Paint portion of current clipboard contents given by PAINT struct
  1507. * NOTE: If the paintstruct rectangle includes any part of the header, the
  1508. * whole header is redrawn.
  1509. */
  1510. void DrawStuff(
  1511. HWND hwnd,
  1512. register PAINTSTRUCT *pps,
  1513. HWND hwndMDI)
  1514. {
  1515. register HDC hdc;
  1516. RECT rcPaint;
  1517. RECT rcClient;
  1518. WORD BestFormat;
  1519. PMDIINFO pMDI;
  1520. pMDI = GETMDIINFO(hwnd);
  1521. if (pMDI)
  1522. {
  1523. hdc = pps->hdc;
  1524. if (pps->fErase)
  1525. FillRect(hdc, (LPRECT)&pps->rcPaint, hbrBackground);
  1526. GetClientRect(hwnd, (LPRECT)&rcClient);
  1527. // make room for scroll controls:
  1528. BestFormat = (WORD)GetBestFormat( hwnd, pMDI->CurSelFormat );
  1529. fOwnerDisplay = (BestFormat == CF_OWNERDISPLAY);
  1530. if ( !fOwnerDisplay )
  1531. {
  1532. ShowScrollBar ( hwnd, SB_BOTH, FALSE );
  1533. rcClient.right -= GetSystemMetrics ( SM_CXVSCROLL );
  1534. rcClient.bottom -= GetSystemMetrics ( SM_CYHSCROLL );
  1535. }
  1536. /* If the display format has changed, Set rcWindow,
  1537. * the display area for clip info.
  1538. */
  1539. if ( pMDI->fDisplayFormatChanged )
  1540. {
  1541. CopyRect((LPRECT)&(pMDI->rcWindow), (LPRECT)&rcClient);
  1542. /* We have changed the size of the clipboard. Tell the owner,
  1543. * if fOwnerDisplay is active.
  1544. */
  1545. if (fOwnerDisplay)
  1546. {
  1547. SendOwnerSizeMessage(hwnd,
  1548. pMDI->rcWindow.left,
  1549. pMDI->rcWindow.top,
  1550. pMDI->rcWindow.right,
  1551. pMDI->rcWindow.bottom);
  1552. }
  1553. else
  1554. {
  1555. /* Give the window a small margin, for looks */
  1556. InflateRect (&(pMDI->rcWindow),
  1557. -(int)(pMDI->cxMargin),
  1558. -(int)(pMDI->cyMargin));
  1559. }
  1560. pMDI->fDisplayFormatChanged = FALSE;
  1561. }
  1562. if (fOwnerDisplay)
  1563. {
  1564. /* Clipboard Owner handles display */
  1565. HANDLE hps;
  1566. hps = GlobalAlloc(GMEM_MOVEABLE | GMEM_LOWER, (LONG)sizeof(PAINTSTRUCT));
  1567. if (hps != NULL)
  1568. {
  1569. LPPAINTSTRUCT lppsT;
  1570. if ((lppsT = (LPPAINTSTRUCT)GlobalLock(hps)) != NULL)
  1571. {
  1572. *lppsT = *pps;
  1573. IntersectRect(&lppsT->rcPaint, &pps->rcPaint, &(pMDI->rcWindow));
  1574. GlobalUnlock(hps);
  1575. SendOwnerMessage(WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LPARAM)hps);
  1576. GlobalFree(hps);
  1577. }
  1578. }
  1579. }
  1580. else
  1581. {
  1582. /* We handle display */
  1583. /* Redraw the portion of the paint rectangle that is in the clipbrd rect */
  1584. IntersectRect(&rcPaint, &pps->rcPaint, &(pMDI->rcWindow));
  1585. /* Always draw from left edge of window */
  1586. rcPaint.left = pMDI->rcWindow.left;
  1587. if ((rcPaint.bottom > rcPaint.top) && (rcPaint.right > rcPaint.left))
  1588. {
  1589. DrawFormat (hdc,
  1590. &rcPaint,
  1591. (int)(pMDI->cxScrollNow),
  1592. (int)(pMDI->cyScrollNow + rcPaint.top - pMDI->rcWindow.top),
  1593. BestFormat,
  1594. hwndMDI );
  1595. }
  1596. }
  1597. }
  1598. }
  1599. /*
  1600. * SaveOwnerScrollInfo
  1601. *
  1602. * When the user switched the clipboard display from owner disp to
  1603. * a non-owner display, all the information about the scroll bar
  1604. * positions are to be saved. This routine does that.
  1605. * This is required because, when the user returns back to owner
  1606. * display, the scroll bar positions are to be restored.
  1607. */
  1608. void SaveOwnerScrollInfo (
  1609. register HWND hwnd)
  1610. {
  1611. GetScrollRange (hwnd, SB_VERT, (LPINT) & OwnVerMin, (LPINT) & OwnVerMax);
  1612. GetScrollRange (hwnd, SB_HORZ, (LPINT) & OwnHorMin, (LPINT) & OwnHorMax);
  1613. OwnVerPos = GetScrollPos( hwnd, SB_VERT );
  1614. OwnHorPos = GetScrollPos( hwnd, SB_HORZ );
  1615. }
  1616. /*
  1617. * RestoreOwnerScrollInfo
  1618. *
  1619. * When the user sitches back to owner-display, the scroll bar
  1620. * positions are restored by this routine.
  1621. */
  1622. void RestoreOwnerScrollInfo (
  1623. register HWND hwnd)
  1624. {
  1625. PINFO(TEXT("SETSCROLLRANGE in RestoreOwnerScrollInfo\n\r"));
  1626. SetScrollRange( hwnd, SB_VERT, OwnVerMin, OwnVerMax, FALSE);
  1627. SetScrollRange( hwnd, SB_HORZ, OwnHorMin, OwnHorMax, FALSE);
  1628. SetScrollPos( hwnd, SB_VERT, OwnVerPos, TRUE);
  1629. SetScrollPos( hwnd, SB_HORZ, OwnHorPos, TRUE);
  1630. }
  1631. /*
  1632. * InitOwnerScrollInfo
  1633. */
  1634. void InitOwnerScrollInfo(void)
  1635. {
  1636. OwnVerPos = OwnHorPos = OwnVerMin = OwnHorMin = 0;
  1637. OwnVerMax = VPOSLAST;
  1638. OwnHorMax = HPOSLAST;
  1639. }
  1640. /*
  1641. * UpdateCBMenu
  1642. *
  1643. * This routine is called once during initialisation and everytime
  1644. * the contents of the clipboard change. This updates the entries
  1645. * in the "Display" popup menu and the "grey" and "checked" status
  1646. * based on the data formats available in the clipboard.
  1647. */
  1648. void UpdateCBMenu(
  1649. HWND hwnd,
  1650. HWND hwndMDI)
  1651. {
  1652. register WORD wFlags; // Used to store the status flags for menu items
  1653. register UINT fmt;
  1654. WORD cFmt;
  1655. WORD cCBCount; // Number of data items in CB
  1656. int iIndex;
  1657. int nPopupCount;
  1658. BOOL bAutoSelect;
  1659. TCHAR szName[40];
  1660. // Now clipboard contains at least one item...
  1661. // Find out the number entries in the popup menu at present.
  1662. // make sure child window is valid
  1663. if ( !hwndMDI || !IsWindow(hwndMDI))
  1664. {
  1665. PERROR(TEXT("bad window arg to UpdateCBMenu\n\r"));
  1666. return;
  1667. }
  1668. nPopupCount = GetMenuItemCount(hDispMenu);
  1669. if (nPopupCount > 6)
  1670. {
  1671. // Delete all the entries in the popup menu below menu break. */
  1672. for (iIndex = 6; iIndex < nPopupCount; iIndex++)
  1673. {
  1674. // NOTE: The second parameter must always be 6! (because we use
  1675. // MF_BYPOSITION, when 6 is deleted, 7 becomes 6!).
  1676. DeleteMenu(hDispMenu, 6, MF_BYPOSITION | MF_DELETE);
  1677. }
  1678. }
  1679. // If this is not a page MDI window we don't want to show any entries
  1680. if ( GETMDIINFO(hwndMDI)->DisplayMode != DSP_PAGE )
  1681. {
  1682. return;
  1683. }
  1684. bAutoSelect = TRUE;
  1685. if ((cCBCount = (WORD)VCountClipboardFormats( GETMDIINFO(hwndMDI)->pVClpbrd ))
  1686. && VOpenClipboard( GETMDIINFO(hwndMDI)->pVClpbrd, hwnd))
  1687. {
  1688. AppendMenu ( hDispMenu, MF_SEPARATOR, 0, 0 );
  1689. AppendMenu ( hDispMenu, MF_STRING, CBM_AUTO, szDefaultFormat );
  1690. AppendMenu ( hDispMenu, MF_SEPARATOR, 0, 0 );
  1691. for (fmt=0, cFmt=1; cFmt <= cCBCount; cFmt++)
  1692. {
  1693. wFlags = 0;
  1694. fmt = VEnumClipboardFormats( GETMDIINFO(hwndMDI)->pVClpbrd, fmt );
  1695. // don't show preview format in menu...
  1696. if ( fmt != cf_preview )
  1697. {
  1698. switch (fmt)
  1699. {
  1700. case CF_TEXT:
  1701. case CF_OEMTEXT:
  1702. case CF_DSPTEXT:
  1703. case CF_UNICODETEXT:
  1704. case CF_DSPBITMAP:
  1705. case CF_DIB:
  1706. case CF_BITMAP:
  1707. case CF_METAFILEPICT:
  1708. case CF_DSPMETAFILEPICT:
  1709. case CF_ENHMETAFILE:
  1710. case CF_DSPENHMETAFILE:
  1711. case CF_OWNERDISPLAY:
  1712. case CF_PALETTE:
  1713. case CF_HDROP:
  1714. case CF_LOCALE:
  1715. /* can display all of these, put them on menu */
  1716. // Check if the current format is the one selected by the user
  1717. if (GETMDIINFO(hwndMDI)->CurSelFormat == fmt)
  1718. {
  1719. bAutoSelect = FALSE;
  1720. wFlags |= MF_CHECKED;
  1721. }
  1722. GetClipboardMenuName(fmt, szName, sizeof(szName));
  1723. AppendMenu (hDispMenu, wFlags, fmt, (LPTSTR)szName);
  1724. break;
  1725. default: /* all the rest... later */
  1726. break;
  1727. }
  1728. }
  1729. }
  1730. for (fmt=VEnumClipboardFormats (GETMDIINFO(hwndMDI)->pVClpbrd, 0);
  1731. fmt;
  1732. fmt=VEnumClipboardFormats (GETMDIINFO(hwndMDI)->pVClpbrd, fmt))
  1733. if ( fmt != cf_preview )
  1734. switch (fmt)
  1735. {
  1736. case CF_TEXT:
  1737. case CF_OEMTEXT:
  1738. case CF_DSPTEXT:
  1739. case CF_UNICODETEXT:
  1740. case CF_DSPBITMAP:
  1741. case CF_DIB:
  1742. case CF_BITMAP:
  1743. case CF_METAFILEPICT:
  1744. case CF_DSPMETAFILEPICT:
  1745. case CF_ENHMETAFILE:
  1746. case CF_DSPENHMETAFILE:
  1747. case CF_OWNERDISPLAY:
  1748. case CF_PALETTE:
  1749. case CF_HDROP:
  1750. case CF_LOCALE:
  1751. break;
  1752. default:
  1753. /* can't display this, put it on menu and gray it */
  1754. GetClipboardName(fmt, szName, sizeof(szName));
  1755. AppendMenu (hDispMenu, MF_GRAYED, fmt, (LPTSTR)szName);
  1756. // NTRAID#DB-344956-2001/04/14-mdesai : add support for V5 bitmaps requires new strings, help changes, code to convert, etc
  1757. // clipbrd was adding an empty string for this format; now we ignore the format
  1758. case CF_DIBV5:
  1759. break;
  1760. }
  1761. VCloseClipboard( GETMDIINFO(hwndMDI)->pVClpbrd );
  1762. if (bAutoSelect)
  1763. {
  1764. GETMDIINFO(hwndMDI)->CurSelFormat = CBM_AUTO;
  1765. CheckMenuItem(hDispMenu, CBM_AUTO, MF_BYCOMMAND | MF_CHECKED);
  1766. }
  1767. }
  1768. else
  1769. {
  1770. PERROR(TEXT("UpdateCBMenu:couldn't open clip, or no data on clip\r\n"));
  1771. }
  1772. DrawMenuBar(hwnd);
  1773. }
  1774. /*
  1775. * ClearClipboard
  1776. *
  1777. * This is called to clear the clipboard. If the clipboard is not
  1778. * empty the user is asked if it should be cleared.
  1779. */
  1780. BOOL ClearClipboard (
  1781. register HWND hwnd)
  1782. {
  1783. register int RetVal;
  1784. if (CountClipboardFormats() <= 0)
  1785. return(TRUE);
  1786. if ( MessageBoxID( hInst, hwnd, IDS_CONFIRMCLEAR, IDS_CLEARTITLE,
  1787. MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
  1788. {
  1789. if (RetVal = SyncOpenClipboard(hwnd))
  1790. {
  1791. // PINFO("ClearClipboard: emptied clipboard\r\n");
  1792. RetVal &= EmptyClipboard();
  1793. RetVal &= SyncCloseClipboard();
  1794. }
  1795. else
  1796. {
  1797. // PERROR("ClearClipboard: could not open\r\n");
  1798. MessageBoxID (hInst,
  1799. hwnd,
  1800. IDS_CLEAR,
  1801. IDS_ERROR,
  1802. MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
  1803. }
  1804. InvalidateRect(hwnd, NULL, TRUE);
  1805. return RetVal;
  1806. }
  1807. return(FALSE);
  1808. }