Source code of Windows XP (NT5)
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.

2060 lines
61 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* CLIPBRD.C - */
  4. /* */
  5. /* Copyright 1985-92, Microsoft Corporation */
  6. /* */
  7. /* */
  8. /* Window Clipboard Viewer */
  9. /* */
  10. /****************************************************************************/
  11. /*
  12. *
  13. * Modified by Michael Gates (a-mgates), 9/9/92.
  14. *
  15. * Fixed bug #3576 ("Can't copy to clipboard from file manager")
  16. *
  17. * Touched by : Anas Jarrah
  18. * On Date : May 11/1992.
  19. * Revision remarks by Anas Jarrah ext #15201
  20. * This file has been changed to comply with the Unicode standard
  21. * Following is a quick overview of what I have done.
  22. *
  23. * Was Changed it into Remark
  24. * === =============== ======
  25. * CHAR TCHAR if it refers to a text elements
  26. * LPCHAR & LPSTR LPTSTR if it refers to text.
  27. * LPCHAR & LPSTR LPBYTE if it does not refer to text
  28. * "..." TEXT("...") compile time macro resolves it.
  29. * '...' TEXT('...') same
  30. * strlen CharStrLen compile time macro resolves it.
  31. * strcpy CharStrCpy compile time macro resolves it.
  32. * strcmp CharStrCmp compile time macro resolves it.
  33. * strcat CharStrCat compile time macro resolves it.
  34. * RegisterWindow RegisterWindowW tell windows to send Unicode messages.
  35. * LoadResource LoadResource(A/W) NT compiles resource strings into
  36. * Unicode binaries
  37. * MOpenFile() CreateFile replaced to use the Win32 API [pierrej]
  38. *
  39. *
  40. *
  41. * Modified by Pierre Jammes [pierrej] on 5/19/92
  42. *
  43. * The clipboard viewer must be able to display unicode string
  44. * and ansi strings whether it is built as a unicode app or not.
  45. * This is why the functions related to text display are able
  46. * to handle both ansi and unicode strings and are specifically
  47. * calling either the unicode or the ansi API.
  48. * The three functions
  49. * 1) CchLineA(),
  50. * 2) CchLineW() and
  51. * 3) ShowText().
  52. * are able to handle both ansi and unicode text, they contain some code
  53. * that depend on ansi or unicode version of the system APIs and should
  54. * stay the same whether UNICODE is defined or not (whether we are building
  55. * a unicode app or not).
  56. *
  57. * There you will find some occurences of CHAR, WCHAR, LPSTR and LPWSTR.
  58. *
  59. * The Win32 API specifies clipboard ID as 32bit values and the BITMAP and
  60. * METAFILEPICT structures contain fields that are twice as large as the
  61. * same fields under Windows 3.1
  62. * Saving the content of the clipboard into .CLP files that are readable by the
  63. * Windows 3.1 clipboard viewer results in a loss of information.
  64. * As the user may not want this loss of information unless (s)he is planning on
  65. * using the .CLP file with a 16bit version of Windows (s)he is now given the
  66. * oportunity to save the data in a new .CLP format that won't be recognized by
  67. * the Windows 3.1 clipboard viewer (the FileID is different).
  68. *
  69. */
  70. #include "clipbrd.h"
  71. #include "dib.h"
  72. #include <shellapi.h>
  73. #include <memory.h>
  74. void NEAR PASCAL ShowString(HDC, WORD);
  75. BOOL fAnythingToRender = FALSE;
  76. BOOL fOwnerDisplay = FALSE;
  77. BOOL fDisplayFormatChanged = TRUE;
  78. TCHAR szAppName[] = TEXT("Clipboard");
  79. TCHAR szCaptionName[CAPTIONMAX];
  80. TCHAR szHelpFileName[20];
  81. TCHAR szMemErr[MSGMAX];
  82. HWND hwndNextViewer = NULL;
  83. HWND hwndMain;
  84. HINSTANCE hInst;
  85. HANDLE hAccel;
  86. HANDLE hfontSys;
  87. HANDLE hfontOem;
  88. HANDLE hfontUni;
  89. HBRUSH hbrWhite;
  90. HBRUSH hbrBackground;
  91. HMENU hMainMenu;
  92. HMENU hDispMenu;
  93. /* The scroll information for OWNER display is to be preserved, whenever
  94. * the display changes between OWNER and NON-OWNER; The following globals
  95. * are used to save and restore the scroll info.
  96. */
  97. INT OwnVerMin, OwnVerMax, OwnHorMin, OwnHorMax;
  98. INT OwnVerPos, OwnHorPos;
  99. LONG cyScrollLast = -1; /* Y-offset of display start when maximally */
  100. /* scrolled down; -1==invalid */
  101. LONG cyScrollNow = 0; /* Y-offset of current display start */
  102. /* (0=scrolled up all the way) */
  103. INT cxScrollLast = -1; /* Like cyScrollLast, but for horiz scroll */
  104. INT cxScrollNow = 0; /* Like cyScrollNow, but for horiz scroll */
  105. RECT rcWindow; /* Window in which to paint clipboard info */
  106. UINT cyLine, cxChar, cxMaxCharWidth; /* Size of a standard text char */
  107. UINT cxMargin, cyMargin; /* White border size around clip data area */
  108. UINT CurSelFormat = CBM_AUTO;
  109. /* Defines priority order for show format */
  110. UINT rgfmt[] = {
  111. CF_OWNERDISPLAY,
  112. CF_DSPTEXT,
  113. CF_DSPBITMAP,
  114. CF_DSPENHMETAFILE,
  115. CF_DSPMETAFILEPICT,
  116. CF_TEXT,
  117. CF_UNICODETEXT,
  118. CF_OEMTEXT,
  119. CF_ENHMETAFILE,
  120. CF_METAFILEPICT,
  121. CF_BITMAP,
  122. CF_DIB,
  123. CF_PALETTE,
  124. CF_RIFF,
  125. CF_WAVE,
  126. CF_SYLK,
  127. CF_DIF,
  128. CF_TIFF,
  129. CF_PENDATA
  130. };
  131. #define ifmtMax 19
  132. /* variables for the new File Open,File SaveAs and Find Text dialogs */
  133. OPENFILENAME OFN;
  134. TCHAR szFileName[PATHMAX]; /* Unicode AnasJ May 92 */
  135. TCHAR szLastDir[PATHMAX];
  136. TCHAR szDefExt[CCH_szDefExt]; /* default extension for above */
  137. TCHAR szFilterSpec[FILTERMAX]; /* default filter spec. for above */
  138. TCHAR szCustFilterSpec[FILTERMAX]; /* buffer for custom filters created */
  139. UINT wHlpMsg; /* message used to invoke Help */
  140. TCHAR szOpenCaption [CAPTIONMAX]; /* File open dialog caption text */
  141. TCHAR szSaveCaption [CAPTIONMAX]; /* File Save as dialog caption text */
  142. /* MemErrorMessage is called when a failure occurs on either WinHelp or
  143. * ShellAbout.
  144. */
  145. void FAR PASCAL MemErrorMessage()
  146. {
  147. MessageBeep(0);
  148. MessageBox(hwndMain,szMemErr,NULL,MB_ICONHAND|MB_OK);
  149. }
  150. /*--------------------------------------------------------------------------*/
  151. /* */
  152. /* MyOpenClipboard() - */
  153. /* */
  154. /*--------------------------------------------------------------------------*/
  155. BOOL MyOpenClipboard(
  156. HWND hWnd)
  157. {
  158. HDC hDC;
  159. RECT Rect;
  160. if(OpenClipboard(hWnd))
  161. {
  162. return(TRUE);
  163. }
  164. /* Some app forgot to close the clipboard */
  165. hDC = GetDC(hWnd);
  166. GetClientRect(hWnd, (LPRECT)&Rect);
  167. FillRect(hDC, (LPRECT)&Rect, hbrBackground);
  168. ShowString(hDC, IDS_ALREADYOPEN);
  169. ReleaseDC(hWnd, hDC);
  170. return(FALSE);
  171. }
  172. /*--------------------------------------------------------------------------*/
  173. /* */
  174. /* ChangeCharDimensions() - */
  175. /* */
  176. /*--------------------------------------------------------------------------*/
  177. void ChangeCharDimensions(
  178. HWND hwnd,
  179. UINT wOldFormat,
  180. UINT wNewFormat)
  181. {
  182. /* Check if the font has changed. */
  183. if (wOldFormat != wNewFormat)
  184. {
  185. switch (wNewFormat)
  186. {
  187. case CF_OEMTEXT:
  188. SetCharDimensions(hwnd, hfontOem);
  189. break;
  190. case CF_UNICODETEXT:
  191. SetCharDimensions(hwnd, hfontUni);
  192. break;
  193. case CF_TEXT:
  194. default:
  195. SetCharDimensions(hwnd, hfontSys);
  196. break;
  197. }
  198. }
  199. }
  200. /*--------------------------------------------------------------------------*/
  201. /* */
  202. /* RenderFormat() - */
  203. /* */
  204. /*--------------------------------------------------------------------------*/
  205. /* Read the data from fh and SetClipboardData() with it. */
  206. BOOL RenderFormat(
  207. FORMATHEADER *FormatHeader,
  208. register INT fh)
  209. {
  210. HANDLE hBitmap;
  211. register HANDLE hData;
  212. LPBYTE lpData;
  213. DWORD MetaOffset; /* special case hack for metafiles */
  214. BITMAP bitmap;
  215. HPALETTE hPalette;
  216. LPLOGPALETTE lpLogPalette;
  217. if (PRIVATE_FORMAT(FormatHeader->FormatID))
  218. FormatHeader->FormatID = (UINT)RegisterClipboardFormat(FormatHeader->Name);
  219. /* Special case hack for metafiles to get hData referencing
  220. * the metafile bits, not the METAFILEPICT structure.
  221. */
  222. switch (FormatHeader->FormatID)
  223. {
  224. case CF_METAFILEPICT:
  225. if (fNTReadFileFormat)
  226. MetaOffset = sizeof(METAFILEPICT);
  227. else
  228. MetaOffset = SIZE_OF_WIN31_METAFILEPICT_STRUCT;
  229. break;
  230. case CF_BITMAP:
  231. if (fNTReadFileFormat)
  232. MetaOffset = sizeof(BITMAP);
  233. else
  234. MetaOffset = SIZE_OF_WIN31_BITMAP_STRUCT;
  235. break;
  236. default:
  237. MetaOffset = 0;
  238. break;
  239. }
  240. if (!(hData = GlobalAlloc(GHND, FormatHeader->DataLen - MetaOffset)))
  241. return(FALSE);
  242. if (!(lpData = GlobalLock(hData)))
  243. {
  244. GlobalFree(hData);
  245. return(FALSE);
  246. }
  247. _llseek(fh, FormatHeader->DataOffset + MetaOffset, 0);
  248. if(!lread(fh, lpData, FormatHeader->DataLen - MetaOffset))
  249. {
  250. /* Error in reading the file */
  251. GlobalUnlock(hData);
  252. GlobalFree(hData);
  253. return(FALSE);
  254. }
  255. GlobalUnlock(hData);
  256. /* As when we write these we have to special case a few of
  257. * these guys. This code and the write code should match in terms
  258. * of the sizes and positions of data blocks being written out.
  259. */
  260. switch (FormatHeader->FormatID)
  261. {
  262. case CF_ENHMETAFILE:
  263. {
  264. HENHMETAFILE hEMF;
  265. hEMF = (HENHMETAFILE)SetEnhMetaFileBits(FormatHeader->DataLen, lpData);
  266. GlobalUnlock(hData);
  267. GlobalFree(hData);
  268. hData = hEMF; /* Stuff this in the clipboard */
  269. break;
  270. }
  271. case CF_METAFILEPICT:
  272. {
  273. HANDLE hMF;
  274. HANDLE hMFP;
  275. LPMETAFILEPICT lpMFP;
  276. /* Create the METAFILE with the bits we read in. */
  277. if (!(hMF = SetMetaFileBitsEx(FormatHeader->DataLen, lpData))) /* portable code */
  278. return(FALSE);
  279. /* Alloc a METAFILEPICT header. */
  280. if (!(hMFP = GlobalAlloc(GHND, (DWORD)sizeof(METAFILEPICT))))
  281. return(FALSE);
  282. if (!(lpMFP = (LPMETAFILEPICT)GlobalLock(hMFP)))
  283. {
  284. GlobalFree(hMFP);
  285. return(FALSE);
  286. }
  287. /* Reposition to the start of the METAFILEPICT header. */
  288. _llseek(fh, FormatHeader->DataOffset, 0);
  289. /* Read it in. */
  290. if (fNTReadFileFormat)
  291. _lread(fh, (LPBYTE)lpMFP, sizeof(METAFILEPICT));
  292. else {
  293. /* If we read a win 3.1 metafile we have to read the fields
  294. one after the other as they aren't of the same size as
  295. the corresponding Win 3.1 METAFILEPICT structure fields.
  296. We initialize the fields to zero their hight word.
  297. [pierrej 5/27/92] */
  298. lpMFP->mm = 0;
  299. lpMFP->xExt = 0;
  300. lpMFP->yExt = 0;
  301. _lread(fh, (LPBYTE)&(lpMFP->mm), sizeof(WORD));
  302. _lread(fh, (LPBYTE)&(lpMFP->xExt), sizeof(WORD));
  303. _lread(fh, (LPBYTE)&(lpMFP->yExt), sizeof(WORD));
  304. /* No, we don't need to read in the handle, we wouldn't
  305. use it anyways. [pierrej, 5/27/92] */
  306. }
  307. lpMFP->hMF = hMF; /* Update the METAFILE handle */
  308. GlobalUnlock(hMFP); /* Unlock the header */
  309. hData = hMFP; /* Stuff this in the clipboard */
  310. break;
  311. }
  312. case CF_BITMAP:
  313. /* Reposition to the start of the METAFILEPICT header. */
  314. _llseek(fh, FormatHeader->DataOffset, 0);
  315. /* Read it in. */
  316. if (fNTReadFileFormat)
  317. _lread(fh, (LPBYTE)&bitmap, sizeof(BITMAP));
  318. else {
  319. /* If we read a win 3.1 bitmap we have to read the fields
  320. one after the other as they aren't of the same size as
  321. the corresponding Win 3.1 BITMAP structure fields.
  322. We initialize the fields to zero their hight word or byte.
  323. [pierrej 5/27/92] */
  324. bitmap.bmType = 0;
  325. bitmap.bmWidth = 0;
  326. bitmap.bmHeight = 0;
  327. bitmap.bmWidthBytes = 0;
  328. bitmap.bmPlanes = 0;
  329. bitmap.bmBitsPixel = 0;
  330. bitmap.bmBits = NULL;
  331. _lread(fh, (LPBYTE)&(bitmap.bmType), sizeof(WORD));
  332. _lread(fh, (LPBYTE)&(bitmap.bmWidth), sizeof(WORD));
  333. _lread(fh, (LPBYTE)&(bitmap.bmHeight), sizeof(WORD));
  334. _lread(fh, (LPBYTE)&(bitmap.bmWidthBytes), sizeof(WORD));
  335. _lread(fh, (LPBYTE)&(bitmap.bmPlanes), sizeof(BYTE));
  336. _lread(fh, (LPBYTE)&(bitmap.bmBitsPixel), sizeof(BYTE));
  337. _lread(fh, (LPBYTE)&(bitmap.bmBits), sizeof(LPVOID));
  338. }
  339. if (!(lpData = GlobalLock(hData)))
  340. {
  341. GlobalFree(hData);
  342. return FALSE;
  343. }
  344. bitmap.bmBits = lpData;
  345. /* If this fails we should avoid doing the SetClipboardData()
  346. * below with the hData check.
  347. */
  348. hBitmap = CreateBitmapIndirect(&bitmap);
  349. GlobalUnlock(hData);
  350. GlobalFree(hData);
  351. hData = hBitmap; /* Stuff this in the clipboard */
  352. break;
  353. case CF_DIB:
  354. break;
  355. case CF_PALETTE:
  356. if (!(lpLogPalette = (LPLOGPALETTE)GlobalLock(hData)))
  357. {
  358. GlobalFree(hData);
  359. return(FALSE);
  360. }
  361. /* Create a logical palette. */
  362. if (!(hPalette = CreatePalette(lpLogPalette)))
  363. {
  364. GlobalUnlock(hData);
  365. GlobalFree(hData);
  366. return(FALSE);
  367. }
  368. GlobalUnlock(hData);
  369. GlobalFree(hData);
  370. hData = hPalette; /* Stuff this into clipboard */
  371. break;
  372. }
  373. if (!hData)
  374. return(FALSE);
  375. SetClipboardData(FormatHeader->FormatID, hData);
  376. return(TRUE);
  377. }
  378. /*--------------------------------------------------------------------------*/
  379. /* */
  380. /* ClipbrdVScroll() - */
  381. /* */
  382. /*--------------------------------------------------------------------------*/
  383. /* Scroll contents of window vertically, according to action code in wParam. */
  384. void ClipbrdVScroll(
  385. HWND hwnd,
  386. WORD wParam,
  387. WORD wThumb)
  388. {
  389. INT cyWindow;
  390. LONG dyScroll;
  391. LONG cyScrollT;
  392. LONG dyScrollAbs;
  393. LONG cyPartialChar;
  394. /* Ensure that all the bits are valid first, before scrolling them */
  395. UpdateWindow(hwnd);
  396. cyScrollT = cyScrollNow;
  397. cyWindow = rcWindow.bottom - rcWindow.top;
  398. /* Compute scroll results as an effect on cyScrollNow */
  399. switch (wParam)
  400. {
  401. case SB_LINEUP:
  402. cyScrollT -= cyLine;
  403. break;
  404. case SB_LINEDOWN:
  405. cyScrollT += cyLine;
  406. break;
  407. case SB_THUMBPOSITION:
  408. cyScrollT = (LONG)(((LONG)wThumb * (LONG)cyScrollLast) / VPOSLAST);
  409. break;
  410. case SB_PAGEUP:
  411. case SB_PAGEDOWN:
  412. {
  413. INT cyPageScroll;
  414. cyPageScroll = cyWindow - cyLine;
  415. if (cyPageScroll < (INT)cyLine)
  416. cyPageScroll = cyLine;
  417. cyScrollT += (wParam == SB_PAGEUP) ? -cyPageScroll : cyPageScroll;
  418. break;
  419. }
  420. default:
  421. return;
  422. }
  423. if ((cyScrollT < 0) || (cyScrollLast <= 0))
  424. cyScrollT = 0;
  425. else if (cyScrollT > cyScrollLast)
  426. cyScrollT = cyScrollLast;
  427. else if ((cyPartialChar = cyScrollT % cyLine) != 0)
  428. {
  429. /* Round to the nearest character increment. */
  430. if (cyPartialChar > (LONG)(cyLine >> 1))
  431. cyScrollT += cyLine;
  432. cyScrollT -= cyPartialChar;
  433. }
  434. dyScroll = cyScrollNow - cyScrollT;
  435. if (dyScroll > 0)
  436. dyScrollAbs = dyScroll;
  437. else if (dyScroll < 0)
  438. dyScrollAbs = -dyScroll;
  439. else
  440. return; /* Scrolling has no effect here. */
  441. cyScrollNow = cyScrollT;
  442. if (dyScrollAbs >= rcWindow.bottom - rcWindow.top)
  443. /* ScrollWindow does not handle this case */
  444. InvalidateRect(hwnd, (LPRECT)&rcWindow, TRUE);
  445. else
  446. ScrollWindow(hwnd, 0, (INT)dyScroll, &rcWindow, &rcWindow);
  447. UpdateWindow(hwnd);
  448. SetScrollPos(hwnd,
  449. SB_VERT,
  450. (cyScrollLast <= 0) ? 0 : (INT)((cyScrollT * (DWORD)VPOSLAST) / cyScrollLast),
  451. TRUE);
  452. }
  453. /*--------------------------------------------------------------------------*/
  454. /* */
  455. /* ClipbrdHScroll() - */
  456. /* */
  457. /*--------------------------------------------------------------------------*/
  458. /* Scroll contents of window horizontally, according to op code in wParam. */
  459. void NEAR PASCAL ClipbrdHScroll(HWND hwnd,WORD wParam,WORD wThumb)
  460. {
  461. INT cxWindow;
  462. register INT dxScroll;
  463. register INT cxScrollT;
  464. INT dxScrollAbs;
  465. LONG cxPartialChar;
  466. cxScrollT = cxScrollNow;
  467. cxWindow = rcWindow.right - rcWindow.left;
  468. /* Compute scroll results as an effect on cxScrollNow */
  469. switch (wParam)
  470. {
  471. case SB_LINEUP:
  472. cxScrollT -= cxChar;
  473. break;
  474. case SB_LINEDOWN:
  475. cxScrollT += cxChar;
  476. break;
  477. case SB_THUMBPOSITION:
  478. cxScrollT = (INT)(((LONG)wThumb * (LONG)cxScrollLast) / HPOSLAST);
  479. break;
  480. case SB_PAGEUP:
  481. case SB_PAGEDOWN:
  482. {
  483. INT cxPageScroll;
  484. cxPageScroll = cxWindow - cxChar;
  485. if (cxPageScroll < (INT)cxChar)
  486. cxPageScroll = cxChar;
  487. cxScrollT += (wParam == SB_PAGEUP) ? -cxPageScroll : cxPageScroll;
  488. break;
  489. }
  490. default:
  491. return;
  492. }
  493. if ((cxScrollT < 0) || (cxScrollLast <= 0))
  494. cxScrollT = 0;
  495. else if (cxScrollT > cxScrollLast)
  496. cxScrollT = cxScrollLast;
  497. else if ((cxPartialChar = cxScrollT % cxChar) != 0)
  498. { /* Round to the nearest character increment */
  499. if (cxPartialChar > (LONG)(cxChar >> 1))
  500. cxScrollT += cxChar;
  501. cxScrollT -= cxPartialChar;
  502. }
  503. /* Now we have a good cxScrollT value */
  504. dxScroll = cxScrollNow - cxScrollT;
  505. if (dxScroll > 0)
  506. dxScrollAbs = dxScroll;
  507. else if (dxScroll < 0)
  508. dxScrollAbs = -dxScroll;
  509. else
  510. return; /* Scrolling has no effect here. */
  511. cxScrollNow = cxScrollT;
  512. if (dxScrollAbs >= rcWindow.right - rcWindow.left)
  513. /* ScrollWindow does not handle this case */
  514. InvalidateRect( hwnd, (LPRECT) & rcWindow, TRUE );
  515. else
  516. ScrollWindow(hwnd, dxScroll, 0, (LPRECT)&rcWindow, (LPRECT)&rcWindow);
  517. UpdateWindow(hwnd);
  518. SetScrollPos(hwnd,
  519. SB_HORZ,
  520. (cxScrollLast <= 0) ? 0 : (INT)(((DWORD)cxScrollT * (DWORD)HPOSLAST) / (DWORD)cxScrollLast),
  521. TRUE );
  522. }
  523. /*--------------------------------------------------------------------------*/
  524. /* */
  525. /* DibPaletteSize() - */
  526. /* */
  527. /*--------------------------------------------------------------------------*/
  528. INT NEAR PASCAL DibPaletteSize(LPBITMAPINFOHEADER lpbi)
  529. {
  530. register INT bits;
  531. /* With the new format headers, the size of the palette is in biClrUsed
  532. * else is dependent on bits per pixel.
  533. */
  534. if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  535. {
  536. if (lpbi->biClrUsed != 0)
  537. return((WORD)lpbi->biClrUsed * sizeof(RGBQUAD));
  538. bits = lpbi->biBitCount;
  539. return((bits == 24) ? 0 : (1 << bits) * sizeof(RGBQUAD));
  540. }
  541. else
  542. {
  543. bits = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  544. return((bits == 24) ? 0 : (1 << bits) * sizeof(RGBTRIPLE));
  545. }
  546. }
  547. /*--------------------------------------------------------------------------*/
  548. /* */
  549. /* DibGetInfo() - */
  550. /* */
  551. /*--------------------------------------------------------------------------*/
  552. void NEAR PASCAL DibGetInfo(HANDLE hdib,LPBITMAP pbm)
  553. {
  554. LPBITMAPINFOHEADER lpbi;
  555. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  556. if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  557. {
  558. pbm->bmWidth = (INT)lpbi->biWidth;
  559. pbm->bmHeight = (INT)lpbi->biHeight;
  560. }
  561. else
  562. {
  563. pbm->bmWidth = (INT)((LPBITMAPCOREHEADER)lpbi)->bcWidth;
  564. pbm->bmHeight = (INT)((LPBITMAPCOREHEADER)lpbi)->bcHeight;
  565. }
  566. GlobalUnlock(hdib);
  567. }
  568. /*--------------------------------------------------------------------------*/
  569. /* */
  570. /* DrawDib() - */
  571. /* */
  572. /*--------------------------------------------------------------------------*/
  573. BOOL NEAR PASCAL DrawDib(HDC hdc,INT x0,INT y0,HANDLE hdib)
  574. {
  575. BITMAP bm;
  576. LPBYTE lpBits;
  577. LPBITMAPINFOHEADER lpbi;
  578. if (!hdib)
  579. return(FALSE);
  580. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
  581. if (!lpbi)
  582. return(FALSE);
  583. DibGetInfo(hdib, (LPBITMAP)&bm);
  584. lpBits = (LPBYTE)lpbi + (WORD)lpbi->biSize + DibPaletteSize(lpbi);
  585. SetDIBitsToDevice(hdc,
  586. x0, y0, bm.bmWidth, bm.bmHeight,
  587. 0, 0,
  588. 0, bm.bmHeight,
  589. lpBits, (LPBITMAPINFO)lpbi,
  590. DIB_RGB_COLORS);
  591. GlobalUnlock(hdib);
  592. return(TRUE);
  593. }
  594. /*--------------------------------------------------------------------------
  595. FShowDIBitmap() -
  596. Parameters:
  597. hdc - DC to draw into.
  598. prc - Pointer to bounds rectangle within DC.
  599. hdib - DIB to draw.
  600. cxScroll, cyScroll - Position the window's scrolled to.
  601. --------------------------------------------------------------------------*/
  602. BOOL NEAR PASCAL FShowDIBitmap(register HDC hdc,PRECT prc,
  603. HANDLE hdib /* Bitmap in DIB format */,INT cxScroll,INT cyScroll)
  604. {
  605. BITMAP bm;
  606. DibGetInfo(hdib, (LPBITMAP)&bm);
  607. if (cyScrollLast == -1)
  608. {
  609. /* Compute last scroll offset into bitmap */
  610. cyScrollLast = bm.bmHeight - (rcWindow.bottom - rcWindow.top);
  611. if (cyScrollLast < 0)
  612. cyScrollLast = 0;
  613. }
  614. if (cxScrollLast == -1)
  615. {
  616. /* Compute last scroll offset into bitmap */
  617. cxScrollLast = bm.bmWidth - (rcWindow.right - rcWindow.left);
  618. if (cxScrollLast < 0)
  619. cxScrollLast = 0;
  620. }
  621. SaveDC(hdc);
  622. IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  623. /* MSetViewportOrg(hdc, prc->left - cxScroll, prc->top - cyScroll); */
  624. DrawDib(hdc, -cxScroll, -cyScroll, hdib);
  625. RestoreDC(hdc, -1);
  626. return(TRUE);
  627. }
  628. /*--------------------------------------------------------------------------
  629. FShowBitmap() -
  630. Purpose: Draw a bitmap in the given HDC.
  631. Parameters:
  632. hdc - hDC to draw into.
  633. prc - Bounds rectangle in the DC.
  634. hbm - The bitmap to draw
  635. cxScroll, cyScroll - Where the DC's scrolled to
  636. Returns:
  637. TRUE on success, FALSE on failure.
  638. --------------------------------------------------------------------------*/
  639. BOOL NEAR PASCAL FShowBitmap(HDC hdc,register PRECT prc,
  640. HBITMAP hbm,INT cxScroll,INT cyScroll)
  641. {
  642. register HDC hMemDC;
  643. BITMAP bitmap;
  644. INT cxBlt, cyBlt;
  645. INT cxRect, cyRect;
  646. if ((hMemDC = CreateCompatibleDC(hdc)) == NULL)
  647. return(FALSE);
  648. SelectObject(hMemDC, (HBITMAP)hbm);
  649. GetObject((HBITMAP)hbm, sizeof(BITMAP), (LPBYTE)&bitmap);
  650. if (cyScrollLast == -1)
  651. {
  652. /* Compute last scroll offset into bitmap */
  653. cyScrollLast = bitmap.bmHeight - (rcWindow.bottom - rcWindow.top);
  654. if (cyScrollLast < 0)
  655. cyScrollLast = 0;
  656. }
  657. if (cxScrollLast == -1)
  658. {
  659. /* Compute last scroll offset into bitmap */
  660. cxScrollLast = bitmap.bmWidth - (rcWindow.right - rcWindow.left);
  661. if (cxScrollLast < 0)
  662. cxScrollLast = 0;
  663. }
  664. cxRect = prc->right - prc->left;
  665. cyRect = prc->bottom - prc->top;
  666. /* Bug #10656: Subtract 1 so we won't fall off the end of the bitmap
  667. * (the bitmap is zero based).
  668. * 11 January 1992 Clark R. Cyr
  669. */
  670. cxBlt = min(cxRect, bitmap.bmWidth - cxScroll);
  671. cyBlt = min(cyRect, bitmap.bmHeight - cyScroll);
  672. /* Bug #14131: Instead of subtracting 1 from the amount to blt, subtract 1
  673. * from the offset to blt from, thus allowing for a full picture
  674. * when no scrolling is needed.
  675. * 06 February 1992 Clark R. Cyr
  676. */
  677. if ((cxBlt != cxRect) && (cxScroll > 0))
  678. cxScroll--;
  679. if ((cyBlt != cyRect) && (cyScroll > 0))
  680. cyScroll--;
  681. BitBlt(hdc, prc->left, prc->top,
  682. cxBlt, cyBlt,
  683. hMemDC,
  684. cxScroll, cyScroll, /* X,Y offset into source DC */
  685. SRCCOPY);
  686. DeleteDC(hMemDC);
  687. return(TRUE);
  688. }
  689. #define DXPAL (cyLine)
  690. #define DYPAL (cyLine)
  691. /*--------------------------------------------------------------------------*/
  692. /* */
  693. /* FShowPalette() - */
  694. /* */
  695. /*--------------------------------------------------------------------------*/
  696. BOOL NEAR PASCAL FShowPalette(register HDC hdc,register PRECT prc,
  697. HPALETTE hpal,INT cxScroll,INT cyScroll)
  698. {
  699. INT n;
  700. INT x, y;
  701. INT nx, ny;
  702. INT nNumEntries = 0;
  703. RECT rc;
  704. HBRUSH hbr;
  705. if (!hpal)
  706. return(FALSE);
  707. GetObject(hpal, sizeof(INT), (LPBYTE)&nNumEntries);
  708. nx = (rcWindow.right - rcWindow.left) / DXPAL;
  709. if (nx == 0)
  710. nx = 1;
  711. ny = (nNumEntries + nx - 1) / nx;
  712. if (cyScrollLast == -1)
  713. {
  714. /* Compute last scroll offset into bitmap */
  715. cyScrollLast = ny * DYPAL - (rcWindow.bottom - rcWindow.top);
  716. if (cyScrollLast < 0)
  717. cyScrollLast = 0;
  718. }
  719. if (cxScrollLast == -1)
  720. {
  721. /* Compute last scroll offset into bitmap */
  722. cxScrollLast = 0;
  723. }
  724. SaveDC(hdc);
  725. IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  726. MSetViewportOrg(hdc, prc->left - cxScroll, prc->top - cyScroll);
  727. SelectPalette(hdc, hpal, FALSE);
  728. RealizePalette(hdc);
  729. x = 0;
  730. y = -((int)DYPAL);
  731. for (n=0; n < nNumEntries; n++, x += DXPAL)
  732. {
  733. if (n % nx == 0)
  734. {
  735. x = 0;
  736. y += DYPAL;
  737. }
  738. rc.left = x;
  739. rc.top = y;
  740. rc.right = x + DXPAL;
  741. rc.bottom = y + DYPAL;
  742. if (RectVisible(hdc,&rc))
  743. {
  744. InflateRect(&rc, -1, -1);
  745. FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
  746. InflateRect(&rc, -1, -1);
  747. hbr = CreateSolidBrush(PALETTEINDEX(n));
  748. FillRect(hdc, &rc, hbr);
  749. DeleteObject(hbr);
  750. }
  751. }
  752. RestoreDC(hdc, -1);
  753. return(TRUE);
  754. }
  755. /*--------------------------------------------------------------------------*/
  756. /* */
  757. /* PxlConvert() - */
  758. /* */
  759. /*--------------------------------------------------------------------------*/
  760. /* Return the # of pixels spanned by 'val', a measurement in coordinates
  761. * appropriate to mapping mode mm. 'pxlDeviceRes' gives the resolution
  762. * of the device in pixels, along the axis of 'val'. 'milDeviceRes' gives
  763. * the same resolution measurement, but in millimeters.
  764. */
  765. INT NEAR PASCAL PxlConvert(INT mm, INT val,INT pxlDeviceRes,INT milDeviceRes)
  766. {
  767. register WORD wMult = 1;
  768. register WORD wDiv = 1;
  769. DWORD ulPxl;
  770. DWORD ulDenom;
  771. /* Should be a constant! This works around a compiler bug as of 07/14/85. */
  772. DWORD ulMaxInt = MAXSHORT;
  773. if (milDeviceRes == 0)
  774. {
  775. /* to make sure we don't get divide-by-0 */
  776. return(0);
  777. }
  778. switch (mm)
  779. {
  780. case MM_LOMETRIC:
  781. wDiv = 10;
  782. break;
  783. case MM_HIMETRIC:
  784. wDiv = 100;
  785. break;
  786. case MM_TWIPS:
  787. wMult = 254;
  788. wDiv = 14400;
  789. break;
  790. case MM_LOENGLISH:
  791. wMult = 2540;
  792. wDiv = 10000;
  793. break;
  794. case MM_HIENGLISH:
  795. wMult = 254;
  796. wDiv = 10000;
  797. break;
  798. case MM_TEXT:
  799. return(val);
  800. case MM_ISOTROPIC:
  801. case MM_ANISOTROPIC:
  802. /* These picture types have no original size */
  803. default:
  804. return(0);
  805. }
  806. /* Add denominator - 1 to numerator, to avoid roundoff */
  807. ulDenom = (DWORD)wDiv * (DWORD)milDeviceRes;
  808. ulPxl = (((DWORD)((DWORD)wMult * (DWORD)val * (DWORD)pxlDeviceRes)) + ulDenom - 1) / ulDenom;
  809. return((ulPxl > ulMaxInt) ? 0 : (INT)ulPxl);
  810. }
  811. /*--------------------------------------------------------------------------*/
  812. /* */
  813. /* FShowEnhMetaFile() - */
  814. /* */
  815. /*--------------------------------------------------------------------------*/
  816. /* Display an enhanced metafile in the specified rectangle. */
  817. BOOL NEAR PASCAL FShowEnhMetaFile(
  818. register HDC hdc,
  819. HANDLE hemf,
  820. LPRECT prc)
  821. {
  822. INT level;
  823. INT f = FALSE;
  824. ENHMETAHEADER EnhHeader;
  825. if ((level = SaveDC( hdc )) != 0)
  826. {
  827. cyScrollLast = 0;
  828. cxScrollLast = 0;
  829. GetEnhMetaFileHeader(hemf, sizeof(ENHMETAHEADER), &EnhHeader);
  830. rcWindow.top--;
  831. rcWindow.left--;
  832. SetWindowOrgEx(hdc, -prc->left, -prc->top, NULL);
  833. f = PlayEnhMetaFile(hdc, hemf, &rcWindow);
  834. rcWindow.top++;
  835. rcWindow.left++;
  836. RestoreDC(hdc, level);
  837. }
  838. return(f);
  839. }
  840. /*--------------------------------------------------------------------------
  841. FShowMetaFilePict()
  842. Display a metafile in the specified rectangle.
  843. --------------------------------------------------------------------------*/
  844. BOOL NEAR PASCAL FShowMetaFilePict(
  845. register HDC hdc,
  846. register PRECT prc,
  847. HANDLE hmfp,
  848. INT cxScroll,
  849. INT cyScroll)
  850. {
  851. INT level;
  852. INT cxBitmap;
  853. INT cyBitmap;
  854. INT f = FALSE;
  855. LPMETAFILEPICT lpmfp;
  856. if ((lpmfp = (LPMETAFILEPICT)GlobalLock( hmfp )) != NULL)
  857. {
  858. METAFILEPICT mfp;
  859. mfp = *lpmfp;
  860. GlobalUnlock( hmfp );
  861. if ((level = SaveDC( hdc )) != 0)
  862. {
  863. /* Compute size of picture to be displayed */
  864. switch (mfp.mm)
  865. {
  866. case MM_ISOTROPIC:
  867. case MM_ANISOTROPIC:
  868. /* Not scrollable. Resize these into the given rect. */
  869. cyScrollLast = 0;
  870. cxScrollLast = 0;
  871. cxBitmap = rcWindow.right - rcWindow.left;
  872. cyBitmap = rcWindow.bottom - rcWindow.top;
  873. break;
  874. default:
  875. cxBitmap = PxlConvert(mfp.mm, mfp.xExt,
  876. GetDeviceCaps(hdc, HORZRES),
  877. GetDeviceCaps(hdc, HORZSIZE)
  878. );
  879. cyBitmap = PxlConvert(mfp.mm, mfp.yExt,
  880. GetDeviceCaps(hdc, VERTRES),
  881. GetDeviceCaps(hdc, VERTSIZE)
  882. );
  883. if (!cxBitmap || !cyBitmap)
  884. goto NoDisplay;
  885. if (cxScrollLast == -1)
  886. {
  887. cxScrollLast = cxBitmap - (rcWindow.right - rcWindow.left);
  888. if (cxScrollLast < 0)
  889. cxScrollLast = 0;
  890. }
  891. if (cyScrollLast == -1)
  892. {
  893. cyScrollLast = cyBitmap - (rcWindow.bottom - rcWindow.top);
  894. if (cyScrollLast < 0)
  895. cyScrollLast = 0;
  896. }
  897. break;
  898. }
  899. /* We make the "viewport" to be an area the same size as the
  900. * clipboard object, and set the origin and clip region so as
  901. * to show the area we want. Note that the viewport may well be
  902. * bigger than the window.
  903. */
  904. // IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  905. SetMapMode(hdc, mfp.mm);
  906. // MSetViewportOrg(hdc, cxScroll, cyScroll);
  907. switch (mfp.mm)
  908. {
  909. case MM_ANISOTROPIC:
  910. if (mfp.xExt && mfp.yExt)
  911. {
  912. /* So we get the correct shape rectangle when
  913. * SetViewportExtEx gets called.
  914. */
  915. MSetWindowExt(hdc, mfp.xExt, mfp.yExt);
  916. }
  917. /* FALL THRU */
  918. case MM_ISOTROPIC:
  919. MSetViewportExt(hdc, cxBitmap, cyBitmap);
  920. break;
  921. }
  922. /* Since we may have scrolled, force brushes to align */
  923. // MSetBrushOrg(hdc, cxScroll - prc->left, cyScroll - prc->top);
  924. f = PlayMetaFile(hdc, mfp.hMF);
  925. NoDisplay:
  926. RestoreDC(hdc, level);
  927. }
  928. }
  929. return(f);
  930. }
  931. /*--------------------------------------------------------------------------*/
  932. /* */
  933. /* ShowString() - */
  934. /* */
  935. /*--------------------------------------------------------------------------*/
  936. /* Blank rcWindow and show the string on the top line of the client area. */
  937. void NEAR PASCAL ShowString(HDC hdc,WORD id)
  938. {
  939. TCHAR szBuffer[BUFFERLEN];
  940. /* Cancel any scrolling effects. */
  941. cyScrollNow = 0;
  942. cxScrollNow = 0;
  943. LoadString(hInst, id, szBuffer, BUFFERLEN);
  944. FillRect(hdc, &rcWindow, hbrBackground);
  945. DrawText(hdc, szBuffer, -1, &rcWindow, DT_CENTER | DT_WORDBREAK | DT_NOCLIP | DT_TOP);
  946. }
  947. /*--------------------------------------------------------------------------*/
  948. /* */
  949. /* CchLineA() - */
  950. /* */
  951. /*--------------------------------------------------------------------------*/
  952. /* Determine the # of characters in one display line's worth of lpch.
  953. * lpch is assumed to be an ansi string.
  954. *
  955. * Return the following:
  956. * HI WORD: # of chars to display (excludes CR, LF; will not
  957. * exceed cchLine)
  958. * LO WORD: offset of start of next line in lpch; If the current line
  959. * is NULL terminated, this contains offset to the NULL char;
  960. * In RgchBuf: characters to display
  961. *
  962. * Expands Tabs
  963. *
  964. * Accepts any of the following as valid end-of-line terminators:
  965. * CR, LF, CR-LF, LF-CR, NULL
  966. * Callers may test for having reached NULL by (lpch[LOWORD] == '\0')
  967. */
  968. LONG NEAR PASCAL CchLineA(HDC hDC, CHAR rgchBuf[],
  969. #ifdef WIN16
  970. CHAR huge *lpch,
  971. #else
  972. CHAR FAR *lpch,
  973. #endif
  974. INT cchLine,WORD wWidth)
  975. {
  976. CHAR ch;
  977. CHAR *pch = rgchBuf;
  978. register INT cchIn = 0;
  979. register INT cchOut = 0;
  980. INT iMinNoOfChars;
  981. SIZE size;
  982. INT iTextWidth = 0;
  983. iMinNoOfChars = wWidth / cxMaxCharWidth;
  984. while (cchOut < cchLine)
  985. {
  986. switch (ch = *(lpch + (DWORD)cchIn++))
  987. {
  988. case '\0':
  989. /* cchIn is already incremented; So, it is pointing to
  990. * a character beyond the NULL; So, decrement it.
  991. */
  992. cchIn--;
  993. goto DoubleBreak;
  994. case '\015': /* CR */
  995. case '\012': /* LF */
  996. if ((lpch[cchIn] == '\015') || (lpch[cchIn] == '\012'))
  997. cchIn++;
  998. goto DoubleBreak;
  999. case '\011': /* TAB */
  1000. {
  1001. INT cchT = 8 - (cchOut % 8);
  1002. /* Check if the width has exceeded or the total
  1003. * number of characters has exceeded
  1004. */
  1005. if (((WORD)(iTextWidth + cchT * cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
  1006. /* Tab causes wrap to next line */
  1007. goto DoubleBreak;
  1008. while (cchT--)
  1009. rgchBuf[cchOut++] = ' ';
  1010. break;
  1011. }
  1012. default:
  1013. rgchBuf[cchOut++] = ch;
  1014. #ifdef DBCS
  1015. if( IsDBCSLeadByte(ch) )
  1016. rgchBuf[cchOut++] = *(lpch + (DWORD)cchIn++);
  1017. #endif
  1018. break;
  1019. }
  1020. /* Check if the width has been exceeded. */
  1021. if (cchOut >= iMinNoOfChars)
  1022. {
  1023. GetTextExtentPointA(hDC, rgchBuf, cchOut, (LPSIZE)&size);
  1024. iTextWidth = size.cx;
  1025. if ((WORD)iTextWidth == wWidth)
  1026. break;
  1027. else if((WORD)iTextWidth > wWidth)
  1028. {
  1029. #ifdef DBCS
  1030. if( IsDBCSLeadByte(ch) ){
  1031. cchOut--;
  1032. cchIn--;
  1033. }
  1034. #endif
  1035. cchOut--;
  1036. cchIn--;
  1037. break;
  1038. }
  1039. iMinNoOfChars += (wWidth - iTextWidth) / cxMaxCharWidth;
  1040. }
  1041. }
  1042. DoubleBreak:
  1043. return(MAKELONG(cchIn, cchOut));
  1044. }
  1045. /*--------------------------------------------------------------------------*/
  1046. /* */
  1047. /* CchLineW() - */
  1048. /* */
  1049. /*--------------------------------------------------------------------------*/
  1050. /*Same as previous function but takes unicode strings.
  1051. */
  1052. LONG NEAR PASCAL CchLineW(HDC hDC, WCHAR rgchBuf[],
  1053. WCHAR FAR *lpch,
  1054. INT cchLine,WORD wWidth)
  1055. {
  1056. WCHAR ch;
  1057. WCHAR *pch = rgchBuf;
  1058. register INT cchIn = 0;
  1059. register INT cchOut = 0;
  1060. INT iMinNoOfChars;
  1061. INT iTextWidth = 0;
  1062. SIZE size;
  1063. iMinNoOfChars = wWidth / cxMaxCharWidth;
  1064. while (cchOut < cchLine)
  1065. {
  1066. switch (ch = *(lpch + (DWORD)cchIn++))
  1067. {
  1068. case L'\0':
  1069. /* cchIn is already incremented; So, it is pointing to
  1070. * a character beyond the NULL; So, decrement it.
  1071. */
  1072. cchIn--;
  1073. goto DoubleBreak;
  1074. case L'\015': /* CR */
  1075. case L'\012': /* LF */
  1076. if ((lpch[cchIn] == L'\015') || (lpch[cchIn] == L'\012'))
  1077. cchIn++;
  1078. goto DoubleBreak;
  1079. case L'\011': /* TAB */
  1080. {
  1081. INT cchT = 8 - (cchOut % 8);
  1082. /* Check if the width has exceeded or the total
  1083. * number of characters has exceeded
  1084. */
  1085. if (((WORD)(iTextWidth + cchT * cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
  1086. /* Tab causes wrap to next line */
  1087. goto DoubleBreak;
  1088. while (cchT--)
  1089. rgchBuf[cchOut++] = L' ';
  1090. break;
  1091. }
  1092. default:
  1093. rgchBuf[cchOut++] = ch;
  1094. break;
  1095. }
  1096. /* Check if the width has been exceeded. */
  1097. if (cchOut >= iMinNoOfChars)
  1098. {
  1099. GetTextExtentPointW(hDC, rgchBuf, cchOut, &size);
  1100. iTextWidth = size.cx;
  1101. if ((WORD)iTextWidth == wWidth)
  1102. break;
  1103. else if((WORD)iTextWidth > wWidth)
  1104. {
  1105. cchOut--;
  1106. cchIn--;
  1107. break;
  1108. }
  1109. iMinNoOfChars += (wWidth - iTextWidth) / cxMaxCharWidth;
  1110. }
  1111. }
  1112. DoubleBreak:
  1113. return(MAKELONG(cchIn, cchOut));
  1114. }
  1115. #define cchLineMax 200
  1116. /*--------------------------------------------------------------------------*/
  1117. /* */
  1118. /* ShowText() - */
  1119. /* */
  1120. /*--------------------------------------------------------------------------*/
  1121. void NEAR PASCAL ShowText(register HDC hdc,PRECT prc,HANDLE h,INT cyScroll,
  1122. BOOL fUnicode)
  1123. {
  1124. #ifdef WIN16
  1125. CHAR huge *lpch;
  1126. #else
  1127. CHAR FAR *lpch;
  1128. #endif
  1129. INT yT;
  1130. INT cLine;
  1131. INT cLineAllText = 0;
  1132. RECT rc;
  1133. INT yLine;
  1134. INT iLineFirstShow;
  1135. WORD wLen;
  1136. WORD wWidth;
  1137. CHAR rgch[cchLineMax*sizeof(WCHAR)];
  1138. rc = *prc;
  1139. /* Expand repaint rectangle as necessary to hold an exact number of
  1140. * lines and start on an even line boundary. This is because we may
  1141. * get arbitrarily weird repaint rectangles when popups are moved.
  1142. * Scrolling repaint areas should require no adjustment.
  1143. */
  1144. rc.top -= (rc.top - rcWindow.top) % cyLine;
  1145. /* If expanding the repaint rectangle to the next line expands it */
  1146. /* beyond the bottom of my window, contract it one line. */
  1147. if ((yT = (rc.bottom - rc.top) % cyLine) != 0)
  1148. if ((rc.bottom += cyLine - yT) > rcWindow.bottom)
  1149. rc.bottom -= cyLine;
  1150. if (rc.bottom <= rc.top)
  1151. return;
  1152. if (((wWidth = (WORD)(rcWindow.right - rcWindow.left)) <= 0) ||
  1153. ((cLine = (rc.bottom - rc.top) / cyLine) <= 0) ||
  1154. (NULL == (lpch = (LPSTR)GlobalLock(h))) )
  1155. {
  1156. /* Bad Rectangle or Bad Text Handle */
  1157. ShowString(hdc, IDS_ERROR);
  1158. return;
  1159. }
  1160. /* Advance lpch to point at the text for the first line to show. */
  1161. iLineFirstShow = cyScroll / cyLine;
  1162. /* Advance lpch to point at text for that line. */
  1163. if (!fUnicode)
  1164. while ((*lpch) && (iLineFirstShow--))
  1165. {
  1166. lpch += LOWORD(CchLineA(hdc, rgch, lpch, cchLineMax, wWidth));
  1167. cLineAllText++;
  1168. }
  1169. else
  1170. while ((*((WCHAR *)lpch)) && (iLineFirstShow--))
  1171. {
  1172. lpch += ((LOWORD(CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
  1173. cLineAllText++;
  1174. }
  1175. /* Display string, line by line */
  1176. yLine = rc.top;
  1177. while (cLine--)
  1178. {
  1179. LONG lT;
  1180. if (!fUnicode)
  1181. lT = CchLineA(hdc, rgch, lpch, cchLineMax, wWidth);
  1182. else
  1183. lT = CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth);
  1184. wLen = LOWORD(lT);
  1185. if (!fUnicode) {
  1186. TextOutA(hdc, rc.left, yLine, (LPSTR) rgch, HIWORD(lT));
  1187. lpch += wLen;
  1188. } else {
  1189. if (!TextOutW(hdc, rc.left, yLine, (LPCWSTR) rgch, HIWORD(lT))) {
  1190. GetLastError();
  1191. }
  1192. lpch += (wLen * sizeof(WCHAR));
  1193. }
  1194. yLine += cyLine;
  1195. cLineAllText++;
  1196. if ((!fUnicode && (*lpch == 0)) || (fUnicode && (*((WCHAR *)lpch) == L'\0')))
  1197. break;
  1198. }
  1199. if (cxScrollLast == -1)
  1200. /* We don't use horiz scroll for text */
  1201. cxScrollLast = 0;
  1202. if (cyScrollLast == -1)
  1203. {
  1204. INT cLineInRcWindow;
  1205. /* Validate y-size of text in clipboard. */
  1206. /* Adjust rcWindow dimensions for text display */
  1207. cLineInRcWindow = (rcWindow.bottom - rcWindow.top) / cyLine;
  1208. do {
  1209. if (!fUnicode)
  1210. lpch += LOWORD(CchLineA(hdc, rgch, lpch, cchLineMax, wWidth));
  1211. else
  1212. lpch += ((LOWORD(CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
  1213. cLineAllText++;
  1214. } while ((!fUnicode && (*lpch != 0)) || (fUnicode && ((*lpch != 0) || (*(lpch+1) != 0))));
  1215. cyScrollLast = (cLineAllText - cLineInRcWindow) * cyLine;
  1216. if (cyScrollLast < 0)
  1217. {
  1218. cyScrollLast = 0;
  1219. }
  1220. /* Restrict rcWindow so that it holds an exact # of text lines */
  1221. rcWindow.bottom = rcWindow.top + (cLineInRcWindow * cyLine);
  1222. }
  1223. GlobalUnlock(h);
  1224. }
  1225. /*--------------------------------------------------------------------------*/
  1226. /* */
  1227. /* SendOwnerMessage() - */
  1228. /* */
  1229. /*--------------------------------------------------------------------------*/
  1230. void SendOwnerMessage(
  1231. UINT message,
  1232. WPARAM wParam,
  1233. LPARAM lParam)
  1234. {
  1235. register HWND hwndOwner;
  1236. /* Send a message to the clipboard owner, if there is one */
  1237. hwndOwner = GetClipboardOwner();
  1238. if (hwndOwner != NULL)
  1239. {
  1240. SendMessage(hwndOwner, message, wParam, lParam);
  1241. }
  1242. }
  1243. /*--------------------------------------------------------------------------*/
  1244. /* */
  1245. /* SendOwnerSizeMessage() - */
  1246. /* */
  1247. /*--------------------------------------------------------------------------*/
  1248. /* Send WM_SIZECLIPBOARD message to clipboard owner.
  1249. * wParam is a handle to the clipboard window
  1250. * LOWORD(lParam) is a handle to the passed rect
  1251. */
  1252. void SendOwnerSizeMessage(
  1253. HWND hwnd,
  1254. INT left,
  1255. INT top,
  1256. INT right,
  1257. INT bottom)
  1258. {
  1259. register HANDLE hrc;
  1260. LPRECT lprc;
  1261. if ((hrc = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  1262. (LONG)sizeof(RECT))) != NULL )
  1263. {
  1264. if ((lprc = (LPRECT)GlobalLock(hrc)) != NULL )
  1265. {
  1266. lprc->top = top;
  1267. lprc->bottom = bottom;
  1268. lprc->left = left;
  1269. lprc->right = right;
  1270. GlobalUnlock(hrc);
  1271. SendOwnerMessage(WM_SIZECLIPBOARD, (WPARAM)hwnd, (LONG)hrc);
  1272. }
  1273. GlobalFree(hrc);
  1274. }
  1275. }
  1276. //
  1277. // Purpose: Return the best clipboard format we have available, given a
  1278. // 'starting' clipboard format.
  1279. //
  1280. // Parameters:
  1281. // wFormat - The format selected on the Display menu.
  1282. //
  1283. // Returns:
  1284. // The number of the clipboard format to use, or NULL if no clipboard
  1285. // format matching the requested one exists.
  1286. //
  1287. ////////////////////////////////////////////////////////////////////////
  1288. UINT GetBestFormat(
  1289. UINT wFormat)
  1290. {
  1291. register UINT cFmt;
  1292. register UINT *pfmt;
  1293. if (wFormat == CBM_AUTO)
  1294. {
  1295. wFormat = 0;
  1296. for (cFmt=ifmtMax, pfmt=&rgfmt[0]; cFmt--; pfmt++)
  1297. {
  1298. if (IsClipboardFormatAvailable(*pfmt))
  1299. {
  1300. wFormat = *pfmt;
  1301. break;
  1302. }
  1303. }
  1304. }
  1305. else if (!IsClipboardFormatAvailable(wFormat))
  1306. {
  1307. wFormat = 0;
  1308. }
  1309. return wFormat;
  1310. }
  1311. /*--------------------------------------------------------------------------*/
  1312. /* */
  1313. /* ClearClipboard() - */
  1314. /* */
  1315. /*--------------------------------------------------------------------------*/
  1316. /* This is called to clear the clipboard. If the clipboard is not
  1317. * empty the user is asked if it should be cleared.
  1318. */
  1319. BOOL NEAR PASCAL ClearClipboard(register HWND hwnd)
  1320. {
  1321. CHAR szBuffer[SMALLBUFFERLEN];
  1322. CHAR szLocBuffer[BUFFERLEN];
  1323. if (CountClipboardFormats() <= 0)
  1324. return(TRUE);
  1325. /* Get the confirmation from the user. */
  1326. LoadString(hInst, IDS_CLEARTITLE, szBuffer, SMALLBUFFERLEN);
  1327. LoadString(hInst, IDS_CONFIRMCLEAR, szLocBuffer, BUFFERLEN);
  1328. if (MessageBox(hwnd, szLocBuffer, szBuffer, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
  1329. {
  1330. if (!OpenClipboard(hwnd) ||
  1331. !EmptyClipboard() ||
  1332. !CloseClipboard() )
  1333. {
  1334. LoadString(hInst, IDS_ERROR, szBuffer, SMALLBUFFERLEN);
  1335. LoadString(hInst, IDS_CLEAR, szLocBuffer, BUFFERLEN);
  1336. MessageBox(hwnd, szLocBuffer, szBuffer, MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
  1337. }
  1338. InvalidateRect(hwnd, NULL, TRUE);
  1339. return(TRUE);
  1340. }
  1341. return(FALSE);
  1342. }
  1343. /*--------------------------------------------------------------------------*/
  1344. /* */
  1345. /* GetClipboardName() - */
  1346. /* */
  1347. /*--------------------------------------------------------------------------*/
  1348. void NEAR PASCAL GetClipboardName(register UINT fmt,LPTSTR szName,
  1349. register INT iSize)
  1350. {
  1351. LPTSTR lprgch;
  1352. HANDLE hrgch;
  1353. *szName = 0;
  1354. /* Get global memory that everyone can get to */
  1355. if ((hrgch = GlobalAlloc(GPTR, (LONG)(iSize + 1))) == NULL)
  1356. return;
  1357. if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
  1358. goto ExitPoint;
  1359. switch (fmt)
  1360. {
  1361. case CF_RIFF:
  1362. case CF_WAVE:
  1363. case CF_PENDATA:
  1364. case CF_SYLK:
  1365. case CF_DIF:
  1366. case CF_TIFF:
  1367. case CF_TEXT:
  1368. case CF_BITMAP:
  1369. case CF_METAFILEPICT:
  1370. case CF_OEMTEXT:
  1371. case CF_DIB:
  1372. case CF_PALETTE:
  1373. case CF_DSPTEXT:
  1374. case CF_DSPBITMAP:
  1375. case CF_DSPMETAFILEPICT:
  1376. case CF_UNICODETEXT:
  1377. case CF_ENHMETAFILE:
  1378. case CF_DSPENHMETAFILE:
  1379. LoadString(hInst, fmt, lprgch, iSize);
  1380. break;
  1381. case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
  1382. *lprgch = 0;
  1383. SendOwnerMessage(WM_ASKCBFORMATNAME, iSize, (LONG)(LPTSTR)lprgch);
  1384. if (!*lprgch)
  1385. LoadString(hInst, fmt, lprgch, iSize);
  1386. break;
  1387. default:
  1388. GetClipboardFormatName(fmt, lprgch, iSize);
  1389. break;
  1390. }
  1391. lstrcpy(szName, lprgch);
  1392. GlobalUnlock(hrgch);
  1393. ExitPoint:
  1394. GlobalFree(hrgch);
  1395. }
  1396. /*--------------------------------------------------------------------------
  1397. DrawFormat() -
  1398. Purpose: Draw the data on the clipboard, using the given format.
  1399. Parameters:
  1400. hdc - hDC to draw into.
  1401. prc - Pointer to a rectangle showing bounds to paint into
  1402. cxScroll - Horizontal position we're scrolled to (0=left)
  1403. cyScroll - Vertical position we're scrolled to (0=top)
  1404. BestFormat - Format to use when drawing.
  1405. --------------------------------------------------------------------------*/
  1406. void NEAR PASCAL DrawFormat(
  1407. register HDC hdc,
  1408. PRECT prc,
  1409. INT cxScroll,
  1410. INT cyScroll,
  1411. UINT BestFormat)
  1412. {
  1413. register HANDLE h;
  1414. HFONT hFont;
  1415. INT fOK = TRUE;
  1416. UINT wFormat = 0;
  1417. if ((BestFormat == 0))
  1418. {
  1419. if (CountClipboardFormats() )
  1420. {
  1421. ShowString(hdc, IDS_CANTDISPLAY);
  1422. }
  1423. }
  1424. else if ((h = GetClipboardData(/* wFormat ? wFormat :*/ BestFormat)) != NULL)
  1425. {
  1426. switch (BestFormat)
  1427. {
  1428. case CF_DSPTEXT:
  1429. case CF_TEXT:
  1430. ShowText(hdc, prc, h, cyScroll, FALSE);
  1431. break;
  1432. case CF_UNICODETEXT:
  1433. hFont = SelectObject(hdc, hfontUni);
  1434. ShowText(hdc, prc, h, cyScroll, TRUE);
  1435. SelectObject(hdc, hFont);
  1436. break;
  1437. case CF_OEMTEXT:
  1438. hFont = SelectObject(hdc, hfontOem);
  1439. ShowText(hdc, prc, h, cyScroll, FALSE);
  1440. SelectObject(hdc, hFont);
  1441. break;
  1442. case CF_DSPBITMAP:
  1443. case CF_BITMAP:
  1444. fOK = FShowBitmap(hdc, prc, h, cxScroll, cyScroll);
  1445. break;
  1446. case CF_DIB:
  1447. fOK = FShowDIBitmap(hdc, prc, h, cxScroll, cyScroll);
  1448. break;
  1449. case CF_PALETTE:
  1450. fOK = FShowPalette(hdc, prc, h, cxScroll, cyScroll);
  1451. break;
  1452. case CF_WAVE:
  1453. case CF_RIFF:
  1454. case CF_PENDATA:
  1455. case CF_DIF:
  1456. case CF_SYLK:
  1457. case CF_TIFF:
  1458. ShowString(hdc, IDS_BINARY);
  1459. break;
  1460. case CF_ENHMETAFILE:
  1461. case CF_DSPENHMETAFILE:
  1462. fOK = FShowEnhMetaFile(hdc, h, prc);
  1463. break;
  1464. case CF_DSPMETAFILEPICT:
  1465. case CF_METAFILEPICT:
  1466. fOK = FShowMetaFilePict(hdc, prc, h, cxScroll, cyScroll);
  1467. break;
  1468. /* If "Auto" is chosen and only data in unrecognised formats is
  1469. * available, then display "Can't display data in this format".
  1470. */
  1471. default:
  1472. ShowString(hdc, IDS_CANTDISPLAY);
  1473. break;
  1474. }
  1475. }
  1476. else if (CountClipboardFormats()) // There's data, but we can't Get it..
  1477. {
  1478. ShowString(hdc, IDS_ERROR);
  1479. }
  1480. /* If we are unable to display the data, display "<Error>" */
  1481. if (!fOK)
  1482. {
  1483. ShowString(hdc, IDS_NOTRENDERED);
  1484. }
  1485. }
  1486. /*--------------------------------------------------------------------------
  1487. DrawStuff() -
  1488. Paint portion of current clipboard contents given by PAINT struct
  1489. NOTE: If the paintstruct rectangle includes any part of the header, the
  1490. whole header is redrawn.
  1491. Parameters:
  1492. hwnd - Window to draw in.
  1493. pps - Pointer to PAINTSTRUCT to use.
  1494. Returns:
  1495. Nothing.
  1496. ----------------------------------------------------------------------------*/
  1497. void NEAR PASCAL DrawStuff(
  1498. HWND hwnd,
  1499. register PAINTSTRUCT *pps)
  1500. {
  1501. register HDC hdc;
  1502. RECT rcPaint;
  1503. RECT rcClient;
  1504. UINT BestFormat;
  1505. hdc = pps->hdc;
  1506. if (pps->fErase)
  1507. FillRect(hdc, (LPRECT)&pps->rcPaint, hbrBackground);
  1508. GetClientRect(hwnd, (LPRECT)&rcClient);
  1509. BestFormat = GetBestFormat(CurSelFormat);
  1510. fOwnerDisplay = (BestFormat == CF_OWNERDISPLAY);
  1511. /* If the display format has changed, Set rcWindow,
  1512. * the display area for clip info.
  1513. */
  1514. if (fDisplayFormatChanged)
  1515. {
  1516. CopyRect((LPRECT)&rcWindow, (LPRECT)&rcClient);
  1517. /* We have changed the size of the clipboard. Tell the owner,
  1518. * if fOwnerDisplay is active.
  1519. */
  1520. if (fOwnerDisplay)
  1521. SendOwnerSizeMessage(hwnd, rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
  1522. else
  1523. /* Give the window a small margin, for looks */
  1524. InflateRect(&rcWindow, -((int)cxMargin), -((int)cyMargin));
  1525. fDisplayFormatChanged = FALSE;
  1526. }
  1527. if (fOwnerDisplay)
  1528. {
  1529. /* Clipboard Owner handles display */
  1530. HANDLE hps;
  1531. hps = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  1532. (LONG)sizeof(PAINTSTRUCT));
  1533. if (hps != NULL)
  1534. {
  1535. LPPAINTSTRUCT lppsT;
  1536. if ((lppsT = (LPPAINTSTRUCT)GlobalLock(hps)) != NULL)
  1537. {
  1538. _fmemcpy(lppsT,pps,sizeof(PAINTSTRUCT));
  1539. IntersectRect(&lppsT->rcPaint, &pps->rcPaint, &rcWindow);
  1540. GlobalUnlock(hps);
  1541. SendOwnerMessage(WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LONG)hps);
  1542. GlobalFree(hps);
  1543. }
  1544. }
  1545. }
  1546. else
  1547. {
  1548. /* We handle display */
  1549. /* Redraw the portion of the paint rectangle that is in the clipbrd rect */
  1550. IntersectRect(&rcPaint, &pps->rcPaint, &rcWindow);
  1551. rcPaint.left = rcWindow.left; /* Always draw from left edge of window */
  1552. if ((rcPaint.bottom > rcPaint.top) && (rcPaint.right > rcPaint.left))
  1553. {
  1554. DrawFormat(hdc, &rcPaint,
  1555. /* rcPaint.left always == rcWindow.left | A-MGATES */
  1556. /* (INT)(cxScrollNow + rcPaint.left - rcWindow.left), */
  1557. cxScrollNow,
  1558. (INT)(cyScrollNow + rcPaint.top - rcWindow.top),
  1559. BestFormat);
  1560. }
  1561. }
  1562. }
  1563. /*--------------------------------------------------------------------------*/
  1564. /* */
  1565. /* UpdateCBMenu() - */
  1566. /* */
  1567. /* This routine is called once during initialisation and everytime
  1568. * the contents of the clipboard change. This updates the entries
  1569. * in the "Display" popup menu and the "grey" and "checked" status
  1570. * based on the data formats available in the clipboard.
  1571. */
  1572. void UpdateCBMenu(
  1573. HWND hwnd)
  1574. {
  1575. register UINT fmt;
  1576. WORD cFmt;
  1577. WORD cCBCount; /* Number of data items in CB */
  1578. register WORD wFlags; /* Used to store the status flags for menu items */
  1579. INT iIndex;
  1580. INT nPopupCount;
  1581. BOOL bAutoSelect;
  1582. TCHAR szName[40];
  1583. /* Find out the number of data items present in clipboard. */
  1584. if (!(cCBCount = (WORD)CountClipboardFormats()))
  1585. {
  1586. /* The Clipboard is empty; So, disable both menu items */
  1587. EnableMenuItem(hMainMenu, 2, MF_BYPOSITION | MF_GRAYED);
  1588. EnableMenuItem(hMainMenu, CBM_CLEAR, MF_BYCOMMAND | MF_GRAYED);
  1589. EnableMenuItem(hMainMenu, CBM_SAVEAS, MF_BYCOMMAND | MF_GRAYED);
  1590. goto ExitPoint;
  1591. }
  1592. /* Now clipboard contains at least one item...
  1593. * Find out the number entries in the popup menu at present.
  1594. */
  1595. if (!hDispMenu)
  1596. /* Get the handle to the Display popup menu */
  1597. hDispMenu = GetSubMenu(GetMenu(hwnd), 2);
  1598. nPopupCount = GetMenuItemCount(hDispMenu);
  1599. if (nPopupCount > 2)
  1600. {
  1601. /* Delete all the entries in the popup menu below menu break. */
  1602. for (iIndex = 2; iIndex < nPopupCount; iIndex++)
  1603. {
  1604. /* NOTE: The second parameter must always be 2! (because we use
  1605. * MF_BYPOSITION, when 2 is deleted, 3 becomes 2!).
  1606. */
  1607. DeleteMenu(hDispMenu, 2, MF_BYPOSITION);
  1608. }
  1609. }
  1610. bAutoSelect = TRUE;
  1611. /* EnumClipboard() requires an OpenClipboard(). */
  1612. if (!OpenClipboard(hwnd))
  1613. goto ExitPoint;
  1614. for (fmt=0, cFmt=1; cFmt <= cCBCount; cFmt++)
  1615. {
  1616. wFlags = 0;
  1617. fmt = EnumClipboardFormats(fmt);
  1618. GetClipboardName(fmt, (LPTSTR)szName, sizeof(szName));
  1619. switch (fmt)
  1620. {
  1621. case CF_TEXT: /* can display all of these */
  1622. case CF_BITMAP:
  1623. case CF_METAFILEPICT:
  1624. case CF_OEMTEXT:
  1625. case CF_DIB:
  1626. case CF_DSPTEXT:
  1627. case CF_DSPBITMAP:
  1628. case CF_DSPMETAFILEPICT:
  1629. case CF_OWNERDISPLAY:
  1630. case CF_PALETTE:
  1631. case CF_UNICODETEXT:
  1632. case CF_ENHMETAFILE:
  1633. case CF_DSPENHMETAFILE:
  1634. break;
  1635. default: /* all the rest... no */
  1636. wFlags |= MF_GRAYED;
  1637. break;
  1638. }
  1639. /* We have the name of the format in szName. */
  1640. wFlags |= MF_STRING;
  1641. /* Check if the current format is the one selected by the user */
  1642. if (CurSelFormat == fmt)
  1643. {
  1644. bAutoSelect = FALSE;
  1645. wFlags |= MF_CHECKED;
  1646. }
  1647. AppendMenu(hDispMenu, wFlags, fmt, (LPTSTR)szName);
  1648. }
  1649. CloseClipboard();
  1650. if (bAutoSelect)
  1651. {
  1652. CurSelFormat = CBM_AUTO;
  1653. CheckMenuItem(hDispMenu, CBM_AUTO, MF_BYCOMMAND | MF_CHECKED);
  1654. }
  1655. /* Enable the menu items in the top level menu. */
  1656. EnableMenuItem(hMainMenu, 2, MF_BYPOSITION | MF_ENABLED);
  1657. EnableMenuItem(hMainMenu, CBM_CLEAR, MF_BYCOMMAND | MF_ENABLED);
  1658. EnableMenuItem(hMainMenu, CBM_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
  1659. ExitPoint:
  1660. DrawMenuBar(hwnd);
  1661. }
  1662. /*--------------------------------------------------------------------------*/
  1663. /* */
  1664. /* SaveOwnerScrollInfo() - */
  1665. /* */
  1666. /* When the user switched the clipboard display from owner disp to
  1667. * a non-owner display, all the information about the scroll bar
  1668. * positions are to be saved. This routine does that.
  1669. * This is required because, when the user returns back to owner
  1670. * display, the scroll bar positions are to be restored.
  1671. */
  1672. void SaveOwnerScrollInfo(
  1673. register HWND hwnd)
  1674. {
  1675. GetScrollRange(hwnd, SB_VERT, (LPINT) & OwnVerMin, (LPINT) & OwnVerMax);
  1676. GetScrollRange(hwnd, SB_HORZ, (LPINT) & OwnHorMin, (LPINT) & OwnHorMax);
  1677. OwnVerPos = GetScrollPos(hwnd, SB_VERT);
  1678. OwnHorPos = GetScrollPos(hwnd, SB_HORZ);
  1679. }
  1680. /*--------------------------------------------------------------------------*/
  1681. /* */
  1682. /* RestoreOwnerScrollInfo() - */
  1683. /* */
  1684. /*--------------------------------------------------------------------------*/
  1685. /* When the user sitches back to owner-display, the scroll bar
  1686. * positions are restored by this routine.
  1687. */
  1688. void RestoreOwnerScrollInfo(
  1689. register HWND hwnd)
  1690. {
  1691. SetScrollRange(hwnd, SB_VERT, OwnVerMin, OwnVerMax, FALSE);
  1692. SetScrollRange(hwnd, SB_HORZ, OwnHorMin, OwnHorMax, FALSE);
  1693. SetScrollPos(hwnd, SB_VERT, OwnVerPos, TRUE);
  1694. SetScrollPos(hwnd, SB_HORZ, OwnHorPos, TRUE);
  1695. }