Fixes for memory leaks on error path.
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winreg.h"
32 #include "winerror.h"
33
34 #include "bitmap.h"
35 #include "local.h"
36 #include "palette.h"
37 #include "gdi.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
41
42 #define HGDIOBJ_32(h16)   ((HGDIOBJ)(ULONG_PTR)(h16))
43
44 /***********************************************************************
45  *          GDI stock objects
46  */
47
48 static const LOGBRUSH WhiteBrush = { BS_SOLID, RGB(255,255,255), 0 };
49 static const LOGBRUSH BlackBrush = { BS_SOLID, RGB(0,0,0), 0 };
50 static const LOGBRUSH NullBrush  = { BS_NULL, 0, 0 };
51
52 /* FIXME: these should perhaps be BS_HATCHED, at least for 1 bitperpixel */
53 static const LOGBRUSH LtGrayBrush = { BS_SOLID, RGB(192,192,192), 0 };
54 static const LOGBRUSH GrayBrush   = { BS_SOLID, RGB(128,128,128), 0 };
55
56 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
57 /* See HatchBrushes in x11drv for the HS_DIAGCROSS+1 hack */
58 static const LOGBRUSH DkGrayBrush = { BS_HATCHED, RGB(0,0,0), (HS_DIAGCROSS+1) };
59
60 static const LOGPEN WhitePen = { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
61 static const LOGPEN BlackPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
62 static const LOGPEN NullPen  = { PS_NULL,  { 0, 0 }, 0 };
63
64
65 /* reserve one extra entry for the stock default bitmap */
66 /* this is what Windows does too */
67 #define NB_STOCK_OBJECTS (STOCK_LAST+2)
68
69 static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
70
71 static SYSLEVEL GDI_level;
72 static CRITICAL_SECTION_DEBUG critsect_debug =
73 {
74     0, 0, &GDI_level.crst,
75     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
76       0, 0, { 0, (DWORD)(__FILE__ ": GDI_level") }
77 };
78 static SYSLEVEL GDI_level = { { &critsect_debug, -1, 0, 0, 0, 0 }, 3 };
79
80 static WORD GDI_HeapSel;
81
82 inline static BOOL get_bool(char *buffer)
83 {
84     return (buffer[0] == 'y' || buffer[0] == 'Y' ||
85             buffer[0] == 't' || buffer[0] == 'T' ||
86             buffer[0] == '1');
87 }
88
89
90 /****************************************************************************
91  *
92  *      language-independent stock fonts
93  *
94  */
95
96 static const LOGFONTW OEMFixedFont =
97 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
98   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
99
100 static const LOGFONTW AnsiFixedFont =
101 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
102   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
103
104 static const LOGFONTW AnsiVarFont =
105 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
106   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
107   {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} };
108
109 /******************************************************************************
110  *
111  *      language-dependent stock fonts
112  *
113  *      'ANSI' charset and 'DEFAULT' charset is not same.
114  *      The chars in CP_ACP should be drawn with 'DEFAULT' charset.
115  *      'ANSI' charset seems to be identical with ISO-8859-1.
116  *      'DEFAULT' charset is a language-dependent charset.
117  *
118  *      'System' font seems to be an alias for language-dependent font.
119  */
120
121 /*
122  * language-dependenet stock fonts for all known charsets
123  * please see TranslateCharsetInfo (objects/font.c) and
124  * CharsetBindingInfo (graphics/x11drv/xfont.c),
125  * and modify entries for your language if needed.
126  */
127 struct DefaultFontInfo
128 {
129         UINT            charset;
130         LOGFONTW        SystemFont;
131         LOGFONTW        DeviceDefaultFont;
132         LOGFONTW        SystemFixedFont;
133         LOGFONTW        DefaultGuiFont;
134 };
135
136 static const struct DefaultFontInfo default_fonts[] =
137 {
138     {   ANSI_CHARSET,
139         { /* System */
140           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
141            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
142            {'S','y','s','t','e','m','\0'}
143         },
144         { /* Device Default */
145           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
146            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
147            {'\0'}
148         },
149         { /* System Fixed */
150           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
151            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
152            {'\0'}
153         },
154         { /* DefaultGuiFont */
155          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
156            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
157            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
158         },
159     },
160     {   EASTEUROPE_CHARSET,
161         { /* System */
162           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
163            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
164            {'S','y','s','t','e','m','\0'}
165         },
166         { /* Device Default */
167           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
168            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
169            {'\0'}
170         },
171         { /* System Fixed */
172           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
173            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
174            {'\0'}
175         },
176         { /* DefaultGuiFont */
177          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
178            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
179            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
180         },
181     },
182     {   RUSSIAN_CHARSET,
183         { /* System */
184           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
185            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
186            {'S','y','s','t','e','m','\0'}
187         },
188         { /* Device Default */
189           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
190            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
191            {'\0'}
192         },
193         { /* System Fixed */
194           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
195            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
196            {'\0'}
197         },
198         { /* DefaultGuiFont */
199          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
200            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
201            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
202         },
203     },
204     {   GREEK_CHARSET,
205         { /* System */
206           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
207            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
208            {'S','y','s','t','e','m','\0'}
209         },
210         { /* Device Default */
211           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
212            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
213            {'\0'}
214         },
215         { /* System Fixed */
216           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
217            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
218            {'\0'}
219         },
220         { /* DefaultGuiFont */
221          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
222            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
223            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
224         },
225     },
226     {   TURKISH_CHARSET,
227         { /* System */
228           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
229            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
230            {'S','y','s','t','e','m','\0'}
231         },
232         { /* Device Default */
233           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
234            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
235            {'\0'}
236         },
237         { /* System Fixed */
238           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
239            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
240            {'\0'}
241         },
242         { /* DefaultGuiFont */
243          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
244            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
245            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
246         },
247     },
248     {   HEBREW_CHARSET,
249         { /* System */
250           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
251            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
252            {'S','y','s','t','e','m','\0'}
253         },
254         { /* Device Default */
255           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
256            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
257            {'\0'}
258         },
259         { /* System Fixed */
260           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
261            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
262            {'\0'}
263         },
264         { /* DefaultGuiFont */
265          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
266            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
267            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
268         },
269     },
270     {   ARABIC_CHARSET,
271         { /* System */
272           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
273            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
274            {'S','y','s','t','e','m','\0'}
275         },
276         { /* Device Default */
277           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
278            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
279            {'\0'}
280         },
281         { /* System Fixed */
282           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
283            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
284            {'\0'}
285         },
286         { /* DefaultGuiFont */
287          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
288            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
289            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
290         },
291     },
292     {   BALTIC_CHARSET,
293         { /* System */
294           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
295            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
296            {'S','y','s','t','e','m','\0'}
297         },
298         { /* Device Default */
299           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
300            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
301            {'\0'}
302         },
303         { /* System Fixed */
304           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
305            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
306            {'\0'}
307         },
308         { /* DefaultGuiFont */
309          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
310            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
311            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
312         },
313     },
314     {   THAI_CHARSET,
315         { /* System */
316           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
317            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
318            {'S','y','s','t','e','m','\0'}
319         },
320         { /* Device Default */
321           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
322            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
323            {'\0'}
324         },
325         { /* System Fixed */
326           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
327            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
328            {'\0'}
329         },
330         { /* DefaultGuiFont */
331          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
332            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
333            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
334         },
335     },
336     {   SHIFTJIS_CHARSET,
337         { /* System */
338           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
339            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
340            {'S','y','s','t','e','m','\0'}
341         },
342         { /* Device Default */
343           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
344            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
345            {'\0'}
346         },
347         { /* System Fixed */
348           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
349            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
350            {'\0'}
351         },
352         { /* DefaultGuiFont */
353          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
354            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
355            {'M','S',' ','P',' ','g','o','t','h','i','c','\0'} /* FIXME: Is this correct? */
356         },
357     },
358     {   GB2312_CHARSET,
359         { /* System */
360           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
361            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
362            {'S','y','s','t','e','m','\0'}
363         },
364         { /* Device Default */
365           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
366            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
367            {'\0'}
368         },
369         { /* System Fixed */
370           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
371            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
372            {'\0'}
373         },
374         { /* DefaultGuiFont */
375          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
376            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
377            {'M','S',' ','S','o','n','g','\0'}   /* FIXME: Is this correct? */
378         },
379     },
380     {   HANGEUL_CHARSET,
381         { /* System */
382           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
383            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
384            {'S','y','s','t','e','m','\0'}
385         },
386         { /* Device Default */
387           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
388            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
389            {'\0'}
390         },
391         { /* System Fixed */
392           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
393            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
394            {'\0'}
395         },
396         { /* DefaultGuiFont */
397          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
398            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
399            {'G','u','l','i','m'},
400         },
401     },
402     {   CHINESEBIG5_CHARSET,
403         { /* System */
404           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
405            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
406            {'S','y','s','t','e','m','\0'}
407         },
408         { /* Device Default */
409           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
410            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
411            {'\0'}
412         },
413         { /* System Fixed */
414           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
415            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
416            {'\0'}
417         },
418         { /* DefaultGuiFont */
419          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
420            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
421            {'\0'}       /* FIXME - what is the native font??? */
422         },
423     },
424     {   JOHAB_CHARSET,
425         { /* System */
426           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
427            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
428            {'S','y','s','t','e','m','\0'}
429         },
430         { /* Device Default */
431           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
432            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
433            {'\0'}
434         },
435         { /* System Fixed */
436           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
437            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
438            {'\0'}
439         },
440         { /* DefaultGuiFont */
441          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
442            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
443            {'M','S',' ','M','i','n','g','l','i','u','\0'} /* FIXME: Is this correct? */
444         },
445     },
446 };
447
448
449 /******************************************************************************
450  *      get_default_fonts
451  */
452 static const struct DefaultFontInfo* get_default_fonts(UINT charset)
453 {
454         int     n;
455
456         for(n=0;n<(sizeof(default_fonts)/sizeof(default_fonts[0]));n++)
457         {
458                 if ( default_fonts[n].charset == charset )
459                         return &default_fonts[n];
460         }
461
462         FIXME( "unhandled charset 0x%08x - use ANSI_CHARSET for default stock objects\n", charset );
463         return &default_fonts[0];
464 }
465
466
467 /******************************************************************************
468  *      get_default_charset    (internal)
469  *
470  * get the language-dependent charset that can handle CP_ACP correctly.
471  */
472 static UINT get_default_charset( void )
473 {
474     CHARSETINFO     csi;
475     UINT    uACP;
476
477     uACP = GetACP();
478     csi.ciCharset = ANSI_CHARSET;
479     if ( ! TranslateCharsetInfo( (LPDWORD)uACP, &csi, TCI_SRCCODEPAGE ) )
480     {
481         FIXME( "unhandled codepage %u - use ANSI_CHARSET for default stock objects\n", uACP );
482         return ANSI_CHARSET;
483     }
484
485     return csi.ciCharset;
486 }
487
488
489 /******************************************************************************
490  *           create_stock_font
491  */
492 static HFONT create_stock_font( char const *fontName, const LOGFONTW *font, HKEY hkey )
493 {
494     LOGFONTW lf;
495     char  key[256];
496     char buffer[MAX_PATH];
497     DWORD type, count;
498
499     if (!hkey) return CreateFontIndirectW( font );
500
501     lf = *font;
502     sprintf(key, "%s.Height", fontName);
503     count = sizeof(buffer);
504     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
505         lf.lfHeight = atoi(buffer);
506
507     sprintf(key, "%s.Bold", fontName);
508     count = sizeof(buffer);
509     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
510         lf.lfWeight = get_bool(buffer) ? FW_BOLD : FW_NORMAL;
511
512     sprintf(key, "%s.Italic", fontName);
513     count = sizeof(buffer);
514     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
515         lf.lfItalic = get_bool(buffer);
516
517     sprintf(key, "%s.Underline", fontName);
518     count = sizeof(buffer);
519     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
520         lf.lfUnderline = get_bool(buffer);
521
522     sprintf(key, "%s.StrikeOut", fontName);
523     count = sizeof(buffer);
524     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
525         lf.lfStrikeOut = get_bool(buffer);
526     return CreateFontIndirectW( &lf );
527 }
528
529
530 #define TRACE_SEC(handle,text) \
531    TRACE("(%p): " text " %ld\n", (handle), GDI_level.crst.RecursionCount)
532
533
534 /***********************************************************************
535  *           inc_ref_count
536  *
537  * Increment the reference count of a GDI object.
538  */
539 inline static void inc_ref_count( HGDIOBJ handle )
540 {
541     GDIOBJHDR *header;
542
543     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
544     {
545         header->dwCount++;
546         GDI_ReleaseObj( handle );
547     }
548 }
549
550
551 /***********************************************************************
552  *           dec_ref_count
553  *
554  * Decrement the reference count of a GDI object.
555  */
556 inline static void dec_ref_count( HGDIOBJ handle )
557 {
558     GDIOBJHDR *header;
559
560     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
561     {
562         if (header->dwCount) header->dwCount--;
563         if (header->dwCount != 0x80000000) GDI_ReleaseObj( handle );
564         else
565         {
566             /* handle delayed DeleteObject*/
567             header->dwCount = 0;
568             GDI_ReleaseObj( handle );
569             TRACE( "executing delayed DeleteObject for %p\n", handle );
570             DeleteObject( handle );
571         }
572     }
573 }
574
575
576 /***********************************************************************
577  *           GDI_Init
578  *
579  * GDI initialization.
580  */
581 BOOL GDI_Init(void)
582 {
583     HINSTANCE16 instance;
584     HKEY hkey;
585     GDIOBJHDR *ptr;
586     const struct DefaultFontInfo* deffonts;
587     int i;
588
589     if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Tweak.Fonts", &hkey))
590         hkey = 0;
591
592     /* create GDI heap */
593     if ((instance = LoadLibrary16( "GDI.EXE" )) >= 32) GDI_HeapSel = instance | 7;
594
595     /* create stock objects */
596     stock_objects[WHITE_BRUSH]  = CreateBrushIndirect( &WhiteBrush );
597     stock_objects[LTGRAY_BRUSH] = CreateBrushIndirect( &LtGrayBrush );
598     stock_objects[GRAY_BRUSH]   = CreateBrushIndirect( &GrayBrush );
599     stock_objects[DKGRAY_BRUSH] = CreateBrushIndirect( &DkGrayBrush );
600     stock_objects[BLACK_BRUSH]  = CreateBrushIndirect( &BlackBrush );
601     stock_objects[NULL_BRUSH]   = CreateBrushIndirect( &NullBrush );
602
603     stock_objects[WHITE_PEN]    = CreatePenIndirect( &WhitePen );
604     stock_objects[BLACK_PEN]    = CreatePenIndirect( &BlackPen );
605     stock_objects[NULL_PEN]     = CreatePenIndirect( &NullPen );
606
607     stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
608     stock_objects[DEFAULT_BITMAP]  = CreateBitmap( 1, 1, 1, 1, NULL );
609
610     /* language-independent stock fonts */
611     stock_objects[OEM_FIXED_FONT]      = create_stock_font( "OEMFixed", &OEMFixedFont, hkey );
612     stock_objects[ANSI_FIXED_FONT]     = create_stock_font( "AnsiFixed", &AnsiFixedFont, hkey );
613     stock_objects[ANSI_VAR_FONT]       = create_stock_font( "AnsiVar", &AnsiVarFont, hkey );
614
615     /* language-dependent stock fonts */
616     deffonts = get_default_fonts(get_default_charset());
617     stock_objects[SYSTEM_FONT]         = create_stock_font( "System", &deffonts->SystemFont, hkey );
618     stock_objects[DEVICE_DEFAULT_FONT] = create_stock_font( "DeviceDefault", &deffonts->DeviceDefaultFont, hkey );
619     stock_objects[SYSTEM_FIXED_FONT]   = create_stock_font( "SystemFixed", &deffonts->SystemFixedFont, hkey );
620     stock_objects[DEFAULT_GUI_FONT]    = create_stock_font( "DefaultGui", &deffonts->DefaultGuiFont, hkey );
621
622
623     /* clear the NOSYSTEM bit on all stock objects*/
624     for (i = 0; i < NB_STOCK_OBJECTS; i++)
625     {
626         if (!stock_objects[i])
627         {
628             if (i == 9) continue;  /* there's no stock object 9 */
629             ERR( "could not create stock object %d\n", i );
630             return FALSE;
631         }
632         ptr = GDI_GetObjPtr( stock_objects[i], MAGIC_DONTCARE );
633         ptr->wMagic &= ~OBJECT_NOSYSTEM;
634         GDI_ReleaseObj( stock_objects[i] );
635     }
636
637     if (hkey) RegCloseKey( hkey );
638
639     WineEngInit();
640
641     return TRUE;
642 }
643
644 #define FIRST_LARGE_HANDLE 16
645 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
646 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
647 static int next_large_handle;
648
649 /***********************************************************************
650  *           alloc_large_heap
651  *
652  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
653  */
654 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
655 {
656     int i;
657     GDIOBJHDR *obj;
658
659     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
660         if (!large_handles[i]) goto found;
661     for (i = 0; i <= next_large_handle; i++)
662         if (!large_handles[i]) goto found;
663     *handle = 0;
664     return NULL;
665
666  found:
667     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
668     {
669         large_handles[i] = obj;
670         *handle = (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2);
671         next_large_handle = i;
672     }
673     return obj;
674 }
675
676
677 /***********************************************************************
678  *           GDI_AllocObject
679  */
680 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle, const struct gdi_obj_funcs *funcs )
681 {
682     GDIOBJHDR *obj;
683     HLOCAL16 hlocal;
684
685     _EnterSysLevel( &GDI_level );
686     switch(magic)
687     {
688     default:
689         if (GDI_HeapSel)
690         {
691             if (!(hlocal = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
692             assert( hlocal & 2 );
693             obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, hlocal );
694             *handle = (HGDIOBJ)(ULONG_PTR)hlocal;
695             break;
696         }
697         /* fall through */
698     case DC_MAGIC:
699     case DISABLED_DC_MAGIC:
700     case META_DC_MAGIC:
701     case METAFILE_MAGIC:
702     case METAFILE_DC_MAGIC:
703     case ENHMETAFILE_MAGIC:
704     case ENHMETAFILE_DC_MAGIC:
705     case MEMORY_DC_MAGIC:
706     case BITMAP_MAGIC:
707     case PALETTE_MAGIC:
708         if (!(obj = alloc_large_heap( size, handle ))) goto error;
709         break;
710     }
711
712     obj->hNext   = 0;
713     obj->wMagic  = magic|OBJECT_NOSYSTEM;
714     obj->dwCount = 0;
715     obj->funcs   = funcs;
716
717     TRACE_SEC( *handle, "enter" );
718     return obj;
719
720 error:
721     _LeaveSysLevel( &GDI_level );
722     *handle = 0;
723     return NULL;
724 }
725
726
727 /***********************************************************************
728  *           GDI_ReallocObject
729  *
730  * The object ptr must have been obtained with GDI_GetObjPtr.
731  * The new pointer must be released with GDI_ReleaseObj.
732  */
733 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
734 {
735     HGDIOBJ new_handle;
736
737     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
738     {
739         HLOCAL16 h = LOWORD(handle);
740         LOCAL_Unlock( GDI_HeapSel, h );
741         if ((new_handle = (HGDIOBJ)(ULONG_PTR)LOCAL_ReAlloc( GDI_HeapSel, h, size, LMEM_MOVEABLE )))
742         {
743             assert( new_handle == handle );  /* moveable handle cannot change */
744             return LOCAL_Lock( GDI_HeapSel, h );
745         }
746     }
747     else
748     {
749         int i = ((ULONG_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
750         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
751         {
752             void *new_ptr = HeapReAlloc( GetProcessHeap(), 0, large_handles[i], size );
753             if (new_ptr)
754             {
755                 large_handles[i] = new_ptr;
756                 return new_ptr;
757             }
758         }
759         else ERR( "Invalid handle %p\n", handle );
760     }
761     TRACE_SEC( handle, "leave" );
762     _LeaveSysLevel( &GDI_level );
763     return NULL;
764 }
765
766
767 /***********************************************************************
768  *           GDI_FreeObject
769  */
770 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
771 {
772     GDIOBJHDR *object = ptr;
773
774     object->wMagic = 0;  /* Mark it as invalid */
775     object->funcs  = NULL;
776     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
777     {
778         HLOCAL16 h = LOWORD(handle);
779         LOCAL_Unlock( GDI_HeapSel, h );
780         LOCAL_Free( GDI_HeapSel, h );
781     }
782     else  /* large heap handle */
783     {
784         int i = ((ULONG_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
785         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
786         {
787             HeapFree( GetProcessHeap(), 0, large_handles[i] );
788             large_handles[i] = NULL;
789         }
790         else ERR( "Invalid handle %p\n", handle );
791     }
792     TRACE_SEC( handle, "leave" );
793     _LeaveSysLevel( &GDI_level );
794     return TRUE;
795 }
796
797
798 /***********************************************************************
799  *           GDI_GetObjPtr
800  *
801  * Return a pointer to the GDI object associated to the handle.
802  * Return NULL if the object has the wrong magic number.
803  * The object must be released with GDI_ReleaseObj.
804  */
805 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
806 {
807     GDIOBJHDR *ptr = NULL;
808
809     _EnterSysLevel( &GDI_level );
810
811     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
812     {
813         HLOCAL16 h = LOWORD(handle);
814         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, h );
815         if (ptr)
816         {
817             if (((magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ||
818                 (GDIMAGIC(ptr->wMagic) < FIRST_MAGIC) ||
819                 (GDIMAGIC(ptr->wMagic) > LAST_MAGIC))
820             {
821                 LOCAL_Unlock( GDI_HeapSel, h );
822                 ptr = NULL;
823             }
824         }
825     }
826     else  /* large heap handle */
827     {
828         int i = ((UINT_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
829         if (i >= 0 && i < MAX_LARGE_HANDLES)
830         {
831             ptr = large_handles[i];
832             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
833         }
834     }
835
836     if (!ptr)
837     {
838         _LeaveSysLevel( &GDI_level );
839         SetLastError( ERROR_INVALID_HANDLE );
840         WARN( "Invalid handle %p\n", handle );
841     }
842     else TRACE_SEC( handle, "enter" );
843
844     return ptr;
845 }
846
847
848 /***********************************************************************
849  *           GDI_ReleaseObj
850  *
851  */
852 void GDI_ReleaseObj( HGDIOBJ handle )
853 {
854     if ((UINT_PTR)handle & 2) LOCAL_Unlock( GDI_HeapSel, LOWORD(handle) );
855     TRACE_SEC( handle, "leave" );
856     _LeaveSysLevel( &GDI_level );
857 }
858
859
860 /***********************************************************************
861  *           GDI_CheckNotLock
862  */
863 void GDI_CheckNotLock(void)
864 {
865     _CheckNotSysLevel( &GDI_level );
866 }
867
868
869 /***********************************************************************
870  *           DeleteObject    (GDI32.@)
871  */
872 BOOL WINAPI DeleteObject( HGDIOBJ obj )
873 {
874       /* Check if object is valid */
875
876     GDIOBJHDR * header;
877     if (HIWORD(obj)) return FALSE;
878
879     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
880
881     if (!(header->wMagic & OBJECT_NOSYSTEM)
882     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
883     {
884         TRACE("Preserving system object %p\n", obj);
885         GDI_ReleaseObj( obj );
886         return TRUE;
887     }
888
889     if (header->dwCount)
890     {
891         TRACE("delayed for %p because object in use, count %ld\n", obj, header->dwCount );
892         header->dwCount |= 0x80000000; /* mark for delete */
893         GDI_ReleaseObj( obj );
894         return TRUE;
895     }
896
897     TRACE("%p\n", obj );
898
899       /* Delete object */
900
901     if (header->funcs && header->funcs->pDeleteObject)
902         return header->funcs->pDeleteObject( obj, header );
903
904     GDI_ReleaseObj( obj );
905     return FALSE;
906 }
907
908
909 /***********************************************************************
910  *           GetStockObject    (GDI32.@)
911  */
912 HGDIOBJ WINAPI GetStockObject( INT obj )
913 {
914     HGDIOBJ ret;
915     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
916     ret = stock_objects[obj];
917     TRACE("returning %p\n", ret );
918     return ret;
919 }
920
921
922 /***********************************************************************
923  *           GetObject    (GDI.82)
924  */
925 INT16 WINAPI GetObject16( HANDLE16 handle16, INT16 count, LPVOID buffer )
926 {
927     GDIOBJHDR * ptr;
928     HGDIOBJ handle = HGDIOBJ_32( handle16 );
929     INT16 result = 0;
930
931     TRACE("%p %d %p\n", handle, count, buffer );
932     if (!count) return 0;
933
934     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
935
936     if (ptr->funcs && ptr->funcs->pGetObject16)
937         result = ptr->funcs->pGetObject16( handle, ptr, count, buffer );
938     else
939         SetLastError( ERROR_INVALID_HANDLE );
940
941     GDI_ReleaseObj( handle );
942     return result;
943 }
944
945
946 /***********************************************************************
947  *           GetObjectA    (GDI32.@)
948  */
949 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
950 {
951     GDIOBJHDR * ptr;
952     INT result = 0;
953     TRACE("%p %d %p\n", handle, count, buffer );
954
955     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
956
957     if (ptr->funcs && ptr->funcs->pGetObjectA)
958         result = ptr->funcs->pGetObjectA( handle, ptr, count, buffer );
959     else
960         SetLastError( ERROR_INVALID_HANDLE );
961
962     GDI_ReleaseObj( handle );
963     return result;
964 }
965
966 /***********************************************************************
967  *           GetObjectW    (GDI32.@)
968  */
969 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
970 {
971     GDIOBJHDR * ptr;
972     INT result = 0;
973     TRACE("%p %d %p\n", handle, count, buffer );
974
975     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
976
977     if (ptr->funcs && ptr->funcs->pGetObjectW)
978         result = ptr->funcs->pGetObjectW( handle, ptr, count, buffer );
979     else
980         SetLastError( ERROR_INVALID_HANDLE );
981
982     GDI_ReleaseObj( handle );
983     return result;
984 }
985
986 /***********************************************************************
987  *           GetObjectType    (GDI32.@)
988  */
989 DWORD WINAPI GetObjectType( HANDLE handle )
990 {
991     GDIOBJHDR * ptr;
992     INT result = 0;
993     TRACE("%p\n", handle );
994
995     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
996
997     switch(GDIMAGIC(ptr->wMagic))
998     {
999       case PEN_MAGIC:
1000           result = OBJ_PEN;
1001           break;
1002       case BRUSH_MAGIC:
1003           result = OBJ_BRUSH;
1004           break;
1005       case BITMAP_MAGIC:
1006           result = OBJ_BITMAP;
1007           break;
1008       case FONT_MAGIC:
1009           result = OBJ_FONT;
1010           break;
1011       case PALETTE_MAGIC:
1012           result = OBJ_PAL;
1013           break;
1014       case REGION_MAGIC:
1015           result = OBJ_REGION;
1016           break;
1017       case DC_MAGIC:
1018           result = OBJ_DC;
1019           break;
1020       case META_DC_MAGIC:
1021           result = OBJ_METADC;
1022           break;
1023       case METAFILE_MAGIC:
1024           result = OBJ_METAFILE;
1025           break;
1026       case METAFILE_DC_MAGIC:
1027           result = OBJ_METADC;
1028           break;
1029       case ENHMETAFILE_MAGIC:
1030           result = OBJ_ENHMETAFILE;
1031           break;
1032       case ENHMETAFILE_DC_MAGIC:
1033           result = OBJ_ENHMETADC;
1034           break;
1035       case MEMORY_DC_MAGIC:
1036           result = OBJ_MEMDC;
1037           break;
1038       default:
1039           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
1040           break;
1041     }
1042     GDI_ReleaseObj( handle );
1043     return result;
1044 }
1045
1046 /***********************************************************************
1047  *           GetCurrentObject           (GDI32.@)
1048  */
1049 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
1050 {
1051     HANDLE ret = 0;
1052     DC * dc = DC_GetDCPtr( hdc );
1053
1054     if (dc)
1055     {
1056     switch (type) {
1057         case OBJ_PEN:    ret = dc->hPen; break;
1058         case OBJ_BRUSH:  ret = dc->hBrush; break;
1059         case OBJ_PAL:    ret = dc->hPalette; break;
1060         case OBJ_FONT:   ret = dc->hFont; break;
1061         case OBJ_BITMAP: ret = dc->hBitmap; break;
1062     default:
1063         /* the SDK only mentions those above */
1064         FIXME("(%p,%d): unknown type.\n",hdc,type);
1065             break;
1066         }
1067         GDI_ReleaseObj( hdc );
1068     }
1069     return ret;
1070 }
1071
1072
1073 /***********************************************************************
1074  *           SelectObject    (GDI32.@)
1075  */
1076 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
1077 {
1078     HGDIOBJ ret = 0;
1079     GDIOBJHDR *header = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1080     if (!header) return 0;
1081
1082     TRACE("hdc=%p %p\n", hdc, handle );
1083
1084     if (header->funcs && header->funcs->pSelectObject)
1085     {
1086         ret = header->funcs->pSelectObject( handle, header, hdc );
1087         if (ret && ret != handle && (INT)ret > COMPLEXREGION)
1088         {
1089             inc_ref_count( handle );
1090             dec_ref_count( ret );
1091         }
1092     }
1093     GDI_ReleaseObj( handle );
1094     return ret;
1095 }
1096
1097
1098 /***********************************************************************
1099  *           UnrealizeObject    (GDI32.@)
1100  */
1101 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
1102 {
1103     BOOL result = TRUE;
1104   /* Check if object is valid */
1105
1106     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
1107     if (!header) return FALSE;
1108
1109     TRACE("%p\n", obj );
1110
1111       /* Unrealize object */
1112
1113     if (header->funcs && header->funcs->pUnrealizeObject)
1114         result = header->funcs->pUnrealizeObject( obj, header );
1115
1116     GDI_ReleaseObj( obj );
1117     return result;
1118 }
1119
1120
1121 /* Solid colors to enumerate */
1122 static const COLORREF solid_colors[] =
1123 { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1124 RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1125 RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1126 RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1127 RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1128 RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1129 RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1130 RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1131 };
1132
1133
1134 /***********************************************************************
1135  *           EnumObjects    (GDI32.@)
1136  */
1137 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
1138                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
1139 {
1140     INT i, retval = 0;
1141     LOGPEN pen;
1142     LOGBRUSH brush;
1143
1144     TRACE("%p %d %p %08lx\n", hdc, nObjType, lpEnumFunc, lParam );
1145     switch(nObjType)
1146     {
1147     case OBJ_PEN:
1148         /* Enumerate solid pens */
1149         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1150         {
1151             pen.lopnStyle   = PS_SOLID;
1152             pen.lopnWidth.x = 1;
1153             pen.lopnWidth.y = 0;
1154             pen.lopnColor   = solid_colors[i];
1155             retval = lpEnumFunc( &pen, lParam );
1156             TRACE("solid pen %08lx, ret=%d\n",
1157                          solid_colors[i], retval);
1158             if (!retval) break;
1159         }
1160         break;
1161
1162     case OBJ_BRUSH:
1163         /* Enumerate solid brushes */
1164         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1165         {
1166             brush.lbStyle = BS_SOLID;
1167             brush.lbColor = solid_colors[i];
1168             brush.lbHatch = 0;
1169             retval = lpEnumFunc( &brush, lParam );
1170             TRACE("solid brush %08lx, ret=%d\n",
1171                          solid_colors[i], retval);
1172             if (!retval) break;
1173         }
1174
1175         /* Now enumerate hatched brushes */
1176         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1177         {
1178             brush.lbStyle = BS_HATCHED;
1179             brush.lbColor = RGB(0,0,0);
1180             brush.lbHatch = i;
1181             retval = lpEnumFunc( &brush, lParam );
1182             TRACE("hatched brush %d, ret=%d\n",
1183                          i, retval);
1184             if (!retval) break;
1185         }
1186         break;
1187
1188     default:
1189         /* FIXME: implement Win32 types */
1190         WARN("(%d): Invalid type\n", nObjType );
1191         break;
1192     }
1193     return retval;
1194 }
1195
1196
1197 /***********************************************************************
1198  *           IsGDIObject    (GDI.462)
1199  *
1200  * returns type of object if valid (W95 system programming secrets p. 264-5)
1201  */
1202 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle16 )
1203 {
1204     UINT16 magic = 0;
1205     HGDIOBJ handle = HGDIOBJ_32( handle16 );
1206
1207     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1208     if (object)
1209     {
1210         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
1211         GDI_ReleaseObj( handle );
1212     }
1213     return magic;
1214 }
1215
1216
1217 /***********************************************************************
1218  *           SetObjectOwner    (GDI32.@)
1219  */
1220 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1221 {
1222     /* Nothing to do */
1223 }
1224
1225
1226 /***********************************************************************
1227  *           MakeObjectPrivate    (GDI.463)
1228  *
1229  * What does that mean ?
1230  * Some little docu can be found in "Undocumented Windows",
1231  * but this is basically useless.
1232  * At least we know that this flags the GDI object's wMagic
1233  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1234  * But Wine doesn't react on that yet.
1235  */
1236 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle16, BOOL16 private )
1237 {
1238     HGDIOBJ handle = HGDIOBJ_32( handle16 );
1239     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1240     if (!ptr)
1241     {
1242         ERR("invalid GDI object %p !\n", handle);
1243         return;
1244     }
1245     ptr->wMagic |= OBJECT_PRIVATE;
1246     GDI_ReleaseObj( handle );
1247 }
1248
1249
1250 /***********************************************************************
1251  *           GdiFlush    (GDI32.@)
1252  */
1253 BOOL WINAPI GdiFlush(void)
1254 {
1255     return TRUE;  /* FIXME */
1256 }
1257
1258
1259 /***********************************************************************
1260  *           GdiGetBatchLimit    (GDI32.@)
1261  */
1262 DWORD WINAPI GdiGetBatchLimit(void)
1263 {
1264     return 1;  /* FIXME */
1265 }
1266
1267
1268 /***********************************************************************
1269  *           GdiSetBatchLimit    (GDI32.@)
1270  */
1271 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1272 {
1273     return 1; /* FIXME */
1274 }
1275
1276
1277 /***********************************************************************
1278  *           GdiSeeGdiDo   (GDI.452)
1279  */
1280 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1281                           WORD wParam3 )
1282 {
1283     switch (wReqType)
1284     {
1285     case 0x0001:  /* LocalAlloc */
1286         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1287     case 0x0002:  /* LocalFree */
1288         return LOCAL_Free( GDI_HeapSel, wParam1 );
1289     case 0x0003:  /* LocalCompact */
1290         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1291     case 0x0103:  /* LocalHeap */
1292         return GDI_HeapSel;
1293     default:
1294         WARN("(wReqType=%04x): Unknown\n", wReqType);
1295         return (DWORD)-1;
1296     }
1297 }
1298
1299 /***********************************************************************
1300  *           GdiSignalProc32     (GDI.610)
1301  */
1302 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1303                            DWORD dwFlags, HMODULE16 hModule )
1304 {
1305     return 0;
1306 }
1307
1308 /***********************************************************************
1309  *           GdiInit2     (GDI.403)
1310  *
1311  * See "Undocumented Windows"
1312  */
1313 HANDLE16 WINAPI GdiInit216(
1314     HANDLE16 h1, /* [in] GDI object */
1315     HANDLE16 h2  /* [in] global data */
1316 )
1317 {
1318     FIXME("(%04x, %04x), stub.\n", h1, h2);
1319     if (h2 == 0xffff)
1320         return 0xffff; /* undefined return value */
1321     return h1; /* FIXME: should be the memory handle of h1 */
1322 }
1323
1324 /***********************************************************************
1325  *           FinalGdiInit     (GDI.405)
1326  */
1327 void WINAPI FinalGdiInit16( HBRUSH16 hPattern /* [in] fill pattern of desktop */ )
1328 {
1329 }
1330
1331 /***********************************************************************
1332  *           GdiFreeResources   (GDI.609)
1333  */
1334 WORD WINAPI GdiFreeResources16( DWORD reserve )
1335 {
1336    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1337                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1338 }
1339
1340
1341 /*******************************************************************
1342  *      GetColorAdjustment [GDI32.@]
1343  *
1344  *
1345  */
1346 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1347 {
1348         FIXME("GetColorAdjustment, stub\n");
1349         return 0;
1350 }
1351
1352 /*******************************************************************
1353  *      GetMiterLimit [GDI32.@]
1354  *
1355  *
1356  */
1357 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1358 {
1359         FIXME("GetMiterLimit, stub\n");
1360         return 0;
1361 }
1362
1363 /*******************************************************************
1364  *      SetMiterLimit [GDI32.@]
1365  *
1366  *
1367  */
1368 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1369 {
1370         FIXME("SetMiterLimit, stub\n");
1371         return 0;
1372 }
1373
1374 /*******************************************************************
1375  *      GdiComment [GDI32.@]
1376  *
1377  *
1378  */
1379 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1380 {
1381     DC *dc = DC_GetDCPtr(hdc);
1382     BOOL ret = FALSE;
1383     if(dc)
1384     {
1385         if (dc->funcs->pGdiComment)
1386             ret = dc->funcs->pGdiComment( dc->physDev, cbSize, lpData );
1387     }
1388     GDI_ReleaseObj( hdc );
1389     return ret;
1390 }
1391
1392 /*******************************************************************
1393  *      SetColorAdjustment [GDI32.@]
1394  *
1395  *
1396  */
1397 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1398 {
1399         FIXME("SetColorAdjustment, stub\n");
1400         return 0;
1401 }