windows-nt/Source/XPSP1/NT/base/mvdm/wow16/write/picture.c

799 lines
24 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/************************************************************/
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
/************************************************************/
/* picture.c -- MW format and display routines for pictures */
//#define NOGDICAPMASKS
#define NOWINMESSAGES
#define NOVIRTUALKEYCODES
#define NOWINSTYLES
#define NOCLIPBOARD
#define NOCTLMGR
#define NOSYSMETRICS
#define NOMENUS
#define NOICON
#define NOKEYSTATE
//#define NOATOM
#define NOCREATESTRUCT
#define NODRAWTEXT
#define NOFONT
#define NOMB
#define NOMENUS
#define NOOPENFILE
#define NOREGION
#define NOSCROLL
#define NOSOUND
#define NOWH
#define NOWINOFFSETS
#define NOWNDCLASS
#define NOCOMM
#include <windows.h>
#include "mw.h"
#define NOKCCODES
#include "ch.h"
#include "docdefs.h"
#include "fmtdefs.h"
#include "dispdefs.h"
#include "cmddefs.h"
#include "propdefs.h"
#include "stcdefs.h"
#include "wwdefs.h"
#include "filedefs.h"
#include "editdefs.h"
/* #include "str.h" */
#include "prmdefs.h"
/* #include "fkpdefs.h" */
/* #include "macro.h" */
#include "winddefs.h"
#if defined(OLE)
#include "obj.h"
#endif
extern typeCP cpMacCur;
extern int docCur;
extern int vfSelHidden;
extern struct WWD rgwwd[];
extern int wwCur;
extern int wwMac;
extern struct FLI vfli;
extern struct SEL selCur;
extern struct WWD *pwwdCur;
extern struct PAP vpapCache;
extern typeCP vcpFirstParaCache;
extern typeCP vcpLimParaCache;
extern int vfPictSel;
extern struct PAP vpapAbs;
extern struct SEP vsepAbs;
extern struct SEP vsepPage;
extern struct DOD (**hpdocdod)[];
extern unsigned cwHeapFree;
extern int vfInsertOn;
extern int vfPMS;
extern int dxpLogInch;
extern int dypLogInch;
extern int dxaPrPage;
extern int dyaPrPage;
extern int dxpPrPage;
extern int dypPrPage;
extern HBRUSH hbrBkgrnd;
extern long ropErase;
extern int vdocBitmapCache;
extern typeCP vcpBitmapCache;
extern HBITMAP vhbmBitmapCache;
extern BOOL vfBMBitmapCache;
extern HCURSOR vhcIBeam;
extern BOOL vfMonochrome;
/* Used in this module only */
#ifdef DEBUG
#define STATIC static
#else
#define STATIC
#endif
STATIC RECT rcPictInvalid; /* Rectangle (in window coords) that needs refresh */
int vfWholePictInvalid = TRUE;
FreeBitmapCache()
{
vdocBitmapCache = docNil;
if (vhbmBitmapCache != NULL)
{
DeleteObject( vhbmBitmapCache );
vhbmBitmapCache = NULL;
}
}
MarkInvalidDlPict( ww, dlPict )
int ww;
int dlPict;
{ /* Mark the passed dl (presumed to be part of a picture) as requiring
eventual update, when DisplayGraphics is called */
register struct WWD *pwwd = &rgwwd [ww];
struct EDL (**hdndl)[] = pwwd->hdndl;
struct EDL *pedl = &(**hdndl)[ dlPict ];
RECT rcDl;
SetRect( (LPRECT) &rcDl, 0, pedl->yp - pedl->dyp,
pwwd->xpMac, pedl->yp );
if (vfWholePictInvalid)
{
CopyRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcDl );
vfWholePictInvalid = FALSE;
}
else
{
RECT rcT;
rcT = rcPictInvalid; /* Necessary? i.e. can UnionRect handle
source == destination */
UnionRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcT, (LPRECT) &rcDl );
}
}
DisplayGraphics( ww, dl, fDontDisplay )
int ww;
int dl;
int fDontDisplay;
{ /* Display a line of graphics info */
struct WWD *pwwd = &rgwwd[ww];
struct EDL *pedl;
typeCP cpPictStart;
typeCP cp;
typeCP cpMac = (**hpdocdod)[vfli.doc].cpMac;
struct PICINFOX picInfo;
RECT rcEnclose;
RECT rcPict;
HANDLE hBits=NULL;
HDC hMDC=NULL;
HDC hMDCCache=NULL;
HANDLE hbm=NULL;
HDC hDC=pwwd->hDC;
int cchRun;
unsigned long cbPict=0;
int dxpOrig; /* Size of picture in the original */
int dypOrig;
int dxpDisplay; /* Size of picture as we want to show it */
int dypDisplay;
int fBitmap;
int ilevel=0;
/* THIS ROUTINE COULD USE SOME GDI-CALL ERROR CHECKING! ..pault */
int fDrew=false;
/* In the case of monochrome devices, this raster op will map white in
the bitmap to the background color and black to the foreground color. */
#define ropMonoBm 0x00990066
Assert( dl >= 0 && dl < pwwd->dlMax );
MarkInvalidDlPict( ww, dl );
if (fDontDisplay)
{
return;
}
Diag(CommSz("DisplayGraphics: \n\r"));
FreezeHp();
pedl = &(**(pwwd->hdndl))[dl];
cpPictStart=pedl->cpMin;
GetPicInfo( cpPictStart, cpMac, vfli.doc, &picInfo );
/* Compute desired display size of picture (in device pixels) */
ComputePictRect( &rcPict, &picInfo, pedl, ww );
dxpDisplay = rcPict.right - rcPict.left;
dypDisplay = rcPict.bottom - rcPict.top;
/* Compute original size of picture (in device pixels) */
/* MM_ANISOTROPIC and MM_ISOTROPIC pictures have no original size */
switch ( picInfo.mfp.mm ) {
case MM_ISOTROPIC:
case MM_ANISOTROPIC:
break;
case MM_BITMAP:
dxpOrig = picInfo.bm.bmWidth;
dypOrig = picInfo.bm.bmHeight;
break;
#if defined(OLE)
case MM_OLE:
{
extern BOOL vfObjDisplaying;
if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
goto DontDraw;
/* just to be safe */
if (!CheckPointer(lpOBJ_QUERY_INFO(&picInfo),1))
goto DontDraw;
if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL)
{
typeCP cpRet;
/* this can require memory, so unlock heap */
MeltHp();
vfObjDisplaying = TRUE;
cpRet = ObjLoadObjectInDoc(&picInfo,vfli.doc,cpPictStart);
vfObjDisplaying = FALSE;
FreezeHp();
pedl = &(**(pwwd->hdndl))[dl];
if (cpRet == cp0)
goto DontDraw;
}
}
break;
#endif
default:
dxpOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.xExt,
GetDeviceCaps( hDC, HORZRES ),
GetDeviceCaps( hDC, HORZSIZE ) );
dypOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.yExt,
GetDeviceCaps( hDC, VERTRES ),
GetDeviceCaps( hDC, VERTSIZE ) );
if (! (dxpOrig && dypOrig) )
{
goto DontDraw;
}
break;
}
/* Save DC as a guard against DC attribute alteration by a metafile */
#ifdef WINDOWS_BUG_FIXED /* Currently 0 is a valid level for Own DC's */
if ((ilevel=SaveDC( hDC )) == 0)
goto DontDraw;
#endif
ilevel = SaveDC( hDC );
SetStretchBltMode( hDC, BLACKONWHITE );
/* Clip out top bar, selection bar */
IntersectClipRect( hDC, ((wwCur == wwClipboard) ? 0 : xpSelBar),
pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
if (!vfWholePictInvalid)
/* Repainting less than the whole picture; clip out
what we're not drawing */
IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top,
rcPictInvalid.right, rcPictInvalid.bottom );
/* Build rcEnclose, a rect enclosing the picture that
includes the "space before" and "space after" fields */
rcEnclose.left = xpSelBar;
if ((rcEnclose.top = rcPict.top -
DypFromDya( vpapAbs.dyaBefore, FALSE )) < pwwd->ypMin)
rcEnclose.top = pwwd->ypMin;
rcEnclose.right = pwwd->xpMac;
if ((rcEnclose.bottom = rcPict.bottom +
DypFromDya( vpapAbs.dyaAfter, FALSE )) > pwwd->ypMac)
rcEnclose.bottom = pwwd->ypMac;
/* White out enclosing rect */
PatBlt( hDC, rcEnclose.left, rcEnclose.top,
rcEnclose.right - rcEnclose.left,
rcEnclose.bottom - rcEnclose.top, ropErase );
/* If we have it cached, do display the easy way */
if (pwwd->doc == vdocBitmapCache && cpPictStart == vcpBitmapCache)
{
Assert( pwwd->doc != docNil && vhbmBitmapCache != NULL);
if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) &&
SelectObject( hMDC, vhbmBitmapCache ))
{
Diag(CommSz("DisplayGraphics: BitBlt\n\r"));
BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay, dypDisplay,
hMDC, 0, 0, vfMonochrome && vfBMBitmapCache ?
ropMonoBm : SRCCOPY );
fDrew = TRUE;
goto DontDraw;
}
else
{ /* Using the cache failed -- empty it
(SelectObject will fail if bitmap was discarded) */
FreeBitmapCache();
}
}
StartLongOp(); /* Put up an hourglass */
/* Build up all bytes associated with the picture (except the header)
into the global Windows handle hBits */
if ( picInfo.mfp.mm != MM_OLE)
{
if ((hBits=GlobalAlloc( GMEM_MOVEABLE, (long)picInfo.cbSize )) == NULL)
{ /* Not enough global heap space to load bitmap/metafile */
goto DontDraw;
}
#ifdef DCLIP
{
char rgch[200];
wsprintf(rgch,"DisplayGraphics: picinfo.cbSize %lu \n\r", picInfo.cbSize);
CommSz(rgch);
}
#endif
for ( cbPict = 0, cp = cpPictStart + picInfo.cbHeader;
cbPict < picInfo.cbSize;
cbPict += cchRun, cp += (typeCP) cchRun )
{
CHAR rgch[ 256 ];
#if WINVER >= 0x300
HPCH lpch;
#else
LPCH lpch;
#endif
#define ulmin(a,b) ((unsigned long)(a) < (unsigned long)(b) ? \
(unsigned long)(a) : (unsigned long)(b))
FetchRgch( &cchRun, rgch, vfli.doc, cp, cpMac,
(int) ulmin( picInfo.cbSize - cbPict, 256 ) );
if ((lpch=GlobalLock( hBits )) != NULL)
{
#ifdef DCLIP
{
char rgch[200];
wsprintf(rgch," copying %d bytes from %lX to %lX \n\r",cchRun,(LPSTR)rgch,lpch+cbPict);
CommSz(rgch);
}
{
char rgchT[200];
int i;
for (i = 0; i< min(20,cchRun); i++,i++)
{
wsprintf(rgchT,"%X ",* (int *) &(rgch[i]));
CommSz(rgchT);
}
CommSz("\n\r");
}
#endif
#if WINVER >= 0x300
bltbh( (LPSTR)rgch, lpch+cbPict, cchRun );
#else
bltbx( (LPSTR)rgch, lpch+cbPict, cchRun );
#endif
GlobalUnlock( hBits );
}
else
{
goto DontDraw;
}
}
}
/* Display the picture */
MeltHp();
#if defined(OLE)
/* CASE 0: OLE */
if (picInfo.mfp.mm == MM_OLE)
{
Diag(CommSz("Case 0:\n\r"));
if (ObjDisplayObjectInDoc(&picInfo, vfli.doc, cpPictStart,
hDC, &rcPict) == FALSE)
goto DontDraw;
fDrew = true;
}
else
#endif
/* CASE 1: Bitmap */
if (fBitmap = (picInfo.mfp.mm == MM_BITMAP))
{
Diag(CommSz("Case 1: \n\r"));
if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) &&
((picInfo.bm.bmBits = GlobalLock( hBits )) != NULL) &&
((hbm=CreateBitmapIndirect((LPBITMAP)&picInfo.bm))!=NULL))
{
picInfo.bm.bmBits = NULL;
GlobalUnlock( hBits );
GlobalFree( hBits ); /* Free handle to bits to allow max room */
hBits = NULL;
SelectObject( hMDC, hbm );
goto CacheIt;
}
}
/* Case 2: non-scalable metafile pictures which we are, for
user interface consistency, scaling by force using StretchBlt */
else if ( ((dxpDisplay != dxpOrig) || (dypDisplay != dypOrig)) &&
(picInfo.mfp.mm != MM_ISOTROPIC) &&
(picInfo.mfp.mm != MM_ANISOTROPIC) )
{
Diag(CommSz("Case 2: \n\r"));
if (((hMDC=CreateCompatibleDC( hDC)) != NULL) &&
((hbm=CreateCompatibleBitmap( hDC, dxpOrig, dypOrig ))!=NULL) &&
SelectObject( hMDC, hbm ) && SelectObject( hMDC, hbrBkgrnd ))
{
extern int vfOutOfMemory;
PatBlt( hMDC, 0, 0, dxpOrig, dypOrig, ropErase );
SetMapMode( hMDC, picInfo.mfp.mm );
/* To cover StretchBlt calls within the metafile */
SetStretchBltMode( hMDC, BLACKONWHITE );
PlayMetaFile( hMDC, hBits );
/* Because we pass pixels to StretchBlt */
SetMapMode( hMDC, MM_TEXT );
CacheIt: Assert( hbm != NULL && hMDC != NULL );
if (vfOutOfMemory)
goto NoCache;
#ifndef NOCACHE
FreeBitmapCache();
/* Among other things, this code caches the current picture.
Notice that there are two assumptions: (1) all bitmaps are
monochrome, and (2) a newly created memory DC has a monochrome
bitmap selected in. */
if ( ((hMDCCache = CreateCompatibleDC( hDC )) != NULL) &&
((vhbmBitmapCache = CreateDiscardableBitmap(
fBitmap ? hMDCCache : hDC, dxpDisplay, dypDisplay )) !=
NULL) &&
SelectObject( hMDCCache, vhbmBitmapCache ))
{
if (!StretchBlt( hMDCCache, 0, 0, dxpDisplay,
dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, SRCCOPY ))
{ /* may get here if memory is low */
DeleteDC( hMDCCache );
hMDCCache = NULL;
DeleteObject( vhbmBitmapCache );
vhbmBitmapCache = NULL;
goto NoCache;
}
#ifdef DCLIP
if (vfMonochrome && fBitmap)
CommSzNum("BitBlt using ropMonoBm == ",ropMonoBm);
#endif
BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay,
dypDisplay, hMDCCache, 0, 0, vfMonochrome && fBitmap ?
ropMonoBm : SRCCOPY );
/* Cached bitmap OK, make cache valid */
vdocBitmapCache = pwwd->doc;
vcpBitmapCache = cpPictStart;
vfBMBitmapCache = fBitmap;
}
else
#endif /* ndef NOCACHE */
{
NoCache:
StretchBlt( hDC, rcPict.left, rcPict.top,
dxpDisplay, dypDisplay,
hMDC, 0, 0, dxpOrig, dypOrig, vfMonochrome &&
fBitmap ? ropMonoBm : SRCCOPY );
}
fDrew = TRUE;
}
}
/* Case 3: A metafile picture which can be directly scaled
or does not need to be because its size has not changed */
else
{
fDrew = true;
Diag(CommSz("Case 3:\n\r"));
SetMapMode( hDC, picInfo.mfp.mm );
SetViewportOrg( hDC, rcPict.left, rcPict.top );
switch( picInfo.mfp.mm ) {
case MM_ISOTROPIC:
if (picInfo.mfp.xExt && picInfo.mfp.yExt)
/* So we get the correct shape rectangle when
SetViewportExt gets called */
SetWindowExt( hDC, picInfo.mfp.xExt, picInfo.mfp.yExt );
/* FALL THROUGH */
case MM_ANISOTROPIC:
/** (9.17.91) v-dougk
Set the window extent in case the metafile is bad
and doesn't call it itself. This will prevent
possible gpfaults in GDI
**/
SetWindowExt( hDC, dxpDisplay, dypDisplay );
SetViewportExt( hDC, dxpDisplay, dypDisplay );
break;
}
PlayMetaFile( hDC, hBits );
}
DontDraw:
/* Clean up */
if ( *(pLocalHeap+1) )
MeltHp();
if (ilevel > 0)
RestoreDC( hDC, ilevel );
if (hMDCCache != NULL)
DeleteDC( hMDCCache );
if (hMDC != NULL)
DeleteDC( hMDC );
if (hbm != NULL)
DeleteObject( hbm );
if (hBits != NULL)
{
if (fBitmap && picInfo.bm.bmBits != NULL)
GlobalUnlock( hBits );
GlobalFree( hBits );
}
if (!fDrew)
{
void DrawBlank(HDC hDC, RECT FAR *rc);
DrawBlank(hDC,&rcPict);
}
/* Invert the selection */
if (ww == wwDocument && !vfSelHidden && !vfPMS)
{
extern int vypCursLine;
ilevel = SaveDC( hDC ); /* Because of clip calls below */
if (!vfWholePictInvalid)
/* Repainting less than the whole picture; clip out
what we're not drawing */
IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top,
rcPictInvalid.right, rcPictInvalid.bottom );
/* Clip out top bar, selection bar */
IntersectClipRect( hDC, xpSelBar,
pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
if (selCur.cpLim > cpPictStart && selCur.cpFirst <= cpPictStart)
{ /* Take into account 'space before' field */
rcEnclose.left = rcPict.left;
rcEnclose.right = rcPict.right;
InvertRect( hDC, (LPRECT) &rcEnclose );
}
else if ((selCur.cpLim == selCur.cpFirst) &&
(selCur.cpFirst == cpPictStart) &&
(vfWholePictInvalid || rcPictInvalid.top < vypCursLine))
{ /* We erased the insert point */
vfInsertOn = fFalse;
}
RestoreDC( hDC, ilevel );
}
vfWholePictInvalid = TRUE; /* Next picture, start invalidation anew */
{
extern int vfPMS;
extern HCURSOR vhcPMS;
EndLongOp( vfPMS ? vhcPMS : vhcIBeam );
}
}
#ifdef ENABLE /* Don't use this anymore */
int
FPointInPict(pt)
POINT pt;
{ /* Return true if point is within the picture frame */
struct EDL *pedl;
struct PICINFOX picInfo;
RECT rcPict;
GetPicInfo(selCur.cpFirst, cpMacCur, docCur, &picInfo);
if (!FGetPictPedl(&pedl))
return false;
ComputePictRect( &rcPict, &picInfo, pedl, wwCur );
return PtInRect( (LPRECT)&rcPict, pt );
}
#endif /* ENABLE */
/* C O M P U T E P I C T R E C T */
ComputePictRect( prc, ppicInfo, pedl, ww )
RECT *prc;
register struct PICINFOX *ppicInfo;
struct EDL *pedl;
int ww;
{ /* Compute rect containing picture indicated by passed ppicInfo,
pedl, in the indicated ww. Return the computed rect through
prc. picInfo structure is not altered. */
int dypTop, xaLeft;
struct WWD *pwwd = &rgwwd[ww];
int xaStart;
int dxaText, dxa;
int dxpSize, dypSize;
int dxaSize, dyaSize;
CacheSectPic(pwwd->doc, pedl->cpMin);
if (ppicInfo->mfp.mm == MM_BITMAP && ((ppicInfo->dxaSize == 0) ||
(ppicInfo->dyaSize == 0)))
{
GetBitmapSize( &dxpSize, &dypSize, ppicInfo, FALSE );
dxaSize = DxaFromDxp( dxpSize, FALSE );
dyaSize = DyaFromDyp( dypSize, FALSE );
}
#if defined(OLE)
else if (ppicInfo->mfp.mm == MM_OLE)
{
dxpSize = DxpFromDxa(ppicInfo->dxaSize, FALSE );
dypSize = DypFromDya(ppicInfo->dyaSize, FALSE );
dxpSize = MultDiv( dxpSize, ppicInfo->mx, mxMultByOne );
dypSize = MultDiv( dypSize, ppicInfo->my, myMultByOne );
dxaSize = DxaFromDxp( dxpSize, FALSE );
dyaSize = DyaFromDyp( dypSize, FALSE );
}
#endif
else
{
dxpSize = DxpFromDxa( dxaSize = ppicInfo->dxaSize, FALSE );
dypSize = DypFromDya( dyaSize = ppicInfo->dyaSize, FALSE );
}
dypTop = pedl->dcpMac != 0 ?
/* Last line of picture */
DypFromDya( dyaSize + vpapAbs.dyaAfter, FALSE ) :
(pedl->ichCpMin + 1) * dypPicSizeMin;
dypTop = pedl->yp - dypTop;
xaStart = DxaFromDxp( xpSelBar - (int) pwwd->xpMin, FALSE );
dxaText = vsepAbs.dxaText;
switch (vpapAbs.jc)
{
case jcBoth:
case jcLeft:
dxa = ppicInfo->dxaOffset;
break;
case jcCenter:
dxa = (dxaText - (int)vpapAbs.dxaRight + (int)vpapAbs.dxaLeft -
dxaSize) / 2;
break;
case jcRight:
dxa = dxaText - (int)vpapAbs.dxaRight - dxaSize;
break;
}
xaLeft = xaStart + max( (int)vpapAbs.dxaLeft, dxa );
prc->right = (prc->left = DxpFromDxa( xaLeft, FALSE )) + dxpSize;
prc->bottom = (prc->top = dypTop) + dypSize;
}
FGetPictPedl(ppedl)
struct EDL **ppedl;
{
int dlLim = pwwdCur->dlMac;
int dl;
typeCP cpFirst = selCur.cpFirst;
struct EDL *pedl;
//Assert(vfPictSel);
if (!vfPictSel)
return FALSE;
pedl = &(**(pwwdCur->hdndl)[0]);
for (dl = 0; dl < dlLim; ++dl, ++pedl)
{
//if (!pedl->fValid)
//return false;
if (pedl->cpMin == cpFirst)
break;
}
if (dl >= dlLim)
return false; /* No part of picture is on screen */
*ppedl = pedl;
return true;
}
/* C P W I N G R A P H I C */
typeCP CpWinGraphic(pwwd)
struct WWD *pwwd;
{
int cdlPict, dl;
struct EDL *dndl = &(**(pwwd->hdndl))[0];
Assert( !pwwd->fDirty ); /* So we can rely on dl info */
CachePara(pwwd->doc, dndl->cpMin);
for (dl = 0; (dl < pwwd->dlMac - 1 && dndl[dl].fIchCpIncr); ++dl)
;
Assert(dndl[dl].fGraphics);
cdlPict = dndl[dl].ichCpMin + 1;
return (dndl[0].cpMin +
(vcpLimParaCache - vcpFirstParaCache) * dndl[0].ichCpMin / cdlPict);
}
CacheSectPic(doc, cp)
int doc;
typeCP cp;
{ /* Cache section and para props, taking into account that footnotes take props
from the reference point */
#ifdef FOOTNOTES
struct DOD *pdod = &(**hpdocdod)[doc];
struct FNTB (**hfntb) = pdod->hfntb;
#endif
CachePara(doc, cp);
#ifdef FOOTNOTES
if ( (hfntb != 0) && (cp >= (**hfntb).rgfnd[0].cpFtn) )
CacheSect( doc, CpRefFromFtn( doc, cp ) )
else
#endif
CacheSect(doc, cp); /* Normal text */
}
void DrawBlank(HDC hDC, RECT FAR *rc)
{ /* To tell us when the draw tried but failed */
int xpMid=rc->left + (rc->right-rc->left)/2;
int ypMid=rc->top + (rc->bottom - rc->top)/2;
int dxpQ=(rc->right-rc->left)/4;
int dypQ=(rc->bottom-rc->top)/4;
HPEN hOldPen;
HBRUSH hOldBrush;
hOldPen = SelectObject( hDC, GetStockObject( BLACK_PEN ) );
hOldBrush = SelectObject( hDC, GetStockObject( WHITE_BRUSH ) );
Rectangle(hDC,rc->left,rc->top,rc->right,rc->bottom);
MoveTo( hDC, rc->left, rc->top );
LineTo( hDC, rc->right, rc->bottom );
MoveTo( hDC, rc->left, rc->bottom );
LineTo( hDC, rc->right, rc->top );
MoveTo( hDC, xpMid, rc->top );
LineTo( hDC, xpMid, rc->bottom );
MoveTo( hDC, rc->left, ypMid );
LineTo( hDC, rc->right, ypMid );
Ellipse( hDC,
xpMid-dxpQ, ypMid-dypQ,
xpMid+dxpQ, ypMid+dypQ );
SelectObject( hDC, hOldPen );
SelectObject( hDC, hOldBrush );
}