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