Added an unknown VxD error code.
[wine] / objects / metafile.c
1 /*
2  * Metafile functions
3  *
4  * Copyright  David W. Metcalfe, 1994
5  *            Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
6  *
7  */
8
9 /*
10  * These functions are primarily involved with metafile playback or anything
11  * that touches a HMETAFILE.
12  * For recording of metafiles look in graphics/metafiledrv/
13  *
14  * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are 
15  * global memory handles so these cannot be interchanged.
16  *
17  * Memory-based metafiles are just stored as a continuous block of memory with
18  * a METAHEADER at the head with METARECORDs appended to it.  mtType is
19  * METAFILE_MEMORY (1).  Note this is indentical to the disk image of a
20  * disk-based metafile - even mtType is METAFILE_MEMORY.
21  * 16bit HMETAFILE16s are global handles to this block
22  * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
23  * the memory.
24  * Disk-based metafiles are rather different. HMETAFILE16s point to a
25  * METAHEADER which has mtType equal to METAFILE_DISK (2).  Following the 9
26  * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
27  * more 0, then 2 which may be a time stamp of the file and then the path of
28  * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
29  *
30  * HDMD - 14/4/1999
31  */  
32
33
34 #include <string.h>
35 #include <fcntl.h>
36 #include "wine/winbase16.h"
37 #include "metafile.h"
38 #include "bitmap.h"
39 #include "heap.h"
40 #include "toolhelp.h"
41 #include "debugtools.h"
42 #include "global.h"
43
44 DEFAULT_DEBUG_CHANNEL(metafile);
45
46 /******************************************************************
47  *         MF_AddHandle
48  *
49  *    Add a handle to an external handle table and return the index
50  */
51 static int MF_AddHandle(HANDLETABLE16 *ht, WORD htlen, HGDIOBJ16 hobj)
52 {
53     int i;
54
55     for (i = 0; i < htlen; i++)
56     {
57         if (*(ht->objectHandle + i) == 0)
58         {
59             *(ht->objectHandle + i) = hobj;
60             return i;
61         }
62     }
63     return -1;
64 }
65
66
67 /******************************************************************
68  *         MF_Create_HMETATFILE
69  *
70  * Creates a (32 bit) HMETAFILE object from a METAHEADER
71  *
72  * HMETAFILEs are GDI objects.
73  */
74 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
75 {
76     HMETAFILE hmf = 0;
77     METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC, &hmf );
78     if (metaObj)
79     {
80     metaObj->mh = mh;
81         GDI_ReleaseObj( hmf );
82     }
83     return hmf;
84 }
85
86 /******************************************************************
87  *         MF_Create_HMETATFILE16
88  *
89  * Creates a HMETAFILE16 object from a METAHEADER
90  *
91  * HMETAFILE16s are Global memory handles.
92  */
93 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
94 {
95     HMETAFILE16 hmf;
96     DWORD size = mh->mtSize * sizeof(WORD);
97
98     hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
99     if(hmf)
100     {
101         METAHEADER *mh_dest = GlobalLock16(hmf);
102         memcpy(mh_dest, mh, size);
103         GlobalUnlock16(hmf);
104     }
105     HeapFree(GetProcessHeap(), 0, mh);
106     return hmf;
107 }
108
109 /******************************************************************
110  *         MF_GetMetaHeader
111  *
112  * Returns ptr to METAHEADER associated with HMETAFILE
113  * Should be followed by call to MF_ReleaseMetaHeader
114  */
115 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
116 {
117     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
118     return metaObj ? metaObj->mh : 0;
119 }
120
121 /******************************************************************
122  *         MF_GetMetaHeader16
123  *
124  * Returns ptr to METAHEADER associated with HMETAFILE16
125  * Should be followed by call to MF_ReleaseMetaHeader16
126  */
127 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
128 {
129     return GlobalLock16(hmf);
130 }
131
132 /******************************************************************
133  *         MF_ReleaseMetaHeader
134  *
135  * Releases METAHEADER associated with HMETAFILE
136  */
137 static void MF_ReleaseMetaHeader( HMETAFILE hmf )
138 {
139     GDI_ReleaseObj( hmf );
140 }
141
142 /******************************************************************
143  *         MF_ReleaseMetaHeader16
144  *
145  * Releases METAHEADER associated with HMETAFILE16
146  */
147 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
148 {
149     return GlobalUnlock16( hmf );
150 }
151
152
153 /******************************************************************
154  *           DeleteMetaFile16   (GDI.127)
155  */
156 BOOL16 WINAPI DeleteMetaFile16(  HMETAFILE16 hmf )
157 {
158     return !GlobalFree16( hmf );
159 }
160
161 /******************************************************************
162  *          DeleteMetaFile  (GDI32.@)
163  *
164  *  Delete a memory-based metafile.
165  */
166
167 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
168 {
169     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
170     if (!metaObj) return FALSE;
171     HeapFree( GetProcessHeap(), 0, metaObj->mh );
172     GDI_FreeObject( hmf, metaObj );
173     return TRUE;
174 }
175
176 /******************************************************************
177  *         MF_ReadMetaFile
178  *
179  * Returns a pointer to a memory based METAHEADER read in from file HFILE
180  *
181  */
182 static METAHEADER *MF_ReadMetaFile(HFILE hfile)
183 {
184     METAHEADER *mh;
185     DWORD BytesRead, size;
186
187     size = sizeof(METAHEADER);
188     mh = HeapAlloc( GetProcessHeap(), 0, size );
189     if(!mh) return NULL;
190     if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
191        BytesRead != size) {
192         HeapFree( GetProcessHeap(), 0, mh );
193         return NULL;
194     }
195     size = mh->mtSize * 2;
196     mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
197     if(!mh) return NULL;
198     size -= sizeof(METAHEADER);
199     if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
200                  NULL) == 0 ||
201        BytesRead != size) {
202         HeapFree( GetProcessHeap(), 0, mh );
203         return NULL;
204     }
205
206     if (mh->mtType != METAFILE_MEMORY) {
207         WARN("Disk metafile had mtType = %04x\n", mh->mtType);
208         mh->mtType = METAFILE_MEMORY;
209     }
210     return mh;
211 }
212
213 /******************************************************************
214  *         GetMetaFile16   (GDI.124)
215  */
216 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
217 {
218     METAHEADER *mh;
219     HANDLE hFile;
220  
221     TRACE("%s\n", lpFilename);
222
223     if(!lpFilename)
224         return 0;
225
226     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
227                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
228         return 0;
229
230     mh = MF_ReadMetaFile(hFile);
231     CloseHandle(hFile);
232     if(!mh) return 0;
233     return MF_Create_HMETAFILE16( mh );
234 }
235
236 /******************************************************************
237  *         GetMetaFileA   (GDI32.@)
238  *
239  *  Read a metafile from a file. Returns handle to a memory-based metafile.
240  */
241 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
242 {
243     METAHEADER *mh;
244     HANDLE hFile;
245  
246     TRACE("%s\n", lpFilename);
247
248     if(!lpFilename)
249         return 0;
250
251     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
252                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
253         return 0;
254
255     mh = MF_ReadMetaFile(hFile);
256     CloseHandle(hFile);
257     if(!mh) return 0;
258     return MF_Create_HMETAFILE( mh );
259 }
260
261
262
263 /******************************************************************
264  *         GetMetaFileW   (GDI32.@)
265  */
266 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
267 {
268     METAHEADER *mh;
269     HANDLE hFile;
270  
271     TRACE("%s\n", debugstr_w(lpFilename));
272
273     if(!lpFilename)
274         return 0;
275
276     if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
277                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
278         return 0;
279
280     mh = MF_ReadMetaFile(hFile);
281     CloseHandle(hFile);
282     if(!mh) return 0;
283     return MF_Create_HMETAFILE( mh );
284 }
285
286
287 /******************************************************************
288  *         MF_LoadDiskBasedMetaFile
289  *
290  * Creates a new memory-based metafile from a disk-based one.
291  */
292 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
293 {
294     METAHEADERDISK *mhd;
295     HANDLE hfile;
296     METAHEADER *mh2;
297
298     if(mh->mtType != METAFILE_DISK) {
299         ERR("Not a disk based metafile\n");
300         return NULL;
301     }
302     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
303
304     if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
305                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
306         WARN("Can't open file of disk based metafile\n");
307         return NULL;
308     }
309     mh2 = MF_ReadMetaFile(hfile);
310     CloseHandle(hfile);
311     return mh2;
312 }
313
314 /******************************************************************
315  *         MF_CreateMetaHeaderDisk
316  *
317  * Take a memory based METAHEADER and change it to a disk based METAHEADER
318  * assosiated with filename.  Note: Trashes contents of old one. 
319  */
320 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
321 {
322     METAHEADERDISK *mhd;
323     DWORD size;
324
325     mh = HeapReAlloc( GetProcessHeap(), 0, mh,
326                       sizeof(METAHEADER) + sizeof(METAHEADERDISK));
327     mh->mtType = METAFILE_DISK;
328     size = HeapSize( GetProcessHeap(), 0, mh );
329     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
330     strcpy(mhd->filename, filename);
331     return mh;
332 }
333
334 /******************************************************************
335  *         CopyMetaFile16   (GDI.151)
336  */
337 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
338 {
339     METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
340     METAHEADER *mh2 = NULL;
341     HANDLE hFile;
342
343     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
344     
345     if(!mh) return 0;
346     
347     if(mh->mtType == METAFILE_DISK)
348         mh2 = MF_LoadDiskBasedMetaFile(mh);
349     else {
350         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
351         memcpy( mh2, mh, mh->mtSize * 2 );
352     }
353     MF_ReleaseMetaHeader16( hSrcMetaFile );
354
355     if(lpFilename) {         /* disk based metafile */
356         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
357                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
358             HeapFree( GetProcessHeap(), 0, mh2 );
359             return 0;
360         }
361         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
362         CloseHandle(hFile);
363         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
364     }
365
366     return MF_Create_HMETAFILE16( mh2 );
367 }
368
369
370 /******************************************************************
371  *         CopyMetaFileA   (GDI32.@)
372  *
373  *  Copies the metafile corresponding to hSrcMetaFile to either
374  *  a disk file, if a filename is given, or to a new memory based
375  *  metafile, if lpFileName is NULL.
376  *
377  * RETURNS
378  *
379  *  Handle to metafile copy on success, NULL on failure.
380  *
381  * BUGS
382  *
383  *  Copying to disk returns NULL even if successful.
384  */
385 HMETAFILE WINAPI CopyMetaFileA(
386                    HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
387                    LPCSTR lpFilename       /* [in] filename if copying to a file */
388 ) {
389     METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
390     METAHEADER *mh2 = NULL;
391     HANDLE hFile;
392
393     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
394     
395     if(!mh) return 0;
396     
397     if(mh->mtType == METAFILE_DISK)
398         mh2 = MF_LoadDiskBasedMetaFile(mh);
399     else {
400         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
401         memcpy( mh2, mh, mh->mtSize * 2 );
402     }
403     MF_ReleaseMetaHeader( hSrcMetaFile );
404
405     if(lpFilename) {         /* disk based metafile */
406         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
407                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
408             HeapFree( GetProcessHeap(), 0, mh2 );
409             return 0;
410         }
411         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
412         CloseHandle(hFile);
413         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
414     }
415
416     return MF_Create_HMETAFILE( mh2 );
417 }
418
419
420 /******************************************************************
421  *         CopyMetaFileW   (GDI32.@)
422  */
423 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
424                                     LPCWSTR lpFilename )
425 {
426     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFilename );
427     HMETAFILE ret = CopyMetaFileA( hSrcMetaFile, p );
428     HeapFree( GetProcessHeap(), 0, p );
429     return ret;
430 }
431
432
433 /******************************************************************
434  *         IsValidMetaFile   (GDI.410)
435  *
436  *  Attempts to check if a given metafile is correctly formatted.
437  *  Currently, the only things verified are several properties of the
438  *  header.
439  *
440  * RETURNS
441  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
442  *
443  * BUGS
444  *  This is not exactly what windows does, see _Undocumented_Windows_
445  *  for details.
446  */
447 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
448 {
449     BOOL16 res=FALSE;
450     METAHEADER *mh = MF_GetMetaHeader16(hmf);
451     if (mh) {
452         if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK) 
453             if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
454                 if (mh->mtVersion == MFVERSION)
455                     res=TRUE;
456         MF_ReleaseMetaHeader16(hmf);
457     }
458     TRACE("IsValidMetaFile %x => %d\n",hmf,res);
459     return res;         
460 }
461
462
463 /*******************************************************************
464  *         MF_PlayMetaFile
465  *
466  * Helper for PlayMetaFile
467  */
468 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
469 {
470
471     METARECORD *mr;
472     HANDLETABLE16 *ht;
473     unsigned int offset = 0;
474     WORD i;
475     HPEN hPen;
476     HBRUSH hBrush;
477     HFONT hFont;
478     BOOL loaded = FALSE;
479
480     if (!mh) return FALSE;
481     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
482         mh = MF_LoadDiskBasedMetaFile(mh);
483         if(!mh) return FALSE;
484         loaded = TRUE;
485     }
486
487     /* save the current pen, brush and font */
488     hPen = GetCurrentObject(hdc, OBJ_PEN);
489     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
490     hFont = GetCurrentObject(hdc, OBJ_FONT);
491
492     /* create the handle table */
493     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
494                     sizeof(HANDLETABLE16) * mh->mtNoObjects);
495     if(!ht) return FALSE;
496     
497     /* loop through metafile playing records */
498     offset = mh->mtHeaderSize * 2;
499     while (offset < mh->mtSize * 2)
500     {
501         mr = (METARECORD *)((char *)mh + offset);
502         TRACE("offset=%04x,size=%08lx\n",
503             offset, mr->rdSize);
504         if (!mr->rdSize) {
505             TRACE(
506                   "Entry got size 0 at offset %d, total mf length is %ld\n",
507                   offset,mh->mtSize*2);
508                 break; /* would loop endlessly otherwise */
509         }
510         offset += mr->rdSize * 2;
511         PlayMetaFileRecord16( hdc, ht, mr, mh->mtNoObjects );
512     }
513
514     SelectObject(hdc, hBrush);
515     SelectObject(hdc, hPen);
516     SelectObject(hdc, hFont);
517
518     /* free objects in handle table */
519     for(i = 0; i < mh->mtNoObjects; i++)
520       if(*(ht->objectHandle + i) != 0)
521         DeleteObject(*(ht->objectHandle + i));
522     
523     /* free handle table */
524     HeapFree( GetProcessHeap(), 0, ht );
525     if(loaded)
526         HeapFree( GetProcessHeap(), 0, mh );
527     return TRUE;
528 }
529
530 /******************************************************************
531  *         PlayMetaFile16   (GDI.123)
532  *
533  */
534 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
535 {
536     BOOL16 ret;
537     METAHEADER *mh = MF_GetMetaHeader16( hmf );
538     ret = MF_PlayMetaFile( hdc, mh );
539     MF_ReleaseMetaHeader16( hmf );
540     return ret;
541 }
542
543 /******************************************************************
544  *         PlayMetaFile   (GDI32.@)
545  *
546  *  Renders the metafile specified by hmf in the DC specified by
547  *  hdc. Returns FALSE on failure, TRUE on success.
548  */
549 BOOL WINAPI PlayMetaFile( 
550                              HDC hdc,      /* [in] handle of DC to render in */
551                              HMETAFILE hmf /* [in] handle of metafile to render */
552 )
553 {
554     BOOL ret;
555     METAHEADER *mh = MF_GetMetaHeader( hmf );
556     ret = MF_PlayMetaFile( hdc, mh );
557     MF_ReleaseMetaHeader( hmf );
558     return ret;
559 }
560
561
562 /******************************************************************
563  *            EnumMetaFile16   (GDI.175)
564  *
565  */
566 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
567                               MFENUMPROC16 lpEnumFunc, LPARAM lpData )
568 {
569     METAHEADER *mh = MF_GetMetaHeader16(hmf);
570     METARECORD *mr;
571     HANDLETABLE16 *ht;
572     HGLOBAL16 hHT;
573     SEGPTR spht;
574     unsigned int offset = 0;
575     WORD i, seg;
576     HPEN hPen;
577     HBRUSH hBrush;
578     HFONT hFont;
579     BOOL16 result = TRUE, loaded = FALSE;
580
581     TRACE("(%04x, %04x, %08lx, %08lx)\n",
582                      hdc, hmf, (DWORD)lpEnumFunc, lpData);
583
584
585     if(!mh) return FALSE;
586     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
587         mh = MF_LoadDiskBasedMetaFile(mh);
588         if(!mh) return FALSE;
589         loaded = TRUE;
590     }
591
592     /* save the current pen, brush and font */
593     hPen = GetCurrentObject(hdc, OBJ_PEN);
594     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
595     hFont = GetCurrentObject(hdc, OBJ_FONT);
596
597     /* create the handle table */
598     
599     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
600                      sizeof(HANDLETABLE16) * mh->mtNoObjects);
601     spht = K32WOWGlobalLock16(hHT);
602    
603     seg = hmf | 7;
604     offset = mh->mtHeaderSize * 2;
605     
606     /* loop through metafile records */
607     
608     while (offset < (mh->mtSize * 2))
609     {
610         mr = (METARECORD *)((char *)mh + offset);
611         if (!lpEnumFunc( hdc, (HANDLETABLE16 *)spht,
612                          (METARECORD *)MAKESEGPTR( seg + (HIWORD(offset) << __AHSHIFT), LOWORD(offset) ),
613                          mh->mtNoObjects, (LONG)lpData ))
614         {
615             result = FALSE;
616             break;
617         }
618         
619
620         offset += (mr->rdSize * 2);
621     }
622
623     SelectObject(hdc, hBrush);
624     SelectObject(hdc, hPen);
625     SelectObject(hdc, hFont);
626
627     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
628
629     /* free objects in handle table */
630     for(i = 0; i < mh->mtNoObjects; i++)
631       if(*(ht->objectHandle + i) != 0)
632         DeleteObject(*(ht->objectHandle + i));
633
634     /* free handle table */
635     GlobalFree16(hHT);
636     if(loaded)
637         HeapFree( GetProcessHeap(), 0, mh );
638     MF_ReleaseMetaHeader16(hmf);
639     return result;
640 }
641
642 /******************************************************************
643  *            EnumMetaFile   (GDI32.@)
644  *
645  *  Loop through the metafile records in hmf, calling the user-specified
646  *  function for each one, stopping when the user's function returns FALSE
647  *  (which is considered to be failure)
648  *  or when no records are left (which is considered to be success). 
649  *
650  * RETURNS
651  *  TRUE on success, FALSE on failure.
652  * 
653  * HISTORY
654  *   Niels de carpentier, april 1996
655  */
656 BOOL WINAPI EnumMetaFile( 
657                              HDC hdc, 
658                              HMETAFILE hmf,
659                              MFENUMPROC lpEnumFunc, 
660                              LPARAM lpData 
661 ) {
662     METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
663     METARECORD *mr;
664     HANDLETABLE *ht;
665     BOOL result = TRUE;
666     int i;
667     unsigned int offset = 0;
668     HPEN hPen;
669     HBRUSH hBrush;
670     HFONT hFont;
671
672     TRACE("(%08x,%08x,%p,%p)\n",
673                      hdc, hmf, lpEnumFunc, (void*)lpData);
674     if (!mh) return 0;
675     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
676         mhTemp = MF_LoadDiskBasedMetaFile(mh);
677         if(!mhTemp)
678         {
679             MF_ReleaseMetaHeader(hmf);
680             return FALSE;
681         }
682         mh = mhTemp;
683     }
684     else
685     {
686         /* We need to copy this thing instead of use it directly because we
687          * have to close the hmf handle for the purpose of avoiding deadlock.
688          */
689         mhTemp = HeapAlloc( GetProcessHeap(), 0, mh->mtHeaderSize + mh->mtSize*2 );
690         if(!mhTemp)
691         {
692             MF_ReleaseMetaHeader(hmf);
693             return FALSE;
694         }
695         memcpy( mhTemp, mh, mh->mtHeaderSize + mh->mtSize*2 );
696         mh = mhTemp;
697     }
698     MF_ReleaseMetaHeader(hmf);
699     hmf = 0; /* just in case */
700     
701     /* save the current pen, brush and font */
702     hPen = GetCurrentObject(hdc, OBJ_PEN);
703     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
704     hFont = GetCurrentObject(hdc, OBJ_FONT);
705
706     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
707                             sizeof(HANDLETABLE) * mh->mtNoObjects);
708
709     /* loop through metafile records */
710     offset = mh->mtHeaderSize * 2;
711     
712     while (offset < (mh->mtSize * 2))
713     {
714         mr = (METARECORD *)((char *)mh + offset);
715         TRACE("Calling EnumFunc with record type %x\n",
716               mr->rdFunction);
717         if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
718         {
719             result = FALSE;
720             break;
721         }
722         
723         offset += (mr->rdSize * 2);
724     }
725
726     /* restore pen, brush and font */
727     SelectObject(hdc, hBrush);
728     SelectObject(hdc, hPen);
729     SelectObject(hdc, hFont);
730
731     /* free objects in handle table */
732     for(i = 0; i < mh->mtNoObjects; i++)
733       if(*(ht->objectHandle + i) != 0)
734         DeleteObject(*(ht->objectHandle + i));
735
736     /* free handle table */
737     HeapFree( GetProcessHeap(), 0, ht);
738     /* free a copy of metafile */
739     HeapFree( GetProcessHeap(), 0, mh );
740     return result;
741 }
742
743 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
744 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr);
745 /******************************************************************
746  *             PlayMetaFileRecord16   (GDI.176)
747  *
748  *   Render a single metafile record specified by *mr in the DC hdc, while
749  *   using the handle table *ht, of length nHandles, 
750  *   to store metafile objects.
751  *
752  * BUGS
753  *  The following metafile records are unimplemented:
754  *
755  *  DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
756  *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
757  *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
758  *
759  */
760 void WINAPI PlayMetaFileRecord16( 
761           HDC16 hdc,         /* [in] DC to render metafile into */
762           HANDLETABLE16 *ht, /* [in] pointer to handle table for metafile objects */
763           METARECORD *mr,    /* [in] pointer to metafile record to render */
764           UINT16 nHandles    /* [in] size of handle table */
765 ) {
766     short s1;
767     HANDLE16 hndl;
768     char *ptr;
769     BITMAPINFOHEADER *infohdr;
770
771     TRACE("(%04x %08lx %08lx %04x) function %04x\n",
772                  hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
773     
774     switch (mr->rdFunction)
775     {
776     case META_EOF:
777         break;
778
779     case META_DELETEOBJECT:
780         DeleteObject(*(ht->objectHandle + *(mr->rdParm)));
781         *(ht->objectHandle + *(mr->rdParm)) = 0;
782         break;
783
784     case META_SETBKCOLOR:
785         SetBkColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
786         break;
787
788     case META_SETBKMODE:
789         SetBkMode16(hdc, *(mr->rdParm));
790         break;
791
792     case META_SETMAPMODE:
793         SetMapMode16(hdc, *(mr->rdParm));
794         break;
795
796     case META_SETROP2:
797         SetROP216(hdc, *(mr->rdParm));
798         break;
799
800     case META_SETRELABS:
801         SetRelAbs16(hdc, *(mr->rdParm));
802         break;
803
804     case META_SETPOLYFILLMODE:
805         SetPolyFillMode16(hdc, *(mr->rdParm));
806         break;
807
808     case META_SETSTRETCHBLTMODE:
809         SetStretchBltMode16(hdc, *(mr->rdParm));
810         break;
811
812     case META_SETTEXTCOLOR:
813         SetTextColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
814         break;
815
816     case META_SETWINDOWORG:
817         SetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
818         break;
819
820     case META_SETWINDOWEXT:
821         SetWindowExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
822         break;
823
824     case META_SETVIEWPORTORG:
825         SetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
826         break;
827
828     case META_SETVIEWPORTEXT:
829         SetViewportExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
830         break;
831
832     case META_OFFSETWINDOWORG:
833         OffsetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
834         break;
835
836     case META_SCALEWINDOWEXT:
837         ScaleWindowExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
838                        *(mr->rdParm + 1), *(mr->rdParm));
839         break;
840
841     case META_OFFSETVIEWPORTORG:
842         OffsetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
843         break;
844
845     case META_SCALEVIEWPORTEXT:
846         ScaleViewportExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
847                          *(mr->rdParm + 1), *(mr->rdParm));
848         break;
849
850     case META_LINETO:
851         LineTo(hdc, (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
852         break;
853
854     case META_MOVETO:
855         MoveTo16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
856         break;
857
858     case META_EXCLUDECLIPRECT:
859         ExcludeClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
860                            *(mr->rdParm + 1), *(mr->rdParm) );
861         break;
862
863     case META_INTERSECTCLIPRECT:
864         IntersectClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
865                              *(mr->rdParm + 1), *(mr->rdParm) );
866         break;
867
868     case META_ARC:
869         Arc(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
870                  (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
871                  (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
872                  (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
873         break;
874
875     case META_ELLIPSE:
876         Ellipse(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
877                      (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
878         break;
879
880     case META_FLOODFILL:
881         FloodFill(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
882                     MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
883         break;
884
885     case META_PIE:
886         Pie(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
887                  (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
888                  (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
889                  (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
890         break;
891
892     case META_RECTANGLE:
893         Rectangle(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
894                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
895         break;
896
897     case META_ROUNDRECT:
898         RoundRect(hdc, (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
899                        (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
900                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
901         break;
902
903     case META_PATBLT:
904         PatBlt16(hdc, *(mr->rdParm + 5), *(mr->rdParm + 4),
905                  *(mr->rdParm + 3), *(mr->rdParm + 2),
906                  MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
907         break;
908
909     case META_SAVEDC:
910         SaveDC(hdc);
911         break;
912
913     case META_SETPIXEL:
914         SetPixel(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
915                    MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
916         break;
917
918     case META_OFFSETCLIPRGN:
919         OffsetClipRgn16( hdc, *(mr->rdParm + 1), *(mr->rdParm) );
920         break;
921
922     case META_TEXTOUT:
923         s1 = *(mr->rdParm);
924         TextOut16(hdc, *(mr->rdParm + ((s1 + 1) >> 1) + 2),
925                   *(mr->rdParm + ((s1 + 1) >> 1) + 1), 
926                   (char *)(mr->rdParm + 1), s1);
927         break;
928
929     case META_POLYGON:
930         Polygon16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
931         break;
932
933     case META_POLYPOLYGON:
934       PolyPolygon16(hdc, (LPPOINT16)(mr->rdParm + *(mr->rdParm) + 1),
935                     (LPINT16)(mr->rdParm + 1), *(mr->rdParm)); 
936       break;
937
938     case META_POLYLINE:
939         Polyline16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
940         break;
941
942     case META_RESTOREDC:
943         RestoreDC(hdc, (INT16)*(mr->rdParm));
944         break;
945
946     case META_SELECTOBJECT:
947         SelectObject(hdc, *(ht->objectHandle + *(mr->rdParm)));
948         break;
949
950     case META_CHORD:
951         Chord(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
952                    (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
953                    (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
954                    (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
955         break;
956
957     case META_CREATEPATTERNBRUSH:
958         switch (*(mr->rdParm))
959         {
960         case BS_PATTERN:
961             infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
962             MF_AddHandle(ht, nHandles,
963                          CreatePatternBrush(CreateBitmap(infohdr->biWidth, 
964                                       infohdr->biHeight, 
965                                       infohdr->biPlanes, 
966                                       infohdr->biBitCount,
967                                       (LPSTR)(mr->rdParm + 
968                                       (sizeof(BITMAPINFOHEADER) / 2) + 4))));
969             break;
970
971         case BS_DIBPATTERN:
972             s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
973             hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
974             ptr = GlobalLock16(hndl);
975             memcpy(ptr, mr->rdParm + 2, s1);
976             GlobalUnlock16(hndl);
977             MF_AddHandle(ht, nHandles,
978                          CreateDIBPatternBrush(hndl, *(mr->rdParm + 1)));
979             GlobalFree16(hndl);
980             break;
981
982         default:
983             ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
984                 mr->rdParm[0]);
985             break;
986         }
987         break;
988         
989     case META_CREATEPENINDIRECT:
990         MF_AddHandle(ht, nHandles, 
991                      CreatePenIndirect16((LOGPEN16 *)(&(mr->rdParm))));
992         break;
993
994     case META_CREATEFONTINDIRECT:
995         MF_AddHandle(ht, nHandles, 
996                      CreateFontIndirect16((LOGFONT16 *)(&(mr->rdParm))));
997         break;
998
999     case META_CREATEBRUSHINDIRECT:
1000         MF_AddHandle(ht, nHandles, 
1001                      CreateBrushIndirect16((LOGBRUSH16 *)(&(mr->rdParm))));
1002         break;
1003
1004     case META_CREATEPALETTE:
1005         MF_AddHandle(ht, nHandles, 
1006                      CreatePalette16((LPLOGPALETTE)mr->rdParm));
1007         break;
1008
1009     case META_SETTEXTALIGN:
1010         SetTextAlign16(hdc, *(mr->rdParm));
1011         break;
1012
1013     case META_SELECTPALETTE:
1014         GDISelectPalette16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1015                         *(mr->rdParm));
1016         break;
1017
1018     case META_SETMAPPERFLAGS:
1019         SetMapperFlags16(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1020         break;
1021
1022     case META_REALIZEPALETTE:
1023         GDIRealizePalette16(hdc);
1024         break;
1025
1026     case META_ESCAPE:
1027         FIXME("META_ESCAPE unimplemented.\n");
1028         break;
1029
1030     case META_EXTTEXTOUT:
1031         MF_Play_MetaExtTextOut( hdc, mr );
1032         break;
1033     
1034     case META_STRETCHDIB:
1035       {
1036         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1037         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1038         StretchDIBits16(hdc,mr->rdParm[10],mr->rdParm[9],mr->rdParm[8],
1039                        mr->rdParm[7],mr->rdParm[6],mr->rdParm[5],
1040                        mr->rdParm[4],mr->rdParm[3],bits,info,
1041                        mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1042       }
1043       break;
1044
1045     case META_DIBSTRETCHBLT:
1046       {
1047         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]); 
1048         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1049         StretchDIBits16(hdc,mr->rdParm[9],mr->rdParm[8],mr->rdParm[7],
1050                        mr->rdParm[6],mr->rdParm[5],mr->rdParm[4],
1051                        mr->rdParm[3],mr->rdParm[2],bits,info,
1052                        DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1053       }
1054       break;              
1055
1056     case META_STRETCHBLT:
1057       {
1058         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1059         HBITMAP hbitmap=CreateBitmap(mr->rdParm[10], /*Width */
1060                                         mr->rdParm[11], /*Height*/
1061                                         mr->rdParm[13], /*Planes*/
1062                                         mr->rdParm[14], /*BitsPixel*/
1063                                         (LPSTR)&mr->rdParm[15]);  /*bits*/
1064         SelectObject(hdcSrc,hbitmap);
1065         StretchBlt16(hdc,mr->rdParm[9],mr->rdParm[8],
1066                     mr->rdParm[7],mr->rdParm[6],
1067                     hdcSrc,mr->rdParm[5],mr->rdParm[4],
1068                     mr->rdParm[3],mr->rdParm[2],
1069                     MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1070         DeleteDC(hdcSrc);                   
1071       }
1072       break;
1073
1074     case META_BITBLT:
1075       {
1076         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1077         HBITMAP hbitmap=CreateBitmap(mr->rdParm[7]/*Width */,
1078                                         mr->rdParm[8]/*Height*/,
1079                                         mr->rdParm[10]/*Planes*/,
1080                                         mr->rdParm[11]/*BitsPixel*/,
1081                                         (LPSTR)&mr->rdParm[12]/*bits*/);
1082         SelectObject(hdcSrc,hbitmap);
1083         BitBlt(hdc,(INT16)mr->rdParm[6],(INT16)mr->rdParm[5],
1084                 (INT16)mr->rdParm[4],(INT16)mr->rdParm[3],
1085                 hdcSrc, (INT16)mr->rdParm[2],(INT16)mr->rdParm[1],
1086                 MAKELONG(0,mr->rdParm[0]));
1087         DeleteDC(hdcSrc);                   
1088       }
1089       break;
1090
1091     case META_CREATEREGION:
1092       {
1093         HRGN hrgn = CreateRectRgn(0,0,0,0);
1094  
1095         MF_Play_MetaCreateRegion(mr, hrgn);
1096         MF_AddHandle(ht, nHandles, hrgn);
1097       }
1098       break;
1099
1100     case META_FILLREGION:
1101         FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1102                        *(ht->objectHandle + *(mr->rdParm)));
1103         break;
1104
1105     case META_FRAMEREGION:
1106         FrameRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+3)),
1107                         *(ht->objectHandle + *(mr->rdParm+2)),
1108                         *(mr->rdParm+1), *(mr->rdParm));
1109         break;
1110
1111     case META_INVERTREGION:
1112         InvertRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1113         break; 
1114
1115     case META_PAINTREGION:
1116         PaintRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1117         break;
1118
1119     case META_SELECTCLIPREGION:
1120         SelectClipRgn(hdc, *(ht->objectHandle + *(mr->rdParm)));
1121         break;
1122
1123     case META_DIBCREATEPATTERNBRUSH:
1124         /*  *(mr->rdParm) may be BS_PATTERN or BS_DIBPATTERN:
1125             but there's no difference */
1126
1127         TRACE("%d\n",*(mr->rdParm));
1128         s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
1129         hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
1130         ptr = GlobalLock16(hndl);
1131         memcpy(ptr, mr->rdParm + 2, s1);
1132         GlobalUnlock16(hndl);
1133         MF_AddHandle(ht, nHandles,
1134                      CreateDIBPatternBrush16(hndl, *(mr->rdParm + 1)));
1135         GlobalFree16(hndl);
1136         break;
1137
1138     case META_DIBBITBLT:
1139       /* In practice I've found that there are two layouts for
1140          META_DIBBITBLT, one (the first here) is the usual one when a src
1141          dc is actually passed to it, the second occurs when the src dc is
1142          passed in as NULL to the creating BitBlt. As the second case has
1143          no dib, a size check will suffice to distinguish.
1144
1145          Caolan.McNamara@ul.ie */
1146
1147         if (mr->rdSize > 12) {
1148             LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1149             LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1150
1151             StretchDIBits16(hdc, mr->rdParm[7], mr->rdParm[6], mr->rdParm[5],
1152                                  mr->rdParm[4], mr->rdParm[3], mr->rdParm[2],
1153                                  mr->rdParm[5], mr->rdParm[4], bits, info,
1154                                  DIB_RGB_COLORS,
1155                                  MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1156         } else { /* equivalent to a PatBlt */
1157             PatBlt16(hdc, mr->rdParm[8], mr->rdParm[7],
1158                           mr->rdParm[6], mr->rdParm[5],
1159                           MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1160         }
1161         break;  
1162        
1163     case META_SETTEXTCHAREXTRA:
1164         SetTextCharacterExtra16(hdc, (INT16)*(mr->rdParm));
1165         break;
1166
1167     case META_SETTEXTJUSTIFICATION:
1168         SetTextJustification(hdc, *(mr->rdParm + 1), *(mr->rdParm));
1169         break;
1170
1171     case META_EXTFLOODFILL:
1172         ExtFloodFill(hdc, (INT16)*(mr->rdParm + 4), (INT16)*(mr->rdParm + 3),
1173                      MAKELONG(*(mr->rdParm+1), *(mr->rdParm + 2)),
1174                      *(mr->rdParm));
1175         break;
1176
1177     case META_SETDIBTODEV:
1178       {
1179         BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1180         char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1181         SetDIBitsToDevice(hdc, (INT16)mr->rdParm[8], (INT16)mr->rdParm[7],
1182                           (INT16)mr->rdParm[6], (INT16)mr->rdParm[5],
1183                           (INT16)mr->rdParm[4], (INT16)mr->rdParm[3],
1184                           mr->rdParm[2], mr->rdParm[1], bits, info,
1185                           mr->rdParm[0]);
1186         break;
1187       }
1188
1189 #define META_UNIMP(x) case x: \
1190 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1191 break;
1192     META_UNIMP(META_DRAWTEXT)
1193     META_UNIMP(META_ANIMATEPALETTE)
1194     META_UNIMP(META_SETPALENTRIES)
1195     META_UNIMP(META_RESIZEPALETTE)
1196     META_UNIMP(META_RESETDC)
1197     META_UNIMP(META_STARTDOC)
1198     META_UNIMP(META_STARTPAGE)
1199     META_UNIMP(META_ENDPAGE)
1200     META_UNIMP(META_ABORTDOC)
1201     META_UNIMP(META_ENDDOC)
1202     META_UNIMP(META_CREATEBRUSH)
1203     META_UNIMP(META_CREATEBITMAPINDIRECT)
1204     META_UNIMP(META_CREATEBITMAP)
1205 #undef META_UNIMP
1206
1207     default:
1208         WARN("PlayMetaFileRecord: Unknown record type %x\n",
1209                                               mr->rdFunction);
1210     }
1211 }
1212
1213 /******************************************************************
1214  *         PlayMetaFileRecord   (GDI32.@)
1215  */
1216 BOOL WINAPI PlayMetaFileRecord( HDC hdc,  HANDLETABLE *handletable, 
1217                                 METARECORD *metarecord, UINT handles )
1218 {
1219     HANDLETABLE16 * ht = (void *)GlobalAlloc(GPTR, 
1220                                              handles*sizeof(HANDLETABLE16));
1221     unsigned int i = 0;
1222     TRACE("(%08x,%p,%p,%d)\n", hdc, handletable, metarecord,
1223           handles); 
1224     for (i=0; i<handles; i++)  
1225         ht->objectHandle[i] =  handletable->objectHandle[i];
1226     PlayMetaFileRecord16(hdc, ht, metarecord, handles);
1227     for (i=0; i<handles; i++) 
1228         handletable->objectHandle[i] = ht->objectHandle[i];
1229     GlobalFree((HGLOBAL)ht);
1230     return TRUE;
1231 }
1232
1233 /******************************************************************
1234  *         GetMetaFileBits   (GDI.159)
1235  *
1236  * Trade in a metafile object handle for a handle to the metafile memory.
1237  *
1238  */
1239
1240 HGLOBAL16 WINAPI GetMetaFileBits16(
1241                                  HMETAFILE16 hmf /* [in] metafile handle */
1242                                  )
1243 {
1244     TRACE("hMem out: %04x\n", hmf);
1245     return hmf;
1246 }
1247
1248 /******************************************************************
1249  *         SetMetaFileBits   (GDI.160)
1250  *
1251  * Trade in a metafile memory handle for a handle to a metafile object.
1252  * The memory region should hold a proper metafile, otherwise
1253  * problems will occur when it is used. Validity of the memory is not
1254  * checked. The function is essentially just the identity function.
1255  */
1256 HMETAFILE16 WINAPI SetMetaFileBits16( 
1257                                    HGLOBAL16 hMem 
1258                         /* [in] handle to a memory region holding a metafile */
1259 )
1260 {
1261     TRACE("hmf out: %04x\n", hMem);
1262
1263     return hMem;
1264 }
1265
1266 /******************************************************************
1267  *         SetMetaFileBitsBetter   (GDI.196)
1268  *
1269  * Trade in a metafile memory handle for a handle to a metafile object,
1270  * making a cursory check (using IsValidMetaFile()) that the memory
1271  * handle points to a valid metafile.
1272  *
1273  * RETURNS
1274  *  Handle to a metafile on success, NULL on failure..
1275  */
1276 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1277 {
1278     if( IsValidMetaFile16( hMeta ) )
1279         return (HMETAFILE16)GlobalReAlloc16( hMeta, 0, 
1280                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1281     return (HMETAFILE16)0;
1282 }
1283
1284 /******************************************************************
1285  *         SetMetaFileBitsEx    (GDI32.@)
1286  * 
1287  *  Create a metafile from raw data. No checking of the data is performed.
1288  *  Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1289  */
1290 HMETAFILE WINAPI SetMetaFileBitsEx( 
1291      UINT size,         /* [in] size of metafile, in bytes */
1292      const BYTE *lpData /* [in] pointer to metafile data */  
1293     )
1294 {
1295     METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1296     if (!mh) return 0;
1297     memcpy(mh, lpData, size);
1298     return MF_Create_HMETAFILE(mh);
1299 }
1300
1301 /*****************************************************************
1302  *  GetMetaFileBitsEx     (GDI32.@)  Get raw metafile data
1303  * 
1304  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1305  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1306  *  returns number of bytes copied.
1307  */
1308 UINT WINAPI GetMetaFileBitsEx( 
1309      HMETAFILE hmf, /* [in] metafile */
1310      UINT nSize,    /* [in] size of buf */ 
1311      LPVOID buf     /* [out] buffer to receive raw metafile data */  
1312 ) {
1313     METAHEADER *mh = MF_GetMetaHeader(hmf);
1314     UINT mfSize;
1315
1316     TRACE("(%08x,%d,%p)\n", hmf, nSize, buf);
1317     if (!mh) return 0;  /* FIXME: error code */
1318     if(mh->mtType == METAFILE_DISK)
1319         FIXME("Disk-based metafile?\n");
1320     mfSize = mh->mtSize * 2;
1321     if (!buf) {
1322         MF_ReleaseMetaHeader(hmf);
1323         TRACE("returning size %d\n", mfSize);
1324         return mfSize;
1325     }
1326     if(mfSize > nSize) mfSize = nSize;
1327     memmove(buf, mh, mfSize);
1328     MF_ReleaseMetaHeader(hmf);
1329     return mfSize;
1330 }
1331
1332 /******************************************************************
1333  *         GetWinMetaFileBits [GDI32.@]
1334  */
1335 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1336                                 UINT cbBuffer, LPBYTE lpbBuffer,
1337                                 INT fnMapMode, HDC hdcRef)
1338 {
1339     FIXME("(%d,%d,%p,%d,%d): stub\n",
1340           hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1341     return 0;
1342 }
1343
1344 /******************************************************************
1345  *         MF_Play_MetaCreateRegion
1346  *
1347  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1348  */
1349
1350 /*
1351  *      The layout of the record looks something like this:
1352  *       
1353  *       rdParm meaning
1354  *       0              Always 0?
1355  *       1              Always 6?
1356  *       2              Looks like a handle? - not constant
1357  *       3              0 or 1 ??
1358  *       4              Total number of bytes
1359  *       5              No. of separate bands = n [see below]
1360  *       6              Largest number of x co-ords in a band
1361  *       7-10           Bounding box x1 y1 x2 y2
1362  *       11-...         n bands
1363  *
1364  *       Regions are divided into bands that are uniform in the
1365  *       y-direction. Each band consists of pairs of on/off x-coords and is
1366  *       written as
1367  *              m y0 y1 x1 x2 x3 ... xm m
1368  *       into successive rdParm[]s.
1369  *
1370  *       This is probably just a dump of the internal RGNOBJ?
1371  *
1372  *       HDMD - 18/12/97
1373  *
1374  */
1375
1376 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1377 {
1378     WORD band, pair;
1379     WORD *start, *end;
1380     INT16 y0, y1;
1381     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1382
1383     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1384                                                 band++, start = end + 1) {
1385         if(*start / 2 != (*start + 1) / 2) {
1386             WARN("Delimiter not even.\n");
1387             DeleteObject( hrgn2 );
1388             return FALSE;
1389         }
1390
1391         end = start + *start + 3;
1392         if(end > (WORD *)mr + mr->rdSize) {
1393             WARN("End points outside record.\n");
1394             DeleteObject( hrgn2 );
1395             return FALSE;
1396         }
1397
1398         if(*start != *end) {
1399             WARN("Mismatched delimiters.\n");
1400             DeleteObject( hrgn2 );
1401             return FALSE;
1402         }
1403
1404         y0 = *(INT16 *)(start + 1);
1405         y1 = *(INT16 *)(start + 2);
1406         for(pair = 0; pair < *start / 2; pair++) {
1407             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1408                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1409             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1410         }
1411     }
1412     DeleteObject( hrgn2 );
1413     return TRUE;
1414  }
1415  
1416
1417 /******************************************************************
1418  *         MF_Play_MetaExtTextOut
1419  *
1420  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1421  */
1422
1423 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr)
1424 {
1425     LPINT16 dxx;
1426     LPSTR sot; 
1427     DWORD len;
1428     WORD s1;
1429
1430     s1 = mr->rdParm[2];                              /* String length */
1431     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1432       + sizeof(UINT16) +  (mr->rdParm[3] ? sizeof(RECT16) : 0); 
1433                                            /* rec len without dx array */
1434
1435     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1436     if (mr->rdParm[3])
1437         sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1438          
1439     if (mr->rdSize == len / 2)
1440         dxx = NULL;                      /* determine if array present */
1441     else 
1442         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1443             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));          
1444         else {
1445             TRACE("%s  len: %ld\n",  sot, mr->rdSize);
1446             WARN(
1447              "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1448                  len, s1, mr->rdSize, mr->rdParm[3]);
1449             dxx = NULL; /* should't happen -- but if, we continue with NULL */
1450         }
1451     ExtTextOut16( hdc, mr->rdParm[1],              /* X position */
1452                        mr->rdParm[0],              /* Y position */
1453                        mr->rdParm[3],              /* options */
1454                        mr->rdParm[3] ? (LPRECT16) &mr->rdParm[4]:NULL,  
1455                                                    /* rectangle */
1456                        sot,                            /* string */
1457                        s1, dxx);                   /* length, dx array */
1458     if (dxx)                      
1459         TRACE("%s  len: %ld  dx0: %d\n", sot, mr->rdSize, dxx[0]);
1460     return TRUE;
1461 }