| /* | 
 |  * Metafile functions | 
 |  * | 
 |  * Copyright  David W. Metcalfe, 1994 | 
 |  * Copyright  Niels de Carpentier, 1996 | 
 |  * Copyright  Albrecht Kleine, 1996 | 
 |  * Copyright  Huw Davies, 1996 | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 |  | 
 | #include <string.h> | 
 | #include <fcntl.h> | 
 |  | 
 | #include "wine/winbase16.h" | 
 | #include "wine/wingdi16.h" | 
 | #include "wownt32.h" | 
 | #include "winreg.h" | 
 | #include "winternl.h" | 
 | #include "gdi_private.h" | 
 | #include "wine/debug.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(metafile); | 
 |  | 
 | /****************************************************************** | 
 |  *         MF_GetMetaHeader16 | 
 |  * | 
 |  * Returns ptr to METAHEADER associated with HMETAFILE16 | 
 |  * Should be followed by call to MF_ReleaseMetaHeader16 | 
 |  */ | 
 | static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf ) | 
 | { | 
 |     return GlobalLock16(hmf); | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         MF_ReleaseMetaHeader16 | 
 |  * | 
 |  * Releases METAHEADER associated with HMETAFILE16 | 
 |  */ | 
 | static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf ) | 
 | { | 
 |     return GlobalUnlock16( hmf ); | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *	     DeleteMetaFile   (GDI.127) | 
 |  */ | 
 | BOOL16 WINAPI DeleteMetaFile16(  HMETAFILE16 hmf ) | 
 | { | 
 |     return !GlobalFree16( hmf ); | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         GetMetaFile   (GDI.124) | 
 |  */ | 
 | HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename ) | 
 | { | 
 |     METAHEADER *mh; | 
 |     HANDLE hFile; | 
 |  | 
 |     TRACE("%s\n", lpFilename); | 
 |  | 
 |     if(!lpFilename) | 
 |         return 0; | 
 |  | 
 |     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, | 
 | 			    OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) | 
 |         return 0; | 
 |  | 
 |     mh = MF_ReadMetaFile(hFile); | 
 |     CloseHandle(hFile); | 
 |     if(!mh) return 0; | 
 |     return MF_Create_HMETAFILE16( mh ); | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         CopyMetaFile   (GDI.151) | 
 |  */ | 
 | HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename) | 
 | { | 
 |     METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile ); | 
 |     METAHEADER *mh2 = NULL; | 
 |     HANDLE hFile; | 
 |  | 
 |     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename); | 
 |  | 
 |     if(!mh) return 0; | 
 |  | 
 |     if(mh->mtType == METAFILE_DISK) | 
 |         mh2 = MF_LoadDiskBasedMetaFile(mh); | 
 |     else { | 
 |         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 ); | 
 |         memcpy( mh2, mh, mh->mtSize * 2 ); | 
 |     } | 
 |     MF_ReleaseMetaHeader16( hSrcMetaFile ); | 
 |  | 
 |     if(lpFilename) {         /* disk based metafile */ | 
 |         DWORD w; | 
 |         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL, | 
 | 				CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) { | 
 | 	    HeapFree( GetProcessHeap(), 0, mh2 ); | 
 | 	    return 0; | 
 | 	} | 
 | 	WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL); | 
 | 	CloseHandle(hFile); | 
 | 	mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE); | 
 |     } | 
 |  | 
 |     return MF_Create_HMETAFILE16( mh2 ); | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         IsValidMetaFile   (GDI.410) | 
 |  * | 
 |  *  Attempts to check if a given metafile is correctly formatted. | 
 |  *  Currently, the only things verified are several properties of the | 
 |  *  header. | 
 |  * | 
 |  * RETURNS | 
 |  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise. | 
 |  * | 
 |  * BUGS | 
 |  *  This is not exactly what windows does, see _Undocumented_Windows_ | 
 |  *  for details. | 
 |  */ | 
 | BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf) | 
 | { | 
 |     BOOL16 res=FALSE; | 
 |     METAHEADER *mh = MF_GetMetaHeader16(hmf); | 
 |     if (mh) { | 
 |         if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK) | 
 | 	    if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16)) | 
 | 	        if (mh->mtVersion == MFVERSION) | 
 | 		    res=TRUE; | 
 | 	MF_ReleaseMetaHeader16(hmf); | 
 |     } | 
 |     TRACE("IsValidMetaFile %x => %d\n",hmf,res); | 
 |     return res; | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         PlayMetaFile   (GDI.123) | 
 |  * | 
 |  */ | 
 | BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf ) | 
 | { | 
 |     BOOL16 ret; | 
 |     METAHEADER *mh = MF_GetMetaHeader16( hmf ); | 
 |     ret = MF_PlayMetaFile( HDC_32(hdc), mh ); | 
 |     MF_ReleaseMetaHeader16( hmf ); | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | /****************************************************************** | 
 |  *            EnumMetaFile   (GDI.175) | 
 |  * | 
 |  */ | 
 | BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf, | 
 | 			      MFENUMPROC16 lpEnumFunc, LPARAM lpData ) | 
 | { | 
 |     METAHEADER *mh = MF_GetMetaHeader16(hmf); | 
 |     METARECORD *mr; | 
 |     HANDLETABLE16 *ht; | 
 |     HDC hdc = HDC_32(hdc16); | 
 |     HGLOBAL16 hHT; | 
 |     SEGPTR spht; | 
 |     unsigned int offset = 0; | 
 |     WORD i, seg; | 
 |     HPEN hPen; | 
 |     HBRUSH hBrush; | 
 |     HFONT hFont; | 
 |     WORD args[8]; | 
 |     BOOL16 result = TRUE, loaded = FALSE; | 
 |  | 
 |     TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData); | 
 |  | 
 |     if(!mh) return FALSE; | 
 |     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */ | 
 |         mh = MF_LoadDiskBasedMetaFile(mh); | 
 | 	if(!mh) return FALSE; | 
 | 	loaded = TRUE; | 
 |     } | 
 |  | 
 |     /* save the current pen, brush and font */ | 
 |     hPen = GetCurrentObject(hdc, OBJ_PEN); | 
 |     hBrush = GetCurrentObject(hdc, OBJ_BRUSH); | 
 |     hFont = GetCurrentObject(hdc, OBJ_FONT); | 
 |  | 
 |     /* create the handle table */ | 
 |  | 
 |     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT, | 
 | 		     sizeof(HANDLETABLE16) * mh->mtNoObjects); | 
 |     spht = WOWGlobalLock16(hHT); | 
 |  | 
 |     seg = hmf | 7; | 
 |     offset = mh->mtHeaderSize * 2; | 
 |  | 
 |     /* loop through metafile records */ | 
 |  | 
 |     args[7] = hdc16; | 
 |     args[6] = SELECTOROF(spht); | 
 |     args[5] = OFFSETOF(spht); | 
 |     args[4] = seg + (HIWORD(offset) << __AHSHIFT); | 
 |     args[3] = LOWORD(offset); | 
 |     args[2] = mh->mtNoObjects; | 
 |     args[1] = HIWORD(lpData); | 
 |     args[0] = LOWORD(lpData); | 
 |  | 
 |     while (offset < (mh->mtSize * 2)) | 
 |     { | 
 |         DWORD ret; | 
 |  | 
 | 	mr = (METARECORD *)((char *)mh + offset); | 
 |  | 
 |         WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret ); | 
 |         if (!LOWORD(ret)) | 
 | 	{ | 
 | 	    result = FALSE; | 
 | 	    break; | 
 | 	} | 
 |  | 
 | 	offset += (mr->rdSize * 2); | 
 |         args[4] = seg + (HIWORD(offset) << __AHSHIFT); | 
 |         args[3] = LOWORD(offset); | 
 |     } | 
 |  | 
 |     SelectObject(hdc, hBrush); | 
 |     SelectObject(hdc, hPen); | 
 |     SelectObject(hdc, hFont); | 
 |  | 
 |     ht = (HANDLETABLE16 *)GlobalLock16(hHT); | 
 |  | 
 |     /* free objects in handle table */ | 
 |     for(i = 0; i < mh->mtNoObjects; i++) | 
 |       if(*(ht->objectHandle + i) != 0) | 
 |         DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) )); | 
 |  | 
 |     /* free handle table */ | 
 |     GlobalFree16(hHT); | 
 |     if(loaded) | 
 |         HeapFree( GetProcessHeap(), 0, mh ); | 
 |     MF_ReleaseMetaHeader16(hmf); | 
 |     return result; | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         GetMetaFileBits   (GDI.159) | 
 |  * | 
 |  * Trade in a metafile object handle for a handle to the metafile memory. | 
 |  * | 
 |  * PARAMS | 
 |  *  hmf [I] metafile handle | 
 |  */ | 
 |  | 
 | HGLOBAL16 WINAPI GetMetaFileBits16( HMETAFILE16 hmf ) | 
 | { | 
 |     TRACE("hMem out: %04x\n", hmf); | 
 |     return hmf; | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         SetMetaFileBits   (GDI.160) | 
 |  * | 
 |  * Trade in a metafile memory handle for a handle to a metafile object. | 
 |  * The memory region should hold a proper metafile, otherwise | 
 |  * problems will occur when it is used. Validity of the memory is not | 
 |  * checked. The function is essentially just the identity function. | 
 |  * | 
 |  * PARAMS | 
 |  *  hMem [I] handle to a memory region holding a metafile | 
 |  * | 
 |  * RETURNS | 
 |  *  Handle to a metafile on success, NULL on failure.. | 
 |  */ | 
 | HMETAFILE16 WINAPI SetMetaFileBits16( HGLOBAL16 hMem ) | 
 | { | 
 |     TRACE("hmf out: %04x\n", hMem); | 
 |  | 
 |     return hMem; | 
 | } | 
 |  | 
 | /****************************************************************** | 
 |  *         SetMetaFileBitsBetter   (GDI.196) | 
 |  * | 
 |  * Trade in a metafile memory handle for a handle to a metafile object, | 
 |  * making a cursory check (using IsValidMetaFile()) that the memory | 
 |  * handle points to a valid metafile. | 
 |  * | 
 |  * RETURNS | 
 |  *  Handle to a metafile on success, NULL on failure.. | 
 |  */ | 
 | HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta ) | 
 | { | 
 |     if( IsValidMetaFile16( hMeta ) ) | 
 |         return GlobalReAlloc16( hMeta, 0, GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY); | 
 |     return (HMETAFILE16)0; | 
 | } |