/****************************** Module Header ******************************\ * Module Name: MfPlay16.c * * This file contains the routines for playing the GDI metafile. Most of these * routines are adopted from windows gdi code. Most of the code is from * win3.0 except for the GetEvent code which is taken from win2.1 * * Created: 11-Oct-1989 * * Copyright (c) 1985-1999 Microsoft Corporation * * * Public Functions: * PlayMetaFile * PlayMetaFileRecord * GetMetaFile * DeleteMetaFile * Private Functions: * GetEvent * IsDIBBlackAndWhite * * 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" BOOL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, UINT noObjs); BOOL CommonEnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC proc, LPARAM lpData); HANDLE CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo); WORD GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo); BOOL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo); BOOL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest); #if DBG UINT curRecord; // debuging helpers UINT iBreakRecord = 0xFFFFFFFF; #endif /***************************** Public Function ****************************\ * BOOL APIENTRY PlayMetaFile(hdc, hmf) * HDC hDC; * HMETAFILE hMF; * * Play a windows metafile. * * History: * 02-Jul-1991 -by- John Colleran [johnc] * Ported from Windows and WLO \***************************************************************************/ BOOL APIENTRY PlayMetaFile(HDC hdc, HMETAFILE hmf) { return (CommonEnumMetaFile(hdc, hmf, (MFENUMPROC)NULL, (LPARAM)0)); } /******************************** Public Function **************************\ * BOOL EnumMetaFile(hmf) * * The EnumMetaFile function enumerates the GDI calls within the metafile * identified by the hMF parameter. The EnumMetaFile function retrieves each * GDI call within the metafile and passes it to the function pointed to by the * pCallbackFunc parameter. This callback function, an application-supplied * function, can process each GDI call as desired. Enumeration continues until * there are no more GDI calls or the callback function returns zero. * * * Effects: * \***************************************************************************/ BOOL EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC pCallBackFunction, LPARAM pClientData) { // Make sure that the callback function is given. CommonEnumMetaFile expects // it to be given in EnumMetaFile. if (!pCallBackFunction) { GdiSetLastError(ERROR_INVALID_PARAMETER ); return(FALSE); } return (CommonEnumMetaFile(hdc, hmf, pCallBackFunction, pClientData)); } BOOL CommonEnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC pCallBack, LPARAM pClientData) { BOOL fStatus = FALSE; // assume it fails UINT ii; UINT noObjs; PMETAFILE16 pMF; INT oldMapMode = -1; PMETARECORD pMR = (PMETARECORD) NULL; LPHANDLETABLE pht = (LPHANDLETABLE) NULL; HFONT hLFont; HBRUSH hLBrush; HPALETTE hLPal; HPEN hLPen; HRGN hClipRgn = (HRGN)NULL; SIZE sizeOldWndExt; SIZE sizeOldVprtExt; PDC_ATTR pDcAttr; PLDC pldc; int iGraphicsModeOld; BOOL bMetaDC16 = FALSE; FLONG flPlayMetaFile = (FLONG) 0; // First validate the DC type and note whether or not we // are playing into a 16bit metafile.Null hdc is allowed // in win3.0 but disallowed in win3.1. if(LO_TYPE(hdc) == LO_METADC16_TYPE) { bMetaDC16 = TRUE; } else if ((hdc == NULL) && pCallBack) { // Actually win9x can take NULL hdc. There are some image filter // that actually pass in us NULL hdc. Only let NULL hdc thru if there is a // callback routine. [bug 102767] bMetaDC16 = TRUE; } else if((LO_TYPE(hdc) != LO_DC_TYPE ) && (LO_TYPE(hdc) != LO_ALTDC_TYPE)) { WARNING("CommonEnumMetaFile: bogus DC\n"); return(FALSE); } // need a pointer to pDcAttr for DC_PLAYMETAFILE flag PSHARED_GET_VALIDATE((PVOID)pDcAttr,hdc,DC_TYPE); if(!bMetaDC16 && !pDcAttr) { WARNING("CommonEnumMetaFile: Couldn't Validate DC\n"); return(FALSE); } // we still need to PLDC in the case that we are printing and there is // an abort proc pldc = GET_PLDC(hdc); PUTS("CommonEnumMetaFile\n"); #if DBG curRecord = 0; #endif // Validate the 16 bit MetaFile pMF = GET_PMF16(hmf); if (pMF == NULL) { GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); } // Allocate memory for the handle table. if ((noObjs = pMF->metaHeader.mtNoObjects) > 0) if (!(pht = (LPHANDLETABLE) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(HANDLE) * pMF->metaHeader.mtNoObjects + sizeof(WORD)))) // need extra word? return(FALSE); // Save the old objects so we can put them back if this is not a metafile. // Only do object save/reselect for real DC's. if( !bMetaDC16 ) { hLBrush = (HBRUSH) GetDCObject(hdc, LO_BRUSH_TYPE); hLFont = (HFONT) GetDCObject(hdc, LO_FONT_TYPE); hLPal = (HPALETTE) GetDCObject(hdc, LO_PALETTE_TYPE); hLPen = (HPEN) GetDCObject(hdc, LO_PEN_TYPE); // Set a bit in the DC to indicate that we are playing the metafile. // This bit is cleared by CancelDC() to stop playing the metafile. // At the same time, remember the previous DC_PLAYMETAFILE bit. try { flPlayMetaFile = pDcAttr->ulDirty_ & DC_PLAYMETAFILE; if (flPlayMetaFile) { PUTS("CommonEnumMetaFile: DC_PLAYMETAFILE bit is set!\n"); } pDcAttr->ulDirty_ |= DC_PLAYMETAFILE; } except(EXCEPTION_EXECUTE_HANDLER) { WARNING("except in SetBkMode\n"); GdiSetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } // Create a region in case there is a clip region to receive from GetClipRgn if (!(hClipRgn = CreateRectRgn(0,0,0,0))) goto pmf_cleanup; switch (GetClipRgn(hdc, hClipRgn)) { case -1: // error ASSERTGDI(FALSE, "GetClipRgn failed"); goto pmf_cleanup; case 0: // no initial clip region if (!DeleteObject(hClipRgn)) ASSERTGDI(FALSE, "CommonEnumMetaFile: Detele region failed\n"); hClipRgn = (HRGN) 0; break; case 1: // has initial clip region break; } // The metafile is to be played in the compatible graphics mode only. iGraphicsModeOld = GetGraphicsMode(hdc); if (iGraphicsModeOld != GM_COMPATIBLE) SetGraphicsMode(hdc, GM_COMPATIBLE); } // Are we doing an EnumMetaFile or PlayMetaFile if (pCallBack) { fStatus = TRUE; // assume success // EnumMetaFile while (pMR = (PMETARECORD) GetEvent(pMF, pMR)) { if (pMR == (PMETARECORD) -1) { fStatus = FALSE; break; } if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE)) { WARNING("CommonEnumMetaFile: CancelDC called\n"); fStatus = FALSE; break; } if (!(fStatus = (*pCallBack)(hdc, pht, (METARECORD FAR *) pMR, (int) noObjs, pClientData))) break; #if DBG curRecord++; if (curRecord == iBreakRecord) ASSERTGDI(FALSE, "CommonEnumMetaFile: iBreakRecord reached\n"); #endif } } else { // PlayMetaFile fStatus = TRUE; // assume success while (pMR = (PMETARECORD) GetEvent(pMF, pMR)) { if (pMR == (PMETARECORD) -1) { fStatus = FALSE; break; } if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE)) { WARNING("CommonEnumMetaFile: CancelDC called\n"); fStatus = FALSE; break; } if (pldc && pldc->pfnAbort != NULL) { if (!(*pldc->pfnAbort)(hdc, 0)) { fStatus = FALSE; break; } } // For win3.1 compatability, ignore the return value from PlayMetaFileRecord PlayMetaFileRecord(hdc, pht, pMR, noObjs); #if DBG curRecord++; if (curRecord == iBreakRecord) ASSERTGDI(FALSE, "CommonEnumMetaFile: iBreakRecord reached\n"); #endif } } // if we fail restoring an object, we need to select some // default object so that we can DeleteObject any Metafile- // selected objects if( !bMetaDC16 ) { if (iGraphicsModeOld != GM_COMPATIBLE) SetGraphicsMode(hdc, iGraphicsModeOld); if (!SelectObject(hdc,hLPen)) SelectObject(hdc,GetStockObject(BLACK_PEN)); if (!SelectObject(hdc,hLBrush)) SelectObject(hdc,GetStockObject(BLACK_BRUSH)); if (!SelectPalette(hdc, hLPal, FALSE)) SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); if (hLFont != (HFONT) GetDCObject(hdc, LO_FONT_TYPE)) { if (!SelectObject(hdc,hLFont)) { // if we cannot select the original font back in, we // select the system font. this will allow us to delete // the metafile font selected. to insure that the system // font gets selected, we reset the DC's transform to // default. after the selection, we restore this stuff // GetWindowExtEx(hdc, &sizeOldWndExt); GetViewportExtEx(hdc, &sizeOldVprtExt); oldMapMode = SetMapMode(hdc, MM_TEXT); SelectObject(hdc,GetStockObject(SYSTEM_FONT)); SetMapMode(hdc,oldMapMode); SetWindowExtEx( hdc, sizeOldWndExt.cx, sizeOldWndExt.cy, NULL); SetViewportExtEx(hdc, sizeOldVprtExt.cx, sizeOldVprtExt.cy, NULL); } } if (SelectClipRgn(hdc, hClipRgn) == RGN_ERROR) SelectClipRgn(hdc, (HRGN) 0); } // Cleanup all created objects for (ii = 0; ii < noObjs; ii++) { if (pht->objectHandle[ii]) if (!DeleteObject(pht->objectHandle[ii])) ERROR_ASSERT(FALSE, "CommonEnumMetaFile: DeleteObject(objectHandle) failed\n"); } // if we fiddled with the map mode because we could not // restore the original font, then maybe we can restore the // font now if (oldMapMode > 0) SelectObject(hdc,hLFont); pmf_cleanup: if (pldc) { // Preserve the DC_PLAYMETAFILE bit. // If we hit a CancelDC, then we will leave the bit clear. ASSERTGDI(!(flPlayMetaFile & ~DC_PLAYMETAFILE), "CommonEnumMetaFile: bad flPlayMetaFile\n"); if (!bMetaDC16 && !( pDcAttr->ulDirty_ & DC_PLAYMETAFILE) ) { pDcAttr->ulDirty_ &= ~DC_PLAYMETAFILE; pDcAttr->ulDirty_ |= flPlayMetaFile; // restore the original flag } } if (hClipRgn) if (!DeleteObject(hClipRgn)) ASSERTGDI(FALSE, "CommonEnumMetaFile: Delete region 2 failed\n"); if (pht) if (LocalFree((HANDLE) pht)) ASSERTGDI(FALSE, "CommonEnumMetaFile: LocalFree failed\n"); return(fStatus); } /***************************** Internal Function **************************\ * BOOL NEAR PASCAL IsDIBBlackAndWhite * * Check to see if this DIB is a black and white DIB (and should be * converted into a mono bitmap as opposed to a color bitmap). * * Returns: TRUE it is a B&W bitmap * FALSE this is for color * * Effects: ? * * Warnings: ? * * History: \***************************************************************************/ BOOL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo) { LPDWORD lpRGB; PUTS("IsDIBBlackAndWhite\n"); ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "IsDIBBlackAndWhite: dword alignment error\n"); /* pointer color table */ lpRGB = (LPDWORD)((LPBITMAPINFO)lpDIBInfo)->bmiColors; return (lpDIBInfo->biBitCount == 1 && lpDIBInfo->biPlanes == 1 && lpRGB[0] == (DWORD) 0 && lpRGB[1] == (DWORD) 0xFFFFFF); } /***************************** Internal Function **************************\ * UseStretchDIBits * * set this directly to the device using StretchDIBits. * if DIB is black&white, don't do this. * * Returns: * TRUE --- operation successful * FALSE -- decided not to use StretchDIBits * * History: \***************************************************************************/ BOOL UseStretchDIB(HDC hDC, WORD magic, LPMETARECORD lpMR) { LPBITMAPINFOHEADER lpDIBInfo; INT sExtX, sExtY; INT sSrcX, sSrcY; INT DstX, DstY, DstXE, DstYE; if (magic == META_DIBBITBLT) { lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[8]; DstX = (INT) (SHORT) lpMR->rdParm[7]; DstY = (INT) (SHORT) lpMR->rdParm[6]; sSrcX = (INT) (SHORT) lpMR->rdParm[3]; sSrcY = (INT) (SHORT) lpMR->rdParm[2]; DstXE = sExtX = (INT) (SHORT) lpMR->rdParm[5]; DstYE = sExtY = (INT) (SHORT) lpMR->rdParm[4]; } else { lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[10]; DstX = (INT) (SHORT) lpMR->rdParm[9]; DstY = (INT) (SHORT) lpMR->rdParm[8]; DstXE = (INT) (SHORT) lpMR->rdParm[7]; DstYE = (INT) (SHORT) lpMR->rdParm[6]; sSrcX = (INT) (SHORT) lpMR->rdParm[5]; sSrcY = (INT) (SHORT) lpMR->rdParm[4]; sExtX = (INT) (SHORT) lpMR->rdParm[3]; sExtY = (INT) (SHORT) lpMR->rdParm[2]; } ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "UseStretchDIB: dword alignment error\n"); /* if DIB is black&white, we don't really want to do this */ if (IsDIBBlackAndWhite(lpDIBInfo)) return(FALSE); // Need to flip the source y coordinates to call StretchDIBits. sSrcY = ABS(lpDIBInfo->biHeight) - sSrcY - sExtY; StretchDIBits(hDC, DstX, DstY, DstXE, DstYE, sSrcX, sSrcY, sExtX, sExtY, (LPBYTE)((LPSTR)lpDIBInfo + lpDIBInfo->biSize + GetSizeOfColorTable(lpDIBInfo)), (LPBITMAPINFO)lpDIBInfo, DIB_RGB_COLORS, (MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]))); return(TRUE); } BOOL bValidExtent(PMETAFILE16 pmf16, LPMETARECORD lpMR, DWORD cbSize) { #if 0 // No absolute pointer validations as the records can be copied and played back. BYTE *pB = (BYTE*)pmf16->hMem; BYTE *pE = (BYTE*)lpMR + cbSize; #endif if (pmf16->fl & MF16_DISKFILE) { UINT64 fileSize; if (!GetFileSizeEx(pmf16->hFile, (PLARGE_INTEGER)&fileSize)) { EMFVALFAIL(("GetFileSize(%p) failed\n", pmf16->hFile)); return(FALSE); } if (cbSize > fileSize) { EMFVALFAIL(("Record Size (%d) larger than file size (%d)!\n", cbSize, (UINT32)fileSize)); return(FALSE); } } else { if (cbSize > (((PMETAHEADER)pmf16->hMem)->mtSize * sizeof(WORD))) { EMFVALFAIL(("Record Size (%d) larger than file size (%d)!\n", cbSize, (UINT32)(((PMETAHEADER)pmf16->hMem)->mtSize * sizeof(WORD)))); return(FALSE); } } #if 0 // No absolute pointer validations as the records can be copied and played back. if (pE < pB) { EMFVALFAIL(("End pointer(%p) is less than Begin pointer (%p). Arithmetic wrap around!\n", pE, pB)); return(FALSE); } #endif return (TRUE); } /***************************** Internal Function **************************\ * GetEvent * * This routine will now open a disk metafile in READ_ONLY mode. This will * allow us to play read-only metafiles or to share such file. * * To start the enumeration, the first lpMR must be NULL. * It does not enumerate the first (header) and last (terminator) records. * * Returns: Next MetaFile Record to be played * NULL if the next metafile record is the EOF record * -1 if an error occurs. * \***************************************************************************/ PMETARECORD GetEvent(PMETAFILE16 pmf16, PMETARECORD lpMR) { PMETARECORD lpMRNext; PUTS("GetEvent\n"); if (lpMR == (PMETARECORD) NULL) { if (!bValidExtent(pmf16, (PMETARECORD)pmf16, sizeof(METAHEADER))) { EMFVALFAIL(("GetEvent: bValidExtent(%p) (%p) (%08x) failed\n", pmf16, pmf16, sizeof(METAHEADER))); return((PMETARECORD) -1); } pmf16->iMem = sizeof(METAHEADER); } else { if (lpMR->rdSize * sizeof(WORD) < lpMR->rdSize) { EMFVALFAIL(("GetEvent: arithmetic overflow\n")); return((PMETARECORD) -1); } if (lpMR->rdSize == 0 || !bValidExtent(pmf16, lpMR, lpMR->rdSize * sizeof(WORD))) { EMFVALFAIL(("GetEvent: bValidExtent(%p) (%p) (%08x) failed\n", pmf16, lpMR, lpMR->rdSize * sizeof(WORD))); return((PMETARECORD) -1); } pmf16->iMem += (lpMR->rdSize * sizeof(WORD)); } // Make sure that we don't read past the EOF. A minimal record includes // rdSize (DWORD) and rdFunction (WORD). if (pmf16->iMem > pmf16->metaHeader.mtSize * sizeof(WORD) - sizeof(DWORD) - sizeof(WORD)) { VERIFYGDI(FALSE, "GetEvent: Metafile contains bad data\n"); return((PMETARECORD) -1); } lpMRNext = (PMETARECORD) ((LPBYTE) pmf16->hMem + pmf16->iMem); // If we are at the end of the metafile then return NULL. if (lpMRNext->rdFunction == 0) return((PMETARECORD) NULL); return(lpMRNext); } /***************************** Internal Function **************************\ * BOOL GDIENTRY PlayMetaFileRecord * * Plays a metafile record by executing the GDI function call contained * withing the metafile record * * Effects: * \***************************************************************************/ //LPSTR lpZapfDingbats = "ZAPFDINGBATS"; //LPSTR lpZapf_Dingbats = "ZAPF DINGBATS"; //LPSTR lpSymbol = "SYMBOL"; //LPSTR lpTmsRmn = "TMS RMN"; //LPSTR lpHelv = "HELV"; #define PITCH_MASK ( FIXED_PITCH | VARIABLE_PITCH ) BOOL APIENTRY PlayMetaFileRecord( HDC hdc, LPHANDLETABLE lpHandleTable, LPMETARECORD lpMR, UINT noObjs ) { BOOL fStatus = FALSE; LPMETARECORD lpMRdup = (LPMETARECORD) NULL; WORD magic; HANDLE hObject; HANDLE hOldObject; HBRUSH hBrush; HRGN hRgn; HANDLE hPal; PUTSX("PlayMetaFileRecord 0x%p\n", lpMR); magic = lpMR->rdFunction; switch (magic & 255) { case (META_BITBLT & 255): case (META_STRETCHBLT & 255): { HDC hSDC; HANDLE hBitmap; PBITMAP16 lpBitmap16; INT delta = 0; DWORD rop; WARNING("PlayMetaFileRecord: obsolete META_BITBLT/META_STRETCHBLT record\n"); /* if playing into another Metafile, do direct copy */ if (PlayIntoAMetafile(lpMR, hdc)) { fStatus = TRUE; break; } if ((lpMR->rdSize - 3) == ((DWORD) magic >> 8)) { hSDC = hdc; delta = 1; } else { LPMETARECORD lpMRtmp; // Make the bitmap bits dword aligned. To do this, // lpMR has to fall on a dword aligned even address so that // the bitmap bits (&lpMR->rdParm[8+5] or &lpMR->rdParm[10+5]) // will fall on the dword aligned addresses. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD)))) break; lpMRtmp = lpMRdup; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); if (hSDC = CreateCompatibleDC(hdc)) { if (magic == META_BITBLT) lpBitmap16 = (PBITMAP16) &lpMRtmp->rdParm[8]; else lpBitmap16 = (PBITMAP16) &lpMRtmp->rdParm[10]; if (hBitmap = CreateBitmap(lpBitmap16->bmWidth, lpBitmap16->bmHeight, lpBitmap16->bmPlanes, lpBitmap16->bmBitsPixel, (LPBYTE)&lpBitmap16->bmBits)) hOldObject = SelectObject(hSDC, hBitmap); else goto PMFR_BitBlt_cleanup; } else break; } rop = MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]); if (magic == META_BITBLT) fStatus = BitBlt(hdc, (int) (SHORT) lpMR->rdParm[7 + delta], (int) (SHORT) lpMR->rdParm[6 + delta], (int) (SHORT) lpMR->rdParm[5 + delta], (int) (SHORT) lpMR->rdParm[4 + delta], (delta && !ISSOURCEINROP3(rop)) ? 0 : hSDC, (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], rop); else fStatus = StretchBlt(hdc, (int) (SHORT) lpMR->rdParm[9 + delta], (int) (SHORT) lpMR->rdParm[8 + delta], (int) (SHORT) lpMR->rdParm[7 + delta], (int) (SHORT) lpMR->rdParm[6 + delta], (delta && !ISSOURCEINROP3(rop)) ? 0 : hSDC, (int) (SHORT) lpMR->rdParm[5], (int) (SHORT) lpMR->rdParm[4], (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], rop); if (hSDC != hdc) { if (!SelectObject(hSDC, hOldObject)) ASSERTGDI(FALSE, "PlayMetaFileRecord: SelectObject Bitblt Failed\n"); if (!DeleteObject(hBitmap)) ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject Bitblt Failed\n"); PMFR_BitBlt_cleanup: if (!DeleteDC(hSDC)) ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteDC BitBlt Failed\n"); } } break; case (META_DIBBITBLT & 255): case (META_DIBSTRETCHBLT & 255): { HDC hSDC; HANDLE hBitmap; LPBITMAPINFOHEADER lpDIBInfo ; INT delta = 0; HANDLE hOldPal; /* if playing into another metafile, do direct copy */ if (PlayIntoAMetafile(lpMR, hdc)) { fStatus = TRUE; break; } if ((lpMR->rdSize - 3) == ((DWORD) magic >> 8)) { hSDC = hdc; delta = 1; } else { LPMETARECORD lpMRtmp; // Make the bitmap info and bits dword aligned. To do this, // lpMR has to fall on a non dword aligned even address so that // the bitmap info (&lpMR->rdParm[8] or &lpMR->rdParm[10]) and // the bitmap bits will fall on the dword aligned addresses. // Note that the size of the bitmap info is always a multiple // of 4. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD)))) break; lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1]; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); if (UseStretchDIB(hdc, magic, lpMRtmp)) { fStatus = TRUE; break; } if (hSDC = CreateCompatibleDC(hdc)) { /* set up the memDC to have the same palette */ hOldPal = SelectPalette(hSDC, GetCurrentObject(hdc,OBJ_PAL), TRUE); if (magic == META_DIBBITBLT) lpDIBInfo = (LPBITMAPINFOHEADER)&lpMRtmp->rdParm[8]; else lpDIBInfo = (LPBITMAPINFOHEADER)&lpMRtmp->rdParm[10]; /* now create the bitmap for the MemDC and fill in the bits */ /* the processing for old and new format of metafiles is different here (till hBitmap is obtained) */ /* new metafile version */ hBitmap = CreateBitmapForDC (hdc,lpDIBInfo); if (hBitmap) hOldObject = SelectObject (hSDC, hBitmap) ; else goto PMFR_DIBBITBLT_cleanup; } else break; } if (magic == META_DIBBITBLT) fStatus = BitBlt(hdc, (int) (SHORT) lpMR->rdParm[7 + delta], (int) (SHORT) lpMR->rdParm[6 + delta], (int) (SHORT) lpMR->rdParm[5 + delta], (int) (SHORT) lpMR->rdParm[4 + delta], delta ? 0 : hSDC, (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1])); else fStatus = StretchBlt(hdc, (int) (SHORT) lpMR->rdParm[9 + delta], (int) (SHORT) lpMR->rdParm[8 + delta], (int) (SHORT) lpMR->rdParm[7 + delta], (int) (SHORT) lpMR->rdParm[6 + delta], delta ? 0 : hSDC, (int) (SHORT) lpMR->rdParm[5], (int) (SHORT) lpMR->rdParm[4], (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1])); if (hSDC != hdc) { /* Deselect hDC's palette from memDC */ SelectPalette(hSDC, hOldPal, TRUE); if (!SelectObject(hSDC, hOldObject)) ASSERTGDI(FALSE, "PlayMetaFileRecord: SelectObject DIBBitBlt Failed\n"); if (!DeleteObject(hBitmap)) ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) DIBBitBlt Failed\n"); PMFR_DIBBITBLT_cleanup: if (!DeleteDC(hSDC)) ASSERTGDI(FALSE, "PlayMetaFileRecord DeleteDC DIBBitblt failed\n"); } } break; case (META_SELECTOBJECT & 255): { if (hObject = lpHandleTable->objectHandle[lpMR->rdParm[0]]) { fStatus = SelectObject(hdc, hObject) != (HANDLE)0; // new in win3.1 if (!fStatus) { switch (GetObjectType(hObject)) { case OBJ_PAL: SelectObject(hdc, (HGDIOBJ) GetStockObject(DEFAULT_PALETTE)); break; case OBJ_BRUSH: SelectObject(hdc, (HGDIOBJ) GetStockObject(WHITE_BRUSH)); break; case OBJ_PEN: SelectObject(hdc, (HGDIOBJ) GetStockObject(BLACK_PEN)); break; case OBJ_FONT: SelectObject(hdc, (HGDIOBJ) GetStockObject(DEVICE_DEFAULT_FONT)); break; case OBJ_REGION: SelectClipRgn(hdc, 0); break; default: ASSERTGDI(FALSE, "PlayMetaFileRecord:SELECTOBJECT unknown object\n"); break; } } } } break; case (META_CREATEPENINDIRECT & 255): { LOGPEN lp; LOGPEN32FROMLOGPEN16(&lp, (PLOGPEN16) &lpMR->rdParm[0]); if (hObject = CreatePenIndirect(&lp)) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); } break; case (META_CREATEFONTINDIRECT & 255): { LOGFONTA lf; PLOGFONT16 plf16 = (PLOGFONT16) &lpMR->rdParm[0]; CHAR achCapString[LF_FACESIZE]; LOGFONT32FROMLOGFONT16(&lf, (PLOGFONT16) &lpMR->rdParm[0]); // Capitalize the string for faster compares. lstrcpynA(achCapString, lf.lfFaceName, LF_FACESIZE); CharUpperBuffA(achCapString, LF_FACESIZE); // Here we are going to implement a bunch of Win 3.1 hacks rather // than contaminate the 32-bit engine. These same hacks can be found // in WOW (in the CreateFont/CreateFontIndirect code). // // These hacks are keyed off the facename in the LOGFONTA. String // comparisons have been unrolled for maximal performance. // Win 3.1 facename-based hack. Some apps, like // Publisher, create a "Helv" font but have the lfPitchAndFamily // set to specify FIXED_PITCH. To work around this, we will patch // the pitch field for a "Helv" font to be variable. // if ( !lstrcmp(achCapString, lpHelv) ) if ( ((achCapString[0] == 'H') && (achCapString[1] == 'E') && (achCapString[2] == 'L') && (achCapString[3] == 'V') && (achCapString[4] == '\0')) ) { lf.lfPitchAndFamily |= ( (lf.lfPitchAndFamily & ~PITCH_MASK) | VARIABLE_PITCH ); } else { // Win 3.1 hack for Legacy 2.0. When a printer does not enumerate // a "Tms Rmn" font, the app enumerates and gets the LOGFONTA for // "Script" and then create a font with the name "Tms Rmn" but with // the lfCharSet and lfPitchAndFamily taken from the LOGFONTA for // "Script". Here we will over the lfCharSet to be ANSI_CHARSET. // if ( !lstrcmp(achCapString, lpTmsRmn) ) if ( ((achCapString[0] == 'T') && (achCapString[1] == 'M') && (achCapString[2] == 'S') && (achCapString[3] == ' ') && (achCapString[4] == 'R') && (achCapString[5] == 'M') && (achCapString[6] == 'N') && (achCapString[7] == '\0')) ) { lf.lfCharSet = ANSI_CHARSET; } else { // If the lfFaceName is "Symbol", "Zapf Dingbats", or "ZapfDingbats", // enforce lfCharSet to be SYMBOL_CHARSET. Some apps (like Excel) ask // for a "Symbol" font but have the char set set to ANSI. PowerPoint // has the same problem with "Zapf Dingbats". //if ( !lstrcmp(achCapString, lpSymbol) || // !lstrcmp(achCapString, lpZapfDingbats) || // !lstrcmp(achCapString, lpZapf_Dingbats) ) if ( ((achCapString[0] == 'S') && (achCapString[1] == 'Y') && (achCapString[2] == 'M') && (achCapString[3] == 'B') && (achCapString[4] == 'O') && (achCapString[5] == 'L') && (achCapString[6] == '\0')) || ((achCapString[0] == 'Z') && (achCapString[1] == 'A') && (achCapString[2] == 'P') && (achCapString[3] == 'F') && (achCapString[4] == 'D') && (achCapString[5] == 'I') && (achCapString[6] == 'N') && (achCapString[7] == 'G') && (achCapString[8] == 'B') && (achCapString[9] == 'A') && (achCapString[10] == 'T') && (achCapString[11] == 'S') && (achCapString[12] == '\0')) || ((achCapString[0] == 'Z') && (achCapString[1] == 'A') && (achCapString[2] == 'P') && (achCapString[3] == 'F') && (achCapString[4] == ' ') && (achCapString[5] == 'D') && (achCapString[6] == 'I') && (achCapString[7] == 'N') && (achCapString[8] == 'G') && (achCapString[9] == 'B') && (achCapString[10] == 'A') && (achCapString[11] == 'T') && (achCapString[12] == 'S') && (achCapString[13] == '\0')) ) { lf.lfCharSet = SYMBOL_CHARSET; } } } if (hObject = CreateFontIndirectA(&lf)) { fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); } } break; case (META_CREATEPATTERNBRUSH & 255): { HANDLE hBitmap; BITMAP Bitmap; LPMETARECORD lpMRtmp; WARNING("PlayMetaFileRecord: obsolete META_CREATEPATTERNBRUSH record\n"); // Make the bitmap bits dword aligned. To do this, // lpMR has to fall on a non dword aligned even address so that // the bitmap bits (bmBits) will fall on the dword aligned address. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD)))) break; lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1]; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); BITMAP32FROMBITMAP16(&Bitmap, (PBITMAP16) &lpMRtmp->rdParm[0]); // The magic number 18 is based on the IPBITMAP structure in win3.1 Bitmap.bmBits = (PBYTE) &lpMRtmp->rdParm + sizeof(BITMAP16) + 18; if (hBitmap = CreateBitmapIndirect(&Bitmap)) { if (hObject = CreatePatternBrush(hBitmap)) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); if (!DeleteObject(hBitmap)) ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) CreatePatternBrush Failed\n"); } } break; case (META_DIBCREATEPATTERNBRUSH & 255): { HDC hMemDC ; HANDLE hBitmap; LPBITMAPINFOHEADER lpDIBInfo ; LPMETARECORD lpMRtmp; // Make the bitmap info and bits dword aligned. To do this, // lpMR has to fall on a non dword aligned even address so that // the bitmap info (&lpMR->rdParm[2]) and // the bitmap bits will fall on the dword aligned addresses. // Note that the size of the bitmap info is always a multiple // of 4. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD)))) break; lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1]; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); if (lpMRtmp->rdParm[0] == BS_PATTERN) { /* the address of the second paramter is the address of the DIB header, extract it */ lpDIBInfo = (LPBITMAPINFOHEADER) &lpMRtmp->rdParm[2]; /* now create a device dependend bitmap compatible to the default screen DC - hScreenDC and extract the bits from the DIB into it. The following function does all these, and returns a HANDLE to the device dependent BItmap. */ /* we will use a dummy memory DC compatible to the screen DC */ hMemDC = CreateCompatibleDC((HDC)NULL); if (!hMemDC) { ERROR_ASSERT(FALSE, "PlayMetaRecord: CreateCompDC Failed\n"); break; } hBitmap = CreateBitmapForDC(hMemDC,lpDIBInfo); if (hBitmap) { if (hObject = CreatePatternBrush(hBitmap)) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); if (!DeleteObject(hBitmap)) ASSERTGDI(FALSE, "PlayMetaFileRecord: DeleteObject(hBitmap) DIBCreatePatternBrush Failed\n"); } /* delete the dummy memory DC for new version Metafiles*/ if (!DeleteDC (hMemDC)) ASSERTGDI(FALSE, "PlayMetaRecord: DeleteDC DIBCreatePatternBrush Failed\n"); } /* this is a DIBPattern brush */ else { if (hObject = CreateDIBPatternBrushPt((LPVOID)&lpMRtmp->rdParm[2], (DWORD) lpMRtmp->rdParm[1])) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); } } break; case (META_CREATEBRUSHINDIRECT & 255): { LOGBRUSH lb; LOGBRUSH32FROMLOGBRUSH16(&lb, (PLOGBRUSH16) &lpMR->rdParm[0]); if (hObject = CreateBrushIndirect(&lb)) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); } break; case (META_POLYLINE & 255): case (META_POLYGON & 255): { PPOINTL pptl; UINT cpts = lpMR->rdParm[0]; if (!(pptl = (PPOINTL) LocalAlloc (LMEM_FIXED, (UINT) cpts * sizeof(POINTL)))) break; INT32FROMINT16(pptl, &lpMR->rdParm[1], cpts * 2); switch (magic) { case META_POLYGON: fStatus = Polygon(hdc, (LPPOINT) pptl, (int) cpts); break; case META_POLYLINE: fStatus = Polyline(hdc, (LPPOINT) pptl, (int) cpts); break; default: ASSERTGDI(FALSE, "Bad record type"); break; } if (LocalFree(pptl)) ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n"); } break; case (META_POLYPOLYGON & 255): { PPOINTL pptl; LPINT lpPolyCount; PBYTE pb; UINT ii; UINT cpts = 0; UINT cPoly = lpMR->rdParm[0]; for (ii = 0; ii < cPoly; ii++) cpts += ((LPWORD)&lpMR->rdParm[1])[ii]; if (!(pb = (PBYTE) LocalAlloc ( LMEM_FIXED, cPoly * sizeof(INT) + cpts * sizeof(POINTL) ) ) ) break; lpPolyCount = (LPINT) pb; pptl = (PPOINTL) (pb + cPoly * sizeof(INT)); for (ii = 0; ii < cPoly; ii++) lpPolyCount[ii] = (INT) (UINT) ((LPWORD)&lpMR->rdParm[1])[ii]; INT32FROMINT16(pptl, &lpMR->rdParm[1] + cPoly, cpts * 2); fStatus = PolyPolygon(hdc, (LPPOINT) pptl, lpPolyCount, (int) cPoly); if (LocalFree((HANDLE) pb)) ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n"); } break; case (META_EXTTEXTOUT & 255): { PSHORT lpdx16; LPINT lpdx; LPSTR lpch; RECT rc; LPRECT lprc; lprc = (lpMR->rdParm[3] & (ETO_OPAQUE|ETO_CLIPPED)) ? (LPRECT) &lpMR->rdParm[4] : (LPRECT) NULL; if (lprc) { rc.left = ((PRECT16)lprc)->left; rc.right = ((PRECT16)lprc)->right; rc.top = ((PRECT16)lprc)->top; rc.bottom = ((PRECT16)lprc)->bottom; lprc = &rc; } lpch = (LPSTR)&lpMR->rdParm[4] + ((lprc) ? sizeof(RECT16) : 0); /* dx array starts at next word boundary after char string */ lpdx16 = (PSHORT) (lpch + ((lpMR->rdParm[2] + 1) / 2 * 2)); /* check to see if there is a Dx array by seeing if structure ends after the string itself */ if (((DWORD)((LPWORD)lpdx16 - (LPWORD)(lpMR))) >= lpMR->rdSize) lpdx = NULL; else { lpdx = (LPINT)LocalAlloc(LMEM_FIXED, lpMR->rdParm[2]*sizeof(INT)); if (!lpdx) { ERROR_ASSERT(FALSE, "PlayMetaFileRecord: out of memory exttextout"); break; } INT32FROMINT16(lpdx, lpdx16, (UINT) lpMR->rdParm[2]); } // Mask off bit 0x80 that an old Excel used to add to its // Metafiles and the GDI errors on. fStatus = ExtTextOutA(hdc, (int) (SHORT) lpMR->rdParm[1], (int) (SHORT) lpMR->rdParm[0], gbLpk ? ((UINT) lpMR->rdParm[3]) : ((UINT) lpMR->rdParm[3] & ~ETO_RTLREADING), lprc, lpch, (UINT) lpMR->rdParm[2], lpdx); if (lpdx) if (LocalFree((HANDLE)lpdx)) ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n"); break; } case (META_TEXTOUT & 255): fStatus = TextOutA(hdc, (int) (SHORT) lpMR->rdParm[lpMR->rdSize-4], (int) (SHORT) lpMR->rdParm[lpMR->rdSize-5], (LPSTR) &lpMR->rdParm[1], (int) (UINT) lpMR->rdParm[0]); break; case (META_ESCAPE & 255): if (!(fStatus = PlayIntoAMetafile(lpMR, hdc))) { if ((int)(UINT)lpMR->rdParm[0] != MFCOMMENT) { fStatus = Escape(hdc, (int) (UINT) lpMR->rdParm[0], (int) (UINT) lpMR->rdParm[1], (LPCSTR) &lpMR->rdParm[2], (LPVOID) NULL) != 0; } else { fStatus = TRUE; } } break; case (META_FRAMEREGION & 255): if ((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]]) && (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]])) fStatus = FrameRgn(hdc, hRgn, hBrush, (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2]); break; case (META_PAINTREGION & 255): if (hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]]) fStatus = PaintRgn(hdc, hRgn); break; case (META_INVERTREGION & 255): if (hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]]) fStatus = InvertRgn(hdc, hRgn); break; case (META_FILLREGION & 255): if ((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]]) && (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]])) fStatus = FillRgn(hdc, hRgn, hBrush); 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 read a win2 header with region, and actually *** create a win3 header with same region internals */ case (META_CREATEREGION & 255): { HRGN hrgn; PSHORT pXs; PWIN3REGION pW3Rgn = (PWIN3REGION) lpMR->rdParm; UINT ii, jj; UINT cscn; PSCAN pscn; DWORD nrcl; PRECTL prcl; UINT cRgnData; PRGNDATA pRgnData; cscn = (UINT) pW3Rgn->cScans; // Handle the empty region. if (!cscn) { hrgn = CreateRectRgn(0, 0, 0, 0); fStatus = AddToHandleTable(lpHandleTable, hrgn, noObjs); break; } // Count the number of rectangles in the region. nrcl = 0; pscn = pW3Rgn->aScans; for (ii = 0; ii < cscn; ii++) { nrcl += pscn->scnPntCnt / 2; pscn = (PSCAN) ((PBYTE) pscn + sizeof(SCAN) - 2 * sizeof(WORD) + (int) (UINT) pscn->scnPntCnt * sizeof(WORD)); } cRgnData = sizeof(RGNDATAHEADER) + nrcl * sizeof(RECTL); if (!(pRgnData = (PRGNDATA) LocalAlloc(LMEM_FIXED, cRgnData))) break; pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); pRgnData->rdh.iType = RDH_RECTANGLES; pRgnData->rdh.nCount = nrcl; pRgnData->rdh.nRgnSize = 0; pRgnData->rdh.rcBound.left = (LONG) pW3Rgn->rcBounding.left ; pRgnData->rdh.rcBound.top = (LONG) pW3Rgn->rcBounding.top ; pRgnData->rdh.rcBound.right = (LONG) pW3Rgn->rcBounding.right ; pRgnData->rdh.rcBound.bottom = (LONG) pW3Rgn->rcBounding.bottom ; prcl = (PRECTL) pRgnData->Buffer; pscn = pW3Rgn->aScans; for (ii = 0; ii < cscn; ii++) { pXs = (PSHORT) pscn->scnPntsX; for (jj = pscn->scnPntCnt / 2; jj; jj--) { prcl->left = (LONG) (*pXs++); prcl->top = (LONG) (SHORT) pscn->scnPntTop; prcl->right = (LONG) (*pXs++); prcl->bottom = (LONG) (SHORT) pscn->scnPntBottom; prcl++; } pscn = (PSCAN) ((PBYTE) pscn + sizeof(SCAN) - 2 * sizeof(WORD) + (int) (UINT) pscn->scnPntCnt * sizeof(WORD)); } hrgn = ExtCreateRegion((LPXFORM) NULL, cRgnData, pRgnData); fStatus = AddToHandleTable(lpHandleTable, hrgn, noObjs); if (LocalFree((HANDLE) pRgnData)) ASSERTGDI(FALSE, "PlayMetaRecord: LocalFree failed\n"); } break; case (META_DELETEOBJECT & 255): { HANDLE h; if (h = lpHandleTable->objectHandle[lpMR->rdParm[0]]) { if (!(fStatus = DeleteObject(h))) ERROR_ASSERT(FALSE, "PlayMetaFileRecord: DeleteObject(h) Failed\n"); lpHandleTable->objectHandle[lpMR->rdParm[0]] = NULL; } } break; case (META_CREATEPALETTE & 255): { LPMETARECORD lpMRtmp; // Make the logical palette dword aligned. To do this, // lpMR has to fall on a non dword aligned even address so that // the logical palette (&lpMR->rdParm[0]) will fall on the // dword aligned address. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD)))) break; lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1]; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); if (hObject = CreatePalette((LPLOGPALETTE)&lpMRtmp->rdParm[0])) fStatus = AddToHandleTable(lpHandleTable, hObject, noObjs); } break; case (META_SELECTPALETTE & 255): if (hPal = lpHandleTable->objectHandle[lpMR->rdParm[0]]) fStatus = SelectPalette(hdc, hPal, 0) != 0; break; case (META_REALIZEPALETTE & 255): fStatus = RealizePalette(hdc) != -1; break; case (META_SETPALENTRIES & 255): case (META_ANIMATEPALETTE & 255): { LPMETARECORD lpMRtmp; // Make the palette entry array dword aligned. To do this, // lpMR has to fall on a non dword aligned even address so that // the palette entry array (&lpMR->rdParm[2]) will fall on the // dword aligned address. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD) + sizeof(WORD)))) break; lpMRtmp = (LPMETARECORD) &((PWORD) lpMRdup)[1]; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); // we know the palette being set is the current palette if (magic == META_SETPALENTRIES) fStatus = SetPaletteEntries(GetCurrentObject(hdc,OBJ_PAL), (UINT) lpMRtmp->rdParm[0], (UINT) lpMRtmp->rdParm[1], (LPPALETTEENTRY)&lpMRtmp->rdParm[2] ) != 0; else fStatus = AnimatePalette(GetCurrentObject(hdc,OBJ_PAL), (UINT) lpMR->rdParm[0], (UINT) lpMR->rdParm[1], (LPPALETTEENTRY)&lpMR->rdParm[2]); } break; case (META_RESIZEPALETTE & 255): fStatus = ResizePalette(GetCurrentObject(hdc,OBJ_PAL), (UINT) lpMR->rdParm[0]); break; case (META_SETDIBTODEV & 255): { LPBITMAPINFOHEADER lpBitmapInfo; DWORD ColorSize; LPMETARECORD lpMRtmp; /* if playing into another metafile, do direct copy */ if (PlayIntoAMetafile(lpMR, hdc)) { fStatus = TRUE; break; } // Make the bitmap info and bits dword aligned. To do this, // lpMR has to fall on a dword aligned address so that // the bitmap info (&lpMR->rdParm[9]) and // the bitmap bits will fall on the dword aligned addresses. // Note that the size of the bitmap info is always a multiple // of 4. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD)))) break; lpMRtmp = lpMRdup; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMRtmp->rdParm[9]); if (lpBitmapInfo->biBitCount == 16 || lpBitmapInfo->biBitCount == 32) ColorSize = 3 * sizeof(DWORD); else if (lpBitmapInfo->biClrUsed) ColorSize = lpBitmapInfo->biClrUsed * (DWORD)(lpMRtmp->rdParm[0] == DIB_RGB_COLORS ? sizeof(RGBQUAD) : sizeof(WORD)); else if (lpBitmapInfo->biBitCount == 24) ColorSize = 0; else ColorSize = (DWORD)(1 << lpBitmapInfo->biBitCount) * (DWORD)(lpMRtmp->rdParm[0] == DIB_RGB_COLORS ? sizeof(RGBQUAD) : sizeof(WORD)); ColorSize = (ColorSize + 3) / 4 * 4; // make sure it is aligned ColorSize += lpBitmapInfo->biSize; fStatus = SetDIBitsToDevice(hdc, (int) (SHORT) lpMRtmp->rdParm[8], (int) (SHORT) lpMRtmp->rdParm[7], (DWORD) (int) (SHORT)lpMRtmp->rdParm[6], (DWORD) (int) (SHORT)lpMRtmp->rdParm[5], (int) (SHORT) lpMRtmp->rdParm[4], (int) (SHORT) lpMRtmp->rdParm[3], (UINT) lpMRtmp->rdParm[2], (UINT) lpMRtmp->rdParm[1], (PBYTE)(((PBYTE)lpBitmapInfo) + ColorSize), (LPBITMAPINFO) lpBitmapInfo, (DWORD) lpMRtmp->rdParm[0] ) != 0; } break; case (META_STRETCHDIB & 255): { LPBITMAPINFOHEADER lpBitmapInfo; DWORD ColorSize; LPMETARECORD lpMRtmp; /* if playing into another metafile, do direct copy */ if (PlayIntoAMetafile(lpMR, hdc)) { fStatus = TRUE; break; } // Make the bitmap info and bits dword aligned. To do this, // lpMR has to fall on a dword aligned address so that // the bitmap info (&lpMR->rdParm[11]) and // the bitmap bits will fall on the dword aligned addresses. // Note that the size of the bitmap info is always a multiple // of 4. if (!(lpMRdup = (LPMETARECORD) LocalAlloc(LMEM_FIXED, (UINT) lpMR->rdSize * sizeof(WORD)))) break; lpMRtmp = lpMRdup; RtlCopyMemory((PBYTE) lpMRtmp, (PBYTE) lpMR, (UINT) lpMR->rdSize * sizeof(WORD)); // // rdsize is SIZEOF_METARECORDHEADER/sizeof(WORD) + cw; // where cw is from MF16_RecordDIBits (11) // if (lpMR->rdSize > SIZEOF_METARECORDHEADER/sizeof(WORD) + 11) { lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMRtmp->rdParm[11]); if (lpBitmapInfo->biBitCount == 16 || lpBitmapInfo->biBitCount == 32) ColorSize = 3 * sizeof(DWORD); else if (lpBitmapInfo->biClrUsed) ColorSize = lpBitmapInfo->biClrUsed * (DWORD)(lpMRtmp->rdParm[2] == DIB_RGB_COLORS ? sizeof(RGBQUAD) : sizeof(WORD)); else if (lpBitmapInfo->biBitCount == 24) ColorSize = 0; else ColorSize = (DWORD)(1 << lpBitmapInfo->biBitCount) * (DWORD)(lpMRtmp->rdParm[2] == DIB_RGB_COLORS ? sizeof(RGBQUAD) : sizeof(WORD)); ColorSize = (ColorSize + 3) / 4 * 4; // make sure it is aligned ColorSize += lpBitmapInfo->biSize; } else { lpBitmapInfo = NULL; } fStatus = StretchDIBits(hdc, (int) (SHORT) lpMRtmp->rdParm[10], (int) (SHORT) lpMRtmp->rdParm[9], (int) (SHORT) lpMRtmp->rdParm[8], (int) (SHORT) lpMRtmp->rdParm[7], (int) (SHORT) lpMRtmp->rdParm[6], (int) (SHORT) lpMRtmp->rdParm[5], (int) (SHORT) lpMRtmp->rdParm[4], (int) (SHORT) lpMRtmp->rdParm[3], lpBitmapInfo ? (LPBYTE)(((PBYTE)lpBitmapInfo) + ColorSize) : NULL, (LPBITMAPINFO) lpBitmapInfo, (DWORD) lpMRtmp->rdParm[2], MAKELONG(lpMRtmp->rdParm[0], lpMRtmp->rdParm[1]) ) != ERROR; } break; // Function that have new parameters on WIN32 // Or have DWORDs that stayed DWORDs; all other INTs to DWORDs case (META_PATBLT & 255): fStatus = PatBlt(hdc, (int) (SHORT) lpMR->rdParm[5], (int) (SHORT) lpMR->rdParm[4], (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1])); break; case (META_MOVETO & 255): fStatus = MoveToEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], NULL); break; case (META_RESTOREDC & 255): fStatus = RestoreDC(hdc, (int)(SHORT)lpMR->rdParm[0]); break; case (META_SETBKCOLOR & 255): fStatus = SetBkColor(hdc, *(COLORREF UNALIGNED *)lpMR->rdParm) != CLR_INVALID; break; case (META_SETTEXTCOLOR & 255): fStatus = SetTextColor(hdc, *(COLORREF UNALIGNED *)lpMR->rdParm) != CLR_INVALID; break; case (META_SETPIXEL & 255): fStatus = SetPixel(hdc, (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], *(COLORREF UNALIGNED *) lpMR->rdParm ) != CLR_INVALID; break; case (META_SETMAPPERFLAGS & 255): fStatus = SetMapperFlags(hdc, *(DWORD UNALIGNED *)lpMR->rdParm) != GDI_ERROR; break; case (META_FLOODFILL & 255): fStatus = FloodFill(hdc, (int) (SHORT) lpMR->rdParm[3], (int) (SHORT) lpMR->rdParm[2], *(COLORREF UNALIGNED *) lpMR->rdParm); break; case (META_EXTFLOODFILL & 255): fStatus = ExtFloodFill(hdc, (int) (SHORT) lpMR->rdParm[4], (int) (SHORT) lpMR->rdParm[3], *(COLORREF UNALIGNED *) &lpMR->rdParm[1], (UINT) lpMR->rdParm[0]); break; case (META_SCALEWINDOWEXT & 255): fStatus = ScaleWindowExtEx(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], NULL); break; case (META_SCALEVIEWPORTEXT & 255): fStatus = ScaleViewportExtEx(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], NULL); break; case (META_SETWINDOWORG & 255): fStatus = SetWindowOrgEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPPOINT) NULL); break; case (META_SETWINDOWEXT & 255): fStatus = SetWindowExtEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPSIZE) NULL); break; case (META_SETVIEWPORTORG & 255): fStatus = SetViewportOrgEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPPOINT) NULL); break; case (META_SETVIEWPORTEXT & 255): fStatus = SetViewportExtEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPSIZE) NULL); break; case (META_OFFSETWINDOWORG & 255): fStatus = OffsetWindowOrgEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPPOINT) NULL); break; case (META_OFFSETVIEWPORTORG & 255): fStatus = OffsetViewportOrgEx(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0], (LPPOINT) NULL); break; case (META_SETTEXTCHAREXTRA & 255): fStatus = SetTextCharacterExtra(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0x80000000; break; case (META_SETTEXTALIGN & 255): fStatus = SetTextAlign(hdc, (UINT)lpMR->rdParm[0]) != GDI_ERROR; break; case (META_SAVEDC & 255): fStatus = (SaveDC(hdc) != 0); break; case (META_SELECTCLIPREGION & 255): // Win3.1 has never got this right except when the handle is 0. hObject = (lpMR->rdParm[0] == 0) ? 0 : lpHandleTable->objectHandle[lpMR->rdParm[0]]; fStatus = (SelectClipRgn(hdc, hObject) != RGN_ERROR); break; case (META_SETBKMODE & 255): fStatus = (SetBkMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0); break; case (META_SETMAPMODE & 255): fStatus = (SetMapMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0); break; case (META_SETLAYOUT & 255): fStatus = (SetLayout(hdc, (DWORD)lpMR->rdParm[0]) != GDI_ERROR); break; case (META_SETPOLYFILLMODE & 255): fStatus = (SetPolyFillMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0); break; case (META_SETROP2 & 255): fStatus = (SetROP2(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0); break; case (META_SETSTRETCHBLTMODE & 255): fStatus = (SetStretchBltMode(hdc, (int)(SHORT)lpMR->rdParm[0]) != 0); break; case (META_LINETO & 255): fStatus = LineTo(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0]); break; case (META_OFFSETCLIPRGN & 255): fStatus = OffsetClipRgn(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ) != RGN_ERROR; break; case (META_SETTEXTJUSTIFICATION & 255): fStatus = SetTextJustification(hdc, (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0]); break; case (META_ELLIPSE & 255): fStatus = Ellipse(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0]); break; case (META_RECTANGLE & 255): fStatus = Rectangle(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0]); break; case (META_EXCLUDECLIPRECT & 255): fStatus = ExcludeClipRect(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ) != RGN_ERROR; break; case (META_INTERSECTCLIPRECT & 255): fStatus = IntersectClipRect(hdc, (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ) != RGN_ERROR; break; case (META_ROUNDRECT & 255): fStatus = RoundRect(hdc, (int)(SHORT)lpMR->rdParm[5], (int)(SHORT)lpMR->rdParm[4], (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ); break; case (META_ARC & 255): fStatus = Arc(hdc, (int)(SHORT)lpMR->rdParm[7], (int)(SHORT)lpMR->rdParm[6], (int)(SHORT)lpMR->rdParm[5], (int)(SHORT)lpMR->rdParm[4], (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ); break; case (META_CHORD & 255): fStatus = Chord(hdc, (int)(SHORT)lpMR->rdParm[7], (int)(SHORT)lpMR->rdParm[6], (int)(SHORT)lpMR->rdParm[5], (int)(SHORT)lpMR->rdParm[4], (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ); break; case (META_PIE & 255): fStatus = Pie(hdc, (int)(SHORT)lpMR->rdParm[7], (int)(SHORT)lpMR->rdParm[6], (int)(SHORT)lpMR->rdParm[5], (int)(SHORT)lpMR->rdParm[4], (int)(SHORT)lpMR->rdParm[3], (int)(SHORT)lpMR->rdParm[2], (int)(SHORT)lpMR->rdParm[1], (int)(SHORT)lpMR->rdParm[0] ); break; case (META_SETRELABS & 255): ERROR_ASSERT(FALSE, "PlayMetaFileRecord: unsupported META_SETRELABS record\n"); fStatus = TRUE; break; #if 0 case (META_CREATEBITMAP & 255): case (META_CREATEBITMAPINDIRECT & 255): case (META_CREATEBRUSH & 255): case (META_ABORTDOC & 255): case (META_ENDPAGE & 255): case (META_ENDDOC & 255): case (META_RESETDC & 255): case (META_STARTDOC & 255): case (META_STARTPAGE & 255): // not created or playbacked on Win3.1! ASSERTGDI(FALSE, "PlayMetaFileRecord: unsupported record\n"); fStatus = TRUE; break; #endif // 0 case 0: // End of metafile record fStatus = TRUE; break; default: VERIFYGDI(FALSE, "PlayMetaFileRecord: unknown record\n"); #if DBG DbgPrint("Record %lx pMFRecord %p magic %X\n", curRecord, lpMR, magic); #endif fStatus = TRUE; break; } // switch (magic & 255) if (lpMRdup) if (LocalFree((HANDLE) lpMRdup)) ASSERTGDI(FALSE, "LocalFree failed"); #if DBG if (!fStatus) { DbgPrint("PlayMetaFileRecord Record %lx pMFRecord %p magic %X\n", curRecord, lpMR, magic); ERROR_ASSERT(FALSE, "PlayMetaFileRecord Failing\n"); } #endif return(fStatus); } /****************************** Internal Function **************************\ * AddToHandleTable * * Adds an object to the metafile table of objects * * \***************************************************************************/ BOOL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, UINT noObjs) { UINT ii; PUTS("AddToHandleTable\n"); if (lpHandleTable == (LPHANDLETABLE) NULL) { ASSERTGDI(FALSE, "AddToHandleTable: lpHT is NULL\n"); return(FALSE); } /* linear search through table for first open slot */ for (ii = 0; ((lpHandleTable->objectHandle[ii] != NULL) && (ii < noObjs)); ++ii); if (ii < noObjs) /* ok index */ { lpHandleTable->objectHandle[ii] = hObject; return (TRUE); } else { ASSERTGDI(FALSE, "AddToHandleTable: Too many objects in table\n"); return(FALSE); } } BOOL IsValidMetaHeader16(PMETAHEADER pMetaHeader) { BOOL status; PUTS("IsValidMetaHeader16\n"); status = ( (pMetaHeader->mtType == MEMORYMETAFILE || pMetaHeader->mtType == DISKMETAFILE) && (pMetaHeader->mtHeaderSize == (sizeof(METAHEADER)/sizeof(WORD))) && ((pMetaHeader->mtVersion == METAVERSION300) || (pMetaHeader->mtVersion ==METAVERSION100)) ); ERROR_ASSERT(status, "IsValidMetaHeader16 is failing\n"); return status; } /****************************** Internal Function **************************\ * CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo) * * This routine takes a memory device context and a DIB bitmap, creates a * compatible bitmap for the DC and fills it with the bits from the DIB * converting to the device dependent format). The pointer to the DIB bits * start immediately after the color table in the INFO header. * * The routine returns the handle to the bitmap with the bits filled in if * everything goes well else it returns NULL. \***************************************************************************/ HANDLE CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo) { HBITMAP hBitmap ; LPBYTE lpDIBits ; PUTS("CreateBitmapForDC\n"); ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "CreateBitmapForDC: dword alignment error\n"); /* preserve monochrome if it started out as monochrome ** and check for REAL Black&white monochrome as opposed ** to a 2-color DIB */ if (IsDIBBlackAndWhite(lpDIBInfo)) hBitmap = CreateBitmap ((WORD)lpDIBInfo->biWidth, (WORD)lpDIBInfo->biHeight, 1, 1, (LPBYTE) NULL); else /* otherwise, make a compatible bitmap */ hBitmap = CreateCompatibleBitmap (hMemDC, (WORD)lpDIBInfo->biWidth, (WORD)lpDIBInfo->biHeight); if (!hBitmap) goto CreateBitmapForDCErr ; /* take a pointer past the header of the DIB, to the start of the color table */ lpDIBits = (LPBYTE) lpDIBInfo + lpDIBInfo->biSize; /* take the pointer past the color table */ lpDIBits += GetSizeOfColorTable (lpDIBInfo) ; /* get the bits from the DIB into the Bitmap */ if (!SetDIBits (hMemDC, hBitmap, 0, (WORD)lpDIBInfo->biHeight, lpDIBits, (LPBITMAPINFO)lpDIBInfo, DIB_RGB_COLORS)) { if (!DeleteObject(hBitmap)) ASSERTGDI(FALSE, "CreateBitmapForDC: DeleteObject(hBitmap) Failed\n"); goto CreateBitmapForDCErr ; } /* return success */ return (hBitmap) ; CreateBitmapForDCErr: /* returm failure for function */ return (NULL); } /****************************** Internal Function **************************\ * GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo) * * Returns the number of bytes in the color table for the giving info header * \***************************************************************************/ WORD GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo) { PUTS("GetSizeOfColorTable\n"); ASSERTGDI(!((ULONG_PTR) lpDIBInfo & 0x3), "GetSizeOfColorTable: dword alignment error\n"); if (lpDIBInfo->biBitCount == 16 || lpDIBInfo->biBitCount == 32) return(3 * sizeof(DWORD)); if (lpDIBInfo->biClrUsed) return((WORD)lpDIBInfo->biClrUsed * (WORD)sizeof(RGBQUAD)); if (lpDIBInfo->biBitCount < 16) return((1 << lpDIBInfo->biBitCount) * sizeof(RGBQUAD)); else return(0); } /***************************** Public Function ****************************\ * BOOL APIENTRY DeleteMetaFile(hmf) * * Frees a metafile handle. * * Effects: * \***************************************************************************/ BOOL APIENTRY DeleteMetaFile(HMETAFILE hmf) { PMETAFILE16 pmf16; PUTS("DeleteMetaFile\n"); pmf16 = GET_PMF16(hmf); if (pmf16 == NULL) { GdiSetLastError(ERROR_INVALID_HANDLE); return(FALSE); } // Free the metafile and its handle. vFreeMF16(pmf16); bDeleteHmf16(hmf); return(TRUE); } /***************************** Public Function ****************************\ * HMETAFILE APIENTRY GetMetaFileW(pszwFilename) * * Returns a metafile handle for a disk based metafile. * * Effects: * * History: * Fri May 15 14:11:22 1992 -by- Hock San Lee [hockl] * Wrote it. \***************************************************************************/ HMETAFILE GetMetaFileA(LPCSTR pszFileName) { UINT cch; WCHAR awch[MAX_PATH]; cch = strlen(pszFileName)+1; if (cch > MAX_PATH) { ERROR_ASSERT(FALSE, "GetMetaFileA filename too long"); GdiSetLastError(ERROR_FILENAME_EXCED_RANGE); return ((HMETAFILE)0); } vToUnicodeN(awch, MAX_PATH, pszFileName, cch); return (GetMetaFileW(awch)); } HMETAFILE APIENTRY GetMetaFileW(LPCWSTR pwszFileName) { PMETAFILE16 pmf16; HMETAFILE hmf; PUTS("GetMetaFileW\n"); // Allocate and initialize a metafile. if (!(pmf16 = pmf16AllocMF16(0, 0, (PDWORD) NULL, (LPWSTR) pwszFileName))) return((HMETAFILE) 0); ASSERTGDI(pmf16->metaHeader.mtType == DISKMETAFILE, "GetMetaFileW: Bad mtType\n"); // Allocate a local handle. hmf = hmf16Create(pmf16); if (!hmf) { vFreeMF16(pmf16); } // Return the metafile handle. return(hmf); } /***************************** Internal Function **************************\ * BOOL FAR PASCAL PlayIntoAMetafile * * if this record is being played into another metafile, simply record * it into that metafile, without hassling with a real playing. * * Returns: TRUE if record was played (copied) into another metafile * FALSE if destination DC was a real (non-meta) DC * * Effects: ? * * Warnings: ? * \***************************************************************************/ BOOL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest) { PUTS("PlayIntoAMetafile\n"); if (LO_TYPE(hdcDest) != LO_METADC16_TYPE) return(FALSE); // If a metafile is retrieved with GetWinMetaFileBits, it may contain // an embedded enhanced metafile. Do not include the enhanced metafile // if we are playing the metafile to another metafile. if (IS_META_ESCAPE_ENHANCED_METAFILE((PMETA_ESCAPE_ENHANCED_METAFILE) lpMR)) return(TRUE); // the size is the same minus 3 words for the record header return(RecordParms(hdcDest, (DWORD)lpMR->rdFunction, (DWORD)lpMR->rdSize - 3, (LPWORD)&(lpMR->rdParm[0]))); }