|
|
/****************************** Module Header ******************************\
* Module Name: MfRec16.c * * Copyright (c) 1991-1999 Microsoft Corporation * * DESCRIPTIVE NAME: Metafile Recorder * * FUNCTION: Records GDI functions in memory and disk metafiles. * * PUBLIC ENTRY POINTS: * CloseMetaFile * CopyMetaFile * CreateMetaFile * GetMetaFileBitsEx * SetMetaFileBitsEx * PRIVATE ENTRY POINTS: * RecordParms * AttemptWrite * MarkMetaFile * RecordObject * ProbeSize * AddObjectToDCTable * * History: * 02-Jul-1991 -by- John Colleran [johnc] * Combined From Win 3.1 and WLO 1.0 sources \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "mf16.h"
UINT AddObjectToDCTable(HDC hdc, HANDLE hObject, PUINT piPosition, BOOL bRealAdd); BOOL AddDCToObjectMetaList16(HDC hMeta16DC, HANDLE hObject); BOOL AttemptWrite(PMFRECORDER16 pMFRec, DWORD dwBytes, LPBYTE lpData); VOID MarkMetaFile(PMFRECORDER16 pMFRec); BOOL MakeLogPalette(HDC hdc, HANDLE hPal, WORD magic); HANDLE ProbeSize(PMFRECORDER16 pMF, DWORD dwLength); BOOL RecordCommonBitBlt(HDC hdcDest, INT x, INT y, INT nWidth, INT nHeight, HDC hdcSrc, INT xSrc, INT ySrc, INT nSrcWidth, INT nSrcHeight, DWORD rop, WORD wFunc); BOOL UnlistObjects(HDC hMetaDC); BOOL MF16_DeleteRgn(HDC hdc, HANDLE hrgn);
// Metafile Logging stubs for 3.x Metafiles
/******************************Public*Routine******************************\
* XXX_RecordParms * * These routines package up the parameters of an NT GDI call and send * them to a general purpose recording routine that validates the metafile * DC and records the parameters. * * Returns * TRUE iff successful * * Warnings * Windows 3.x metafile behavior is that when a function is being metafiled * the routine itself is not called; eg SetPixel does not call GreSetPixel * but (GDI) SetPixel intercepts the calls and records the parameters and * returns without taking further action * * History: * 24-Nov-1991 -by- John Colleran [johnc] * Wrote it. \**************************************************************************/
BOOL MF16_RecordParms1(HDC hdc, WORD Func) { return RecordParms(hdc, Func, 0, (LPWORD)NULL); }
BOOL MF16_RecordParms2(HDC hdc, INT parm2, WORD Func) { return RecordParms(hdc, Func, 1, (LPWORD)&parm2); }
BOOL MF16_RecordParms3(HDC hdc, INT parm2, INT parm3, WORD Func) { WORD aw[2];
aw[0] = (WORD)parm3; aw[1] = (WORD)parm2; return RecordParms(hdc, Func, 2, aw); }
BOOL MF16_RecordParms5(HDC hdc, INT parm2, INT parm3, INT parm4, INT parm5, WORD Func) { WORD aw[4];
aw[0] = (WORD)parm5; aw[1] = (WORD)parm4; aw[2] = (WORD)parm3; aw[3] = (WORD)parm2; return RecordParms(hdc, Func, 4, aw); }
BOOL MF16_RecordParms7(HDC hdc, INT parm2, INT parm3, INT parm4, INT parm5, INT parm6, INT parm7, WORD Func) { WORD aw[6];
aw[0] = (WORD)parm7; aw[1] = (WORD)parm6; aw[2] = (WORD)parm5; aw[3] = (WORD)parm4; aw[4] = (WORD)parm3; aw[5] = (WORD)parm2; return RecordParms(hdc, Func, 6, aw); }
BOOL MF16_RecordParms9(HDC hdc, INT parm2, INT parm3, INT parm4, INT parm5, INT parm6, INT parm7, INT parm8, INT parm9, WORD Func) { WORD aw[8];
aw[0] = (WORD)parm9; aw[1] = (WORD)parm8; aw[2] = (WORD)parm7; aw[3] = (WORD)parm6; aw[4] = (WORD)parm5; aw[5] = (WORD)parm4; aw[6] = (WORD)parm3; aw[7] = (WORD)parm2; return RecordParms(hdc, Func, 8, aw); }
BOOL MF16_RecordParmsD(HDC hdc, DWORD d1, WORD Func) { return RecordParms(hdc, Func, 2, (LPWORD) &d1); }
BOOL MF16_RecordParmsWWD(HDC hdc, WORD w1, WORD w2, DWORD d3, WORD Func) { WORD aw[4];
aw[0] = LOWORD(d3); aw[1] = HIWORD(d3); aw[2] = w2; aw[3] = w1; return RecordParms(hdc, Func, 4, aw); }
BOOL MF16_RecordParmsWWDW(HDC hdc, WORD w1, WORD w2, DWORD d3, WORD w4, WORD Func) { WORD aw[5];
aw[0] = w4; aw[1] = LOWORD(d3); aw[2] = HIWORD(d3); aw[3] = w2; aw[4] = w1; return RecordParms(hdc, Func, 5, aw); }
BOOL MF16_RecordParmsWWWWD(HDC hdc, WORD w1, WORD w2, WORD w3, WORD w4, DWORD d5, WORD Func) { WORD aw[6];
aw[0] = LOWORD(d5); aw[1] = HIWORD(d5); aw[2] = w4; aw[3] = w3; aw[4] = w2; aw[5] = w1; return RecordParms(hdc, Func, 6, aw); }
BOOL MF16_RecordParmsPoly(HDC hdc, LPPOINT lpPoint, INT nCount, WORD Func) { BOOL fRet; LPWORD lpW,lpT; DWORD cw; INT ii;
cw = (nCount*sizeof(POINTS)/sizeof(WORD))+1; lpT = lpW = (LPWORD)LocalAlloc(LMEM_FIXED, cw*sizeof(WORD)); if (!lpW) return(FALSE);
*lpW++ = (WORD)nCount;
for(ii=0; ii<nCount; ii++) { *lpW++ = (WORD)lpPoint[ii].x; *lpW++ = (WORD)lpPoint[ii].y; }
fRet = RecordParms(hdc, Func, cw, lpT);
if (LocalFree((HANDLE)lpT)) ASSERTGDI(FALSE, "MF16_RecordParmsPoly: LocalFree Failed\n");
return (fRet); }
// SetDIBitsToDevice
// StretchDIBits
BOOL MF16_RecordDIBits ( HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst, int xDib, int yDib, int cxDib, int cyDib, DWORD iStartScan, DWORD cScans, DWORD cbBitsDib, CONST VOID * pBitsDib, DWORD cbBitsInfoDib, CONST BITMAPINFO *pBitsInfoDib, DWORD iUsageDib, DWORD rop, DWORD mrType ) { BOOL fRet; LPWORD lpW; LPWORD lpWStart; WORD cwParms; PBMIH lpDIBInfoHeader;
PUTS("MF16_RecrodDIBits\n");
ASSERTGDI(mrType == META_SETDIBTODEV || mrType == META_STRETCHDIB, "MF16_RecrodDIBits: Bad mrType");
// Get the number of parameters to save.
cwParms = (WORD) ((mrType == META_SETDIBTODEV) ? 9 : 11); // in words
// Allocate space for DIB plus parameters.
lpWStart = lpW = (LPWORD) LocalAlloc(LMEM_FIXED, cbBitsInfoDib + (cbBitsDib + 1) / 2 * 2 + cwParms*sizeof(WORD)); if (!lpW) { ERROR_ASSERT(FALSE, "MF16_RecordDIBits: out of memory\n"); return(FALSE); }
// Copy the parameters.
if (mrType == META_SETDIBTODEV) { *lpW++ = (WORD) iUsageDib; *lpW++ = (WORD) cScans; *lpW++ = (WORD) iStartScan; *lpW++ = (WORD) yDib; *lpW++ = (WORD) xDib; *lpW++ = (WORD) cyDib; *lpW++ = (WORD) cxDib; *lpW++ = (WORD) yDst; *lpW++ = (WORD) xDst; } else { *lpW++ = (WORD) LOWORD(rop); *lpW++ = (WORD) HIWORD(rop); *lpW++ = (WORD) iUsageDib; *lpW++ = (WORD) cyDib; *lpW++ = (WORD) cxDib; *lpW++ = (WORD) yDib; *lpW++ = (WORD) xDib; *lpW++ = (WORD) cyDst; *lpW++ = (WORD) cxDst; *lpW++ = (WORD) yDst; *lpW++ = (WORD) xDst; }
// Save the start of the bitmap info header field.
lpDIBInfoHeader = (LPBITMAPINFOHEADER) lpW;
// cbBitsInfoDib must be word sized
ASSERTGDI(cbBitsInfoDib % 2 == 0, "MF16_RecordDIBits: cbBitsInfoDib is not word aligned");
// Copy dib info if given.
if (cbBitsInfoDib) { if (pBitsInfoDib->bmiHeader.biSize == sizeof(BMCH)) { CopyCoreToInfoHeader ( lpDIBInfoHeader, (LPBITMAPCOREHEADER) pBitsInfoDib );
if (iUsageDib == DIB_RGB_COLORS) { RGBQUAD *prgbq; RGBTRIPLE *prgbt; UINT ui;
prgbq = ((PBMI) lpDIBInfoHeader)->bmiColors; prgbt = ((PBMC) pBitsInfoDib)->bmciColors;
ASSERTGDI(cbBitsInfoDib >= sizeof(BMIH), "MF16_RecordDIBits: Bad cbBitsInfoDib size");
for ( ui = (UINT) (cbBitsInfoDib - sizeof(BMIH)) / sizeof(RGBQUAD); ui; ui-- ) { prgbq->rgbBlue = prgbt->rgbtBlue; prgbq->rgbGreen = prgbt->rgbtGreen; prgbq->rgbRed = prgbt->rgbtRed; prgbq->rgbReserved = 0; prgbq++; prgbt++; } } else { RtlCopyMemory ( (PBYTE) lpDIBInfoHeader + sizeof(BMIH), (PBYTE) pBitsInfoDib + sizeof(BMCH), cbBitsInfoDib - sizeof(BMIH) ); } } else { RtlCopyMemory ( (PBYTE) lpDIBInfoHeader, (PBYTE) pBitsInfoDib, cbBitsInfoDib );
if (pBitsInfoDib->bmiHeader.biBitCount >= 16) { DWORD UNALIGNED *pClrUsed = (DWORD UNALIGNED *)&lpDIBInfoHeader->biClrUsed; *pClrUsed = 0; }
} }
// Copy dib bits.
RtlCopyMemory((PBYTE) lpDIBInfoHeader + cbBitsInfoDib, pBitsDib, cbBitsDib);
// Finally record the parameters into the file.
fRet = RecordParms(hdcDst, mrType, cwParms + (cbBitsInfoDib + cbBitsDib + 1) / sizeof(WORD), lpWStart);
if (lpWStart) if (LocalFree((HANDLE) lpWStart)) ASSERTGDI(FALSE, "MF16_RecordDIBits: LocalFree Failed\n");
return(fRet); }
BOOL MF16_BitBlt(HDC hdcDest, INT x, INT y, INT nWidth, INT nHeight, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop) { WORD aw[9];
// This is how windows works but really it should look at the ROP
if (hdcDest == hdcSrc || hdcSrc == NULL) { aw[0] = (WORD)LOWORD(rop); aw[1] = (WORD)HIWORD(rop); aw[2] = (WORD)ySrc; aw[3] = (WORD)xSrc; aw[4] = (WORD)0; // No DC necessary
aw[5] = (WORD)nHeight; aw[6] = (WORD)nWidth; aw[7] = (WORD)y; aw[8] = (WORD)x;
return(RecordParms(hdcDest, META_DIBBITBLT, 9, aw)); } else return(RecordCommonBitBlt(hdcDest,x,y,nWidth,nHeight,hdcSrc, xSrc,ySrc,nWidth,nHeight,rop,META_DIBBITBLT)); }
BOOL MF16_StretchBlt(HDC hdcDest, INT x, INT y, INT nWidth, INT nHeight, HDC hdcSrc, INT xSrc, INT ySrc, INT nSrcWidth, INT nSrcHeight, DWORD rop) { WORD aw[11];
// This is how windows works but really it should look at the ROP
if (hdcDest == hdcSrc || hdcSrc == NULL) { aw[0] = (WORD)LOWORD(rop); aw[1] = (WORD)HIWORD(rop); aw[2] = (WORD)nSrcHeight; aw[3] = (WORD)nSrcWidth; aw[4] = (WORD)ySrc; aw[5] = (WORD)xSrc; aw[6] = (WORD)0; // No DC necessary
aw[7] = (WORD)nHeight; aw[8] = (WORD)nWidth; aw[9] = (WORD)y; aw[10] = (WORD)x;
return(RecordParms(hdcDest, META_DIBSTRETCHBLT, 11, aw)); } else return(RecordCommonBitBlt(hdcDest,x,y,nWidth,nHeight,hdcSrc, xSrc,ySrc,nSrcWidth,nSrcHeight,rop,META_DIBSTRETCHBLT)); }
BOOL RecordCommonBitBlt(HDC hdcDest, INT x, INT y, INT nWidth, INT nHeight, HDC hdcSrc, INT xSrc, INT ySrc, INT nSrcWidth, INT nSrcHeight, DWORD rop, WORD wFunc) { BOOL fRet = FALSE; HBITMAP hBitmap; LPWORD lpW; LPWORD lpWStart = (LPWORD) NULL; WORD cwParms; BMIH bmih; DWORD cbBitsInfo; DWORD cbBits; PBMIH lpDIBInfoHeader;
// hdcSrc must be a memory DC.
if (GetObjectType((HANDLE)hdcSrc) != OBJ_MEMDC) { ERROR_ASSERT(FALSE, "RecordCommonBitblt hdcSrc must be MEMDC\n"); GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); }
// Retrieve the source bitmap.
hBitmap = SelectObject(hdcSrc, GetStockObject(PRIV_STOCK_BITMAP)); ERROR_ASSERT(hBitmap, "RecordCommonBitblt: SelectObject1 failed\n");
// Get the bitmap info header and sizes.
if (!bMetaGetDIBInfo(hdcSrc, hBitmap, &bmih, &cbBitsInfo, &cbBits, DIB_RGB_COLORS, 0, TRUE)) goto RecordCommonBitBlt_exit;
// Get the number of parameters to save.
cwParms = (WORD) ((wFunc == META_DIBSTRETCHBLT) ? 10 : 8); // in words
// Allocate space for DIB plus parameters.
lpWStart = lpW = (LPWORD) LocalAlloc(LMEM_FIXED, cbBitsInfo + cbBits + cwParms*sizeof(WORD)); if (!lpW) { ERROR_ASSERT(FALSE, "RecordCommonBitblt: out of memory\n"); goto RecordCommonBitBlt_exit; }
// Copy the parameters.
*lpW++ = (WORD)LOWORD(rop); *lpW++ = (WORD)HIWORD(rop);
if (wFunc == META_DIBSTRETCHBLT) { *lpW++ = (WORD)nSrcHeight; *lpW++ = (WORD)nSrcWidth; }
*lpW++ = (WORD)ySrc; *lpW++ = (WORD)xSrc; *lpW++ = (WORD)nHeight; *lpW++ = (WORD)nWidth; *lpW++ = (WORD)y; *lpW++ = (WORD)x;
// Save the start of the bitmap info header field.
lpDIBInfoHeader = (LPBITMAPINFOHEADER) lpW;
// Copy the bitmap info header.
*lpDIBInfoHeader = bmih;
// Get bitmap info and bits.
if (!GetDIBits(hdcSrc, hBitmap, 0, (UINT) bmih.biHeight, (LPBYTE) ((PBYTE) lpW + cbBitsInfo), (LPBITMAPINFO) lpDIBInfoHeader, DIB_RGB_COLORS)) { ERROR_ASSERT(FALSE, "RecordCommonBitBlt: GetDIBits2 failed\n"); goto RecordCommonBitBlt_exit; }
// Finally record the parameters into the file.
fRet = RecordParms(hdcDest, wFunc, cwParms + (cbBitsInfo + cbBits) / sizeof(WORD), lpWStart);
RecordCommonBitBlt_exit:
if (lpWStart) if (LocalFree((HANDLE)lpWStart)) ASSERTGDI(FALSE, "RecordCommonBitBlt: LocalFree Failed\n");
if (!SelectObject(hdcSrc, hBitmap)) ASSERTGDI(FALSE, "RecordCommonBitblt: SelectObject2 failed\n");
return(fRet); }
BOOL MF16_DeleteRgn(HDC hdc, HANDLE hrgn) { UINT pos;
if (AddObjectToDCTable(hdc, hrgn, &pos, FALSE) != 1) ASSERTGDI(FALSE, "MF16_DeleteRgn: AddObjectToDCTable failed");
return(RecordParms(hdc, META_DELETEOBJECT, 1, (LPWORD)&pos)); }
BOOL MF16_DeleteObject(HANDLE hObject) { INT iCurDC; UINT pos; UINT iObjType; PMFRECORDER16 pMFRec; PMETALINK16 pml16;
pml16 = pmetalink16Get(hObject); ASSERTGDI(pml16, "MF16_DeleteObject: Metalink is NULL\n");
iObjType = GetObjectType(hObject); ASSERTGDI(iObjType != OBJ_REGION, "MF16_DeleteObject: region unexpected");
// Delete the object from each metafile DC which references it.
for(iCurDC = pml16->cMetaDC16 - 1; iCurDC >= 0; iCurDC--) { // Send a DeleteObject record to each metafile
HDC hdc16 = pml16->ahMetaDC16[iCurDC];
if (!IS_METADC16_TYPE(hdc16)) { RIP("MF16_DELETEOBJECT: invalid metaDC16\n"); continue; }
// If the object is not selected then delete it, if it is then mark as predeleted
GET_PMFRECORDER16(pMFRec,hdc16);
if (pMFRec->recCurObjects[iObjType - MIN_OBJ_TYPE] != hObject) { if (AddObjectToDCTable(hdc16, hObject, &pos, FALSE) == 1) RecordParms(hdc16, META_DELETEOBJECT, 1, (LPWORD)&pos); else RIP("MF16_DeleteObject Metalink16 and metadc table not in sync\n"); } else { if (pMFRec->metaHeader.mtNoObjects) { UINT ii; POBJECTTABLE pobjt;
pobjt = (POBJECTTABLE) pMFRec->hObjectTable;
for (ii=0; ii < (UINT) pMFRec->metaHeader.mtNoObjects; ii++) { if (pobjt[ii].CurHandle == hObject) { pobjt[ii].fPreDeleted = TRUE; break; } } } } }
// This Object has been freed from all 3.x metafiles so free its MetaList16
// if the metalink field is in use resize METALINK16
if (pml16->metalink) { if (pml16->cMetaDC16 > 1) pml16 = pmetalink16Resize(hObject,1);
if (pml16 == NULL) { ASSERTGDI(FALSE, "MF16_DeleteObject LocalReAlloc failed\n"); return (FALSE); }
pml16->cMetaDC16 = 0; pml16->ahMetaDC16[0] = (HDC) 0; } else { if (!bDeleteMetalink16(hObject)) ASSERTGDI(FALSE, "MF16_DeleteObject LocalFree failed\n"); }
return(TRUE); }
BOOL MF16_RealizePalette(HDC hdc) { HPALETTE hpal; PMFRECORDER16 pMFRec; PMETALINK16 pml16;
ASSERTGDI(IS_METADC16_TYPE(hdc),"MF16_RealizePalette - invalid handle\n");
GET_PMFRECORDER16(pMFRec,hdc);
hpal = pMFRec->recCurObjects[OBJ_PAL - MIN_OBJ_TYPE]; ASSERTGDI(hpal, "MF16_RealizePalette: bad hpal\n");
// emit the palette again only if the palette is dirty.
pml16 = pmetalink16Get(hpal);
ASSERTGDI(IS_STOCKOBJ(hpal) || pml16,"MF16_RealizePalette - pml16 == NULL\n");
if (pml16) { if (PtrToUlong(pml16->pv) != pMFRec->iPalVer) if (!MakeLogPalette(hdc, hpal, META_SETPALENTRIES)) return(FALSE);
// record which version of the palette the metafile is synced to.
pMFRec->iPalVer = PtrToUlong(pml16->pv); }
return(RecordParms(hdc, META_REALIZEPALETTE, 0, (LPWORD)NULL)); }
BOOL MF16_AnimatePalette ( HPALETTE hpal, UINT iStart, UINT cEntries, CONST PALETTEENTRY *pPalEntries ) { INT iCurDC; PMETALINK16 pml16; LPWORD lpW,lpT; DWORD cw; UINT ii; PMFRECORDER16 pMFRec;
if (!(pml16 = pmetalink16Get(hpal))) return(FALSE);
cw = (cEntries * sizeof(PALETTEENTRY) / sizeof(WORD)) + 2; lpT = lpW = (LPWORD) LocalAlloc(LMEM_FIXED, cw * sizeof(WORD));
if (!lpW) return(FALSE);
*lpW++ = (WORD) iStart; *lpW++ = (WORD) cEntries;
for (ii = 0; ii < cEntries; ii++) ((PPALETTEENTRY) lpW)[ii] = pPalEntries[ii];
// Send a AnimatePalette record to each associated metafile that has the
// palette selected.
for (iCurDC = pml16->cMetaDC16 - 1; iCurDC >= 0; iCurDC--) { HDC hdc16 = pml16->ahMetaDC16[iCurDC];
if (!IS_METADC16_TYPE(hdc16)) { ASSERTGDI(FALSE, "MF16_AnimatePalette: invalid metaDC16\n"); continue; }
GET_PMFRECORDER16(pMFRec,hdc16); if (pMFRec->recCurObjects[OBJ_PAL - MIN_OBJ_TYPE] == hpal) if (!RecordParms(pml16->ahMetaDC16[iCurDC], META_ANIMATEPALETTE, cw, lpT)) ASSERTGDI(FALSE, "MF16_AnimatePalette: RecordParms Failed\n"); }
if (LocalFree((HANDLE) lpT)) ASSERTGDI(FALSE, "MF16_AnimatePalette: LocalFree Failed\n");
return(TRUE); }
BOOL MF16_ResizePalette(HPALETTE hpal, UINT nCount) { INT iCurDC; PMETALINK16 pml16; PMFRECORDER16 pMFRec;
if (!(pml16 = pmetalink16Get(hpal))) return(FALSE);
// Send a ResizePalette record to each associated metafile that has the
// palette selected.
for (iCurDC = pml16->cMetaDC16 - 1; iCurDC >= 0; iCurDC--) { HDC hdc16 = pml16->ahMetaDC16[iCurDC];
if (!IS_METADC16_TYPE(hdc16)) { ASSERTGDI(FALSE, "MF16_ResizePalette: invalid metaDC16\n"); continue; }
GET_PMFRECORDER16(pMFRec,hdc16);
if (pMFRec->recCurObjects[OBJ_PAL - MIN_OBJ_TYPE] == hpal) if (!RecordParms(pml16->ahMetaDC16[iCurDC], META_RESIZEPALETTE, 1, (LPWORD) &nCount)) ASSERTGDI(FALSE, "MF16_ResizePalette: RecordParms Failed\n"); } return(TRUE); }
BOOL MF16_DrawRgn(HDC hdc, HRGN hrgn, HBRUSH hBrush, INT cx, INT cy, WORD Func) { WORD aw[4]; BOOL bRet;
// Each region function has at least a region to record
aw[0] = (WORD)RecordObject(hdc, hrgn);
switch(Func) { case META_PAINTREGION: case META_INVERTREGION: bRet = RecordParms(hdc, Func, 1, aw); break;
case META_FILLREGION: aw[1] = (WORD)RecordObject(hdc, hBrush); bRet = RecordParms(hdc, Func, 2, aw); break;
case META_FRAMEREGION: aw[1] = (WORD)RecordObject(hdc, hBrush); aw[2] = (WORD)cy; aw[3] = (WORD)cx; bRet = RecordParms(hdc, Func, 4, aw); break;
default: ASSERTGDI(FALSE, "MF16_DrawRgn: Bad Func\n"); bRet = FALSE; break; }
// Delete the metafile region handle in the metafile after use!
// The reason is that a region can be modified (e.g. SetRectRgn)
// between each use and we have to re-record it each time it is used
// unless we use a dirty flag.
if (!MF16_DeleteRgn(hdc, hrgn)) ASSERTGDI(FALSE, "MF16_DrawRgn: MF16_DeleteRgn failed\n");
return(bRet); }
BOOL MF16_PolyPolygon(HDC hdc, CONST POINT *lpPoint, CONST INT *lpPolyCount, INT nCount) { BOOL fRet; LPWORD lpW,lpT; DWORD cw; INT cPt = 0; INT ii;
for(ii=0; ii<nCount; ii++) cPt += lpPolyCount[ii];
cw = 1+nCount+(cPt*sizeof(POINTS)/sizeof(WORD)); lpT = lpW = (LPWORD)LocalAlloc(LMEM_FIXED, cw*sizeof(WORD)); if (!lpW) return(FALSE);
// first is the count
*lpW++ = (WORD)nCount;
// second is the list of poly counts
for(ii=0; ii<nCount; ii++) *lpW++ = (WORD)lpPolyCount[ii];
// third is the list of points
for(ii=0; ii<cPt; ii++) { *lpW++ = (WORD)lpPoint[ii].x; *lpW++ = (WORD)lpPoint[ii].y; }
fRet = RecordParms(hdc, META_POLYPOLYGON, cw, lpT);
if(LocalFree((HANDLE)lpT)) ASSERTGDI(FALSE, "MF16_PolyPolygon: LocalFree Failed\n");
return (fRet); }
BOOL MF16_SelectClipRgn(HDC hdc, HRGN hrgn, int iMode) { PMFRECORDER16 pMFRec;
if (!IS_METADC16_TYPE(hdc)) { GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); }
PUTS("MF16_SelectClipRgn\n");
GET_PMFRECORDER16(pMFRec,hdc);
if (iMode != RGN_COPY) return(FALSE);
// We will emit SelectObject record for clip region just like Windows.
// However, a null region cannot be recorded in the SelectObject call since
// the handle does not identify the object type. This is a bug in Win 3.1!
//
// BUG 8419 winproj 4 has a bug where it counts on this bug. Chicago
// also has this bug so we will have this bug.
if (hrgn == (HRGN) 0) { #ifdef RECORD_SELECTCLIPRGN_NULL
BOOL fRet;
fRet = MF16_RecordParms2(hdc, 0, META_SELECTCLIPREGION);
// maintain the new selection in the CurObject table
pMFRec->recCurObjects[OBJ_REGION - MIN_OBJ_TYPE] = 0;
return(fRet); #else
return TRUE; #endif
} else return(MF16_SelectObject(hdc, hrgn) ? TRUE : FALSE); }
// SelectObject returns previous object! - new in win3.1
HANDLE MF16_SelectObject(HDC hdc, HANDLE h) { HANDLE hOldObject; WORD position; PMFRECORDER16 pMFRec; UINT iType;
PUTS("MF16_SelectObject\n");
GET_PMFRECORDER16(pMFRec,hdc);
if (!IS_METADC16_TYPE(hdc) || !pMFRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return(0); }
iType = GetObjectType(h);
if ((iType == 0) || !h || (position = (WORD) RecordObject(hdc, h)) == (WORD) -1) return((HANDLE) 0); else { if (!RecordParms(hdc, META_SELECTOBJECT, 1, &position)) return((HANDLE) 0);
// maintain the new selection in the CurObject table
ASSERTGDI(iType <= MAX_OBJ_TYPE && iType >= MIN_OBJ_TYPE, "MF16_SelectObject type > max\n");
hOldObject = pMFRec->recCurObjects[iType - MIN_OBJ_TYPE]; pMFRec->recCurObjects[iType - MIN_OBJ_TYPE] = h;
// return the previously selected object or 1 if it is a region
// (for compatibility) - new in win3.1
if (iType == OBJ_REGION) { // We also delete the region handle here!
// The reason is that a region can be modified (e.g. SetRectRgn)
// between each use and we have to re-record it each time it is used
// unless we use a dirty flag. This is a bug in win3.1
return(MF16_DeleteRgn(hdc, h) ? (HANDLE) 1 : (HANDLE) 0); } else { return(hOldObject); } } }
BOOL MF16_SelectPalette(HDC hdc, HPALETTE hpal) { WORD position; PMFRECORDER16 pMFRec;
GET_PMFRECORDER16(pMFRec,hdc);
if (!IS_METADC16_TYPE(hdc) || !pMFRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return(0); }
if (!hpal || (position = (WORD) RecordObject(hdc, (HANDLE) hpal)) == (WORD) -1) return(FALSE); else { PMETALINK16 pml16;
if (!RecordParms(hdc, META_SELECTPALETTE, 1, &position)) return(FALSE);
// maintain the new selection in the CurObject table
pMFRec->recCurObjects[OBJ_PAL - MIN_OBJ_TYPE] = hpal;
// Also record which version of the palette we are synced with
// so we know whether to emit a new palette when RealizePalette
// is called
pml16 = pmetalink16Get(hpal); ASSERTGDI(IS_STOCKOBJ(hpal) || pml16,"MF16_RealizePalette - pml16 == NULL\n");
if (pml16) pMFRec->iPalVer = PtrToUlong(pml16->pv);
return(TRUE); } }
BOOL MF16_TextOut(HDC hdc, INT x, INT y, LPCSTR lpString, INT nCount, BOOL bUnicode) { BOOL fRet; LPWORD lpw, lpT; DWORD cw;
cw = (nCount + 1)/sizeof(WORD) + 3; // word-aligned character string
lpT = lpw = (LPWORD) LocalAlloc(LMEM_FIXED, cw*sizeof(WORD));
if (!lpw) return(FALSE);
*lpw++ = (WORD)nCount;
// Copy the string
if (!bUnicode) { RtlCopyMemory(lpw, lpString, nCount); } else { (void) bToASCII_N((LPSTR) lpw, nCount, (LPWSTR) lpString, nCount); }
lpw += (nCount+1)/sizeof(WORD); // keep word aligned
*lpw++ = (WORD)y; *lpw++ = (WORD)x;
fRet = RecordParms(hdc, META_TEXTOUT, cw, lpT);
if(LocalFree((HANDLE)lpT)) ASSERTGDI(FALSE, "MF16_TextOut: LocalFree Failed\n"); return (fRet); }
BOOL MF16_PolyTextOut(HDC hdc, CONST POLYTEXTA *ppta, int cpta, BOOL bUnicode) { int i;
for (i = 0; i < cpta; i++) { if (!MF16_ExtTextOut(hdc, ppta[i].x, ppta[i].y, ppta[i].uiFlags, &ppta[i].rcl, (LPCSTR) ppta[i].lpstr, (INT) ppta[i].n, (LPINT) ppta[i].pdx, bUnicode)) return(FALSE); }
return(TRUE); }
BOOL MF16_ExtTextOut(HDC hdc, INT x, INT y, UINT flOptions, CONST RECT *lpRect, LPCSTR lpString, INT nCount, CONST INT *lpDX, BOOL bUnicode) { BOOL fRet; LPWORD lpw, lpT; DWORD cw = 0; INT nUnicodeCount = nCount; char *pjAnsiString = NULL;
if(bUnicode) { // compute the real count of characters in the string
RtlUnicodeToMultiByteSize((PULONG) &nCount, (PWCH) lpString, nCount * sizeof(WCHAR)); }
// Compute buffer space needed
// room for the char string
// room for the 4 words that are the fixed parms
// if there is a dx array, we need room for it
// if the rectangle is being used, we need room for it
// and we need extra byte for eventual word roundoff
//
if (flOptions & ETO_PDY) return FALSE;
cw += (lpDX) ? nCount : 0; // DX array
cw += (flOptions & (ETO_OPAQUE | ETO_CLIPPED)) ? 4 : 0; // sizeof RECTS
cw += 4; // x,y,options and count
cw += (nCount + 1)/sizeof(WORD);
lpT = lpw = (LPWORD) LocalAlloc(LMEM_FIXED, cw*sizeof(WORD)); if (!lpw) return(FALSE);
*lpw++ = (WORD)y; *lpw++ = (WORD)x; *lpw++ = (WORD)nCount; *lpw++ = (WORD)flOptions;
// Copy the rect if present
if (flOptions & (ETO_OPAQUE | ETO_CLIPPED)) { ERROR_ASSERT(lpRect, "MF16_ExtTextOut: expect valid lpRect\n"); *lpw++ = (WORD)lpRect->left; *lpw++ = (WORD)lpRect->top; *lpw++ = (WORD)lpRect->right; *lpw++ = (WORD)lpRect->bottom; }
// Copy the string
if (!bUnicode) { RtlCopyMemory(lpw, lpString, nCount); } else { (void) bToASCII_N((LPSTR) lpw, nCount, (LPWSTR) lpString, nUnicodeCount); pjAnsiString = (char*) lpw; }
lpw += (nCount+1)/sizeof(WORD); // keep word aligned
if (lpDX) { INT ii;
if(nCount != nUnicodeCount) { INT jj;
for(ii=0,jj=0; ii < nCount; ii++,jj++) { *lpw++ = (WORD)lpDX[jj];
if(IsDBCSLeadByte(pjAnsiString[ii])) { *lpw++ = 0; ii++; } } } else { for(ii=0; ii<nCount; ii++) *lpw++ = (WORD)lpDX[ii]; }
}
fRet = RecordParms(hdc, META_EXTTEXTOUT, cw, lpT);
if (LocalFree((HANDLE)lpT)) ASSERTGDI(FALSE, "MF16_ExtTextOut: LocalFree Failed\n");
return (fRet); }
BOOL MF16_Escape(HDC hdc, int nEscape, int nCount, LPCSTR lpInData, LPVOID lpOutData) { BOOL fRet; LPWORD lpW,lpT; DWORD cw;
// If a metafile is retrieved from GetWinMetaFileBits, it may contain
// an embedded enhanced metafile. Do not include the enhanced metafile
// if we are playing the metafile to another metafile.
if (nEscape == MFCOMMENT && nCount > sizeof(META_ESCAPE_ENHANCED_METAFILE) - sizeof(DWORD) - 3 * sizeof(WORD) && ((DWORD UNALIGNED *) lpInData)[0] == MFCOMMENT_IDENTIFIER && ((DWORD UNALIGNED *) lpInData)[1] == MFCOMMENT_ENHANCED_METAFILE) { return(TRUE); }
// Some wow apps (e.g. amipro) use metafiles for printing. As a result,
// we need to record these printing escapes.
cw = 2 + ((nCount + 1) / sizeof(WORD)); lpT = lpW = (LPWORD) LocalAlloc(LMEM_FIXED, cw * sizeof(WORD)); if (!lpW) return(FALSE);
*lpW++ = (WORD) nEscape; // escape number
*lpW++ = (WORD) nCount; // count of input data buffer
RtlCopyMemory(lpW, lpInData, nCount);
fRet = RecordParms(hdc, META_ESCAPE, cw, lpT);
if (LocalFree((HANDLE) lpT)) ASSERTGDI(FALSE, "MF16_Escape: LocalFree Failed\n");
return(fRet); }
/****************************************************************************
* * * RecordParms * * * * Parameters: 1.hMF handle to a metafile header. * * 2.The magic number of the function being recorded. * * 3.The number of parmmeter of the function (size of lpParm * * in words) * * 4.A long pointer to parameters stored in reverse order * * * * Warning call only once per function because max record is updated. * * * ****************************************************************************/
BOOL RecordParms(HDC hdc, DWORD magic, DWORD cw, CONST WORD *lpParm) { PMFRECORDER16 pMFRec; METARECORD MFRecord;
PUTSX("RecordParms %lX\n", (ULONG)magic); ASSERTGDI(HIWORD(magic) == 0, "RecordParms: bad magic\n");
GET_PMFRECORDER16(pMFRec,hdc);
if (!IS_METADC16_TYPE(hdc) || !pMFRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); }
// Make sure the Metafile hasn't died before we continue
if (!(pMFRec->recFlags & METAFILEFAILURE)) { MFRecord.rdSize = SIZEOF_METARECORDHEADER/sizeof(WORD) + cw; MFRecord.rdFunction = (WORD)magic;
// Write the header
if (!AttemptWrite(pMFRec, SIZEOF_METARECORDHEADER, (LPBYTE)&MFRecord)) return(FALSE);
// Write the data
if (!AttemptWrite(pMFRec, cw*sizeof(WORD), (LPBYTE)lpParm)) return(FALSE);
// Update max record size
if (MFRecord.rdSize > pMFRec->metaHeader.mtMaxRecord) pMFRec->metaHeader.mtMaxRecord = MFRecord.rdSize; } return (TRUE); // Win 3.1 returns true even if METAFAILEFAILURE is on!
}
/***************************** Internal Function ***************************\
* AttemptWrite * * Tries to write data to a metafile disk file * * dwBytes is the byte count of lpData. * * Returns TRUE iff the write was sucessful * * \***************************************************************************/
BOOL AttemptWrite(PMFRECORDER16 pMFRec, DWORD dwBytes, LPBYTE lpData) { DWORD cbWritten; BOOL fRet;
PUTS("AttemptWrite\n");
ASSERTGDI(dwBytes % 2 == 0, "AttemptWrite: bad dwBytes\n"); // must be even
ASSERTGDI(!(pMFRec->recFlags & METAFILEFAILURE), "AttemptWrite: Bad recording\n");
// Handle disk file.
if (pMFRec->metaHeader.mtType == DISKMETAFILE) { // Flush the buffer if it's not large enough.
if (dwBytes + pMFRec->ibBuffer > pMFRec->cbBuffer) { fRet = WriteFile(pMFRec->hFile, (LPBYTE)pMFRec->hMem, pMFRec->ibBuffer, &cbWritten, (LPOVERLAPPED)NULL); if (!fRet || (cbWritten != pMFRec->ibBuffer)) { ERROR_ASSERT(FALSE, "AttemptWrite: Write1 failed\n"); goto AttemptWrite_Error; } pMFRec->ibBuffer = 0; // reset buffer info
}
// If the data is still too large, write it out to disk directly.
if (dwBytes + pMFRec->ibBuffer > pMFRec->cbBuffer) { fRet = WriteFile(pMFRec->hFile, lpData, dwBytes, &cbWritten, (LPOVERLAPPED)NULL); if (!fRet || (cbWritten != dwBytes)) { ERROR_ASSERT(FALSE, "AttemptWrite: Write2 failed\n"); goto AttemptWrite_Error; } } else { // Store data in the buffer.
RtlCopyMemory((LPBYTE)pMFRec->hMem + pMFRec->ibBuffer, lpData, dwBytes); pMFRec->ibBuffer += dwBytes; } } else { // Handle memory file.
// Grow the buffer if necessary.
if (dwBytes + pMFRec->ibBuffer > pMFRec->cbBuffer) { DWORD cbNewSize; HANDLE hMem;
cbNewSize = pMFRec->cbBuffer + MF16_BUFSIZE_INC + dwBytes / MF16_BUFSIZE_INC * MF16_BUFSIZE_INC;
hMem = LocalReAlloc(pMFRec->hMem, cbNewSize, LMEM_MOVEABLE); if (hMem == NULL) { ERROR_ASSERT(FALSE, "AttemptWrite: out of memory\n"); goto AttemptWrite_Error; } pMFRec->hMem = hMem; pMFRec->cbBuffer = cbNewSize; }
// Record the data.
RtlCopyMemory((LPBYTE)pMFRec->hMem + pMFRec->ibBuffer, lpData, dwBytes); pMFRec->ibBuffer += dwBytes; }
// Update the header size.
pMFRec->metaHeader.mtSize += dwBytes/sizeof(WORD);
return(TRUE);
AttemptWrite_Error:
MarkMetaFile(pMFRec); return(FALSE); }
/***************************** Internal Function ***************************\
* VOID MarkMetaFile * * Marks a metafile as failed * * Effects: * Frees the metafile resources * \***************************************************************************/
VOID MarkMetaFile(PMFRECORDER16 pMFRec) { // Clean up is done in CloseMetaFile.
PUTS("MarkMetaFile\n");
pMFRec->recFlags |= METAFILEFAILURE; }
/***************************** Internal Function **************************\
* MakeLogPalette * * Records either CreatePalette or SetPaletteEntries * * Returns TRUE iff sucessful * * \***************************************************************************/
BOOL MakeLogPalette(HDC hdc, HANDLE hPal, WORD magic) { WORD cPalEntries; BOOL fStatus = FALSE; DWORD cbPalette; LPLOGPALETTE lpPalette;
PUTS("MakeLogPalette\n");
if (!GetObject(hPal, sizeof(WORD), &cPalEntries)) { ERROR_ASSERT(FALSE, "MakeLogPalette: GetObject Failed\n"); return(fStatus); }
// alloc memory and get the palette entries
if (lpPalette = (LPLOGPALETTE)LocalAlloc(LMEM_FIXED, cbPalette = sizeof(LOGPALETTE)-sizeof(PALETTEENTRY)+sizeof(PALETTEENTRY)*cPalEntries)) { lpPalette->palNumEntries = cPalEntries;
GetPaletteEntries(hPal, 0, cPalEntries, lpPalette->palPalEntry);
if (magic == (META_CREATEPALETTE & 255)) { lpPalette->palVersion = 0x300; magic = META_CREATEPALETTE; } else if (magic == (META_SETPALENTRIES & 255)) { lpPalette->palVersion = 0; /* really "starting index" */ magic = META_SETPALENTRIES; }
fStatus = RecordParms(hdc, magic, (DWORD)cbPalette >> 1, (LPWORD)lpPalette);
if (LocalFree((HANDLE)lpPalette)) ASSERTGDI(FALSE, "MakeLogPalette: LocalFree Failed\n"); }
return(fStatus); }
/***************************** Internal Function ***************************\
* RecordObject * * Records the use of an object by creating the object * * Returns: index of object in table * -1 if error * \***************************************************************************/
WIN3REGION w3rgnEmpty = { 0, // nextInChain
6, // ObjType
0x2F6, // ObjCount
sizeof(WIN3REGION) - sizeof(SCAN) + 2, // cbRegion
0, // cScans
0, // maxScan
{0,0,0,0}, // rcBounding
{0,0,0,{0,0},0} // aScans[]
};
WORD RecordObject(HDC hdc, HANDLE hObject) { UINT status; UINT iPosition; HDC hdcScreen = (HDC) 0; int iType; UINT iUsage;
PUTS("RecordObject\n");
// Validate the object.
iType = LO_TYPE(hObject);
if (iType != LO_PEN_TYPE && iType != LO_BRUSH_TYPE && iType != LO_FONT_TYPE && iType != LO_REGION_TYPE && iType != LO_PALETTE_TYPE ) { GdiSetLastError(ERROR_INVALID_HANDLE); return((WORD) -1); }
// Add the object to the metafiles list.
status = AddObjectToDCTable(hdc, hObject, &iPosition, TRUE);
// An error occurred.
if (status == (UINT) -1) return((WORD) -1);
// Object already exists.
if (status == 1) return((WORD) iPosition);
ASSERTGDI(!status, "RecordObject: Bad return code from AddObjectToDCTable\n");
// Object does not exist, record it.
if (iType != LO_REGION_TYPE) // don't add regions to the metalist!
if (!AddDCToObjectMetaList16(hdc,hObject)) return((WORD) -1);
switch (iType) { case LO_PEN_TYPE: { LOGPEN16 logpen16;
GetObject16AndType(hObject, (LPVOID)&logpen16); status = (UINT) RecordParms(hdc, (WORD)META_CREATEPENINDIRECT, (DWORD)((sizeof(LOGPEN16) + 1) >> 1), (LPWORD)&logpen16); break; }
case LO_FONT_TYPE: { LOGFONT16 logfont16;
GetObject16AndType(hObject, (LPVOID)&logfont16);
/* size of LOGFONT adjusted based on the length of the facename */ status = (UINT) RecordParms(hdc, META_CREATEFONTINDIRECT, (DWORD)((sizeof(LOGFONT16) + 1) >> 1), (LPWORD) &logfont16); break; }
/*
* in win2, METACREATEREGION records contained an entire region object, * including the full header. this header changed in win3. * * to remain compatible, the region records will be saved with the * win2 header. here we save our region with a win2 header. */ case LO_REGION_TYPE: { PWIN3REGION lpw3rgn; DWORD cbNTRgnData; DWORD curRectl; WORD cScans; WORD maxScanEntry; WORD curScanEntry; DWORD cbw3data; PRGNDATA lprgn; LPRECT lprc; PSCAN lpScan;
ASSERTGDI(!status, "RecordObject: bad status\n");
// Get the NT Region Data
cbNTRgnData = GetRegionData(hObject, 0, NULL); if (cbNTRgnData == 0) break;
lprgn = (PRGNDATA) LocalAlloc(LMEM_FIXED, cbNTRgnData); if (!lprgn) break;
cbNTRgnData = GetRegionData(hObject, cbNTRgnData, lprgn); if (cbNTRgnData == 0) { LocalFree((HANDLE) lprgn); break; }
// Handle the empty region.
if (!lprgn->rdh.nCount) { status = (UINT) RecordParms(hdc, META_CREATEREGION, (sizeof(WIN3REGION) - sizeof(SCAN)) >> 1, // Convert to count of words
(LPWORD) &w3rgnEmpty);
LocalFree((HANDLE)lprgn); break; }
lprc = (LPRECT)lprgn->Buffer;
// Create the Windows 3.x equivalent
// worst case is one scan for each rect
cbw3data = 2*sizeof(WIN3REGION) + (WORD)lprgn->rdh.nCount*sizeof(SCAN);
lpw3rgn = (PWIN3REGION)LocalAlloc(LMEM_FIXED, cbw3data); if (!lpw3rgn) { LocalFree((HANDLE) lprgn); break; }
// Grab the bounding rect.
lpw3rgn->rcBounding.left = (SHORT)lprgn->rdh.rcBound.left; lpw3rgn->rcBounding.right = (SHORT)lprgn->rdh.rcBound.right; lpw3rgn->rcBounding.top = (SHORT)lprgn->rdh.rcBound.top; lpw3rgn->rcBounding.bottom = (SHORT)lprgn->rdh.rcBound.bottom;
cbw3data = sizeof(WIN3REGION) - sizeof(SCAN) + 2;
// visit all the rects
curRectl = 0; cScans = 0; maxScanEntry = 0; lpScan = lpw3rgn->aScans;
while(curRectl < lprgn->rdh.nCount) { LPWORD lpXEntry; DWORD cbScan;
curScanEntry = 0; // Current X pair in this scan
lpScan->scnPntTop = (WORD)lprc[curRectl].top; lpScan->scnPntBottom = (WORD)lprc[curRectl].bottom;
lpXEntry = (LPWORD) lpScan->scnPntsX;
// handle rects on this scan
do { lpXEntry[curScanEntry + 0] = (WORD)lprc[curRectl].left; lpXEntry[curScanEntry + 1] = (WORD)lprc[curRectl].right; curScanEntry += 2; curRectl++; } while ((curRectl < lprgn->rdh.nCount) && (lprc[curRectl-1].top == lprc[curRectl].top) && (lprc[curRectl-1].bottom == lprc[curRectl].bottom) );
lpScan->scnPntCnt = curScanEntry; lpXEntry[curScanEntry] = curScanEntry; // Count also follows Xs
cScans++;
if (curScanEntry > maxScanEntry) maxScanEntry = curScanEntry;
// account for each new scan + each X1 X2 Entry but the first
cbScan = sizeof(SCAN)-(sizeof(WORD)*2) + (curScanEntry*sizeof(WORD)); cbw3data += cbScan; lpScan = (PSCAN)(((LPBYTE)lpScan) + cbScan); }
// Initialize the header
lpw3rgn->nextInChain = 0; lpw3rgn->ObjType = 6; // old Windows OBJ_RGN identifier
lpw3rgn->ObjCount= 0x2F6; // any non-zero number
lpw3rgn->cbRegion = (WORD)cbw3data; // don't count type and next
lpw3rgn->cScans = cScans; lpw3rgn->maxScan = maxScanEntry;
status = (UINT) RecordParms(hdc, META_CREATEREGION, (cbw3data-2) >> 1, // Convert to count of words
(LPWORD) lpw3rgn);
if (LocalFree((HANDLE)lprgn)) ASSERTGDI(FALSE, "RecordObject: LocalFree(lprgn) Failed\n"); if (LocalFree((HANDLE)lpw3rgn)) ASSERTGDI(FALSE, "RecordObject: LocalFree(lpw3rgn) Failed\n");
break; }
case LO_BRUSH_TYPE: { LOGBRUSH lb;
if (!GetObjectA(hObject, sizeof(LOGBRUSH), &lb)) break;
switch (lb.lbStyle) { case BS_HATCHED: case BS_HOLLOW: case BS_SOLID: { LOGBRUSH16 lb16;
LOGBRUSH16FROMLOGBRUSH32(&lb16, &lb);
// non-pattern brush
status = (UINT) RecordParms(hdc, META_CREATEBRUSHINDIRECT, (DWORD) ((sizeof(LOGBRUSH16) + 1) >> 1), (LPWORD) &lb16); break; }
case BS_PATTERN: case BS_DIBPATTERN: case BS_DIBPATTERNPT: { HBITMAP hbmRemote; BMIH bmih; DWORD cbBitsInfo; DWORD cbBits; LPWORD lpWStart, lpW; DWORD lbStyle = BS_DIBPATTERN; PBMIH lpDIBInfoHeader;
if (!(hbmRemote = GetObjectBitmapHandle((HBRUSH) hObject, &iUsage))) { ASSERTGDI(FALSE, "RecordObject: GetObjectBitmapHandle failed"); break; }
// For a pattern brush, if it is color, it is recorded as a
// DIB pattern brush with BS_DIBPATTERN style. If it is
// monochrome, it is recorded as a DIB pattern brush with
// BS_PATTERN style. The playback code has a special
// case to deal with monochrome brushes.
if (lb.lbStyle == BS_PATTERN) { iUsage = DIB_RGB_COLORS; if (MonoBitmap(hbmRemote)) lbStyle = BS_PATTERN; }
hdcScreen = CreateCompatibleDC((HDC) 0); // freed below
// Get the bitmap info header and sizes.
if (!bMetaGetDIBInfo(hdcScreen, hbmRemote, &bmih, &cbBitsInfo, &cbBits, iUsage, 0, TRUE)) break;
// Make sure that cbBitsInfo is dword aligned
// If we have converted the bitmap format in bMetaGetDIBInfo,
// modify the iUsage to match the new format.
if (bmih.biBitCount == 24) iUsage = DIB_RGB_COLORS;
// Allocate space for DIB plus parameters.
lpWStart = lpW = (LPWORD) LocalAlloc(LMEM_FIXED, cbBitsInfo + cbBits + 2*sizeof(WORD)); if (!lpW) { ERROR_ASSERT(FALSE, "RecordObject: out of memory\n"); break; }
*lpW++ = (WORD) lbStyle; // BS_PATTERN or BS_DIBPATTERN
*lpW++ = (WORD) iUsage; // usage word
// Save the start of the bitmap info header field.
lpDIBInfoHeader = (LPBITMAPINFOHEADER) lpW;
// Copy the bitmap info header.
*lpDIBInfoHeader = bmih;
// Get bitmap info and bits.
if (GetBrushBits(hdcScreen, hbmRemote, (UINT) iUsage, cbBitsInfo, (LPVOID) ((PBYTE) lpW + cbBitsInfo), (LPBITMAPINFO) lpDIBInfoHeader)) { // Finally record the parameters into the file.
status = (UINT) RecordParms(hdc, META_DIBCREATEPATTERNBRUSH, 2 + (cbBitsInfo + cbBits) / sizeof(WORD), (LPWORD) lpWStart); }
if (LocalFree((HANDLE) lpWStart)) ASSERTGDI(FALSE, "RecordObject: LocalFree Failed\n");
break; }
default: { ASSERTGDI(FALSE, "RecordObject: Bad brush style"); break; } } // switch(lb.lbStyle)
break; } // case LO_BRUSH
case LO_PALETTE_TYPE: status = (UINT) MakeLogPalette(hdc, hObject, META_CREATEPALETTE); break;
default: ERROR_ASSERT(FALSE, "unknown case RecordObject"); break; }
// Free the DC created in the brush case.
if (hdcScreen) if (!DeleteDC(hdcScreen)) ASSERTGDI(FALSE, "RecordObject: DeleteDC Failed\n");
ASSERTGDI(status == TRUE, "RecordObject: Failing\n"); return ((WORD) (status == TRUE ? iPosition : -1)); } /* RecordObject */
BOOL AddDCToObjectMetaList16(HDC hMetaDC16, HANDLE hObject) { ULONG cMetaDC16New; PMETALINK16 pml16;
ASSERTGDI(LO_TYPE(hObject) != LO_REGION_TYPE, "AddDCToObjectMetaList16: unexpected region object");
// If the object is a stock object there is no work to do
if (IS_STOCKOBJ(hObject)) return(TRUE);
// If the Object's MetaList16 is NULL create allocate one
pml16 = pmetalink16Get(hObject);
if (!pml16) { ENTERCRITICALSECTION(&semLocal); pml16 = pmetalink16Create(hObject); LEAVECRITICALSECTION(&semLocal);
if (pml16) { pml16->metalink = 0; pml16->cMetaDC16 = 1; pml16->ahMetaDC16[0] = hMetaDC16; } else { ASSERTGDI(FALSE, "AddDCToObjectMetaList16: Out of Memory 1"); return(FALSE); } } else { int cj;
cMetaDC16New = pml16->cMetaDC16 + 1;
if (pml16 = pmetalink16Resize(hObject,cMetaDC16New)) { pml16->ahMetaDC16[pml16->cMetaDC16++] = hMetaDC16; } else { ASSERTGDI(FALSE, "AddDCToObjectMetaList16: Out of Memory 2"); return(FALSE); } }
return(TRUE); }
/***************************** Internal Function ***************************\
* AddObjectToDCTable * * Add an object (brush, pen...) to a list of objects associated with the * metafile. * * * * Returns: 1 if object is already in table * 0 if object was just added to table * -1 if failure * * Remarks * bAdd is TRUE iff the object is being added otherwise it is being deleted * \***************************************************************************/
UINT AddObjectToDCTable(HDC hdc, HANDLE hObject, PUINT pPosition, BOOL bAdd) { UINT iEmptySpace = (UINT) -1; UINT i; UINT status = (UINT) -1; POBJECTTABLE pHandleTable; PMFRECORDER16 pMFRec;
PUTS("AddObjectToDCTable\n");
GET_PMFRECORDER16(pMFRec,hdc);
if (!IS_METADC16_TYPE(hdc) || !pMFRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return((UINT)-1); }
// if the Object table already exists search it for the object
if (pHandleTable = (POBJECTTABLE)pMFRec->hObjectTable) { for (i=0; i < (UINT) pMFRec->metaHeader.mtNoObjects; ++i) { if (hObject == pHandleTable[i].CurHandle) { *pPosition = i; status = 1; // the object exists in the table
// if we are doing a METADELETEOBJECT.
// delete object from table
if (!bAdd) { pHandleTable[i].fPreDeleted = FALSE; pHandleTable[i].CurHandle = (HANDLE)NULL; } goto AddObjectToTable10; } else if ((pHandleTable[i].CurHandle == 0) && (iEmptySpace == (UINT) -1)) { // if the entry has been deleted, we want to add a new object
// in its place. iEmptySpace will tell us where that place is.
iEmptySpace = i; } } // for
}
if (bAdd) { // If there is no object table for this MetaFile then Allocate one.
if (pHandleTable == (POBJECTTABLE)NULL) { pHandleTable = (POBJECTTABLE) LocalAlloc(LMEM_FIXED, sizeof(OBJECTTABLE)); pMFRec->hObjectTable = (HANDLE) pHandleTable; } else if (iEmptySpace == (UINT) -1) { pHandleTable = (POBJECTTABLE) LocalReAlloc(pMFRec->hObjectTable, (pMFRec->metaHeader.mtNoObjects + 1) * sizeof(OBJECTTABLE), LMEM_MOVEABLE); if (pHandleTable) pMFRec->hObjectTable = (HANDLE) pHandleTable; }
if (pHandleTable) { if (iEmptySpace == (UINT) -1) *pPosition = pMFRec->metaHeader.mtNoObjects++; else *pPosition = iEmptySpace;
pHandleTable[*pPosition].fPreDeleted = FALSE; pHandleTable[*pPosition].CurHandle = hObject;
status = 0; // the object is added to the table
} } AddObjectToTable10:
ERROR_ASSERT(status != (UINT) -1, "AddObjectToTable: Failing\n"); return(status); }
/***************************** Internal Function **************************\
* HDC WINAPI CreateMetaFileW * * Creates a MetaFile DC * * The internal format for a MetaFileRecorder has two formats one * for a memory MetaFile and one for a disk based MetaFile * \***************************************************************************/
HDC WINAPI CreateMetaFileA(LPCSTR pszFileName) { UINT cch; WCHAR awch[MAX_PATH];
if (pszFileName) { cch = strlen(pszFileName)+1;
if (cch > MAX_PATH) { ERROR_ASSERT(FALSE, "CreateMetaFileA filename too long"); GdiSetLastError(ERROR_FILENAME_EXCED_RANGE); return((HDC) 0); } vToUnicodeN(awch, MAX_PATH, pszFileName, cch);
return (CreateMetaFileW(awch)); } else return (CreateMetaFileW((LPWSTR)NULL)); }
HDC WINAPI CreateMetaFileW(LPCWSTR pwszFileName) { PMFRECORDER16 pMFRec; HDC hdc;
PUTS("CreateMetaFileW\n");
if (!(pMFRec = (PMFRECORDER16) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(MFRECORDER16)))) goto CreateMetaFileW_error;
// pMFRec->ident = ID_METADC16;
// pMFRec->hMem = 0;
pMFRec->hFile = INVALID_HANDLE_VALUE; pMFRec->cbBuffer = MF16_BUFSIZE_INIT; // pMFRec->ibBuffer = 0;
pMFRec->metaHeader.mtHeaderSize = sizeof(METAHEADER)/sizeof(WORD); pMFRec->metaHeader.mtVersion = METAVERSION300; // pMFRec->metaHeader.mtSize = 0;
// pMFRec->metaHeader.mtNoObjects = 0;
// pMFRec->metaHeader.mtMaxRecord = 0;
// pMFRec->metaHeader.mtNoParameters = 0;
// pMFRec->recFlags = 0;
// pMFRec->recCurObjects[] = 0;
pMFRec->recCurObjects[OBJ_PEN - MIN_OBJ_TYPE] = GetStockObject(BLACK_PEN); pMFRec->recCurObjects[OBJ_BRUSH - MIN_OBJ_TYPE] = GetStockObject(WHITE_BRUSH); pMFRec->recCurObjects[OBJ_FONT - MIN_OBJ_TYPE] = GetStockObject(DEVICE_DEFAULT_FONT); pMFRec->recCurObjects[OBJ_BITMAP - MIN_OBJ_TYPE] = GetStockObject(PRIV_STOCK_BITMAP); pMFRec->recCurObjects[OBJ_REGION - MIN_OBJ_TYPE] = (HANDLE) NULL; pMFRec->recCurObjects[OBJ_PAL - MIN_OBJ_TYPE] = GetStockObject(DEFAULT_PALETTE); // pMFRec->iPalVer = 0;
// Create a disk file if given. The filename is given in unicode.
if (pwszFileName) { LPWSTR pwszFilePart; // not used
DWORD cPathname;
// Convert the filename to a fully qualified pathname.
cPathname = GetFullPathNameW(pwszFileName, MAX_PATH, pMFRec->wszFullPathName, &pwszFilePart);
if (!cPathname || cPathname > MAX_PATH) { ERROR_ASSERT(FALSE, "GetFullPathName failed"); if (cPathname > MAX_PATH) GdiSetLastError(ERROR_FILENAME_EXCED_RANGE); goto CreateMetaFileW_error; } pMFRec->wszFullPathName[cPathname] = 0;
// Create the file.
if ((pMFRec->hFile = CreateFileW(pMFRec->wszFullPathName,// Filename
GENERIC_WRITE, // Write access
0L, // Non-shared
(LPSECURITY_ATTRIBUTES) NULL, // No security
CREATE_ALWAYS, // Always create
FILE_ATTRIBUTE_NORMAL, // normal attributes
(HANDLE) 0)) // no template file
== INVALID_HANDLE_VALUE) { // Milestones, Etc. 3.1 creates the file for read/write access when
// it calls CreateMetaFile. This causes the above CreateFile to
// fail. However, we do not want to modify the above call since
// it provides serialization and access to the metafile. Instead,
// we add in this hack for Milestones. The only difference is
// that the metafile is shared for read/write access.
if ((pMFRec->hFile = CreateFileW(pMFRec->wszFullPathName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) 0)) == INVALID_HANDLE_VALUE) { ERROR_ASSERT(FALSE, "CreateFile failed"); goto CreateMetaFileW_error; }
WARNING("CreateMetaFileW: Creating metafile with read/write share\n"); } pMFRec->metaHeader.mtType = DISKMETAFILE; } else { pMFRec->metaHeader.mtType = MEMORYMETAFILE; }
// Allocate memory for metafile.
// For disk metafile, it is used as a buffer.
// For memory metafile, it is the storage for the metafile.
if (!(pMFRec->hMem = LocalAlloc(LMEM_FIXED, MF16_BUFSIZE_INIT))) goto CreateMetaFileW_error;
// Write the header.
if (!AttemptWrite(pMFRec, sizeof(METAHEADER), (LPBYTE)&pMFRec->metaHeader)) goto CreateMetaFileW_error;
// Finally, allocate a local handle for the metafile DC. It references
// the metafile recorder info.
hdc = hCreateClientObjLink(pMFRec,LO_METADC16_TYPE);
if (!hdc) { ERROR_ASSERT(FALSE, "CreateMetaFileW: iAllocHandle failed\n"); goto CreateMetaFileW_error; }
return(hdc);
CreateMetaFileW_error:
if (pMFRec) { if (pMFRec->hFile != INVALID_HANDLE_VALUE) { if (!CloseHandle(pMFRec->hFile)) ASSERTGDI(FALSE, "CloseHandle failed\n");
if (!DeleteFileW(pMFRec->wszFullPathName)) WARNING("CreateMetaFileW: DeleteFile failed\n"); }
if (pMFRec->hMem) if (LocalFree(pMFRec->hMem)) ASSERTGDI(FALSE, "LocalFree failed");
if (LocalFree((HANDLE) pMFRec)) ASSERTGDI(FALSE, "CreateMetaFileW: LocalFree failed\n"); }
ERROR_ASSERT(FALSE, "CreateMetaFileW failed\n"); return((HDC) 0); }
/***************************** Internal Function **************************\
* HMETAFILE WINAPI CloseMetaFile * * The CloseMetaFile function closes the metafile device context and creates a * metafile handle that can be used to play the metafile by using the * PlayMetaFile function. * * The internal format for a MetaFile has two formats one * for a memory MetaFile and one for a disk based MetaFile * * Effects: * \***************************************************************************/
HMETAFILE WINAPI CloseMetaFile(HDC hdc) { PMFRECORDER16 pmfRec; HMETAFILE hmf = (HMETAFILE) 0;
PUTS("CloseMetaFile\n");
GET_PMFRECORDER16(pmfRec,hdc);
ASSERTGDI(pmfRec, "CloseMetaFile: pmfRec is NULL!");
if (!IS_METADC16_TYPE(hdc) || !pmfRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return(hmf); }
// If the metafile was aborted then free the MetaDC handle memory and go home.
if (pmfRec->recFlags & METAFILEFAILURE) goto CLM_Cleanup;
// Write the terminate Record
if (!RecordParms(hdc, 0, 0, (LPWORD)NULL)) goto CLM_Cleanup;
// Flush the buffer and update the header record.
if (pmfRec->metaHeader.mtType == DISKMETAFILE) { BOOL fRet; DWORD dwT;
ASSERTGDI(pmfRec->metaHeader.mtType == DISKMETAFILE, "CloseMetaFile: unknown metafile type");
// Flush the memory buffer
fRet = WriteFile(pmfRec->hFile, (LPBYTE)pmfRec->hMem, pmfRec->ibBuffer, &dwT, (LPOVERLAPPED)NULL); if (!fRet || (dwT != pmfRec->ibBuffer)) { ERROR_ASSERT(FALSE, "CloseMetaFile: Write1 failed\n"); goto CLM_Cleanup; }
// Rewind the file and write the header out
if (SetFilePointer(pmfRec->hFile, 0, (LPLONG)NULL, FILE_BEGIN) != 0) { ERROR_ASSERT(FALSE, "CloseMetaFile: SetFilePointer failed\n"); goto CLM_Cleanup; }
// Fix up data written to disk as a memory metafile
pmfRec->metaHeader.mtType = MEMORYMETAFILE; fRet = WriteFile(pmfRec->hFile, (LPBYTE)& pmfRec->metaHeader, sizeof(METAHEADER), &dwT, (LPOVERLAPPED)NULL); pmfRec->metaHeader.mtType = DISKMETAFILE; // restore it
if (!fRet || (dwT != sizeof(METAHEADER))) { ERROR_ASSERT(FALSE, "CloseMetaFile: Write2 failed\n"); goto CLM_Cleanup; }
// Close the file.
if (!CloseHandle(pmfRec->hFile)) ASSERTGDI(FALSE, "CloseMetaFile: FileError\n");
pmfRec->hFile = INVALID_HANDLE_VALUE; // don't close it again below
} else { HANDLE hMemNew;
// Flush the header record.
*(PMETAHEADER) pmfRec->hMem = pmfRec->metaHeader;
// Realloc memory metafile to exact size
hMemNew = LocalReAlloc(pmfRec->hMem, pmfRec->metaHeader.mtSize * sizeof(WORD), LMEM_MOVEABLE);
if (!hMemNew) { ASSERTGDI(FALSE, "LocalReAlloc failed"); goto CLM_Cleanup; }
pmfRec->hMem = hMemNew; }
// Allocate and initialize a metafile.
if (pmfRec->metaHeader.mtType == DISKMETAFILE) { hmf = GetMetaFileW(pmfRec->wszFullPathName); } else { hmf = SetMetaFileBitsAlt((HLOCAL) pmfRec->hMem); if (hmf) pmfRec->hMem = 0; // don't free it below because it has been transfered
}
CLM_Cleanup:
// Remove the MetaFile from the list of active metafiles
if (pmfRec->hObjectTable) { UnlistObjects(hdc); if (LocalFree((HANDLE) pmfRec->hObjectTable)) ASSERTGDI( FALSE, "CloseMetaFile: LocalFree object table failed\n"); }
// If the file handle exists at this time, we have an error.
if (pmfRec->hFile != INVALID_HANDLE_VALUE) { if (!CloseHandle(pmfRec->hFile)) ASSERTGDI(FALSE, "CloseHandle failed\n");
if (!DeleteFileW(pmfRec->wszFullPathName)) WARNING("CloseMetaFile: DeleteFile failed\n"); }
// Free the cache buffer.
if (pmfRec->hMem) if (LocalFree(pmfRec->hMem)) ASSERTGDI(FALSE, "LocalFree failed");
// Free the memory for the metafile DC.
if (LocalFree((HANDLE) pmfRec)) ASSERTGDI(FALSE, "CloseMetaFile: LocalFree failed\n");
// Free the handle for the metafile DC.
if (!bDeleteClientObjLink(hdc)) RIP("CloseMetaFile - failed bDeleteClientObjLink\n");
ERROR_ASSERT(hmf != (HMETAFILE) 0, "CloseMetaFile failed\n"); return(hmf); }
/***************************** Internal Function **************************\
* CopyMetaFile(hSrcMF, lpFileName) * * Copies the metafile (hSrcMF) to a new metafile with name lpFileName. The * function then returns a handle to this new metafile if the function was * successful. * * Retuns a handle to a new metafile, 0 iff failure * * IMPLEMENTATION: * The source and target metafiles are checked to see if they are both memory * metafile and if so a piece of Local memory is allocated and the metafile * is simply copied. * If this is not the case CreateMetaFile is called with lpFileName and then * records are pulled out of the source metafile (using GetEvent) and written * into the destination metafile one at a time (using RecordParms). * * Lock the source * if source is a memory metafile and the destination is a memory metafile * alloc the same size Local memory as the source * copy the bits directly * else * get a metafile handle by calling CreateMetaFile * while GetEvent returns records form the source * record the record in the new metafile * * close the metafile * * return the new metafile handle * \***************************************************************************/
HMETAFILE WINAPI CopyMetaFileA(HMETAFILE hmf, LPCSTR psz) { UINT cch; WCHAR awch[MAX_PATH];
if (psz != (LPSTR)NULL) { cch = strlen(psz)+1;
if (cch > MAX_PATH) { ERROR_ASSERT(FALSE, "CopyMetaFileA filename too long"); GdiSetLastError(ERROR_FILENAME_EXCED_RANGE); return((HMETAFILE)0); }
vToUnicodeN(awch, MAX_PATH, psz, cch);
return (CopyMetaFileW(hmf, awch)); } else return (CopyMetaFileW(hmf, (LPWSTR)NULL)); }
HMETAFILE WINAPI CopyMetaFileW(HMETAFILE hSrcMF, LPCWSTR pwszFileName) { PMETAFILE16 pMFSource; HMETAFILE hMFDest = (HMETAFILE) 0; HDC hMDCDest; UINT state;
PUTS("CopyMetaFile\n");
pMFSource = GET_PMF16(hSrcMF); if (pMFSource == NULL) { GdiSetLastError(ERROR_INVALID_HANDLE); return(hMFDest); }
state = (pMFSource->fl & MF16_DISKFILE) ? 2 : 0; state |= (pwszFileName) ? 1 : 0;
switch (state) { case 0: /* memory -> memory */ hMFDest = SetMetaFileBitsEx ( pMFSource->metaHeader.mtSize * sizeof(WORD), (LPBYTE) pMFSource->hMem ); break;
case 3: /* disk -> disk */ hMFDest = CopyFileW(pMFSource->wszFullPathName, pwszFileName, FALSE) ? GetMetaFileW(pwszFileName) : 0;
ERROR_ASSERT(hMFDest, "CopyMetaFileW: GetMetaFile Failed\n"); break;
case 1: case 2: if (hMDCDest = CreateMetaFileW(pwszFileName)) { PMFRECORDER16 pMFRecDest; PMETARECORD lpMR = NULL;
GET_PMFRECORDER16(pMFRecDest,hMDCDest);
while (lpMR = GetEvent(pMFSource, lpMR)) if ((lpMR == (PMETARECORD) -1) || !RecordParms(hMDCDest, (DWORD)lpMR->rdFunction, (DWORD)lpMR->rdSize - 3, (LPWORD) lpMR->rdParm)) { HMETAFILE hmfT;
MarkMetaFile(pMFRecDest);
if (hmfT = CloseMetaFile(hMDCDest)) DeleteMetaFile(hmfT); return((HMETAFILE) 0); }
// touch up the destination metafile header before we close
// the metafile!
pMFRecDest->metaHeader.mtNoObjects = pMFSource->metaHeader.mtNoObjects; ASSERTGDI(sizeof(METAHEADER) == 18, "CopyMetaFile: METAHEADER has changed!");
hMFDest = CloseMetaFile(hMDCDest); } break; }
ERROR_ASSERT(hMFDest, "CopyMetaFileW Failing\n"); return(hMFDest); }
/***************************** Internal Function ***************************\
* HANDLE WINAPI GetMetaFileBitsEx * * The GetMetaFileBits function returns a handle to a Windows metafile that * contains the specified data describing the metafile. * * It does not invalidate the metafile handle like Windows! * * Effects: * \***************************************************************************/
UINT WINAPI GetMetaFileBitsEx(HMETAFILE hMF, UINT cbBuffer, LPVOID lpData) { DWORD cbHave; PMETAFILE16 pmf16;
PUTS("GetMetaFileBitsEx\n");
pmf16 = GET_PMF16(hMF); if (pmf16 == NULL) { GdiSetLastError(ERROR_INVALID_HANDLE); return(0); }
cbHave = pmf16->metaHeader.mtSize * sizeof(WORD);
// If lpData is NULL, return the size necessary to hold the data.
if (!lpData) return(cbHave);
// Make sure the input buffer is large enough.
if (cbBuffer < cbHave) return(0);
// Copy the bits. Win3.1 returns the bits for memory metafile only!
// We will do the right thing here.
RtlCopyMemory(lpData, (PBYTE) pmf16->hMem, cbHave);
// Return the number of bytes copied.
return(cbHave); }
/***************************** Internal Function **************************\
* HMETAFILE WINAPI SetMetaFileBitsEx * * Creates a memory based Windows 3.X metafile from the data provided * * Returns: HMETAFILE iff succesful. * * Effects: * \***************************************************************************/
HMETAFILE WINAPI SetMetaFileBitsEx(UINT cbBuffer, CONST BYTE *lpData) { PMETAFILE16 pmf16; HMETAFILE hmf;
PUTS("SetMetaFileBitsEx\n");
// Verify the input data.
if (cbBuffer < sizeof(METAHEADER) || !IsValidMetaHeader16((PMETAHEADER) lpData)) { ERROR_ASSERT(FALSE, "SetMetaFileBitsEx: Bad input data\n"); GdiSetLastError(ERROR_INVALID_DATA); return((HMETAFILE) 0); }
ERROR_ASSERT(((PMETAHEADER) lpData)->mtType == MEMORYMETAFILE, "SetMetaFileBitsEx: Bad mtType\n");
// Allocate and initialize a metafile.
// Some Windows metafiles contain bad values in mtSize. As a result,
// we have to verify and fix the mtSize if neccessary. This is fixed
// in the following call.
if (!(pmf16 = pmf16AllocMF16(0, (DWORD) cbBuffer, (PDWORD)lpData, (LPWSTR) NULL))) return((HMETAFILE) 0);
ASSERTGDI(pmf16->metaHeader.mtType == MEMORYMETAFILE, "SetMetaFileBitsEx: Bad mtType\n"); ((PMETAHEADER) pmf16->hMem)->mtType = MEMORYMETAFILE; // just in case
// Allocate a local handle.
hmf = hmf16Create(pmf16); if (hmf == NULL) { vFreeMF16(pmf16); }
// Return the metafile handle.
return(hmf); }
// Similar to Win3.x SetMetaFileBits.
// It is assumed that hMem is allocated with the LMEM_FIXED option.
// For internal use only.
HMETAFILE WINAPI SetMetaFileBitsAlt(HLOCAL hMem) { PMETAFILE16 pmf16; HMETAFILE hmf;
PUTS("SetMetaFileBitsAlt\n");
// Allocate and initialize a metafile.
if (!(pmf16 = pmf16AllocMF16(ALLOCMF16_TRANSFER_BUFFER, 0, (PDWORD) hMem, (LPWSTR) NULL))) return((HMETAFILE) 0);
ASSERTGDI(pmf16->metaHeader.mtType == MEMORYMETAFILE, "SetMetaFileBitsAlt: Bad mtType\n"); ((PMETAHEADER) pmf16->hMem)->mtType = MEMORYMETAFILE; // just in case
// Allocate a local handle.
hmf = hmf16Create(pmf16);
if (hmf == NULL) { pmf16->hMem = NULL; // let caller free the buffer!
vFreeMF16(pmf16); }
// Return the metafile handle.
return(hmf); }
/***************************** Internal Function **************************\
* GetObject16AndType * * Returns the object type, eg OBJ_FONT, as well as a the LogObject * in Windows 3.x Format * \***************************************************************************/
#define MAXOBJECTSIZE sizeof(LOGFONT)
DWORD GetObject16AndType(HANDLE hObj, LPVOID lpObjBuf16) { BYTE objBuf32[MAXOBJECTSIZE]; int iObj;
PUTS("GetObjectAndType\n");
ASSERTGDI(MAXOBJECTSIZE >= sizeof(LOGPEN), "GetObject16AndType MAXOBJECTSIZE wrong\n");
if (!GetObject(hObj, MAXOBJECTSIZE, &objBuf32)) { ERROR_ASSERT(FALSE, "GetObject16AndType GetObject Failed\n"); return(0); }
switch(iObj = GetObjectType(hObj)) { case OBJ_PEN: LOGPEN16FROMLOGPEN32((PLOGPEN16)lpObjBuf16,(LPLOGPEN)objBuf32); break;
case OBJ_FONT: LOGFONT16FROMLOGFONT32((PLOGFONT16)lpObjBuf16,(LPLOGFONT)objBuf32); break;
default: ASSERTGDI(FALSE, "GetObject16AndType unknown object type\n"); return(0); break; }
return((DWORD) iObj); }
/***************************** Internal Function **************************\
* BOOL UnlistObjects(hMetaDC) * * Each object has a list of metafiles the object is associated with. * UnlistObjects removes hMetaDC from all of its object's metafile lists * * Effects: * \***************************************************************************/
BOOL UnlistObjects(HDC hMetaDC) { PMETALINK16 pml16; UINT iCurObject; UINT iCurMetaListEntry; POBJECTTABLE pht; PMFRECORDER16 pMFRec;
PUTS("UnlistObjects\n");
GET_PMFRECORDER16(pMFRec,hMetaDC);
if (!IS_METADC16_TYPE(hMetaDC) || !pMFRec) { GdiSetLastError(ERROR_INVALID_HANDLE); return((UINT)-1); }
if (pMFRec->metaHeader.mtNoObjects) { pht = (POBJECTTABLE) pMFRec->hObjectTable; ASSERTGDI(pht, "UnlistObject: called even with no handle table");
// Loop through the objects and unlink this metafile
for (iCurObject=0; iCurObject < (UINT) pMFRec->metaHeader.mtNoObjects; iCurObject++) { HANDLE hObj;
if( (hObj = pht[iCurObject].CurHandle) && (!pht[iCurObject].fPreDeleted)) { if (IS_STOCKOBJ(hObj)) continue;
ASSERTGDI(LO_TYPE(hObj) != LO_REGION_TYPE, "UnlistObjects: unexpected region object");
pml16 = pmetalink16Get(hObj);
// It cannot be a empty list.
ASSERTGDI(pml16, "UnlistObject: pml16 is NULL");
if (!pml16 || pml16->cMetaDC16 == 0) continue;
// Find the metafile in the objects MetaLink16 list
for (iCurMetaListEntry=0; iCurMetaListEntry<pml16->cMetaDC16; iCurMetaListEntry++) { if(pml16->ahMetaDC16[iCurMetaListEntry] == hMetaDC) break; }
ASSERTGDI(iCurMetaListEntry < pml16->cMetaDC16, "UnlistObject: Metafile not found");
// Slide the rest of the metafiles in the list "up"
for(; iCurMetaListEntry < (pml16->cMetaDC16-1); iCurMetaListEntry++) pml16->ahMetaDC16[iCurMetaListEntry] = pml16->ahMetaDC16[iCurMetaListEntry+1];
pml16->cMetaDC16--; // just got rid of one
if (pml16->cMetaDC16 == 0) { // We can only free the METALINK16 if the metalink field is not being used
if (pml16->metalink) { pml16->cMetaDC16 = 0; pml16->ahMetaDC16[0] = (HDC)NULL; } else { if (!bDeleteMetalink16(hObj)) ASSERTGDI(FALSE,"UnlistObjects: LocalFree Failed\n"); } } else { pml16 = pmetalink16Resize(hObj,pml16->cMetaDC16);
if (pml16 == NULL) { ASSERTGDI(FALSE,"UnlistObjects: LocalReAlloc Failed\n"); return (FALSE); } } } } // for
}
return(TRUE); }
/******************************Public*Routine******************************\
* pmf16AllocMF16(fl, cb, pb, pwszFilename) * * This routine allocates memory for an METAFILE16 and initializes it. * Returns a pointer to the new METAFILE16. On error returns NULL. * It accepts only windows metafiles. * * This routine is called by API level METAFILE16 allocation routines * CloseMetaFile, GetMetaFile, SetMetaFileBitsEx. * * Arguments: * fl - ALLOCMF16_TRANSFER_BUFFER is set if storage for memory * metafile is to be set directly into METAFILE16. Otherwise, * a copy of the memory metafile is duplicated. * cb - Size of pb in bytes if given. This parameter is given * by SetMetaFileBitsEx only. It is used to compare and * fixup bad mtSize if necessary. * pb - Pointer to a memory metafile if non-null. * pwszFilename - Filename of a disk metafile if non-null. * * History: * Fri May 15 14:11:22 1992 -by- Hock San Lee [hockl] * Wrote it. \**************************************************************************/
PMETAFILE16 pmf16AllocMF16(DWORD fl, DWORD cb, CONST UNALIGNED DWORD *pb, LPCWSTR pwszFilename) { PMETAFILE16 pmf16, pmf16Rc = (PMETAFILE16) NULL;
PUTS("pmf16AllocMF16\n");
ASSERTGDI(!(fl & ~ALLOCMF16_TRANSFER_BUFFER), "pmf16AllocMF16: Invalid fl");
// Allocate a new METAFILE16.
if (!(pmf16 = (PMETAFILE16) LocalAlloc(LMEM_FIXED, sizeof(METAFILE16)))) goto pmf16AllocMF16_cleanup;
// Initialize it.
pmf16->ident = MF16_IDENTIFIER; pmf16->hFile = INVALID_HANDLE_VALUE; pmf16->hFileMap = (HANDLE) 0; pmf16->hMem = (HANDLE) 0; pmf16->iMem = 0; pmf16->hMetaFileRecord = (HANDLE) 0; pmf16->fl = 0L;
// Memory mapped the disk file if given.
if (pwszFilename) { LPWSTR pwszFilePart; // not used
DWORD cPathname;
pmf16->fl |= MF16_DISKFILE; // this must be first! See vFreeMF16.
// Convert the filename to a fully qualified pathname.
cPathname = GetFullPathNameW(pwszFilename, MAX_PATH, pmf16->wszFullPathName, &pwszFilePart);
if (!cPathname || cPathname > MAX_PATH) { ERROR_ASSERT(FALSE, "GetFullPathName failed"); if (cPathname > MAX_PATH) GdiSetLastError(ERROR_FILENAME_EXCED_RANGE); goto pmf16AllocMF16_cleanup; } pmf16->wszFullPathName[cPathname] = 0;
if ((pmf16->hFile = CreateFileW(pmf16->wszFullPathName, // Filename
GENERIC_READ, // Read access
FILE_SHARE_READ, // Share read
(LPSECURITY_ATTRIBUTES) 0L,// No security
OPEN_EXISTING, // Re-open
0, // file attributes ignored
(HANDLE) 0)) // no template file
== INVALID_HANDLE_VALUE) { // See the comment for Milestones in CreateMetaFileW.
if ((pmf16->hFile = CreateFileW(pmf16->wszFullPathName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) 0L, OPEN_EXISTING, 0, (HANDLE) 0)) == INVALID_HANDLE_VALUE) { ERROR_ASSERT(FALSE, "CreateFile failed"); goto pmf16AllocMF16_cleanup; } WARNING("pmf16AllocMF16: Opening metafile with read/write share\n"); }
if (!(pmf16->hFileMap = CreateFileMappingW(pmf16->hFile, (LPSECURITY_ATTRIBUTES) 0L, PAGE_READONLY, 0L, 0L, (LPWSTR) NULL))) { ERROR_ASSERT(FALSE, "CreateFileMapping failed"); goto pmf16AllocMF16_cleanup; }
if (!(pmf16->hMem = MapViewOfFile(pmf16->hFileMap, FILE_MAP_READ, 0, 0, 0))) { ERROR_ASSERT(FALSE, "MapViewOfFile failed"); goto pmf16AllocMF16_cleanup; } } else if (fl & ALLOCMF16_TRANSFER_BUFFER) { // If this is our memory metafile from MDC, transfer it to METAFILE16.
pmf16->hMem = (BYTE *) pb; } else { // Otherwise, make a copy of memory metafile.
// We get here only if the caller is SetMetaFileBitsEx. Since some metafiles
// may contain a bad mtSize that is different than the actual file size, we
// need to fix it up if necessary!
DWORD mtSize = ((PMETAHEADER) pb)->mtSize;
if ((mtSize * 2 > cb) // mtSize greater than filesize
|| (((PWORD) pb)[mtSize - 3] != 3) // EOF record should be 3,0,0
|| (((PWORD) pb)[mtSize - 2] != 0) || (((PWORD) pb)[mtSize - 1] != 0)) { // Compute the correct mtSize!
PMETARECORD pMR; DWORD mtSizeMax;
PUTS("pmf16AllocMF16: verifying mtSize\n");
mtSize = ((PMETAHEADER) pb)->mtHeaderSize; pMR = (PMETARECORD) ((PWORD) pb + ((PMETAHEADER) pb)->mtHeaderSize); mtSizeMax = cb / 2 - 3; // max mtSize not counting EOF record
while (mtSize <= mtSizeMax && pMR->rdFunction != 0) { mtSize += pMR->rdSize; pMR = (PMETARECORD) ((PWORD) pMR + pMR->rdSize); }
if (mtSize > mtSizeMax) { ERROR_ASSERT(FALSE, "pmf16AllocMF16: incomplete metafile\n"); goto pmf16AllocMF16_cleanup; }
// Powerpnt uses 0,0,0 for the EOF record! We will change it to 3,0,0 below.
mtSize += 3; // include EOF record (pMR->rdSize may not be valid)
if (((PMETAHEADER) pb)->mtSize != mtSize) { ERROR_ASSERT(FALSE, "pmf16AllocMF16: fixing up bad mtSize\n"); } }
if (!(pmf16->hMem = LocalAlloc(LMEM_FIXED, mtSize * sizeof(WORD)))) goto pmf16AllocMF16_cleanup; RtlCopyMemory((PBYTE) pmf16->hMem, (PBYTE)pb, mtSize * sizeof(WORD)); ((PMETAHEADER) pmf16->hMem)->mtSize = mtSize; // update mtSize
VERIFYGDI(((PWORD) pmf16->hMem)[mtSize - 3] == 3 && ((PWORD) pmf16->hMem)[mtSize - 2] == 0 && ((PWORD) pmf16->hMem)[mtSize - 1] == 0, "pmf16AllocMF16: fixing up bad EOF metafile record\n");
((PWORD) pmf16->hMem)[mtSize - 3] = 3; // update EOF record
((PWORD) pmf16->hMem)[mtSize - 2] = 0; ((PWORD) pmf16->hMem)[mtSize - 1] = 0; }
// Make a copy of the metafile header.
pmf16->metaHeader = *(PMETAHEADER) pmf16->hMem; pmf16->metaHeader.mtType = (pmf16->fl & MF16_DISKFILE) ? DISKMETAFILE : MEMORYMETAFILE;
// Verify metafile header
if (!IsValidMetaHeader16(&pmf16->metaHeader)) { ERROR_ASSERT(FALSE, "pmf16AllocMF16: Metafile has an invalid header; Failing\n"); goto pmf16AllocMF16_cleanup; }
// Everything is golden.
pmf16Rc = pmf16;
// Cleanup and go home.
pmf16AllocMF16_cleanup:
if (!pmf16Rc) if (pmf16) { if (fl & ALLOCMF16_TRANSFER_BUFFER) pmf16->hMem = NULL; // let caller free the buffer!
vFreeMF16(pmf16); }
ERROR_ASSERT(pmf16Rc, "pmf16AllocMF16 failed"); return(pmf16Rc); }
/******************************Public*Routine******************************\
* vFreeMF16 (pmf16) * * This is a low level routine which frees the resouces in the METAFILE16. * * This function is intended to be called from the routines CloseMetaFile * and DeleteMetaFile. * * Arguments: * pmf16 - The METAFILE16 to be freed. * * History: * Fri May 15 14:11:22 1992 -by- Hock San Lee [hockl] * Wrote it. \**************************************************************************/
VOID vFreeMF16(PMETAFILE16 pmf16) { PUTS("vFreeMF16\n");
ASSERTGDI(pmf16->ident == MF16_IDENTIFIER, "Bad METAFILE16");
// Free the resources.
if (!(pmf16->fl & MF16_DISKFILE)) { // Free memory metafile.
if (pmf16->hMem) if (LocalFree(pmf16->hMem)) ASSERTGDI(FALSE, "LocalFree failed"); } else { // Unmap disk file.
if (pmf16->hMem) if (!UnmapViewOfFile((LPVOID) pmf16->hMem)) ASSERTGDI(FALSE, "UmmapViewOfFile failed");
if (pmf16->hFileMap) if (!CloseHandle(pmf16->hFileMap)) ASSERTGDI(FALSE, "CloseHandle failed");
if (pmf16->hFile != INVALID_HANDLE_VALUE) if (!CloseHandle(pmf16->hFile)) ASSERTGDI(FALSE, "CloseHandle failed"); }
// Smash the identifier.
pmf16->ident = 0;
// Free the memory.
if (LocalFree(pmf16)) ASSERTGDI(FALSE, "LocalFree failed"); }
|