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