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