2061 lines
61 KiB
C
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);
|
|
}
|