windows-nt/Source/XPSP1/NT/shell/osshell/accesory/clipbrd/clipbrd.c
2020-09-26 16:20:57 +08:00

2061 lines
61 KiB
C

/****************************************************************************/
/* */
/* CLIPBRD.C - */
/* */
/* Copyright 1985-92, Microsoft Corporation */
/* */
/* */
/* Window Clipboard Viewer */
/* */
/****************************************************************************/
/*
*
* Modified by Michael Gates (a-mgates), 9/9/92.
*
* Fixed bug #3576 ("Can't copy to clipboard from file manager")
*
* Touched by : Anas Jarrah
* On Date : May 11/1992.
* Revision remarks by Anas Jarrah ext #15201
* This file has been changed to comply with the Unicode standard
* Following is a quick overview of what I have done.
*
* Was Changed it into Remark
* === =============== ======
* CHAR TCHAR if it refers to a text elements
* LPCHAR & LPSTR LPTSTR if it refers to text.
* LPCHAR & LPSTR LPBYTE if it does not refer to text
* "..." TEXT("...") compile time macro resolves it.
* '...' TEXT('...') same
* strlen CharStrLen compile time macro resolves it.
* strcpy CharStrCpy compile time macro resolves it.
* strcmp CharStrCmp compile time macro resolves it.
* strcat CharStrCat compile time macro resolves it.
* RegisterWindow RegisterWindowW tell windows to send Unicode messages.
* LoadResource LoadResource(A/W) NT compiles resource strings into
* Unicode binaries
* MOpenFile() CreateFile replaced to use the Win32 API [pierrej]
*
*
*
* Modified by Pierre Jammes [pierrej] on 5/19/92
*
* The clipboard viewer must be able to display unicode string
* and ansi strings whether it is built as a unicode app or not.
* This is why the functions related to text display are able
* to handle both ansi and unicode strings and are specifically
* calling either the unicode or the ansi API.
* The three functions
* 1) CchLineA(),
* 2) CchLineW() and
* 3) ShowText().
* are able to handle both ansi and unicode text, they contain some code
* that depend on ansi or unicode version of the system APIs and should
* stay the same whether UNICODE is defined or not (whether we are building
* a unicode app or not).
*
* There you will find some occurences of CHAR, WCHAR, LPSTR and LPWSTR.
*
* The Win32 API specifies clipboard ID as 32bit values and the BITMAP and
* METAFILEPICT structures contain fields that are twice as large as the
* same fields under Windows 3.1
* Saving the content of the clipboard into .CLP files that are readable by the
* Windows 3.1 clipboard viewer results in a loss of information.
* As the user may not want this loss of information unless (s)he is planning on
* using the .CLP file with a 16bit version of Windows (s)he is now given the
* oportunity to save the data in a new .CLP format that won't be recognized by
* the Windows 3.1 clipboard viewer (the FileID is different).
*
*/
#include "clipbrd.h"
#include "dib.h"
#include <shellapi.h>
#include <memory.h>
void NEAR PASCAL ShowString(HDC, WORD);
BOOL fAnythingToRender = FALSE;
BOOL fOwnerDisplay = FALSE;
BOOL fDisplayFormatChanged = TRUE;
TCHAR szAppName[] = TEXT("Clipboard");
TCHAR szCaptionName[CAPTIONMAX];
TCHAR szHelpFileName[20];
TCHAR szMemErr[MSGMAX];
HWND hwndNextViewer = NULL;
HWND hwndMain;
HINSTANCE hInst;
HANDLE hAccel;
HANDLE hfontSys;
HANDLE hfontOem;
HANDLE hfontUni;
HBRUSH hbrWhite;
HBRUSH hbrBackground;
HMENU hMainMenu;
HMENU hDispMenu;
/* The scroll information for OWNER display is to be preserved, whenever
* the display changes between OWNER and NON-OWNER; The following globals
* are used to save and restore the scroll info.
*/
INT OwnVerMin, OwnVerMax, OwnHorMin, OwnHorMax;
INT OwnVerPos, OwnHorPos;
LONG cyScrollLast = -1; /* Y-offset of display start when maximally */
/* scrolled down; -1==invalid */
LONG cyScrollNow = 0; /* Y-offset of current display start */
/* (0=scrolled up all the way) */
INT cxScrollLast = -1; /* Like cyScrollLast, but for horiz scroll */
INT cxScrollNow = 0; /* Like cyScrollNow, but for horiz scroll */
RECT rcWindow; /* Window in which to paint clipboard info */
UINT cyLine, cxChar, cxMaxCharWidth; /* Size of a standard text char */
UINT cxMargin, cyMargin; /* White border size around clip data area */
UINT CurSelFormat = CBM_AUTO;
/* Defines priority order for show format */
UINT rgfmt[] = {
CF_OWNERDISPLAY,
CF_DSPTEXT,
CF_DSPBITMAP,
CF_DSPENHMETAFILE,
CF_DSPMETAFILEPICT,
CF_TEXT,
CF_UNICODETEXT,
CF_OEMTEXT,
CF_ENHMETAFILE,
CF_METAFILEPICT,
CF_BITMAP,
CF_DIB,
CF_PALETTE,
CF_RIFF,
CF_WAVE,
CF_SYLK,
CF_DIF,
CF_TIFF,
CF_PENDATA
};
#define ifmtMax 19
/* variables for the new File Open,File SaveAs and Find Text dialogs */
OPENFILENAME OFN;
TCHAR szFileName[PATHMAX]; /* Unicode AnasJ May 92 */
TCHAR szLastDir[PATHMAX];
TCHAR szDefExt[CCH_szDefExt]; /* default extension for above */
TCHAR szFilterSpec[FILTERMAX]; /* default filter spec. for above */
TCHAR szCustFilterSpec[FILTERMAX]; /* buffer for custom filters created */
UINT wHlpMsg; /* message used to invoke Help */
TCHAR szOpenCaption [CAPTIONMAX]; /* File open dialog caption text */
TCHAR szSaveCaption [CAPTIONMAX]; /* File Save as dialog caption text */
/* MemErrorMessage is called when a failure occurs on either WinHelp or
* ShellAbout.
*/
void FAR PASCAL MemErrorMessage()
{
MessageBeep(0);
MessageBox(hwndMain,szMemErr,NULL,MB_ICONHAND|MB_OK);
}
/*--------------------------------------------------------------------------*/
/* */
/* MyOpenClipboard() - */
/* */
/*--------------------------------------------------------------------------*/
BOOL MyOpenClipboard(
HWND hWnd)
{
HDC hDC;
RECT Rect;
if(OpenClipboard(hWnd))
{
return(TRUE);
}
/* Some app forgot to close the clipboard */
hDC = GetDC(hWnd);
GetClientRect(hWnd, (LPRECT)&Rect);
FillRect(hDC, (LPRECT)&Rect, hbrBackground);
ShowString(hDC, IDS_ALREADYOPEN);
ReleaseDC(hWnd, hDC);
return(FALSE);
}
/*--------------------------------------------------------------------------*/
/* */
/* ChangeCharDimensions() - */
/* */
/*--------------------------------------------------------------------------*/
void ChangeCharDimensions(
HWND hwnd,
UINT wOldFormat,
UINT wNewFormat)
{
/* Check if the font has changed. */
if (wOldFormat != wNewFormat)
{
switch (wNewFormat)
{
case CF_OEMTEXT:
SetCharDimensions(hwnd, hfontOem);
break;
case CF_UNICODETEXT:
SetCharDimensions(hwnd, hfontUni);
break;
case CF_TEXT:
default:
SetCharDimensions(hwnd, hfontSys);
break;
}
}
}
/*--------------------------------------------------------------------------*/
/* */
/* RenderFormat() - */
/* */
/*--------------------------------------------------------------------------*/
/* Read the data from fh and SetClipboardData() with it. */
BOOL RenderFormat(
FORMATHEADER *FormatHeader,
register INT fh)
{
HANDLE hBitmap;
register HANDLE hData;
LPBYTE lpData;
DWORD MetaOffset; /* special case hack for metafiles */
BITMAP bitmap;
HPALETTE hPalette;
LPLOGPALETTE lpLogPalette;
if (PRIVATE_FORMAT(FormatHeader->FormatID))
FormatHeader->FormatID = (UINT)RegisterClipboardFormat(FormatHeader->Name);
/* Special case hack for metafiles to get hData referencing
* the metafile bits, not the METAFILEPICT structure.
*/
switch (FormatHeader->FormatID)
{
case CF_METAFILEPICT:
if (fNTReadFileFormat)
MetaOffset = sizeof(METAFILEPICT);
else
MetaOffset = SIZE_OF_WIN31_METAFILEPICT_STRUCT;
break;
case CF_BITMAP:
if (fNTReadFileFormat)
MetaOffset = sizeof(BITMAP);
else
MetaOffset = SIZE_OF_WIN31_BITMAP_STRUCT;
break;
default:
MetaOffset = 0;
break;
}
if (!(hData = GlobalAlloc(GHND, FormatHeader->DataLen - MetaOffset)))
return(FALSE);
if (!(lpData = GlobalLock(hData)))
{
GlobalFree(hData);
return(FALSE);
}
_llseek(fh, FormatHeader->DataOffset + MetaOffset, 0);
if(!lread(fh, lpData, FormatHeader->DataLen - MetaOffset))
{
/* Error in reading the file */
GlobalUnlock(hData);
GlobalFree(hData);
return(FALSE);
}
GlobalUnlock(hData);
/* As when we write these we have to special case a few of
* these guys. This code and the write code should match in terms
* of the sizes and positions of data blocks being written out.
*/
switch (FormatHeader->FormatID)
{
case CF_ENHMETAFILE:
{
HENHMETAFILE hEMF;
hEMF = (HENHMETAFILE)SetEnhMetaFileBits(FormatHeader->DataLen, lpData);
GlobalUnlock(hData);
GlobalFree(hData);
hData = hEMF; /* Stuff this in the clipboard */
break;
}
case CF_METAFILEPICT:
{
HANDLE hMF;
HANDLE hMFP;
LPMETAFILEPICT lpMFP;
/* Create the METAFILE with the bits we read in. */
if (!(hMF = SetMetaFileBitsEx(FormatHeader->DataLen, lpData))) /* portable code */
return(FALSE);
/* Alloc a METAFILEPICT header. */
if (!(hMFP = GlobalAlloc(GHND, (DWORD)sizeof(METAFILEPICT))))
return(FALSE);
if (!(lpMFP = (LPMETAFILEPICT)GlobalLock(hMFP)))
{
GlobalFree(hMFP);
return(FALSE);
}
/* Reposition to the start of the METAFILEPICT header. */
_llseek(fh, FormatHeader->DataOffset, 0);
/* Read it in. */
if (fNTReadFileFormat)
_lread(fh, (LPBYTE)lpMFP, sizeof(METAFILEPICT));
else {
/* If we read a win 3.1 metafile we have to read the fields
one after the other as they aren't of the same size as
the corresponding Win 3.1 METAFILEPICT structure fields.
We initialize the fields to zero their hight word.
[pierrej 5/27/92] */
lpMFP->mm = 0;
lpMFP->xExt = 0;
lpMFP->yExt = 0;
_lread(fh, (LPBYTE)&(lpMFP->mm), sizeof(WORD));
_lread(fh, (LPBYTE)&(lpMFP->xExt), sizeof(WORD));
_lread(fh, (LPBYTE)&(lpMFP->yExt), sizeof(WORD));
/* No, we don't need to read in the handle, we wouldn't
use it anyways. [pierrej, 5/27/92] */
}
lpMFP->hMF = hMF; /* Update the METAFILE handle */
GlobalUnlock(hMFP); /* Unlock the header */
hData = hMFP; /* Stuff this in the clipboard */
break;
}
case CF_BITMAP:
/* Reposition to the start of the METAFILEPICT header. */
_llseek(fh, FormatHeader->DataOffset, 0);
/* Read it in. */
if (fNTReadFileFormat)
_lread(fh, (LPBYTE)&bitmap, sizeof(BITMAP));
else {
/* If we read a win 3.1 bitmap we have to read the fields
one after the other as they aren't of the same size as
the corresponding Win 3.1 BITMAP structure fields.
We initialize the fields to zero their hight word or byte.
[pierrej 5/27/92] */
bitmap.bmType = 0;
bitmap.bmWidth = 0;
bitmap.bmHeight = 0;
bitmap.bmWidthBytes = 0;
bitmap.bmPlanes = 0;
bitmap.bmBitsPixel = 0;
bitmap.bmBits = NULL;
_lread(fh, (LPBYTE)&(bitmap.bmType), sizeof(WORD));
_lread(fh, (LPBYTE)&(bitmap.bmWidth), sizeof(WORD));
_lread(fh, (LPBYTE)&(bitmap.bmHeight), sizeof(WORD));
_lread(fh, (LPBYTE)&(bitmap.bmWidthBytes), sizeof(WORD));
_lread(fh, (LPBYTE)&(bitmap.bmPlanes), sizeof(BYTE));
_lread(fh, (LPBYTE)&(bitmap.bmBitsPixel), sizeof(BYTE));
_lread(fh, (LPBYTE)&(bitmap.bmBits), sizeof(LPVOID));
}
if (!(lpData = GlobalLock(hData)))
{
GlobalFree(hData);
return FALSE;
}
bitmap.bmBits = lpData;
/* If this fails we should avoid doing the SetClipboardData()
* below with the hData check.
*/
hBitmap = CreateBitmapIndirect(&bitmap);
GlobalUnlock(hData);
GlobalFree(hData);
hData = hBitmap; /* Stuff this in the clipboard */
break;
case CF_DIB:
break;
case CF_PALETTE:
if (!(lpLogPalette = (LPLOGPALETTE)GlobalLock(hData)))
{
GlobalFree(hData);
return(FALSE);
}
/* Create a logical palette. */
if (!(hPalette = CreatePalette(lpLogPalette)))
{
GlobalUnlock(hData);
GlobalFree(hData);
return(FALSE);
}
GlobalUnlock(hData);
GlobalFree(hData);
hData = hPalette; /* Stuff this into clipboard */
break;
}
if (!hData)
return(FALSE);
SetClipboardData(FormatHeader->FormatID, hData);
return(TRUE);
}
/*--------------------------------------------------------------------------*/
/* */
/* ClipbrdVScroll() - */
/* */
/*--------------------------------------------------------------------------*/
/* Scroll contents of window vertically, according to action code in wParam. */
void ClipbrdVScroll(
HWND hwnd,
WORD wParam,
WORD wThumb)
{
INT cyWindow;
LONG dyScroll;
LONG cyScrollT;
LONG dyScrollAbs;
LONG cyPartialChar;
/* Ensure that all the bits are valid first, before scrolling them */
UpdateWindow(hwnd);
cyScrollT = cyScrollNow;
cyWindow = rcWindow.bottom - rcWindow.top;
/* Compute scroll results as an effect on cyScrollNow */
switch (wParam)
{
case SB_LINEUP:
cyScrollT -= cyLine;
break;
case SB_LINEDOWN:
cyScrollT += cyLine;
break;
case SB_THUMBPOSITION:
cyScrollT = (LONG)(((LONG)wThumb * (LONG)cyScrollLast) / VPOSLAST);
break;
case SB_PAGEUP:
case SB_PAGEDOWN:
{
INT cyPageScroll;
cyPageScroll = cyWindow - cyLine;
if (cyPageScroll < (INT)cyLine)
cyPageScroll = cyLine;
cyScrollT += (wParam == SB_PAGEUP) ? -cyPageScroll : cyPageScroll;
break;
}
default:
return;
}
if ((cyScrollT < 0) || (cyScrollLast <= 0))
cyScrollT = 0;
else if (cyScrollT > cyScrollLast)
cyScrollT = cyScrollLast;
else if ((cyPartialChar = cyScrollT % cyLine) != 0)
{
/* Round to the nearest character increment. */
if (cyPartialChar > (LONG)(cyLine >> 1))
cyScrollT += cyLine;
cyScrollT -= cyPartialChar;
}
dyScroll = cyScrollNow - cyScrollT;
if (dyScroll > 0)
dyScrollAbs = dyScroll;
else if (dyScroll < 0)
dyScrollAbs = -dyScroll;
else
return; /* Scrolling has no effect here. */
cyScrollNow = cyScrollT;
if (dyScrollAbs >= rcWindow.bottom - rcWindow.top)
/* ScrollWindow does not handle this case */
InvalidateRect(hwnd, (LPRECT)&rcWindow, TRUE);
else
ScrollWindow(hwnd, 0, (INT)dyScroll, &rcWindow, &rcWindow);
UpdateWindow(hwnd);
SetScrollPos(hwnd,
SB_VERT,
(cyScrollLast <= 0) ? 0 : (INT)((cyScrollT * (DWORD)VPOSLAST) / cyScrollLast),
TRUE);
}
/*--------------------------------------------------------------------------*/
/* */
/* ClipbrdHScroll() - */
/* */
/*--------------------------------------------------------------------------*/
/* Scroll contents of window horizontally, according to op code in wParam. */
void NEAR PASCAL ClipbrdHScroll(HWND hwnd,WORD wParam,WORD wThumb)
{
INT cxWindow;
register INT dxScroll;
register INT cxScrollT;
INT dxScrollAbs;
LONG cxPartialChar;
cxScrollT = cxScrollNow;
cxWindow = rcWindow.right - rcWindow.left;
/* Compute scroll results as an effect on cxScrollNow */
switch (wParam)
{
case SB_LINEUP:
cxScrollT -= cxChar;
break;
case SB_LINEDOWN:
cxScrollT += cxChar;
break;
case SB_THUMBPOSITION:
cxScrollT = (INT)(((LONG)wThumb * (LONG)cxScrollLast) / HPOSLAST);
break;
case SB_PAGEUP:
case SB_PAGEDOWN:
{
INT cxPageScroll;
cxPageScroll = cxWindow - cxChar;
if (cxPageScroll < (INT)cxChar)
cxPageScroll = cxChar;
cxScrollT += (wParam == SB_PAGEUP) ? -cxPageScroll : cxPageScroll;
break;
}
default:
return;
}
if ((cxScrollT < 0) || (cxScrollLast <= 0))
cxScrollT = 0;
else if (cxScrollT > cxScrollLast)
cxScrollT = cxScrollLast;
else if ((cxPartialChar = cxScrollT % cxChar) != 0)
{ /* Round to the nearest character increment */
if (cxPartialChar > (LONG)(cxChar >> 1))
cxScrollT += cxChar;
cxScrollT -= cxPartialChar;
}
/* Now we have a good cxScrollT value */
dxScroll = cxScrollNow - cxScrollT;
if (dxScroll > 0)
dxScrollAbs = dxScroll;
else if (dxScroll < 0)
dxScrollAbs = -dxScroll;
else
return; /* Scrolling has no effect here. */
cxScrollNow = cxScrollT;
if (dxScrollAbs >= rcWindow.right - rcWindow.left)
/* ScrollWindow does not handle this case */
InvalidateRect( hwnd, (LPRECT) & rcWindow, TRUE );
else
ScrollWindow(hwnd, dxScroll, 0, (LPRECT)&rcWindow, (LPRECT)&rcWindow);
UpdateWindow(hwnd);
SetScrollPos(hwnd,
SB_HORZ,
(cxScrollLast <= 0) ? 0 : (INT)(((DWORD)cxScrollT * (DWORD)HPOSLAST) / (DWORD)cxScrollLast),
TRUE );
}
/*--------------------------------------------------------------------------*/
/* */
/* DibPaletteSize() - */
/* */
/*--------------------------------------------------------------------------*/
INT NEAR PASCAL DibPaletteSize(LPBITMAPINFOHEADER lpbi)
{
register INT bits;
/* With the new format headers, the size of the palette is in biClrUsed
* else is dependent on bits per pixel.
*/
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
{
if (lpbi->biClrUsed != 0)
return((WORD)lpbi->biClrUsed * sizeof(RGBQUAD));
bits = lpbi->biBitCount;
return((bits == 24) ? 0 : (1 << bits) * sizeof(RGBQUAD));
}
else
{
bits = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
return((bits == 24) ? 0 : (1 << bits) * sizeof(RGBTRIPLE));
}
}
/*--------------------------------------------------------------------------*/
/* */
/* DibGetInfo() - */
/* */
/*--------------------------------------------------------------------------*/
void NEAR PASCAL DibGetInfo(HANDLE hdib,LPBITMAP pbm)
{
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
{
pbm->bmWidth = (INT)lpbi->biWidth;
pbm->bmHeight = (INT)lpbi->biHeight;
}
else
{
pbm->bmWidth = (INT)((LPBITMAPCOREHEADER)lpbi)->bcWidth;
pbm->bmHeight = (INT)((LPBITMAPCOREHEADER)lpbi)->bcHeight;
}
GlobalUnlock(hdib);
}
/*--------------------------------------------------------------------------*/
/* */
/* DrawDib() - */
/* */
/*--------------------------------------------------------------------------*/
BOOL NEAR PASCAL DrawDib(HDC hdc,INT x0,INT y0,HANDLE hdib)
{
BITMAP bm;
LPBYTE lpBits;
LPBITMAPINFOHEADER lpbi;
if (!hdib)
return(FALSE);
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
if (!lpbi)
return(FALSE);
DibGetInfo(hdib, (LPBITMAP)&bm);
lpBits = (LPBYTE)lpbi + (WORD)lpbi->biSize + DibPaletteSize(lpbi);
SetDIBitsToDevice(hdc,
x0, y0, bm.bmWidth, bm.bmHeight,
0, 0,
0, bm.bmHeight,
lpBits, (LPBITMAPINFO)lpbi,
DIB_RGB_COLORS);
GlobalUnlock(hdib);
return(TRUE);
}
/*--------------------------------------------------------------------------
FShowDIBitmap() -
Parameters:
hdc - DC to draw into.
prc - Pointer to bounds rectangle within DC.
hdib - DIB to draw.
cxScroll, cyScroll - Position the window's scrolled to.
--------------------------------------------------------------------------*/
BOOL NEAR PASCAL FShowDIBitmap(register HDC hdc,PRECT prc,
HANDLE hdib /* Bitmap in DIB format */,INT cxScroll,INT cyScroll)
{
BITMAP bm;
DibGetInfo(hdib, (LPBITMAP)&bm);
if (cyScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cyScrollLast = bm.bmHeight - (rcWindow.bottom - rcWindow.top);
if (cyScrollLast < 0)
cyScrollLast = 0;
}
if (cxScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cxScrollLast = bm.bmWidth - (rcWindow.right - rcWindow.left);
if (cxScrollLast < 0)
cxScrollLast = 0;
}
SaveDC(hdc);
IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
/* MSetViewportOrg(hdc, prc->left - cxScroll, prc->top - cyScroll); */
DrawDib(hdc, -cxScroll, -cyScroll, hdib);
RestoreDC(hdc, -1);
return(TRUE);
}
/*--------------------------------------------------------------------------
FShowBitmap() -
Purpose: Draw a bitmap in the given HDC.
Parameters:
hdc - hDC to draw into.
prc - Bounds rectangle in the DC.
hbm - The bitmap to draw
cxScroll, cyScroll - Where the DC's scrolled to
Returns:
TRUE on success, FALSE on failure.
--------------------------------------------------------------------------*/
BOOL NEAR PASCAL FShowBitmap(HDC hdc,register PRECT prc,
HBITMAP hbm,INT cxScroll,INT cyScroll)
{
register HDC hMemDC;
BITMAP bitmap;
INT cxBlt, cyBlt;
INT cxRect, cyRect;
if ((hMemDC = CreateCompatibleDC(hdc)) == NULL)
return(FALSE);
SelectObject(hMemDC, (HBITMAP)hbm);
GetObject((HBITMAP)hbm, sizeof(BITMAP), (LPBYTE)&bitmap);
if (cyScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cyScrollLast = bitmap.bmHeight - (rcWindow.bottom - rcWindow.top);
if (cyScrollLast < 0)
cyScrollLast = 0;
}
if (cxScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cxScrollLast = bitmap.bmWidth - (rcWindow.right - rcWindow.left);
if (cxScrollLast < 0)
cxScrollLast = 0;
}
cxRect = prc->right - prc->left;
cyRect = prc->bottom - prc->top;
/* Bug #10656: Subtract 1 so we won't fall off the end of the bitmap
* (the bitmap is zero based).
* 11 January 1992 Clark R. Cyr
*/
cxBlt = min(cxRect, bitmap.bmWidth - cxScroll);
cyBlt = min(cyRect, bitmap.bmHeight - cyScroll);
/* Bug #14131: Instead of subtracting 1 from the amount to blt, subtract 1
* from the offset to blt from, thus allowing for a full picture
* when no scrolling is needed.
* 06 February 1992 Clark R. Cyr
*/
if ((cxBlt != cxRect) && (cxScroll > 0))
cxScroll--;
if ((cyBlt != cyRect) && (cyScroll > 0))
cyScroll--;
BitBlt(hdc, prc->left, prc->top,
cxBlt, cyBlt,
hMemDC,
cxScroll, cyScroll, /* X,Y offset into source DC */
SRCCOPY);
DeleteDC(hMemDC);
return(TRUE);
}
#define DXPAL (cyLine)
#define DYPAL (cyLine)
/*--------------------------------------------------------------------------*/
/* */
/* FShowPalette() - */
/* */
/*--------------------------------------------------------------------------*/
BOOL NEAR PASCAL FShowPalette(register HDC hdc,register PRECT prc,
HPALETTE hpal,INT cxScroll,INT cyScroll)
{
INT n;
INT x, y;
INT nx, ny;
INT nNumEntries = 0;
RECT rc;
HBRUSH hbr;
if (!hpal)
return(FALSE);
GetObject(hpal, sizeof(INT), (LPBYTE)&nNumEntries);
nx = (rcWindow.right - rcWindow.left) / DXPAL;
if (nx == 0)
nx = 1;
ny = (nNumEntries + nx - 1) / nx;
if (cyScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cyScrollLast = ny * DYPAL - (rcWindow.bottom - rcWindow.top);
if (cyScrollLast < 0)
cyScrollLast = 0;
}
if (cxScrollLast == -1)
{
/* Compute last scroll offset into bitmap */
cxScrollLast = 0;
}
SaveDC(hdc);
IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
MSetViewportOrg(hdc, prc->left - cxScroll, prc->top - cyScroll);
SelectPalette(hdc, hpal, FALSE);
RealizePalette(hdc);
x = 0;
y = -((int)DYPAL);
for (n=0; n < nNumEntries; n++, x += DXPAL)
{
if (n % nx == 0)
{
x = 0;
y += DYPAL;
}
rc.left = x;
rc.top = y;
rc.right = x + DXPAL;
rc.bottom = y + DYPAL;
if (RectVisible(hdc,&rc))
{
InflateRect(&rc, -1, -1);
FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
InflateRect(&rc, -1, -1);
hbr = CreateSolidBrush(PALETTEINDEX(n));
FillRect(hdc, &rc, hbr);
DeleteObject(hbr);
}
}
RestoreDC(hdc, -1);
return(TRUE);
}
/*--------------------------------------------------------------------------*/
/* */
/* PxlConvert() - */
/* */
/*--------------------------------------------------------------------------*/
/* Return the # of pixels spanned by 'val', a measurement in coordinates
* appropriate to mapping mode mm. 'pxlDeviceRes' gives the resolution
* of the device in pixels, along the axis of 'val'. 'milDeviceRes' gives
* the same resolution measurement, but in millimeters.
*/
INT NEAR PASCAL PxlConvert(INT mm, INT val,INT pxlDeviceRes,INT milDeviceRes)
{
register WORD wMult = 1;
register WORD wDiv = 1;
DWORD ulPxl;
DWORD ulDenom;
/* Should be a constant! This works around a compiler bug as of 07/14/85. */
DWORD ulMaxInt = MAXSHORT;
if (milDeviceRes == 0)
{
/* to make sure we don't get divide-by-0 */
return(0);
}
switch (mm)
{
case MM_LOMETRIC:
wDiv = 10;
break;
case MM_HIMETRIC:
wDiv = 100;
break;
case MM_TWIPS:
wMult = 254;
wDiv = 14400;
break;
case MM_LOENGLISH:
wMult = 2540;
wDiv = 10000;
break;
case MM_HIENGLISH:
wMult = 254;
wDiv = 10000;
break;
case MM_TEXT:
return(val);
case MM_ISOTROPIC:
case MM_ANISOTROPIC:
/* These picture types have no original size */
default:
return(0);
}
/* Add denominator - 1 to numerator, to avoid roundoff */
ulDenom = (DWORD)wDiv * (DWORD)milDeviceRes;
ulPxl = (((DWORD)((DWORD)wMult * (DWORD)val * (DWORD)pxlDeviceRes)) + ulDenom - 1) / ulDenom;
return((ulPxl > ulMaxInt) ? 0 : (INT)ulPxl);
}
/*--------------------------------------------------------------------------*/
/* */
/* FShowEnhMetaFile() - */
/* */
/*--------------------------------------------------------------------------*/
/* Display an enhanced metafile in the specified rectangle. */
BOOL NEAR PASCAL FShowEnhMetaFile(
register HDC hdc,
HANDLE hemf,
LPRECT prc)
{
INT level;
INT f = FALSE;
ENHMETAHEADER EnhHeader;
if ((level = SaveDC( hdc )) != 0)
{
cyScrollLast = 0;
cxScrollLast = 0;
GetEnhMetaFileHeader(hemf, sizeof(ENHMETAHEADER), &EnhHeader);
rcWindow.top--;
rcWindow.left--;
SetWindowOrgEx(hdc, -prc->left, -prc->top, NULL);
f = PlayEnhMetaFile(hdc, hemf, &rcWindow);
rcWindow.top++;
rcWindow.left++;
RestoreDC(hdc, level);
}
return(f);
}
/*--------------------------------------------------------------------------
FShowMetaFilePict()
Display a metafile in the specified rectangle.
--------------------------------------------------------------------------*/
BOOL NEAR PASCAL FShowMetaFilePict(
register HDC hdc,
register PRECT prc,
HANDLE hmfp,
INT cxScroll,
INT cyScroll)
{
INT level;
INT cxBitmap;
INT cyBitmap;
INT f = FALSE;
LPMETAFILEPICT lpmfp;
if ((lpmfp = (LPMETAFILEPICT)GlobalLock( hmfp )) != NULL)
{
METAFILEPICT mfp;
mfp = *lpmfp;
GlobalUnlock( hmfp );
if ((level = SaveDC( hdc )) != 0)
{
/* Compute size of picture to be displayed */
switch (mfp.mm)
{
case MM_ISOTROPIC:
case MM_ANISOTROPIC:
/* Not scrollable. Resize these into the given rect. */
cyScrollLast = 0;
cxScrollLast = 0;
cxBitmap = rcWindow.right - rcWindow.left;
cyBitmap = rcWindow.bottom - rcWindow.top;
break;
default:
cxBitmap = PxlConvert(mfp.mm, mfp.xExt,
GetDeviceCaps(hdc, HORZRES),
GetDeviceCaps(hdc, HORZSIZE)
);
cyBitmap = PxlConvert(mfp.mm, mfp.yExt,
GetDeviceCaps(hdc, VERTRES),
GetDeviceCaps(hdc, VERTSIZE)
);
if (!cxBitmap || !cyBitmap)
goto NoDisplay;
if (cxScrollLast == -1)
{
cxScrollLast = cxBitmap - (rcWindow.right - rcWindow.left);
if (cxScrollLast < 0)
cxScrollLast = 0;
}
if (cyScrollLast == -1)
{
cyScrollLast = cyBitmap - (rcWindow.bottom - rcWindow.top);
if (cyScrollLast < 0)
cyScrollLast = 0;
}
break;
}
/* We make the "viewport" to be an area the same size as the
* clipboard object, and set the origin and clip region so as
* to show the area we want. Note that the viewport may well be
* bigger than the window.
*/
// IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
SetMapMode(hdc, mfp.mm);
// MSetViewportOrg(hdc, cxScroll, cyScroll);
switch (mfp.mm)
{
case MM_ANISOTROPIC:
if (mfp.xExt && mfp.yExt)
{
/* So we get the correct shape rectangle when
* SetViewportExtEx gets called.
*/
MSetWindowExt(hdc, mfp.xExt, mfp.yExt);
}
/* FALL THRU */
case MM_ISOTROPIC:
MSetViewportExt(hdc, cxBitmap, cyBitmap);
break;
}
/* Since we may have scrolled, force brushes to align */
// MSetBrushOrg(hdc, cxScroll - prc->left, cyScroll - prc->top);
f = PlayMetaFile(hdc, mfp.hMF);
NoDisplay:
RestoreDC(hdc, level);
}
}
return(f);
}
/*--------------------------------------------------------------------------*/
/* */
/* ShowString() - */
/* */
/*--------------------------------------------------------------------------*/
/* Blank rcWindow and show the string on the top line of the client area. */
void NEAR PASCAL ShowString(HDC hdc,WORD id)
{
TCHAR szBuffer[BUFFERLEN];
/* Cancel any scrolling effects. */
cyScrollNow = 0;
cxScrollNow = 0;
LoadString(hInst, id, szBuffer, BUFFERLEN);
FillRect(hdc, &rcWindow, hbrBackground);
DrawText(hdc, szBuffer, -1, &rcWindow, DT_CENTER | DT_WORDBREAK | DT_NOCLIP | DT_TOP);
}
/*--------------------------------------------------------------------------*/
/* */
/* CchLineA() - */
/* */
/*--------------------------------------------------------------------------*/
/* Determine the # of characters in one display line's worth of lpch.
* lpch is assumed to be an ansi string.
*
* Return the following:
* HI WORD: # of chars to display (excludes CR, LF; will not
* exceed cchLine)
* LO WORD: offset of start of next line in lpch; If the current line
* is NULL terminated, this contains offset to the NULL char;
* In RgchBuf: characters to display
*
* Expands Tabs
*
* Accepts any of the following as valid end-of-line terminators:
* CR, LF, CR-LF, LF-CR, NULL
* Callers may test for having reached NULL by (lpch[LOWORD] == '\0')
*/
LONG NEAR PASCAL CchLineA(HDC hDC, CHAR rgchBuf[],
#ifdef WIN16
CHAR huge *lpch,
#else
CHAR FAR *lpch,
#endif
INT cchLine,WORD wWidth)
{
CHAR ch;
CHAR *pch = rgchBuf;
register INT cchIn = 0;
register INT cchOut = 0;
INT iMinNoOfChars;
SIZE size;
INT iTextWidth = 0;
iMinNoOfChars = wWidth / cxMaxCharWidth;
while (cchOut < cchLine)
{
switch (ch = *(lpch + (DWORD)cchIn++))
{
case '\0':
/* cchIn is already incremented; So, it is pointing to
* a character beyond the NULL; So, decrement it.
*/
cchIn--;
goto DoubleBreak;
case '\015': /* CR */
case '\012': /* LF */
if ((lpch[cchIn] == '\015') || (lpch[cchIn] == '\012'))
cchIn++;
goto DoubleBreak;
case '\011': /* TAB */
{
INT cchT = 8 - (cchOut % 8);
/* Check if the width has exceeded or the total
* number of characters has exceeded
*/
if (((WORD)(iTextWidth + cchT * cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
/* Tab causes wrap to next line */
goto DoubleBreak;
while (cchT--)
rgchBuf[cchOut++] = ' ';
break;
}
default:
rgchBuf[cchOut++] = ch;
#ifdef DBCS
if( IsDBCSLeadByte(ch) )
rgchBuf[cchOut++] = *(lpch + (DWORD)cchIn++);
#endif
break;
}
/* Check if the width has been exceeded. */
if (cchOut >= iMinNoOfChars)
{
GetTextExtentPointA(hDC, rgchBuf, cchOut, (LPSIZE)&size);
iTextWidth = size.cx;
if ((WORD)iTextWidth == wWidth)
break;
else if((WORD)iTextWidth > wWidth)
{
#ifdef DBCS
if( IsDBCSLeadByte(ch) ){
cchOut--;
cchIn--;
}
#endif
cchOut--;
cchIn--;
break;
}
iMinNoOfChars += (wWidth - iTextWidth) / cxMaxCharWidth;
}
}
DoubleBreak:
return(MAKELONG(cchIn, cchOut));
}
/*--------------------------------------------------------------------------*/
/* */
/* CchLineW() - */
/* */
/*--------------------------------------------------------------------------*/
/*Same as previous function but takes unicode strings.
*/
LONG NEAR PASCAL CchLineW(HDC hDC, WCHAR rgchBuf[],
WCHAR FAR *lpch,
INT cchLine,WORD wWidth)
{
WCHAR ch;
WCHAR *pch = rgchBuf;
register INT cchIn = 0;
register INT cchOut = 0;
INT iMinNoOfChars;
INT iTextWidth = 0;
SIZE size;
iMinNoOfChars = wWidth / cxMaxCharWidth;
while (cchOut < cchLine)
{
switch (ch = *(lpch + (DWORD)cchIn++))
{
case L'\0':
/* cchIn is already incremented; So, it is pointing to
* a character beyond the NULL; So, decrement it.
*/
cchIn--;
goto DoubleBreak;
case L'\015': /* CR */
case L'\012': /* LF */
if ((lpch[cchIn] == L'\015') || (lpch[cchIn] == L'\012'))
cchIn++;
goto DoubleBreak;
case L'\011': /* TAB */
{
INT cchT = 8 - (cchOut % 8);
/* Check if the width has exceeded or the total
* number of characters has exceeded
*/
if (((WORD)(iTextWidth + cchT * cxChar) > wWidth) || ((cchOut+cchT) >= cchLine))
/* Tab causes wrap to next line */
goto DoubleBreak;
while (cchT--)
rgchBuf[cchOut++] = L' ';
break;
}
default:
rgchBuf[cchOut++] = ch;
break;
}
/* Check if the width has been exceeded. */
if (cchOut >= iMinNoOfChars)
{
GetTextExtentPointW(hDC, rgchBuf, cchOut, &size);
iTextWidth = size.cx;
if ((WORD)iTextWidth == wWidth)
break;
else if((WORD)iTextWidth > wWidth)
{
cchOut--;
cchIn--;
break;
}
iMinNoOfChars += (wWidth - iTextWidth) / cxMaxCharWidth;
}
}
DoubleBreak:
return(MAKELONG(cchIn, cchOut));
}
#define cchLineMax 200
/*--------------------------------------------------------------------------*/
/* */
/* ShowText() - */
/* */
/*--------------------------------------------------------------------------*/
void NEAR PASCAL ShowText(register HDC hdc,PRECT prc,HANDLE h,INT cyScroll,
BOOL fUnicode)
{
#ifdef WIN16
CHAR huge *lpch;
#else
CHAR FAR *lpch;
#endif
INT yT;
INT cLine;
INT cLineAllText = 0;
RECT rc;
INT yLine;
INT iLineFirstShow;
WORD wLen;
WORD wWidth;
CHAR rgch[cchLineMax*sizeof(WCHAR)];
rc = *prc;
/* Expand repaint rectangle as necessary to hold an exact number of
* lines and start on an even line boundary. This is because we may
* get arbitrarily weird repaint rectangles when popups are moved.
* Scrolling repaint areas should require no adjustment.
*/
rc.top -= (rc.top - rcWindow.top) % cyLine;
/* If expanding the repaint rectangle to the next line expands it */
/* beyond the bottom of my window, contract it one line. */
if ((yT = (rc.bottom - rc.top) % cyLine) != 0)
if ((rc.bottom += cyLine - yT) > rcWindow.bottom)
rc.bottom -= cyLine;
if (rc.bottom <= rc.top)
return;
if (((wWidth = (WORD)(rcWindow.right - rcWindow.left)) <= 0) ||
((cLine = (rc.bottom - rc.top) / cyLine) <= 0) ||
(NULL == (lpch = (LPSTR)GlobalLock(h))) )
{
/* Bad Rectangle or Bad Text Handle */
ShowString(hdc, IDS_ERROR);
return;
}
/* Advance lpch to point at the text for the first line to show. */
iLineFirstShow = cyScroll / cyLine;
/* Advance lpch to point at text for that line. */
if (!fUnicode)
while ((*lpch) && (iLineFirstShow--))
{
lpch += LOWORD(CchLineA(hdc, rgch, lpch, cchLineMax, wWidth));
cLineAllText++;
}
else
while ((*((WCHAR *)lpch)) && (iLineFirstShow--))
{
lpch += ((LOWORD(CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
cLineAllText++;
}
/* Display string, line by line */
yLine = rc.top;
while (cLine--)
{
LONG lT;
if (!fUnicode)
lT = CchLineA(hdc, rgch, lpch, cchLineMax, wWidth);
else
lT = CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth);
wLen = LOWORD(lT);
if (!fUnicode) {
TextOutA(hdc, rc.left, yLine, (LPSTR) rgch, HIWORD(lT));
lpch += wLen;
} else {
if (!TextOutW(hdc, rc.left, yLine, (LPCWSTR) rgch, HIWORD(lT))) {
GetLastError();
}
lpch += (wLen * sizeof(WCHAR));
}
yLine += cyLine;
cLineAllText++;
if ((!fUnicode && (*lpch == 0)) || (fUnicode && (*((WCHAR *)lpch) == L'\0')))
break;
}
if (cxScrollLast == -1)
/* We don't use horiz scroll for text */
cxScrollLast = 0;
if (cyScrollLast == -1)
{
INT cLineInRcWindow;
/* Validate y-size of text in clipboard. */
/* Adjust rcWindow dimensions for text display */
cLineInRcWindow = (rcWindow.bottom - rcWindow.top) / cyLine;
do {
if (!fUnicode)
lpch += LOWORD(CchLineA(hdc, rgch, lpch, cchLineMax, wWidth));
else
lpch += ((LOWORD(CchLineW(hdc, (WCHAR *)rgch, (WCHAR FAR *)lpch, cchLineMax, wWidth)))*sizeof(WCHAR));
cLineAllText++;
} while ((!fUnicode && (*lpch != 0)) || (fUnicode && ((*lpch != 0) || (*(lpch+1) != 0))));
cyScrollLast = (cLineAllText - cLineInRcWindow) * cyLine;
if (cyScrollLast < 0)
{
cyScrollLast = 0;
}
/* Restrict rcWindow so that it holds an exact # of text lines */
rcWindow.bottom = rcWindow.top + (cLineInRcWindow * cyLine);
}
GlobalUnlock(h);
}
/*--------------------------------------------------------------------------*/
/* */
/* SendOwnerMessage() - */
/* */
/*--------------------------------------------------------------------------*/
void SendOwnerMessage(
UINT message,
WPARAM wParam,
LPARAM lParam)
{
register HWND hwndOwner;
/* Send a message to the clipboard owner, if there is one */
hwndOwner = GetClipboardOwner();
if (hwndOwner != NULL)
{
SendMessage(hwndOwner, message, wParam, lParam);
}
}
/*--------------------------------------------------------------------------*/
/* */
/* SendOwnerSizeMessage() - */
/* */
/*--------------------------------------------------------------------------*/
/* Send WM_SIZECLIPBOARD message to clipboard owner.
* wParam is a handle to the clipboard window
* LOWORD(lParam) is a handle to the passed rect
*/
void SendOwnerSizeMessage(
HWND hwnd,
INT left,
INT top,
INT right,
INT bottom)
{
register HANDLE hrc;
LPRECT lprc;
if ((hrc = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
(LONG)sizeof(RECT))) != NULL )
{
if ((lprc = (LPRECT)GlobalLock(hrc)) != NULL )
{
lprc->top = top;
lprc->bottom = bottom;
lprc->left = left;
lprc->right = right;
GlobalUnlock(hrc);
SendOwnerMessage(WM_SIZECLIPBOARD, (WPARAM)hwnd, (LONG)hrc);
}
GlobalFree(hrc);
}
}
//
// Purpose: Return the best clipboard format we have available, given a
// 'starting' clipboard format.
//
// Parameters:
// wFormat - The format selected on the Display menu.
//
// Returns:
// The number of the clipboard format to use, or NULL if no clipboard
// format matching the requested one exists.
//
////////////////////////////////////////////////////////////////////////
UINT GetBestFormat(
UINT wFormat)
{
register UINT cFmt;
register UINT *pfmt;
if (wFormat == CBM_AUTO)
{
wFormat = 0;
for (cFmt=ifmtMax, pfmt=&rgfmt[0]; cFmt--; pfmt++)
{
if (IsClipboardFormatAvailable(*pfmt))
{
wFormat = *pfmt;
break;
}
}
}
else if (!IsClipboardFormatAvailable(wFormat))
{
wFormat = 0;
}
return wFormat;
}
/*--------------------------------------------------------------------------*/
/* */
/* ClearClipboard() - */
/* */
/*--------------------------------------------------------------------------*/
/* This is called to clear the clipboard. If the clipboard is not
* empty the user is asked if it should be cleared.
*/
BOOL NEAR PASCAL ClearClipboard(register HWND hwnd)
{
CHAR szBuffer[SMALLBUFFERLEN];
CHAR szLocBuffer[BUFFERLEN];
if (CountClipboardFormats() <= 0)
return(TRUE);
/* Get the confirmation from the user. */
LoadString(hInst, IDS_CLEARTITLE, szBuffer, SMALLBUFFERLEN);
LoadString(hInst, IDS_CONFIRMCLEAR, szLocBuffer, BUFFERLEN);
if (MessageBox(hwnd, szLocBuffer, szBuffer, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
if (!OpenClipboard(hwnd) ||
!EmptyClipboard() ||
!CloseClipboard() )
{
LoadString(hInst, IDS_ERROR, szBuffer, SMALLBUFFERLEN);
LoadString(hInst, IDS_CLEAR, szLocBuffer, BUFFERLEN);
MessageBox(hwnd, szLocBuffer, szBuffer, MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
}
InvalidateRect(hwnd, NULL, TRUE);
return(TRUE);
}
return(FALSE);
}
/*--------------------------------------------------------------------------*/
/* */
/* GetClipboardName() - */
/* */
/*--------------------------------------------------------------------------*/
void NEAR PASCAL GetClipboardName(register UINT fmt,LPTSTR szName,
register INT iSize)
{
LPTSTR lprgch;
HANDLE hrgch;
*szName = 0;
/* Get global memory that everyone can get to */
if ((hrgch = GlobalAlloc(GPTR, (LONG)(iSize + 1))) == NULL)
return;
if (!(lprgch = (LPTSTR)GlobalLock(hrgch)))
goto ExitPoint;
switch (fmt)
{
case CF_RIFF:
case CF_WAVE:
case CF_PENDATA:
case CF_SYLK:
case CF_DIF:
case CF_TIFF:
case CF_TEXT:
case CF_BITMAP:
case CF_METAFILEPICT:
case CF_OEMTEXT:
case CF_DIB:
case CF_PALETTE:
case CF_DSPTEXT:
case CF_DSPBITMAP:
case CF_DSPMETAFILEPICT:
case CF_UNICODETEXT:
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
LoadString(hInst, fmt, lprgch, iSize);
break;
case CF_OWNERDISPLAY: /* Clipbrd owner app supplies name */
*lprgch = 0;
SendOwnerMessage(WM_ASKCBFORMATNAME, iSize, (LONG)(LPTSTR)lprgch);
if (!*lprgch)
LoadString(hInst, fmt, lprgch, iSize);
break;
default:
GetClipboardFormatName(fmt, lprgch, iSize);
break;
}
lstrcpy(szName, lprgch);
GlobalUnlock(hrgch);
ExitPoint:
GlobalFree(hrgch);
}
/*--------------------------------------------------------------------------
DrawFormat() -
Purpose: Draw the data on the clipboard, using the given format.
Parameters:
hdc - hDC to draw into.
prc - Pointer to a rectangle showing bounds to paint into
cxScroll - Horizontal position we're scrolled to (0=left)
cyScroll - Vertical position we're scrolled to (0=top)
BestFormat - Format to use when drawing.
--------------------------------------------------------------------------*/
void NEAR PASCAL DrawFormat(
register HDC hdc,
PRECT prc,
INT cxScroll,
INT cyScroll,
UINT BestFormat)
{
register HANDLE h;
HFONT hFont;
INT fOK = TRUE;
UINT wFormat = 0;
if ((BestFormat == 0))
{
if (CountClipboardFormats() )
{
ShowString(hdc, IDS_CANTDISPLAY);
}
}
else if ((h = GetClipboardData(/* wFormat ? wFormat :*/ BestFormat)) != NULL)
{
switch (BestFormat)
{
case CF_DSPTEXT:
case CF_TEXT:
ShowText(hdc, prc, h, cyScroll, FALSE);
break;
case CF_UNICODETEXT:
hFont = SelectObject(hdc, hfontUni);
ShowText(hdc, prc, h, cyScroll, TRUE);
SelectObject(hdc, hFont);
break;
case CF_OEMTEXT:
hFont = SelectObject(hdc, hfontOem);
ShowText(hdc, prc, h, cyScroll, FALSE);
SelectObject(hdc, hFont);
break;
case CF_DSPBITMAP:
case CF_BITMAP:
fOK = FShowBitmap(hdc, prc, h, cxScroll, cyScroll);
break;
case CF_DIB:
fOK = FShowDIBitmap(hdc, prc, h, cxScroll, cyScroll);
break;
case CF_PALETTE:
fOK = FShowPalette(hdc, prc, h, cxScroll, cyScroll);
break;
case CF_WAVE:
case CF_RIFF:
case CF_PENDATA:
case CF_DIF:
case CF_SYLK:
case CF_TIFF:
ShowString(hdc, IDS_BINARY);
break;
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
fOK = FShowEnhMetaFile(hdc, h, prc);
break;
case CF_DSPMETAFILEPICT:
case CF_METAFILEPICT:
fOK = FShowMetaFilePict(hdc, prc, h, cxScroll, cyScroll);
break;
/* If "Auto" is chosen and only data in unrecognised formats is
* available, then display "Can't display data in this format".
*/
default:
ShowString(hdc, IDS_CANTDISPLAY);
break;
}
}
else if (CountClipboardFormats()) // There's data, but we can't Get it..
{
ShowString(hdc, IDS_ERROR);
}
/* If we are unable to display the data, display "<Error>" */
if (!fOK)
{
ShowString(hdc, IDS_NOTRENDERED);
}
}
/*--------------------------------------------------------------------------
DrawStuff() -
Paint portion of current clipboard contents given by PAINT struct
NOTE: If the paintstruct rectangle includes any part of the header, the
whole header is redrawn.
Parameters:
hwnd - Window to draw in.
pps - Pointer to PAINTSTRUCT to use.
Returns:
Nothing.
----------------------------------------------------------------------------*/
void NEAR PASCAL DrawStuff(
HWND hwnd,
register PAINTSTRUCT *pps)
{
register HDC hdc;
RECT rcPaint;
RECT rcClient;
UINT BestFormat;
hdc = pps->hdc;
if (pps->fErase)
FillRect(hdc, (LPRECT)&pps->rcPaint, hbrBackground);
GetClientRect(hwnd, (LPRECT)&rcClient);
BestFormat = GetBestFormat(CurSelFormat);
fOwnerDisplay = (BestFormat == CF_OWNERDISPLAY);
/* If the display format has changed, Set rcWindow,
* the display area for clip info.
*/
if (fDisplayFormatChanged)
{
CopyRect((LPRECT)&rcWindow, (LPRECT)&rcClient);
/* We have changed the size of the clipboard. Tell the owner,
* if fOwnerDisplay is active.
*/
if (fOwnerDisplay)
SendOwnerSizeMessage(hwnd, rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
else
/* Give the window a small margin, for looks */
InflateRect(&rcWindow, -((int)cxMargin), -((int)cyMargin));
fDisplayFormatChanged = FALSE;
}
if (fOwnerDisplay)
{
/* Clipboard Owner handles display */
HANDLE hps;
hps = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
(LONG)sizeof(PAINTSTRUCT));
if (hps != NULL)
{
LPPAINTSTRUCT lppsT;
if ((lppsT = (LPPAINTSTRUCT)GlobalLock(hps)) != NULL)
{
_fmemcpy(lppsT,pps,sizeof(PAINTSTRUCT));
IntersectRect(&lppsT->rcPaint, &pps->rcPaint, &rcWindow);
GlobalUnlock(hps);
SendOwnerMessage(WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LONG)hps);
GlobalFree(hps);
}
}
}
else
{
/* We handle display */
/* Redraw the portion of the paint rectangle that is in the clipbrd rect */
IntersectRect(&rcPaint, &pps->rcPaint, &rcWindow);
rcPaint.left = rcWindow.left; /* Always draw from left edge of window */
if ((rcPaint.bottom > rcPaint.top) && (rcPaint.right > rcPaint.left))
{
DrawFormat(hdc, &rcPaint,
/* rcPaint.left always == rcWindow.left | A-MGATES */
/* (INT)(cxScrollNow + rcPaint.left - rcWindow.left), */
cxScrollNow,
(INT)(cyScrollNow + rcPaint.top - rcWindow.top),
BestFormat);
}
}
}
/*--------------------------------------------------------------------------*/
/* */
/* UpdateCBMenu() - */
/* */
/* This routine is called once during initialisation and everytime
* the contents of the clipboard change. This updates the entries
* in the "Display" popup menu and the "grey" and "checked" status
* based on the data formats available in the clipboard.
*/
void UpdateCBMenu(
HWND hwnd)
{
register UINT fmt;
WORD cFmt;
WORD cCBCount; /* Number of data items in CB */
register WORD wFlags; /* Used to store the status flags for menu items */
INT iIndex;
INT nPopupCount;
BOOL bAutoSelect;
TCHAR szName[40];
/* Find out the number of data items present in clipboard. */
if (!(cCBCount = (WORD)CountClipboardFormats()))
{
/* The Clipboard is empty; So, disable both menu items */
EnableMenuItem(hMainMenu, 2, MF_BYPOSITION | MF_GRAYED);
EnableMenuItem(hMainMenu, CBM_CLEAR, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(hMainMenu, CBM_SAVEAS, MF_BYCOMMAND | MF_GRAYED);
goto ExitPoint;
}
/* Now clipboard contains at least one item...
* Find out the number entries in the popup menu at present.
*/
if (!hDispMenu)
/* Get the handle to the Display popup menu */
hDispMenu = GetSubMenu(GetMenu(hwnd), 2);
nPopupCount = GetMenuItemCount(hDispMenu);
if (nPopupCount > 2)
{
/* Delete all the entries in the popup menu below menu break. */
for (iIndex = 2; iIndex < nPopupCount; iIndex++)
{
/* NOTE: The second parameter must always be 2! (because we use
* MF_BYPOSITION, when 2 is deleted, 3 becomes 2!).
*/
DeleteMenu(hDispMenu, 2, MF_BYPOSITION);
}
}
bAutoSelect = TRUE;
/* EnumClipboard() requires an OpenClipboard(). */
if (!OpenClipboard(hwnd))
goto ExitPoint;
for (fmt=0, cFmt=1; cFmt <= cCBCount; cFmt++)
{
wFlags = 0;
fmt = EnumClipboardFormats(fmt);
GetClipboardName(fmt, (LPTSTR)szName, sizeof(szName));
switch (fmt)
{
case CF_TEXT: /* can display all of these */
case CF_BITMAP:
case CF_METAFILEPICT:
case CF_OEMTEXT:
case CF_DIB:
case CF_DSPTEXT:
case CF_DSPBITMAP:
case CF_DSPMETAFILEPICT:
case CF_OWNERDISPLAY:
case CF_PALETTE:
case CF_UNICODETEXT:
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
break;
default: /* all the rest... no */
wFlags |= MF_GRAYED;
break;
}
/* We have the name of the format in szName. */
wFlags |= MF_STRING;
/* Check if the current format is the one selected by the user */
if (CurSelFormat == fmt)
{
bAutoSelect = FALSE;
wFlags |= MF_CHECKED;
}
AppendMenu(hDispMenu, wFlags, fmt, (LPTSTR)szName);
}
CloseClipboard();
if (bAutoSelect)
{
CurSelFormat = CBM_AUTO;
CheckMenuItem(hDispMenu, CBM_AUTO, MF_BYCOMMAND | MF_CHECKED);
}
/* Enable the menu items in the top level menu. */
EnableMenuItem(hMainMenu, 2, MF_BYPOSITION | MF_ENABLED);
EnableMenuItem(hMainMenu, CBM_CLEAR, MF_BYCOMMAND | MF_ENABLED);
EnableMenuItem(hMainMenu, CBM_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
ExitPoint:
DrawMenuBar(hwnd);
}
/*--------------------------------------------------------------------------*/
/* */
/* SaveOwnerScrollInfo() - */
/* */
/* When the user switched the clipboard display from owner disp to
* a non-owner display, all the information about the scroll bar
* positions are to be saved. This routine does that.
* This is required because, when the user returns back to owner
* display, the scroll bar positions are to be restored.
*/
void SaveOwnerScrollInfo(
register HWND hwnd)
{
GetScrollRange(hwnd, SB_VERT, (LPINT) & OwnVerMin, (LPINT) & OwnVerMax);
GetScrollRange(hwnd, SB_HORZ, (LPINT) & OwnHorMin, (LPINT) & OwnHorMax);
OwnVerPos = GetScrollPos(hwnd, SB_VERT);
OwnHorPos = GetScrollPos(hwnd, SB_HORZ);
}
/*--------------------------------------------------------------------------*/
/* */
/* RestoreOwnerScrollInfo() - */
/* */
/*--------------------------------------------------------------------------*/
/* When the user sitches back to owner-display, the scroll bar
* positions are restored by this routine.
*/
void RestoreOwnerScrollInfo(
register HWND hwnd)
{
SetScrollRange(hwnd, SB_VERT, OwnVerMin, OwnVerMax, FALSE);
SetScrollRange(hwnd, SB_HORZ, OwnHorMin, OwnHorMax, FALSE);
SetScrollPos(hwnd, SB_VERT, OwnVerPos, TRUE);
SetScrollPos(hwnd, SB_HORZ, OwnHorPos, TRUE);
}