You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
16 KiB
508 lines
16 KiB
/*****************************************************************************
|
|
*
|
|
* apientry.c - This module contains the API entry points for the
|
|
* Win32 to Win16 metafile converter.
|
|
*
|
|
* Date: 8/29/91
|
|
* Author: Jeffrey Newman (c-jeffn)
|
|
*
|
|
* Copyright 1991 Microsoft Corp
|
|
*****************************************************************************/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
BOOL bMemUpdateCheckSum(PLOCALDC pLocalDC) ;
|
|
PLOCALDC pldcInitLocalDC(HDC hdcRef, INT iMapMode, DWORD flags) ;
|
|
VOID vFreeLocalDC(PLOCALDC pLocalDC);
|
|
|
|
|
|
extern VOID __cdecl _cfltcvt_init(VOID) ;
|
|
|
|
// This critical section structure is shared by all the threads of a given
|
|
// process.
|
|
|
|
CRITICAL_SECTION CriticalSection ;
|
|
|
|
// Constant definition for internal static string(s).
|
|
|
|
BYTE szDisplay[] = "DISPLAY" ;
|
|
|
|
/*****************************************************************************
|
|
* Entry point for translation
|
|
*****************************************************************************/
|
|
UINT ConvertEmfToWmf(PVOID pht, PBYTE pMetafileBits, UINT cDest, PBYTE pDest,
|
|
INT iMapMode, HDC hdcRef, UINT flags)
|
|
{
|
|
BOOL b ;
|
|
DWORD lret = 0;
|
|
PLOCALDC pLocalDC ;
|
|
|
|
|
|
// We funnel through one exit to make sure we leave the
|
|
// critical section.
|
|
|
|
EnterCriticalSection(&CriticalSection) ;
|
|
|
|
// Check the requested map mode and if it's valid
|
|
|
|
if (iMapMode < MM_MIN || iMapMode > MM_MAX)
|
|
{
|
|
RIP("MF3216:ConvertEmfToWmf - Invalid MapMode\n") ;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
// Check for a reference DC. If one is not supplied we fail.
|
|
|
|
if (hdcRef == (HDC) 0)
|
|
{
|
|
RIP("MF3216:ConvertEmfToWmf - Invalid RefDC\n") ;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
// Check the validity of the flags.
|
|
|
|
if ((flags & ~MF3216_INCLUDE_WIN32MF) != 0)
|
|
{
|
|
RIP("MF3216: ConvertEmfToWmf - Invalid flags\n") ;
|
|
goto ErrorExit ;
|
|
}
|
|
|
|
// Allocate the LocalDC and initialize some of it's fields.
|
|
|
|
pLocalDC = pldcInitLocalDC(hdcRef, iMapMode, flags) ;
|
|
if (pLocalDC == (PLOCALDC) 0)
|
|
{
|
|
goto ErrorExit ;
|
|
}
|
|
|
|
// If pDest is NULL then we just return the size of the buffer required
|
|
// to hold the Win16 metafile bits.
|
|
|
|
pLocalDC->pht = pht;
|
|
|
|
if (pDest == (PBYTE) 0)
|
|
{
|
|
pLocalDC->flags |= SIZE_ONLY ;
|
|
b = bParseWin32Metafile(pMetafileBits, pLocalDC) ;
|
|
if (b == TRUE)
|
|
{
|
|
lret = pLocalDC->ulBytesEmitted ;
|
|
}
|
|
else
|
|
{
|
|
PUTS("MF3216: ConvertEmfToWmf - Size Only failed\n") ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Put the user specified Win16 buffer pointer and buffer length
|
|
// into the localDC.
|
|
|
|
pLocalDC->pMf16Bits = pDest ;
|
|
pLocalDC->cMf16Dest = cDest ;
|
|
|
|
// Translate the Win32 metafile to a Win16 metafile.
|
|
|
|
b = bParseWin32Metafile(pMetafileBits, pLocalDC) ;
|
|
if (b == TRUE)
|
|
{
|
|
// Update the Win16 metafile header.
|
|
|
|
b = bUpdateMf16Header(pLocalDC) ;
|
|
if (b == TRUE)
|
|
{
|
|
// Only acknowledge that we have translated some bits
|
|
// if everything has gone well.
|
|
|
|
lret = pLocalDC->ulBytesEmitted ;
|
|
|
|
// If we're including the Win32 metafile then update the
|
|
// checksum field in the "Win32Comment header" record.
|
|
|
|
if (pLocalDC->flags & INCLUDE_W32MF_COMMENT)
|
|
bMemUpdateCheckSum(pLocalDC) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PUTS("MF3216: ConvertEmfToWmf - Metafile conversion failed\n") ;
|
|
}
|
|
}
|
|
|
|
// Free the LocalDC and its resources.
|
|
|
|
vFreeLocalDC(pLocalDC);
|
|
|
|
ErrorExit:
|
|
LeaveCriticalSection(&CriticalSection) ;
|
|
|
|
return (lret) ;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* pldcInitLocalDC - Initialize the Local DC.
|
|
*****************************************************************************/
|
|
PLOCALDC pldcInitLocalDC(HDC hdcRef, INT iMapMode, DWORD flags)
|
|
{
|
|
PLOCALDC pLocalDC;
|
|
PLOCALDC pldcRet = (PLOCALDC) NULL; // assume error
|
|
|
|
// Allocate and initialize memory for the LocalDC.
|
|
|
|
pLocalDC = (PLOCALDC) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(LOCALDC));
|
|
if (!pLocalDC)
|
|
{
|
|
PUTS("MF3216:pldcInitLocalDC - LocalAlloc failure\n") ;
|
|
return((PLOCALDC) NULL);
|
|
}
|
|
|
|
// Record the size of the DC.
|
|
|
|
pLocalDC->nSize = sizeof(LOCALDC) ;
|
|
|
|
// Set the LocalDC boolean that controls whether or not we include
|
|
// the Win32 metafile as one or more comment records.
|
|
|
|
if (flags & MF3216_INCLUDE_WIN32MF)
|
|
pLocalDC->flags |= INCLUDE_W32MF_COMMENT ;
|
|
|
|
#if 0
|
|
// Need to create a hdc for the display.
|
|
// Initially this will be used by the bitblt translation code
|
|
// to get a reasonable set of palette entries.
|
|
// The reference DC only has a black & white palette.
|
|
|
|
pLocalDC->hdcDisp = CreateDCA((LPCSTR)szDisplay, (LPCSTR)NULL, (LPCSTR)NULL, (CONST DEVMODEA *)NULL) ;
|
|
if (pLocalDC->hdcDisp == (HDC) 0)
|
|
{
|
|
RIP("MF3216:pldcInitLocalDC - CreateDCA(hdcDisp) failed\n") ;
|
|
goto pldcInitLocalDC_exit;
|
|
}
|
|
#endif // 0
|
|
|
|
// Create the HelperDC.
|
|
|
|
pLocalDC->hdcHelper = CreateICA((LPCSTR) szDisplay,
|
|
(LPCSTR) NULL,
|
|
(LPCSTR) NULL,
|
|
(LPDEVMODEA) NULL) ;
|
|
if (pLocalDC->hdcHelper == (HDC)0)
|
|
{
|
|
PUTS("MF3216: pldcInitLocalDC, Create Helper DC failed\n") ;
|
|
goto pldcInitLocalDC_exit;
|
|
}
|
|
|
|
// Initialize the counters we need to keep for updating the header,
|
|
// and keeping track of the object table.
|
|
|
|
pLocalDC->nObjectHighWaterMark = -1;
|
|
|
|
// Get the play-time device dimensions in millimeters and in pels.
|
|
|
|
pLocalDC->cxPlayDevMM = GetDeviceCaps(hdcRef, HORZSIZE) ;
|
|
pLocalDC->cyPlayDevMM = GetDeviceCaps(hdcRef, VERTSIZE) ;
|
|
pLocalDC->cxPlayDevPels = GetDeviceCaps(hdcRef, HORZRES) ;
|
|
pLocalDC->cyPlayDevPels = GetDeviceCaps(hdcRef, VERTRES) ;
|
|
|
|
// Record the requested map mode and reference DC.
|
|
|
|
pLocalDC->iMapMode = iMapMode ;
|
|
pLocalDC->hdcRef = hdcRef ;
|
|
|
|
// Init Arc Direction.
|
|
|
|
pLocalDC->iArcDirection = AD_COUNTERCLOCKWISE ;
|
|
|
|
// Make current position invalid so that a moveto will be
|
|
// emitted when it is first used. See comments in DoMoveTo.
|
|
|
|
pLocalDC->ptCP.x = MAXLONG ;
|
|
pLocalDC->ptCP.y = MAXLONG ;
|
|
|
|
// Default pen is a black pen.
|
|
|
|
pLocalDC->lhpn32 = BLACK_PEN | ENHMETA_STOCK_OBJECT;
|
|
|
|
// Default brush is a white brush.
|
|
|
|
pLocalDC->lhbr32 = WHITE_BRUSH | ENHMETA_STOCK_OBJECT;
|
|
|
|
// Default palette.
|
|
|
|
pLocalDC->ihpal32 = DEFAULT_PALETTE | ENHMETA_STOCK_OBJECT;
|
|
pLocalDC->ihpal16 = (DWORD) -1; // no W16 palette created yet
|
|
|
|
pLocalDC->crBkColor = RGB(0xFF,0xFF,0xFF);
|
|
|
|
// pLocalDC->pW16ObjHndlSlotStatus = NULL;
|
|
// pLocalDC->cW16ObjHndlSlotStatus = 0;
|
|
// pLocalDC->piW32ToW16ObjectMap = NULL;
|
|
// pLocalDC->cW32ToW16ObjectMap = 0;
|
|
// pLocalDC->crTextColor = RGB(0x0,0x0,0x0);
|
|
// pLocalDC->iLevel = 0;
|
|
// pLocalDC->pLocalDCSaved = NULL;
|
|
// pLocalDC->ulBytesEmitted = 0;
|
|
// pLocalDC->ulMaxRecord = 0;
|
|
// pLocalDC->pW32hPal = NULL;
|
|
|
|
// Set the advanced graphics mode in the helper DC. This is needed
|
|
// to notify the helper DC that rectangles and ellipses are
|
|
// inclusive-inclusive etc., especially when rendering them in a path.
|
|
// Also, the world transform can only be set in the advanced mode.
|
|
|
|
(void) SetGraphicsMode(pLocalDC->hdcHelper, GM_ADVANCED);
|
|
|
|
// We are golden.
|
|
|
|
pldcRet = pLocalDC;
|
|
|
|
pldcInitLocalDC_exit:
|
|
|
|
if (!pldcRet)
|
|
vFreeLocalDC(pLocalDC);
|
|
|
|
return(pldcRet) ;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* vFreeLocalDC - Free the Local DC and its resources.
|
|
*****************************************************************************/
|
|
VOID vFreeLocalDC(PLOCALDC pLocalDC)
|
|
{
|
|
UINT i;
|
|
|
|
// Free the helper DCs.
|
|
|
|
if (pLocalDC->hdcHelper)
|
|
if (!DeleteDC(pLocalDC->hdcHelper))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, DeleteDC failed");
|
|
#if 0
|
|
if (pLocalDC->hdcDisp)
|
|
if (!DeleteDC(pLocalDC->hdcDisp))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, DeleteDC failed");
|
|
#endif // 0
|
|
|
|
// Free the storage for the object translation map.
|
|
|
|
if (pLocalDC->piW32ToW16ObjectMap)
|
|
{
|
|
#if 0
|
|
for (i = 0 ; i < pLocalDC->cW32ToW16ObjectMap ; i++)
|
|
{
|
|
if (pLocalDC->piW32ToW16ObjectMap[i] != UNMAPPED)
|
|
if (i > STOCK_LAST)
|
|
PUTS1("MF3216: vFreeLocalDC, object32 %ld is not freed\n", i - STOCK_LAST - 1);
|
|
else
|
|
PUTS1("MF3216: vFreeLocalDC, stock object32 %ld is mapped\n",i);
|
|
}
|
|
#endif // 0
|
|
|
|
if (LocalFree(pLocalDC->piW32ToW16ObjectMap))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, LocalFree failed");
|
|
}
|
|
|
|
// Free the W32 palette handles.
|
|
|
|
if (pLocalDC->pW32hPal)
|
|
{
|
|
for (i = 0; i < pLocalDC->cW32hPal; i++)
|
|
{
|
|
if (pLocalDC->pW32hPal[i])
|
|
if (!DeleteObject(pLocalDC->pW32hPal[i]))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, delete palette failed");
|
|
}
|
|
|
|
if (LocalFree(pLocalDC->pW32hPal))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, LocalFree failed");
|
|
}
|
|
|
|
// Free the w32 handles in the pW16ObjHndlSlotStatus array.
|
|
// We free the handles after we have deleted the helper DC so that
|
|
// the w32 handles are not selected into any DC.
|
|
|
|
if (pLocalDC->pW16ObjHndlSlotStatus)
|
|
{
|
|
for (i = 0 ; i < pLocalDC->cW16ObjHndlSlotStatus ; i++)
|
|
{
|
|
#if 0
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[i].use
|
|
!= OPEN_AVAILABLE_SLOT)
|
|
PUTS1("MF3216: vFreeLocalDC, object16 %ld is not freed\n", i);
|
|
#endif // 0
|
|
|
|
if (pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle)
|
|
{
|
|
ASSERTGDI(pLocalDC->pW16ObjHndlSlotStatus[i].use
|
|
!= OPEN_AVAILABLE_SLOT,
|
|
"MF3216: error in object handle table");
|
|
|
|
if (!DeleteObject(pLocalDC->pW16ObjHndlSlotStatus[i].w32Handle))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, DeleteObject failed");
|
|
}
|
|
}
|
|
|
|
if (LocalFree(pLocalDC->pW16ObjHndlSlotStatus))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, LocalFree failed");
|
|
}
|
|
|
|
// The DC level should be balanced.
|
|
|
|
if (pLocalDC->pLocalDCSaved != NULL)
|
|
{
|
|
PLOCALDC pNext, pTmp;
|
|
|
|
for (pNext = pLocalDC->pLocalDCSaved; pNext; )
|
|
{
|
|
PUTS("MF3216: vFreeLocalDC, unbalanced DC level\n");
|
|
|
|
pTmp = pNext->pLocalDCSaved;
|
|
if (LocalFree(pNext))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, LocalFree failed");
|
|
pNext = pTmp;
|
|
}
|
|
}
|
|
|
|
// Finally, free the LocalDC.
|
|
|
|
if (LocalFree(pLocalDC))
|
|
ASSERTGDI(FALSE, "MF3216: vFreeLocalDC, LocalFree failed");
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
* Handle emitting the Win32 metafile comment record(s).
|
|
**************************************************************************/
|
|
BOOL bHandleWin32Comment(PLOCALDC pLocalDC)
|
|
{
|
|
INT i;
|
|
BOOL b ;
|
|
META_ESCAPE_ENHANCED_METAFILE mfeEnhMF;
|
|
|
|
// Win30 may have problems with large (over 8K) escape records.
|
|
// We will limit the size of each Win32 Comment record to
|
|
// MAX_WIN32_COMMENT_REC_SIZE.
|
|
|
|
// Initialize the record header.
|
|
|
|
mfeEnhMF.rdFunction = META_ESCAPE;
|
|
mfeEnhMF.wEscape = MFCOMMENT;
|
|
mfeEnhMF.ident = MFCOMMENT_IDENTIFIER;
|
|
mfeEnhMF.iComment = MFCOMMENT_ENHANCED_METAFILE;
|
|
mfeEnhMF.nVersion = ((PENHMETAHEADER) pLocalDC->pMf32Bits)->nVersion;
|
|
mfeEnhMF.wChecksum = 0; // updated by bMemUpdateCheckSum
|
|
mfeEnhMF.fFlags = 0;
|
|
mfeEnhMF.nCommentRecords
|
|
= (pLocalDC->cMf32Bits + MAX_WIN32_COMMENT_REC_SIZE - 1)
|
|
/ MAX_WIN32_COMMENT_REC_SIZE;
|
|
mfeEnhMF.cbEnhMetaFile = pLocalDC->cMf32Bits;
|
|
|
|
mfeEnhMF.cbRemainder = pLocalDC->cMf32Bits;
|
|
i = 0 ;
|
|
while (mfeEnhMF.cbRemainder)
|
|
{
|
|
mfeEnhMF.cbCurrent = min(mfeEnhMF.cbRemainder, MAX_WIN32_COMMENT_REC_SIZE);
|
|
mfeEnhMF.rdSize = (sizeof(mfeEnhMF) + mfeEnhMF.cbCurrent) / 2;
|
|
mfeEnhMF.wCount = (WORD)(sizeof(mfeEnhMF) + mfeEnhMF.cbCurrent - sizeof(METARECORD_ESCAPE));
|
|
mfeEnhMF.cbRemainder -= mfeEnhMF.cbCurrent;
|
|
|
|
b = bEmitWin16EscapeEnhMetaFile(pLocalDC,
|
|
(PMETARECORD_ESCAPE) &mfeEnhMF, &pLocalDC->pMf32Bits[i]);
|
|
|
|
if (!b)
|
|
break;
|
|
i += mfeEnhMF.cbCurrent;
|
|
}
|
|
|
|
return(b) ;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* bMemUpdateCheckSum - Update the checksum
|
|
*****************************************************************************/
|
|
BOOL bMemUpdateCheckSum(PLOCALDC pLocalDC)
|
|
{
|
|
INT i, k ;
|
|
PWORD pword ;
|
|
WORD CheckSum ;
|
|
PMETA_ESCAPE_ENHANCED_METAFILE pmfeEnhMF;
|
|
|
|
|
|
// CheckSum the file.
|
|
// Do a 16 bit checksum
|
|
|
|
pword = (PWORD) pLocalDC->pMf16Bits ;
|
|
k = pLocalDC->ulBytesEmitted / 2 ;
|
|
|
|
CheckSum = 0 ;
|
|
for (i = 0 ; i < k ; i++)
|
|
CheckSum += pword[i] ;
|
|
|
|
// Update the checksum record value with the real checksum.
|
|
|
|
pmfeEnhMF = (PMETA_ESCAPE_ENHANCED_METAFILE)
|
|
&pLocalDC->pMf16Bits[sizeof(METAHEADER)];
|
|
|
|
ASSERTGDI(IS_META_ESCAPE_ENHANCED_METAFILE(pmfeEnhMF)
|
|
&& pmfeEnhMF->wChecksum == 0
|
|
&& pmfeEnhMF->fFlags == 0,
|
|
"MF3216: bMemUpdateCheckSum: Bad pmfeEnhMF");
|
|
|
|
pmfeEnhMF->wChecksum = -CheckSum;
|
|
|
|
#if DBG
|
|
// Now test the checksum. The checksum of the entire file
|
|
// should be 0.
|
|
|
|
CheckSum = 0 ;
|
|
pword = (PWORD) pLocalDC->pMf16Bits ;
|
|
for (i = 0 ; i < k ; i++)
|
|
CheckSum += pword[i] ;
|
|
|
|
if (CheckSum != 0)
|
|
{
|
|
RIP("MF3216: MemUpdateCheckSum, (CheckSum != 0)\n") ;
|
|
}
|
|
#endif
|
|
return (TRUE) ;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* Mf3216DllInitialize *
|
|
* *
|
|
* This is the init procedure for MF3216.DLL, *
|
|
* which is called each time a new *
|
|
* process links to it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL Mf3216DllInitialize(PVOID pvDllHandle, DWORD ulReason, PCONTEXT pcontext)
|
|
{
|
|
|
|
|
|
|
|
NOTUSED(pvDllHandle) ;
|
|
NOTUSED(pcontext) ;
|
|
|
|
if ( ulReason == DLL_PROCESS_ATTACH )
|
|
{
|
|
// This does the critical section initialization for a single
|
|
// process. Each process does this. The CriticalSection data
|
|
// structure is one of the very few (if not the only one) data
|
|
// structures in the data segment.
|
|
|
|
InitializeCriticalSection(&CriticalSection) ;
|
|
}
|
|
else if ( ulReason == DLL_PROCESS_DETACH )
|
|
{
|
|
DeleteCriticalSection(&CriticalSection) ;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
}
|