Documentation update.
[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.69)
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     HFILE 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, -1)) == HFILE_ERROR)
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.197)
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     HFILE 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, -1)) == HFILE_ERROR)
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.199)
264  */
265 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
266 {
267     METAHEADER *mh;
268     HFILE 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, -1)) == HFILE_ERROR)
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     HFILE 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, -1)) == HFILE_ERROR) {
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     HFILE 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, -1)) == HFILE_ERROR) {
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.23)
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     HFILE 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, -1)) == HFILE_ERROR) {
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.24)
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     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.265)
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     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 = WIN16_GlobalLock16(hHT);
601    
602     seg = GlobalHandleToSel16(hmf);
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.88)
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, offset = 0;
666     HPEN hPen;
667     HBRUSH hBrush;
668     HFONT hFont;
669
670     TRACE("(%08x,%08x,%p,%p)\n",
671                      hdc, hmf, lpEnumFunc, (void*)lpData);
672     if (!mh) return 0;
673     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
674         mhTemp = MF_LoadDiskBasedMetaFile(mh);
675         if(!mhTemp)
676         {
677             MF_ReleaseMetaHeader(hmf);
678             return FALSE;
679         }
680         mh = mhTemp;
681     }
682     else
683     {
684         /* We need to copy this thing instead of use it directly because we
685          * have to close the hmf handle for the purpose of avoiding deadlock.
686          */
687         mhTemp = HeapAlloc( GetProcessHeap(), 0, mh->mtHeaderSize + mh->mtSize*2 );
688         if(!mhTemp)
689         {
690             MF_ReleaseMetaHeader(hmf);
691             return FALSE;
692         }
693         memcpy( mhTemp, mh, mh->mtHeaderSize + mh->mtSize*2 );
694         mh = mhTemp;
695     }
696     MF_ReleaseMetaHeader(hmf);
697     hmf = 0; /* just in case */
698     
699     /* save the current pen, brush and font */
700     hPen = GetCurrentObject(hdc, OBJ_PEN);
701     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
702     hFont = GetCurrentObject(hdc, OBJ_FONT);
703
704     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
705                             sizeof(HANDLETABLE) * mh->mtNoObjects);
706
707     /* loop through metafile records */
708     offset = mh->mtHeaderSize * 2;
709     
710     while (offset < (mh->mtSize * 2))
711     {
712         mr = (METARECORD *)((char *)mh + offset);
713         TRACE("Calling EnumFunc with record type %x\n",
714               mr->rdFunction);
715         if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
716         {
717             result = FALSE;
718             break;
719         }
720         
721         offset += (mr->rdSize * 2);
722     }
723
724     /* restore pen, brush and font */
725     SelectObject(hdc, hBrush);
726     SelectObject(hdc, hPen);
727     SelectObject(hdc, hFont);
728
729     /* free objects in handle table */
730     for(i = 0; i < mh->mtNoObjects; i++)
731       if(*(ht->objectHandle + i) != 0)
732         DeleteObject(*(ht->objectHandle + i));
733
734     /* free handle table */
735     HeapFree( GetProcessHeap(), 0, ht);
736     /* free a copy of metafile */
737     HeapFree( GetProcessHeap(), 0, mh );
738     return result;
739 }
740
741 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
742 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr);
743 /******************************************************************
744  *             PlayMetaFileRecord16   (GDI.176)
745  *
746  *   Render a single metafile record specified by *mr in the DC hdc, while
747  *   using the handle table *ht, of length nHandles, 
748  *   to store metafile objects.
749  *
750  * BUGS
751  *  The following metafile records are unimplemented:
752  *
753  *  DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
754  *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
755  *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
756  *
757  */
758 void WINAPI PlayMetaFileRecord16( 
759           HDC16 hdc,         /* [in] DC to render metafile into */
760           HANDLETABLE16 *ht, /* [in] pointer to handle table for metafile objects */
761           METARECORD *mr,    /* [in] pointer to metafile record to render */
762           UINT16 nHandles    /* [in] size of handle table */
763 ) {
764     short s1;
765     HANDLE16 hndl;
766     char *ptr;
767     BITMAPINFOHEADER *infohdr;
768
769     TRACE("(%04x %08lx %08lx %04x) function %04x\n",
770                  hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
771     
772     switch (mr->rdFunction)
773     {
774     case META_EOF:
775         break;
776
777     case META_DELETEOBJECT:
778         DeleteObject(*(ht->objectHandle + *(mr->rdParm)));
779         *(ht->objectHandle + *(mr->rdParm)) = 0;
780         break;
781
782     case META_SETBKCOLOR:
783         SetBkColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
784         break;
785
786     case META_SETBKMODE:
787         SetBkMode16(hdc, *(mr->rdParm));
788         break;
789
790     case META_SETMAPMODE:
791         SetMapMode16(hdc, *(mr->rdParm));
792         break;
793
794     case META_SETROP2:
795         SetROP216(hdc, *(mr->rdParm));
796         break;
797
798     case META_SETRELABS:
799         SetRelAbs16(hdc, *(mr->rdParm));
800         break;
801
802     case META_SETPOLYFILLMODE:
803         SetPolyFillMode16(hdc, *(mr->rdParm));
804         break;
805
806     case META_SETSTRETCHBLTMODE:
807         SetStretchBltMode16(hdc, *(mr->rdParm));
808         break;
809
810     case META_SETTEXTCOLOR:
811         SetTextColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
812         break;
813
814     case META_SETWINDOWORG:
815         SetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
816         break;
817
818     case META_SETWINDOWEXT:
819         SetWindowExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
820         break;
821
822     case META_SETVIEWPORTORG:
823         SetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
824         break;
825
826     case META_SETVIEWPORTEXT:
827         SetViewportExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
828         break;
829
830     case META_OFFSETWINDOWORG:
831         OffsetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
832         break;
833
834     case META_SCALEWINDOWEXT:
835         ScaleWindowExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
836                        *(mr->rdParm + 1), *(mr->rdParm));
837         break;
838
839     case META_OFFSETVIEWPORTORG:
840         OffsetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
841         break;
842
843     case META_SCALEVIEWPORTEXT:
844         ScaleViewportExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
845                          *(mr->rdParm + 1), *(mr->rdParm));
846         break;
847
848     case META_LINETO:
849         LineTo(hdc, (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
850         break;
851
852     case META_MOVETO:
853         MoveTo16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
854         break;
855
856     case META_EXCLUDECLIPRECT:
857         ExcludeClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
858                            *(mr->rdParm + 1), *(mr->rdParm) );
859         break;
860
861     case META_INTERSECTCLIPRECT:
862         IntersectClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
863                              *(mr->rdParm + 1), *(mr->rdParm) );
864         break;
865
866     case META_ARC:
867         Arc(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
868                  (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
869                  (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
870                  (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
871         break;
872
873     case META_ELLIPSE:
874         Ellipse(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
875                      (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
876         break;
877
878     case META_FLOODFILL:
879         FloodFill(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
880                     MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
881         break;
882
883     case META_PIE:
884         Pie(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_RECTANGLE:
891         Rectangle(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
892                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
893         break;
894
895     case META_ROUNDRECT:
896         RoundRect(hdc, (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
897                        (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
898                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
899         break;
900
901     case META_PATBLT:
902         PatBlt16(hdc, *(mr->rdParm + 5), *(mr->rdParm + 4),
903                  *(mr->rdParm + 3), *(mr->rdParm + 2),
904                  MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
905         break;
906
907     case META_SAVEDC:
908         SaveDC(hdc);
909         break;
910
911     case META_SETPIXEL:
912         SetPixel(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
913                    MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
914         break;
915
916     case META_OFFSETCLIPRGN:
917         OffsetClipRgn16( hdc, *(mr->rdParm + 1), *(mr->rdParm) );
918         break;
919
920     case META_TEXTOUT:
921         s1 = *(mr->rdParm);
922         TextOut16(hdc, *(mr->rdParm + ((s1 + 1) >> 1) + 2),
923                   *(mr->rdParm + ((s1 + 1) >> 1) + 1), 
924                   (char *)(mr->rdParm + 1), s1);
925         break;
926
927     case META_POLYGON:
928         Polygon16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
929         break;
930
931     case META_POLYPOLYGON:
932       PolyPolygon16(hdc, (LPPOINT16)(mr->rdParm + *(mr->rdParm) + 1),
933                     (LPINT16)(mr->rdParm + 1), *(mr->rdParm)); 
934       break;
935
936     case META_POLYLINE:
937         Polyline16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
938         break;
939
940     case META_RESTOREDC:
941         RestoreDC(hdc, (INT16)*(mr->rdParm));
942         break;
943
944     case META_SELECTOBJECT:
945         SelectObject(hdc, *(ht->objectHandle + *(mr->rdParm)));
946         break;
947
948     case META_CHORD:
949         Chord(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
950                    (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
951                    (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
952                    (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
953         break;
954
955     case META_CREATEPATTERNBRUSH:
956         switch (*(mr->rdParm))
957         {
958         case BS_PATTERN:
959             infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
960             MF_AddHandle(ht, nHandles,
961                          CreatePatternBrush(CreateBitmap(infohdr->biWidth, 
962                                       infohdr->biHeight, 
963                                       infohdr->biPlanes, 
964                                       infohdr->biBitCount,
965                                       (LPSTR)(mr->rdParm + 
966                                       (sizeof(BITMAPINFOHEADER) / 2) + 4))));
967             break;
968
969         case BS_DIBPATTERN:
970             s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
971             hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
972             ptr = GlobalLock16(hndl);
973             memcpy(ptr, mr->rdParm + 2, s1);
974             GlobalUnlock16(hndl);
975             MF_AddHandle(ht, nHandles,
976                          CreateDIBPatternBrush(hndl, *(mr->rdParm + 1)));
977             GlobalFree16(hndl);
978             break;
979
980         default:
981             ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
982                 mr->rdParm[0]);
983             break;
984         }
985         break;
986         
987     case META_CREATEPENINDIRECT:
988         MF_AddHandle(ht, nHandles, 
989                      CreatePenIndirect16((LOGPEN16 *)(&(mr->rdParm))));
990         break;
991
992     case META_CREATEFONTINDIRECT:
993         MF_AddHandle(ht, nHandles, 
994                      CreateFontIndirect16((LOGFONT16 *)(&(mr->rdParm))));
995         break;
996
997     case META_CREATEBRUSHINDIRECT:
998         MF_AddHandle(ht, nHandles, 
999                      CreateBrushIndirect16((LOGBRUSH16 *)(&(mr->rdParm))));
1000         break;
1001
1002     case META_CREATEPALETTE:
1003         MF_AddHandle(ht, nHandles, 
1004                      CreatePalette16((LPLOGPALETTE)mr->rdParm));
1005         break;
1006
1007     case META_SETTEXTALIGN:
1008         SetTextAlign16(hdc, *(mr->rdParm));
1009         break;
1010
1011     case META_SELECTPALETTE:
1012         GDISelectPalette16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1013                         *(mr->rdParm));
1014         break;
1015
1016     case META_SETMAPPERFLAGS:
1017         SetMapperFlags16(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1018         break;
1019
1020     case META_REALIZEPALETTE:
1021         GDIRealizePalette16(hdc);
1022         break;
1023
1024     case META_ESCAPE:
1025         FIXME("META_ESCAPE unimplemented.\n");
1026         break;
1027
1028     case META_EXTTEXTOUT:
1029         MF_Play_MetaExtTextOut( hdc, mr );
1030         break;
1031     
1032     case META_STRETCHDIB:
1033       {
1034         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1035         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1036         StretchDIBits16(hdc,mr->rdParm[10],mr->rdParm[9],mr->rdParm[8],
1037                        mr->rdParm[7],mr->rdParm[6],mr->rdParm[5],
1038                        mr->rdParm[4],mr->rdParm[3],bits,info,
1039                        mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1040       }
1041       break;
1042
1043     case META_DIBSTRETCHBLT:
1044       {
1045         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]); 
1046         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1047         StretchDIBits16(hdc,mr->rdParm[9],mr->rdParm[8],mr->rdParm[7],
1048                        mr->rdParm[6],mr->rdParm[5],mr->rdParm[4],
1049                        mr->rdParm[3],mr->rdParm[2],bits,info,
1050                        DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1051       }
1052       break;              
1053
1054     case META_STRETCHBLT:
1055       {
1056         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1057         HBITMAP hbitmap=CreateBitmap(mr->rdParm[10], /*Width */
1058                                         mr->rdParm[11], /*Height*/
1059                                         mr->rdParm[13], /*Planes*/
1060                                         mr->rdParm[14], /*BitsPixel*/
1061                                         (LPSTR)&mr->rdParm[15]);  /*bits*/
1062         SelectObject(hdcSrc,hbitmap);
1063         StretchBlt16(hdc,mr->rdParm[9],mr->rdParm[8],
1064                     mr->rdParm[7],mr->rdParm[6],
1065                     hdcSrc,mr->rdParm[5],mr->rdParm[4],
1066                     mr->rdParm[3],mr->rdParm[2],
1067                     MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1068         DeleteDC(hdcSrc);                   
1069       }
1070       break;
1071
1072     case META_BITBLT:
1073       {
1074         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1075         HBITMAP hbitmap=CreateBitmap(mr->rdParm[7]/*Width */,
1076                                         mr->rdParm[8]/*Height*/,
1077                                         mr->rdParm[10]/*Planes*/,
1078                                         mr->rdParm[11]/*BitsPixel*/,
1079                                         (LPSTR)&mr->rdParm[12]/*bits*/);
1080         SelectObject(hdcSrc,hbitmap);
1081         BitBlt(hdc,(INT16)mr->rdParm[6],(INT16)mr->rdParm[5],
1082                 (INT16)mr->rdParm[4],(INT16)mr->rdParm[3],
1083                 hdcSrc, (INT16)mr->rdParm[2],(INT16)mr->rdParm[1],
1084                 MAKELONG(0,mr->rdParm[0]));
1085         DeleteDC(hdcSrc);                   
1086       }
1087       break;
1088
1089     case META_CREATEREGION:
1090       {
1091         HRGN hrgn = CreateRectRgn(0,0,0,0);
1092  
1093         MF_Play_MetaCreateRegion(mr, hrgn);
1094         MF_AddHandle(ht, nHandles, hrgn);
1095       }
1096       break;
1097
1098     case META_FILLREGION:
1099         FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1100                        *(ht->objectHandle + *(mr->rdParm)));
1101         break;
1102
1103     case META_FRAMEREGION:
1104         FrameRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+3)),
1105                         *(ht->objectHandle + *(mr->rdParm+2)),
1106                         *(mr->rdParm+1), *(mr->rdParm));
1107         break;
1108
1109     case META_INVERTREGION:
1110         InvertRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1111         break; 
1112
1113     case META_PAINTREGION:
1114         PaintRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1115         break;
1116
1117     case META_SELECTCLIPREGION:
1118         SelectClipRgn(hdc, *(ht->objectHandle + *(mr->rdParm)));
1119         break;
1120
1121     case META_DIBCREATEPATTERNBRUSH:
1122         /*  *(mr->rdParm) may be BS_PATTERN or BS_DIBPATTERN:
1123             but there's no difference */
1124
1125         TRACE("%d\n",*(mr->rdParm));
1126         s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
1127         hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
1128         ptr = GlobalLock16(hndl);
1129         memcpy(ptr, mr->rdParm + 2, s1);
1130         GlobalUnlock16(hndl);
1131         MF_AddHandle(ht, nHandles,
1132                      CreateDIBPatternBrush16(hndl, *(mr->rdParm + 1)));
1133         GlobalFree16(hndl);
1134         break;
1135
1136     case META_DIBBITBLT:
1137       /* In practice I've found that there are two layouts for
1138          META_DIBBITBLT, one (the first here) is the usual one when a src
1139          dc is actually passed to it, the second occurs when the src dc is
1140          passed in as NULL to the creating BitBlt. As the second case has
1141          no dib, a size check will suffice to distinguish.
1142
1143          Caolan.McNamara@ul.ie */
1144
1145         if (mr->rdSize > 12) {
1146             LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1147             LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1148
1149             StretchDIBits16(hdc, mr->rdParm[7], mr->rdParm[6], mr->rdParm[5],
1150                                  mr->rdParm[4], mr->rdParm[3], mr->rdParm[2],
1151                                  mr->rdParm[5], mr->rdParm[4], bits, info,
1152                                  DIB_RGB_COLORS,
1153                                  MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1154         } else { /* equivalent to a PatBlt */
1155             PatBlt16(hdc, mr->rdParm[8], mr->rdParm[7],
1156                           mr->rdParm[6], mr->rdParm[5],
1157                           MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1158         }
1159         break;  
1160        
1161     case META_SETTEXTCHAREXTRA:
1162         SetTextCharacterExtra16(hdc, (INT16)*(mr->rdParm));
1163         break;
1164
1165     case META_SETTEXTJUSTIFICATION:
1166         SetTextJustification(hdc, *(mr->rdParm + 1), *(mr->rdParm));
1167         break;
1168
1169     case META_EXTFLOODFILL:
1170         ExtFloodFill(hdc, (INT16)*(mr->rdParm + 4), (INT16)*(mr->rdParm + 3),
1171                      MAKELONG(*(mr->rdParm+1), *(mr->rdParm + 2)),
1172                      *(mr->rdParm));
1173         break;
1174
1175     case META_SETDIBTODEV:
1176       {
1177         BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1178         char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1179         SetDIBitsToDevice(hdc, (INT16)mr->rdParm[8], (INT16)mr->rdParm[7],
1180                           (INT16)mr->rdParm[6], (INT16)mr->rdParm[5],
1181                           (INT16)mr->rdParm[4], (INT16)mr->rdParm[3],
1182                           mr->rdParm[2], mr->rdParm[1], bits, info,
1183                           mr->rdParm[0]);
1184         break;
1185       }
1186
1187 #define META_UNIMP(x) case x: \
1188 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1189 break;
1190     META_UNIMP(META_DRAWTEXT)
1191     META_UNIMP(META_ANIMATEPALETTE)
1192     META_UNIMP(META_SETPALENTRIES)
1193     META_UNIMP(META_RESIZEPALETTE)
1194     META_UNIMP(META_RESETDC)
1195     META_UNIMP(META_STARTDOC)
1196     META_UNIMP(META_STARTPAGE)
1197     META_UNIMP(META_ENDPAGE)
1198     META_UNIMP(META_ABORTDOC)
1199     META_UNIMP(META_ENDDOC)
1200     META_UNIMP(META_CREATEBRUSH)
1201     META_UNIMP(META_CREATEBITMAPINDIRECT)
1202     META_UNIMP(META_CREATEBITMAP)
1203 #undef META_UNIMP
1204
1205     default:
1206         WARN("PlayMetaFileRecord: Unknown record type %x\n",
1207                                               mr->rdFunction);
1208     }
1209 }
1210
1211 /******************************************************************
1212  *         PlayMetaFileRecord   (GDI32.266)
1213  */
1214 BOOL WINAPI PlayMetaFileRecord( HDC hdc,  HANDLETABLE *handletable, 
1215                                 METARECORD *metarecord, UINT handles )
1216 {
1217     HANDLETABLE16 * ht = (void *)GlobalAlloc(GPTR, 
1218                                              handles*sizeof(HANDLETABLE16));
1219     int i = 0;
1220     TRACE("(%08x,%p,%p,%d)\n", hdc, handletable, metarecord,
1221           handles); 
1222     for (i=0; i<handles; i++)  
1223         ht->objectHandle[i] =  handletable->objectHandle[i];
1224     PlayMetaFileRecord16(hdc, ht, metarecord, handles);
1225     for (i=0; i<handles; i++) 
1226         handletable->objectHandle[i] = ht->objectHandle[i];
1227     GlobalFree((HGLOBAL)ht);
1228     return TRUE;
1229 }
1230
1231 /******************************************************************
1232  *         GetMetaFileBits   (GDI.159)
1233  *
1234  * Trade in a metafile object handle for a handle to the metafile memory.
1235  *
1236  */
1237
1238 HGLOBAL16 WINAPI GetMetaFileBits16(
1239                                  HMETAFILE16 hmf /* [in] metafile handle */
1240                                  )
1241 {
1242     TRACE("hMem out: %04x\n", hmf);
1243     return hmf;
1244 }
1245
1246 /******************************************************************
1247  *         SetMetaFileBits   (GDI.160)
1248  *
1249  * Trade in a metafile memory handle for a handle to a metafile object.
1250  * The memory region should hold a proper metafile, otherwise
1251  * problems will occur when it is used. Validity of the memory is not
1252  * checked. The function is essentially just the identity function.
1253  */
1254 HMETAFILE16 WINAPI SetMetaFileBits16( 
1255                                    HGLOBAL16 hMem 
1256                         /* [in] handle to a memory region holding a metafile */
1257 )
1258 {
1259     TRACE("hmf out: %04x\n", hMem);
1260
1261     return hMem;
1262 }
1263
1264 /******************************************************************
1265  *         SetMetaFileBitsBetter   (GDI.196)
1266  *
1267  * Trade in a metafile memory handle for a handle to a metafile object,
1268  * making a cursory check (using IsValidMetaFile()) that the memory
1269  * handle points to a valid metafile.
1270  *
1271  * RETURNS
1272  *  Handle to a metafile on success, NULL on failure..
1273  */
1274 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1275 {
1276     if( IsValidMetaFile16( hMeta ) )
1277         return (HMETAFILE16)GlobalReAlloc16( hMeta, 0, 
1278                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1279     return (HMETAFILE16)0;
1280 }
1281
1282 /******************************************************************
1283  *         SetMetaFileBitsEx    (GDI32.323)
1284  * 
1285  *  Create a metafile from raw data. No checking of the data is performed.
1286  *  Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1287  */
1288 HMETAFILE WINAPI SetMetaFileBitsEx( 
1289      UINT size,         /* [in] size of metafile, in bytes */
1290      const BYTE *lpData /* [in] pointer to metafile data */  
1291     )
1292 {
1293     METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1294     if (!mh) return 0;
1295     memcpy(mh, lpData, size);
1296     return MF_Create_HMETAFILE(mh);
1297 }
1298
1299 /*****************************************************************
1300  *  GetMetaFileBitsEx     (GDI32.198)  Get raw metafile data
1301  * 
1302  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1303  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1304  *  returns number of bytes copied.
1305  */
1306 UINT WINAPI GetMetaFileBitsEx( 
1307      HMETAFILE hmf, /* [in] metafile */
1308      UINT nSize,    /* [in] size of buf */ 
1309      LPVOID buf     /* [out] buffer to receive raw metafile data */  
1310 ) {
1311     METAHEADER *mh = MF_GetMetaHeader(hmf);
1312     UINT mfSize;
1313
1314     TRACE("(%08x,%d,%p)\n", hmf, nSize, buf);
1315     if (!mh) return 0;  /* FIXME: error code */
1316     if(mh->mtType == METAFILE_DISK)
1317         FIXME("Disk-based metafile?\n");
1318     mfSize = mh->mtSize * 2;
1319     if (!buf) {
1320         MF_ReleaseMetaHeader(hmf);
1321         TRACE("returning size %d\n", mfSize);
1322         return mfSize;
1323     }
1324     if(mfSize > nSize) mfSize = nSize;
1325     memmove(buf, mh, mfSize);
1326     MF_ReleaseMetaHeader(hmf);
1327     return mfSize;
1328 }
1329
1330 /******************************************************************
1331  *         GetWinMetaFileBits [GDI32.241]
1332  */
1333 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1334                                 UINT cbBuffer, LPBYTE lpbBuffer,
1335                                 INT fnMapMode, HDC hdcRef)
1336 {
1337     FIXME("(%d,%d,%p,%d,%d): stub\n",
1338           hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1339     return 0;
1340 }
1341
1342 /******************************************************************
1343  *         MF_Play_MetaCreateRegion
1344  *
1345  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1346  */
1347
1348 /*
1349  *      The layout of the record looks something like this:
1350  *       
1351  *       rdParm meaning
1352  *       0              Always 0?
1353  *       1              Always 6?
1354  *       2              Looks like a handle? - not constant
1355  *       3              0 or 1 ??
1356  *       4              Total number of bytes
1357  *       5              No. of seperate bands = n [see below]
1358  *       6              Largest number of x co-ords in a band
1359  *       7-10           Bounding box x1 y1 x2 y2
1360  *       11-...         n bands
1361  *
1362  *       Regions are divided into bands that are uniform in the
1363  *       y-direction. Each band consists of pairs of on/off x-coords and is
1364  *       written as
1365  *              m y0 y1 x1 x2 x3 ... xm m
1366  *       into successive rdParm[]s.
1367  *
1368  *       This is probably just a dump of the internal RGNOBJ?
1369  *
1370  *       HDMD - 18/12/97
1371  *
1372  */
1373
1374 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1375 {
1376     WORD band, pair;
1377     WORD *start, *end;
1378     INT16 y0, y1;
1379     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1380
1381     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1382                                                 band++, start = end + 1) {
1383         if(*start / 2 != (*start + 1) / 2) {
1384             WARN("Delimiter not even.\n");
1385             DeleteObject( hrgn2 );
1386             return FALSE;
1387         }
1388
1389         end = start + *start + 3;
1390         if(end > (WORD *)mr + mr->rdSize) {
1391             WARN("End points outside record.\n");
1392             DeleteObject( hrgn2 );
1393             return FALSE;
1394         }
1395
1396         if(*start != *end) {
1397             WARN("Mismatched delimiters.\n");
1398             DeleteObject( hrgn2 );
1399             return FALSE;
1400         }
1401
1402         y0 = *(INT16 *)(start + 1);
1403         y1 = *(INT16 *)(start + 2);
1404         for(pair = 0; pair < *start / 2; pair++) {
1405             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1406                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1407             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1408         }
1409     }
1410     DeleteObject( hrgn2 );
1411     return TRUE;
1412  }
1413  
1414
1415 /******************************************************************
1416  *         MF_Play_MetaExtTextOut
1417  *
1418  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1419  */
1420
1421 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr)
1422 {
1423     LPINT16 dxx;
1424     LPSTR sot; 
1425     DWORD len;
1426     WORD s1;
1427
1428     s1 = mr->rdParm[2];                              /* String length */
1429     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1430       + sizeof(UINT16) +  (mr->rdParm[3] ? sizeof(RECT16) : 0); 
1431                                            /* rec len without dx array */
1432
1433     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1434     if (mr->rdParm[3])
1435         sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1436          
1437     if (mr->rdSize == len / 2)
1438         dxx = NULL;                      /* determine if array present */
1439     else 
1440         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1441             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));          
1442         else {
1443             TRACE("%s  len: %ld\n",  sot, mr->rdSize);
1444             WARN(
1445              "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1446                  len, s1, mr->rdSize, mr->rdParm[3]);
1447             dxx = NULL; /* should't happen -- but if, we continue with NULL */
1448         }
1449     ExtTextOut16( hdc, mr->rdParm[1],              /* X position */
1450                        mr->rdParm[0],              /* Y position */
1451                        mr->rdParm[3],              /* options */
1452                        mr->rdParm[3] ? (LPRECT16) &mr->rdParm[4]:NULL,  
1453                                                    /* rectangle */
1454                        sot,                            /* string */
1455                        s1, dxx);                   /* length, dx array */
1456     if (dxx)                      
1457         TRACE("%s  len: %ld  dx0: %d\n", sot, mr->rdSize, dxx[0]);
1458     return TRUE;
1459 }