1 /*
2  * OLEFONT test program
3  *
4  * Copyright 2003 Marcus Meissner
5  * Copyright 2006 (Google) Benjamin Arai
6  *
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <float.h>
27 
28 #define COBJMACROS
29 
30 #include <wine/test.h>
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winuser.h>
34 #include <wingdi.h>
35 #include <winnls.h>
36 #include <winerror.h>
37 #include <winnt.h>
38 #include <initguid.h>
39 #include <wtypes.h>
40 #include <olectl.h>
41 #include <ocidl.h>
42 
43 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
44 
45 static WCHAR MSSansSerif_font[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
46 static WCHAR system_font[] = { 'S','y','s','t','e','m',0 };
47 static WCHAR arial_font[] = { 'A','r','i','a','l',0 };
48 static WCHAR marlett_font[] = { 'M','a','r','l','e','t','t',0 };
49 
50 static HMODULE hOleaut32;
51 
52 static HRESULT (WINAPI *pOleCreateFontIndirect)(LPFONTDESC,REFIID,LPVOID*);
53 
54 #define EXPECT_HR(hr,hr_exp) \
55     ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
56 
57 /* Create a font with cySize given by lo_size, hi_size,  */
58 /* SetRatio to ratio_logical, ratio_himetric,            */
59 /* check that resulting hfont has height hfont_height.   */
60 /* Various checks along the way.                         */
61 static void test_ifont_size(LONGLONG size, LONG ratio_logical, LONG ratio_himetric,
62                             LONG hfont_height, const char * test_name)
63 {
64 	FONTDESC fd;
65 	LPVOID pvObj = NULL;
66 	IFont* ifnt = NULL;
67 	HFONT hfont;
68 	LOGFONTA lf;
69 	CY psize;
70 	HRESULT hres;
71         DWORD rtnval;
72 
73 	fd.cbSizeofstruct = sizeof(FONTDESC);
74 	fd.lpstrName      = arial_font; /* using scalable instead of bitmap font reduces errors due to font realization */
75 	fd.cySize.int64   = size;
76 	fd.sWeight        = 0;
77 	fd.sCharset       = 0;
78         fd.fItalic        = FALSE;
79         fd.fUnderline     = FALSE;
80         fd.fStrikethrough = FALSE;
81 
82 	/* Create font, test that it worked. */
83 	hres = pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj);
84 	ifnt = pvObj;
85 	ok(hres == S_OK,"%s: OCFI returns 0x%08x instead of S_OK.\n",
86 		test_name, hres);
87 	ok(pvObj != NULL,"%s: OCFI returns NULL.\n", test_name);
88 
89         /* Change the scaling ratio */
90         hres = IFont_SetRatio(ifnt, ratio_logical, ratio_himetric);
91         ok((ratio_logical && ratio_himetric) ? hres == S_OK : hres == E_FAIL,
92            "%s: IFont_SetRatio unexpectedly returned 0x%08x.\n", test_name, hres);
93 
94 	/* Read back size. */
95 	hres = IFont_get_Size(ifnt, &psize);
96 	ok(hres == S_OK,"%s: IFont_get_size returns 0x%08x instead of S_OK.\n",
97 		test_name, hres);
98 
99         /* Check returned size - allow for errors due to rounding & font realization. */
100 	ok((psize.int64 - size) < 10000 && (psize.int64 - size) > -10000,
101 		"%s: IFont_get_Size: Lo=%d, Hi=%d; expected Lo=%d, Hi=%d.\n",
102 		test_name, S(psize).Lo, S(psize).Hi, fd.cySize.Lo, fd.cySize.Hi);
103 
104 	/* Check hFont size. */
105 	hres = IFont_get_hFont (ifnt, &hfont);
106 	ok(hres == S_OK, "%s: IFont_get_hFont returns 0x%08x instead of S_OK.\n",
107 		test_name, hres);
108 	rtnval = GetObjectA(hfont, sizeof(LOGFONTA), &lf);
109         ok(rtnval > 0, "GetObject(hfont) failed\n");
110 
111         /* Since font scaling may encounter rounding errors, allow 1 pixel deviation. */
112 	ok(abs(lf.lfHeight - hfont_height) <= 1,
113 		"%s: hFont has lf.lfHeight=%d, expected %d.\n",
114 		test_name, lf.lfHeight, hfont_height);
115 
116 	/* Free IFont. */
117 	IFont_Release(ifnt);
118 }
119 
120 static void test_ifont_sizes(void)
121 {
122   /* Test various size operations and conversions. */
123   /* Add more as needed. */
124 
125   /* Results of first 2 tests depend on display resolution. */
126   HDC hdc = GetDC(0);
127   LONG dpi = GetDeviceCaps(hdc, LOGPIXELSY); /* expected results depend on display DPI */
128   ReleaseDC(0, hdc);
129   if(dpi == 96) /* normal resolution display */
130   {
131     test_ifont_size(180000, 0, 0, -24, "default");     /* normal font */
132     test_ifont_size(186000, 0, 0, -25, "rounding");    /* test rounding */
133   } else if(dpi == 72) /* low resolution display */
134   {
135     test_ifont_size(180000, 0, 0, -18, "default");     /* normal font */
136     test_ifont_size(186000, 0, 0, -19, "rounding");    /* test rounding */
137   } else if(dpi == 120) /* high resolution display */
138   {
139     test_ifont_size(180000, 0, 0, -30, "default");     /* normal font */
140     test_ifont_size(186000, 0, 0, -31, "rounding");    /* test rounding */
141   } else
142     skip("Skipping resolution dependent font size tests - display resolution is %d\n", dpi);
143 
144   /* Next 4 tests specify a scaling ratio, so display resolution is not a factor. */
145     test_ifont_size(180000, 72,  2540, -18, "ratio1");  /* change ratio */
146     test_ifont_size(180000, 144, 2540, -36, "ratio2");  /* another ratio */
147     test_ifont_size(180000, 72,  1270, -36, "ratio3");  /* yet another ratio */
148     test_ifont_size(186000, 72,  2540, -19, "rounding+ratio"); /* test rounding with ratio */
149 
150     /* test various combinations of logical == himetric */
151     test_ifont_size(180000, 10, 10, -635, "identical ratio 1");
152     test_ifont_size(240000, 10, 10, -848, "identical ratio 2");
153     test_ifont_size(300000, 10, 10, -1058, "identical ratio 3");
154 
155     /* test various combinations of logical and himetric both set to 1 */
156     test_ifont_size(180000, 1, 1, -24, "1:1 ratio 1");
157     test_ifont_size(240000, 1, 1, -32, "1:1 ratio 2");
158     test_ifont_size(300000, 1, 1, -40, "1:1 ratio 3");
159 
160     /* test various combinations of logical set to 1 */
161     test_ifont_size(180000, 1, 0, -24, "1:0 ratio 1");
162     test_ifont_size(240000, 1, 0, -32, "1:0 ratio 2");
163     test_ifont_size(300000, 1, 0, -40, "1:0 ratio 3");
164 
165     /* test various combinations of himetric set to 1 */
166     test_ifont_size(180000, 0, 1, -24, "0:1 ratio 1");
167     test_ifont_size(240000, 0, 1, -32, "0:1 ratio 2");
168     test_ifont_size(300000, 0, 1, -40, "0:1 ratio 3");
169 
170     /* test various combinations of 2:1 logical:himetric */
171     test_ifont_size(180000, 2, 1, -1270, "2:1 ratio 1");
172     test_ifont_size(240000, 2, 1, -1694, "2:1 ratio 2");
173     test_ifont_size(300000, 2, 1, -2117, "2:1 ratio 3");
174 
175     /* test various combinations of 1:2 logical:himetric */
176     test_ifont_size(180000, 1, 2, -318, "1:2 ratio 1");
177     test_ifont_size(240000, 1, 2, -424, "1:2 ratio 2");
178     test_ifont_size(300000, 1, 2, -529, "1:2 ratio 3");
179 
180     /* test various combinations of logical and himetric both set to 2 */
181     test_ifont_size(180000, 2, 2, -635, "2:2 ratio 1");
182     test_ifont_size(240000, 2, 2, -848, "2:2 ratio 2");
183     test_ifont_size(300000, 2, 2, -1058, "2:2 ratio 3");
184 }
185 
186 static void test_QueryInterface(void)
187 {
188     LPVOID pvObj = NULL;
189     HRESULT hr;
190     IFont*  font = NULL;
191     LONG ref;
192 
193     hr = pOleCreateFontIndirect(NULL, &IID_IFont, NULL);
194     EXPECT_HR(hr, E_POINTER);
195 
196     hr = pOleCreateFontIndirect(NULL, &IID_IFont, &pvObj);
197     font = pvObj;
198 
199     EXPECT_HR(hr, S_OK);
200     ok(font != NULL,"OCFI (NULL,..) returns NULL, instead of !NULL\n");
201 
202     pvObj = NULL;
203     hr = IFont_QueryInterface( font, &IID_IFont, &pvObj);
204     EXPECT_HR(hr, S_OK);
205 
206     /* Test if QueryInterface increments ref counter for IFONTs */
207     ref = IFont_AddRef(font);
208     ok(ref == 3 ||
209        broken(ref == 1), /* win95 */
210            "IFont_QI expected ref value 3 but instead got %d\n", ref);
211     IFont_Release(font);
212 
213     ok(pvObj != NULL,"IFont_QI does return NULL, instead of a ptr\n");
214 
215     IFont_Release(font);
216     IFont_Release(font);
217 }
218 
219 static void test_type_info(void)
220 {
221         LPVOID pvObj = NULL;
222         HRESULT hres;
223         IFontDisp*  fontdisp = NULL;
224 	ITypeInfo* pTInfo;
225 	WCHAR name_Name[] = {'N','a','m','e',0};
226 	BSTR names[3];
227 	UINT n;
228         LCID en_us = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
229                 SORT_DEFAULT);
230         DISPPARAMS dispparams;
231         VARIANT varresult;
232 
233         pOleCreateFontIndirect(NULL, &IID_IFontDisp, &pvObj);
234         fontdisp = pvObj;
235 
236 	hres = IFontDisp_GetTypeInfo(fontdisp, 0, en_us, &pTInfo);
237 	ok(hres == S_OK, "GTI returned 0x%08x instead of S_OK.\n", hres);
238 	ok(pTInfo != NULL, "GTI returned NULL.\n");
239 
240 	hres = ITypeInfo_GetNames(pTInfo, DISPID_FONT_NAME, names, 3, &n);
241 	ok(hres == S_OK, "GetNames returned 0x%08x instead of S_OK.\n", hres);
242 	ok(n == 1, "GetNames returned %d names instead of 1.\n", n);
243 	ok(!lstrcmpiW(names[0],name_Name), "DISPID_FONT_NAME doesn't get 'Names'.\n");
244 	SysFreeString(names[0]);
245 
246 	ITypeInfo_Release(pTInfo);
247 
248         dispparams.cNamedArgs = 0;
249         dispparams.rgdispidNamedArgs = NULL;
250         dispparams.cArgs = 0;
251         dispparams.rgvarg = NULL;
252         VariantInit(&varresult);
253         hres = IFontDisp_Invoke(fontdisp, DISPID_FONT_NAME, &IID_NULL,
254             LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult,
255             NULL, NULL);
256         ok(hres == S_OK, "IFontDisp_Invoke return 0x%08x instead of S_OK.\n", hres);
257         VariantClear(&varresult);
258 
259 	IFontDisp_Release(fontdisp);
260 }
261 
262 static HRESULT WINAPI FontEventsDisp_QueryInterface(IFontEventsDisp *iface, REFIID riid, void **ppvObject)
263 {
264     if (IsEqualIID(riid, &IID_IFontEventsDisp) || IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
265     {
266         IFontEventsDisp_AddRef(iface);
267         *ppvObject = iface;
268         return S_OK;
269     }
270     else
271     {
272         *ppvObject = NULL;
273         return E_NOINTERFACE;
274     }
275 }
276 
277 static ULONG WINAPI FontEventsDisp_AddRef(
278     IFontEventsDisp *iface)
279 {
280     return 2;
281 }
282 
283 static ULONG WINAPI FontEventsDisp_Release(
284         IFontEventsDisp *iface)
285 {
286     return 1;
287 }
288 
289 static HRESULT WINAPI FontEventsDisp_GetTypeInfoCount(IFontEventsDisp *iface, UINT *pctinfo)
290 {
291     ok(0, "unexpected call\n");
292     return E_NOTIMPL;
293 }
294 
295 static HRESULT WINAPI FontEventsDisp_GetTypeInfo(IFontEventsDisp *iface, UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
296 {
297     ok(0, "unexpected call\n");
298     return E_NOTIMPL;
299 }
300 
301 static HRESULT WINAPI FontEventsDisp_GetIDsOfNames(IFontEventsDisp *iface, REFIID riid, LPOLESTR *names, UINT cNames, LCID lcid,
302     DISPID *dispid)
303 {
304     ok(0, "unexpected call\n");
305     return E_NOTIMPL;
306 }
307 
308 static int fonteventsdisp_invoke_called;
309 static BSTR fonteventsdisp_invoke_arg0;
310 
311 static HRESULT WINAPI FontEventsDisp_Invoke(
312         IFontEventsDisp *iface,
313         DISPID dispid,
314         REFIID riid,
315         LCID lcid,
316         WORD wFlags,
317         DISPPARAMS *pDispParams,
318         VARIANT *pVarResult,
319         EXCEPINFO *pExcepInfo,
320         UINT *puArgErr)
321 {
322     VARIANTARG *arg0 = &pDispParams->rgvarg[0];
323 
324     ok(dispid == DISPID_FONT_CHANGED, "expected DISPID_FONT_CHANGED instead of 0x%x\n", dispid);
325     ok(IsEqualGUID(riid, &GUID_NULL), "got riid %s\n", wine_dbgstr_guid(riid));
326     ok(wFlags == INVOKE_FUNC, "expected INVOKE_FUNC instead of 0x%x\n", wFlags);
327     ok(pDispParams->cArgs == 1, "expected arg count 1, got %d\n", pDispParams->cArgs);
328     ok(V_VT(arg0) == VT_BSTR, "expected VT_BSTR, got %d\n", V_VT(arg0));
329 
330     fonteventsdisp_invoke_arg0 = SysAllocString(V_BSTR(arg0));
331     fonteventsdisp_invoke_called++;
332     return S_OK;
333 }
334 
335 static IFontEventsDispVtbl FontEventsDisp_Vtbl =
336 {
337     FontEventsDisp_QueryInterface,
338     FontEventsDisp_AddRef,
339     FontEventsDisp_Release,
340     FontEventsDisp_GetTypeInfoCount,
341     FontEventsDisp_GetTypeInfo,
342     FontEventsDisp_GetIDsOfNames,
343     FontEventsDisp_Invoke
344 };
345 
346 static IFontEventsDisp FontEventsDisp = { &FontEventsDisp_Vtbl };
347 
348     struct font_dispid
349     {
350         DISPID dispid;
351         const WCHAR *name;
352     };
353 
354 static void test_font_events_disp(void)
355 {
356     static const WCHAR nameW[] = {'N','a','m','e',0};
357     static const WCHAR sizeW[] = {'S','i','z','e',0};
358     static const WCHAR boldW[] = {'B','o','l','d',0};
359     static const WCHAR italicW[] = {'I','t','a','l','i','c',0};
360     static const WCHAR underlineW[] = {'U','n','d','e','r','l','i','n','e',0};
361     static const WCHAR strikeW[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0};
362     static const WCHAR weightW[] = {'W','e','i','g','h','t',0};
363     static const WCHAR charsetW[] = {'C','h','a','r','s','e','t',0};
364 
365     static const struct font_dispid font_dispids[] =
366     {
367         { DISPID_FONT_NAME, nameW },
368         { DISPID_FONT_SIZE, sizeW },
369         { DISPID_FONT_BOLD, boldW },
370         { DISPID_FONT_ITALIC, italicW },
371         { DISPID_FONT_UNDER, underlineW },
372         { DISPID_FONT_STRIKE, strikeW },
373         { DISPID_FONT_WEIGHT, weightW },
374         { DISPID_FONT_CHARSET, charsetW }
375     };
376 
377     IFont *pFont;
378     IFont *pFont2;
379     IConnectionPointContainer *pCPC;
380     IConnectionPoint *pCP;
381     FONTDESC fontdesc;
382     HRESULT hr;
383     DWORD dwCookie;
384     IFontDisp *pFontDisp;
385     DISPPARAMS dispparams;
386     VARIANTARG vararg;
387     INT i;
388 
389     fontdesc.cbSizeofstruct = sizeof(fontdesc);
390     fontdesc.lpstrName = MSSansSerif_font;
391     fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
392     fontdesc.sWeight = FW_NORMAL;
393     fontdesc.sCharset = 0;
394     fontdesc.fItalic = FALSE;
395     fontdesc.fUnderline = FALSE;
396     fontdesc.fStrikethrough = FALSE;
397 
398     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&pFont);
399     EXPECT_HR(hr, S_OK);
400 
401     hr = IFont_QueryInterface(pFont, &IID_IConnectionPointContainer, (void **)&pCPC);
402     EXPECT_HR(hr, S_OK);
403 
404     hr = IConnectionPointContainer_FindConnectionPoint(pCPC, &IID_IFontEventsDisp, &pCP);
405     EXPECT_HR(hr, S_OK);
406     IConnectionPointContainer_Release(pCPC);
407 
408     hr = IConnectionPoint_Advise(pCP, (IUnknown *)&FontEventsDisp, &dwCookie);
409     EXPECT_HR(hr, S_OK);
410     IConnectionPoint_Release(pCP);
411 
412     fonteventsdisp_invoke_called = 0;
413     fonteventsdisp_invoke_arg0 = NULL;
414     hr = IFont_put_Bold(pFont, TRUE);
415     EXPECT_HR(hr, S_OK);
416 
417     ok(fonteventsdisp_invoke_called == 1, "IFontEventDisp::Invoke wasn't called once\n");
418     SysFreeString(fonteventsdisp_invoke_arg0);
419 
420     hr = IFont_QueryInterface(pFont, &IID_IFontDisp, (void **)&pFontDisp);
421     EXPECT_HR(hr, S_OK);
422 
423     for (i = 0; i < ARRAY_SIZE(font_dispids); i++)
424     {
425         switch (font_dispids[i].dispid)
426         {
427         case DISPID_FONT_NAME:
428         {
429             static const WCHAR arialW[] = {'A','r','i','a','l',0};
430             V_VT(&vararg) = VT_BSTR;
431             V_BSTR(&vararg) = SysAllocString(arialW);
432             break;
433         }
434         case DISPID_FONT_SIZE:
435             V_VT(&vararg) = VT_CY;
436             S(V_CY(&vararg)).Lo = 25;
437             S(V_CY(&vararg)).Hi = 0;
438             break;
439         case DISPID_FONT_BOLD:
440             V_VT(&vararg) = VT_BOOL;
441             V_BOOL(&vararg) = VARIANT_FALSE;
442             break;
443         case DISPID_FONT_ITALIC:
444         case DISPID_FONT_UNDER:
445         case DISPID_FONT_STRIKE:
446             V_VT(&vararg) = VT_BOOL;
447             V_BOOL(&vararg) = VARIANT_TRUE;
448             break;
449         case DISPID_FONT_WEIGHT:
450             V_VT(&vararg) = VT_I2;
451             V_I2(&vararg) = FW_BLACK;
452             break;
453         case DISPID_FONT_CHARSET:
454             V_VT(&vararg) = VT_I2;
455             V_I2(&vararg) = 1;
456             break;
457         default:
458             ;
459         }
460 
461         dispparams.cNamedArgs = 0;
462         dispparams.rgdispidNamedArgs = NULL;
463         dispparams.cArgs = 1;
464         dispparams.rgvarg = &vararg;
465         fonteventsdisp_invoke_called = 0;
466         hr = IFontDisp_Invoke(pFontDisp, font_dispids[i].dispid, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
467         ok(hr == S_OK, "dispid=%d, got 0x%08x\n", font_dispids[i].dispid, hr);
468         ok(fonteventsdisp_invoke_called == 1, "dispid=%d, DISPID_FONT_CHANGED not called, got %d\n", font_dispids[i].dispid,
469             fonteventsdisp_invoke_called);
470         if (hr == S_OK)
471         {
472             ok(!lstrcmpW(font_dispids[i].name, fonteventsdisp_invoke_arg0), "dispid=%d, got %s, expected %s\n",
473                 font_dispids[i].dispid, wine_dbgstr_w(fonteventsdisp_invoke_arg0), wine_dbgstr_w(font_dispids[i].name));
474             SysFreeString(fonteventsdisp_invoke_arg0);
475         }
476         VariantClear(&vararg);
477     }
478 
479     IFontDisp_Release(pFontDisp);
480 
481     hr = IFont_Clone(pFont, &pFont2);
482     EXPECT_HR(hr, S_OK);
483     IFont_Release(pFont);
484 
485     /* this test shows that the notification routine isn't called again */
486     fonteventsdisp_invoke_called = 0;
487     hr = IFont_put_Bold(pFont2, FALSE);
488     EXPECT_HR(hr, S_OK);
489     ok(fonteventsdisp_invoke_called == 0, "got %d\n", fonteventsdisp_invoke_called);
490 
491     IFont_Release(pFont2);
492 }
493 
494 static void test_names_ids(WCHAR* w_name_1, const char* a_name_1,
495                     WCHAR* w_name_2, const char* a_name_2,
496                     LCID lcid, DISPID id_1, DISPID id_2,
497                     HRESULT hres_expect, int numnames)
498 {
499     LPVOID pvObj = NULL;
500     IFontDisp *fontdisp = NULL;
501     HRESULT hres;
502     DISPID rgDispId[2] = {0xdeadbeef, 0xdeadbeef};
503     LPOLESTR names[2] = {w_name_1, w_name_2};
504 
505     pOleCreateFontIndirect(NULL, &IID_IFontDisp, &pvObj);
506     fontdisp = pvObj;
507 
508     hres = IFontDisp_GetIDsOfNames(fontdisp, &IID_NULL, names, numnames,
509                                    lcid, rgDispId);
510 
511     /* test hres */
512     ok(hres == hres_expect,
513         "GetIDsOfNames: \"%s\", \"%s\" returns 0x%08x, expected 0x%08x.\n",
514         a_name_1, a_name_2, hres, hres_expect);
515 
516     /* test first DISPID */
517     ok(rgDispId[0]==id_1,
518         "GetIDsOfNames: \"%s\" gets DISPID 0x%08x, expected 0x%08x.\n",
519         a_name_1, rgDispId[0], id_1);
520 
521     /* test second DISPID is present */
522     if (numnames == 2)
523     {
524         ok(rgDispId[1]==id_2,
525             "GetIDsOfNames: ..., \"%s\" gets DISPID 0x%08x, expected 0x%08x.\n",
526             a_name_2, rgDispId[1], id_2);
527     }
528 
529    IFontDisp_Release(fontdisp);
530 }
531 
532 static void test_GetIDsOfNames(void)
533 {
534     WCHAR name_Name[] = {'N','a','m','e',0};
535     WCHAR name_Italic[] = {'I','t','a','l','i','c',0};
536     WCHAR name_Size[] = {'S','i','z','e',0};
537     WCHAR name_Bold[] = {'B','o','l','d',0};
538     WCHAR name_Underline[] = {'U','n','d','e','r','l','i','n','e',0};
539     WCHAR name_Strikethrough[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0};
540     WCHAR name_Weight[] = {'W','e','i','g','h','t',0};
541     WCHAR name_Charset[] = {'C','h','a','r','s','e','t',0};
542     WCHAR name_Foo[] = {'F','o','o',0};
543     WCHAR name_nAmE[] = {'n','A','m','E',0};
544     WCHAR name_Nom[] = {'N','o','m',0};
545 
546     LCID en_us = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
547                           SORT_DEFAULT);
548     LCID fr_fr = MAKELCID(MAKELANGID(LANG_FRENCH,SUBLANG_FRENCH),
549                           SORT_DEFAULT);
550 
551     /* Test DISPID_FONTs for the various properties. */
552     test_names_ids(name_Name, "Name", NULL, "", en_us,
553                    DISPID_FONT_NAME, 0, S_OK,1);
554     test_names_ids(name_Size, "Size", NULL, "", en_us,
555                    DISPID_FONT_SIZE, 0, S_OK,1);
556     test_names_ids(name_Bold, "Bold", NULL, "", en_us,
557                    DISPID_FONT_BOLD, 0, S_OK,1);
558     test_names_ids(name_Italic, "Italic", NULL, "", en_us,
559                    DISPID_FONT_ITALIC, 0, S_OK,1);
560     test_names_ids(name_Underline, "Underline", NULL, "", en_us,
561                    DISPID_FONT_UNDER, 0, S_OK,1);
562     test_names_ids(name_Strikethrough, "Strikethrough", NULL, "", en_us,
563                    DISPID_FONT_STRIKE, 0, S_OK,1);
564     test_names_ids(name_Weight, "Weight", NULL, "", en_us,
565                    DISPID_FONT_WEIGHT, 0, S_OK,1);
566     test_names_ids(name_Charset, "Charset", NULL, "", en_us,
567                    DISPID_FONT_CHARSET, 0, S_OK,1);
568 
569     /* Capitalization doesn't matter. */
570     test_names_ids(name_nAmE, "nAmE", NULL, "", en_us,
571                    DISPID_FONT_NAME, 0, S_OK,1);
572 
573     /* Unknown name. */
574     test_names_ids(name_Foo, "Foo", NULL, "", en_us,
575                    DISPID_UNKNOWN, 0, DISP_E_UNKNOWNNAME,1);
576 
577     /* Pass several names: first is processed,                */
578     /* second gets DISPID_UNKNOWN and doesn't affect retval.  */
579     test_names_ids(name_Italic, "Italic", name_Name, "Name", en_us,
580                    DISPID_FONT_ITALIC, DISPID_UNKNOWN, S_OK,2);
581     test_names_ids(name_Italic, "Italic", name_Foo, "Foo", en_us,
582                    DISPID_FONT_ITALIC, DISPID_UNKNOWN, S_OK,2);
583 
584     /* Locale ID has no effect. */
585     test_names_ids(name_Name, "Name", NULL, "", fr_fr,
586                    DISPID_FONT_NAME, 0, S_OK,1);
587     test_names_ids(name_Nom, "This is not a font", NULL, "", fr_fr,
588                    DISPID_UNKNOWN, 0, DISP_E_UNKNOWNNAME,1);
589 
590     /* One of the arguments are invalid */
591     test_names_ids(name_Name, "Name", NULL, "", en_us,
592                    0xdeadbeef, 0xdeadbeef, E_INVALIDARG,0);
593     test_names_ids(name_Italic, "Italic", NULL, "", en_us,
594                    0xdeadbeef, 0xdeadbeef, E_INVALIDARG,0);
595     test_names_ids(name_Foo, "Foo", NULL, "", en_us,
596                    0xdeadbeef, 0xdeadbeef, E_INVALIDARG,0);
597 
598     /* Crazy locale ID? */
599     test_names_ids(name_Name, "Name", NULL, "", -1,
600                    DISPID_FONT_NAME, 0, S_OK,1);
601 }
602 
603 static void test_Invoke(void)
604 {
605     IFontDisp *fontdisp;
606     HRESULT hr;
607     VARIANTARG vararg;
608     DISPPARAMS dispparams;
609     VARIANT varresult;
610 
611     hr = pOleCreateFontIndirect(NULL, &IID_IFontDisp, (void **)&fontdisp);
612     EXPECT_HR(hr, S_OK);
613 
614     V_VT(&vararg) = VT_BOOL;
615     V_BOOL(&vararg) = VARIANT_FALSE;
616     dispparams.cNamedArgs = 0;
617     dispparams.rgdispidNamedArgs = NULL;
618     dispparams.cArgs = 1;
619     dispparams.rgvarg = &vararg;
620     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_IFontDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
621     EXPECT_HR(hr, DISP_E_UNKNOWNINTERFACE);
622 
623     dispparams.cArgs = 0;
624     dispparams.rgvarg = NULL;
625     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
626     EXPECT_HR(hr, DISP_E_BADPARAMCOUNT);
627 
628     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
629     EXPECT_HR(hr, DISP_E_PARAMNOTOPTIONAL);
630 
631     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
632     EXPECT_HR(hr, DISP_E_PARAMNOTOPTIONAL);
633 
634     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
635     EXPECT_HR(hr, S_OK);
636 
637     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_METHOD, NULL, &varresult, NULL, NULL);
638     EXPECT_HR(hr, DISP_E_MEMBERNOTFOUND);
639 
640     hr = IFontDisp_Invoke(fontdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
641     EXPECT_HR(hr, DISP_E_MEMBERNOTFOUND);
642 
643     dispparams.cArgs = 1;
644     dispparams.rgvarg = &vararg;
645     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
646     EXPECT_HR(hr, S_OK);
647 
648     IFontDisp_Release(fontdisp);
649 }
650 
651 static void test_IsEqual(void)
652 {
653     FONTDESC fd;
654     IFont* ifnt = NULL;
655     IFont* ifnt2 = NULL;
656     HRESULT hres;
657 
658     /* Basic font description */
659     fd.cbSizeofstruct = sizeof(FONTDESC);
660     fd.lpstrName      = system_font;
661     S(fd.cySize).Lo   = 100;
662     S(fd.cySize).Hi   = 100;
663     fd.sWeight        = 0;
664     fd.sCharset       = 0;
665     fd.fItalic        = FALSE;
666     fd.fUnderline     = FALSE;
667     fd.fStrikethrough = FALSE;
668 
669     /* Create font */
670     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt);
671 
672     /* Test equal fonts */
673     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
674     hres = IFont_IsEqual(ifnt,ifnt2);
675     ok(hres == S_OK,
676         "IFont_IsEqual: (EQUAL) Expected S_OK but got 0x%08x\n",hres);
677     IFont_Release(ifnt2);
678 
679     /* Check for bad pointer */
680     hres = IFont_IsEqual(ifnt,NULL);
681     ok(hres == E_POINTER,
682         "IFont_IsEqual: (NULL) Expected 0x80004003 but got 0x%08x\n",hres);
683 
684     /* Test strName */
685     fd.lpstrName = arial_font;
686     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
687     hres = IFont_IsEqual(ifnt,ifnt2);
688     ok(hres == S_FALSE,
689         "IFont_IsEqual: (strName) Expected S_FALSE but got 0x%08x\n",hres);
690     fd.lpstrName = system_font;
691     IFont_Release(ifnt2);
692 
693     /* Test lo font size */
694     S(fd.cySize).Lo = 10000;
695     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
696     hres = IFont_IsEqual(ifnt,ifnt2);
697     ok(hres == S_FALSE,
698         "IFont_IsEqual: (Lo font size) Expected S_FALSE but got 0x%08x\n",hres);
699     S(fd.cySize).Lo = 100;
700     IFont_Release(ifnt2);
701 
702     /* Test hi font size */
703     S(fd.cySize).Hi = 10000;
704     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
705     hres = IFont_IsEqual(ifnt,ifnt2);
706     ok(hres == S_FALSE,
707         "IFont_IsEqual: (Hi font size) Expected S_FALSE but got 0x%08x\n",hres);
708     S(fd.cySize).Hi = 100;
709     IFont_Release(ifnt2);
710 
711     /* Test font weight  */
712     fd.sWeight = 100;
713     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
714     hres = IFont_IsEqual(ifnt,ifnt2);
715     ok(hres == S_FALSE,
716         "IFont_IsEqual: (Weight) Expected S_FALSE but got 0x%08x\n",hres);
717     fd.sWeight = 0;
718     IFont_Release(ifnt2);
719 
720     /* Test charset */
721     fd.sCharset = 1;
722     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
723     hres = IFont_IsEqual(ifnt,ifnt2);
724     ok(hres == S_FALSE,
725         "IFont_IsEqual: (Charset) Expected S_FALSE but got 0x%08x\n",hres);
726     fd.sCharset = 0;
727     IFont_Release(ifnt2);
728 
729     /* Test italic setting */
730     fd.fItalic = TRUE;
731     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
732     hres = IFont_IsEqual(ifnt,ifnt2);
733     ok(hres == S_FALSE,
734         "IFont_IsEqual: (Italic) Expected S_FALSE but got 0x%08x\n",hres);
735     fd.fItalic = FALSE;
736     IFont_Release(ifnt2);
737 
738     /* Test underline setting */
739     fd.fUnderline = TRUE;
740     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
741     hres = IFont_IsEqual(ifnt,ifnt2);
742     ok(hres == S_FALSE,
743         "IFont_IsEqual: (Underline) Expected S_FALSE but got 0x%08x\n",hres);
744     fd.fUnderline = FALSE;
745     IFont_Release(ifnt2);
746 
747     /* Test strikethrough setting */
748     fd.fStrikethrough = TRUE;
749     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
750     hres = IFont_IsEqual(ifnt,ifnt2);
751     ok(hres == S_FALSE,
752         "IFont_IsEqual: (Strikethrough) Expected S_FALSE but got 0x%08x\n",hres);
753     fd.fStrikethrough = FALSE;
754     IFont_Release(ifnt2);
755 
756     /* Free IFont. */
757     IFont_Release(ifnt);
758 }
759 
760 static void test_ReleaseHfont(void)
761 {
762     FONTDESC fd;
763     LPVOID pvObj1 = NULL;
764     LPVOID pvObj2 = NULL;
765     IFont* ifnt1 = NULL;
766     IFont* ifnt2 = NULL;
767     HFONT hfnt1 = 0;
768     HFONT hfnt2 = 0;
769     HRESULT hres;
770 
771     /* Basic font description */
772     fd.cbSizeofstruct = sizeof(FONTDESC);
773     fd.lpstrName      = system_font;
774     S(fd.cySize).Lo   = 100;
775     S(fd.cySize).Hi   = 100;
776     fd.sWeight        = 0;
777     fd.sCharset       = 0;
778     fd.fItalic        = FALSE;
779     fd.fUnderline     = FALSE;
780     fd.fStrikethrough = FALSE;
781 
782     /* Create HFONTs and IFONTs */
783     pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj1);
784     ifnt1 = pvObj1;
785     IFont_get_hFont(ifnt1,&hfnt1);
786     fd.lpstrName = arial_font;
787     pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj2);
788     ifnt2 = pvObj2;
789     IFont_get_hFont(ifnt2,&hfnt2);
790 
791     /* Try invalid HFONT */
792     hres = IFont_ReleaseHfont(ifnt1,NULL);
793     ok(hres == E_INVALIDARG,
794         "IFont_ReleaseHfont: (Bad HFONT) Expected E_INVALIDARG but got 0x%08x\n",
795         hres);
796 
797     /* Try to add a bad HFONT */
798     hres = IFont_ReleaseHfont(ifnt1,(HFONT)32);
799     ok(hres == S_FALSE,
800         "IFont_ReleaseHfont: (Bad HFONT) Expected S_FALSE but got 0x%08x\n",
801         hres);
802 
803     /* Release all refs */
804     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
805     ok(hres == S_OK,
806         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
807         hres);
808 
809     hres = IFont_ReleaseHfont(ifnt2,hfnt2);
810     ok(hres == S_OK,
811         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
812         hres);
813 
814     /* Check that both lists are empty */
815     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
816     ok(hres == S_FALSE,
817         "IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
818         hres);
819 
820     /* The list should be empty */
821     hres = IFont_ReleaseHfont(ifnt2,hfnt2);
822     ok(hres == S_FALSE,
823         "IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
824         hres);
825 
826     IFont_Release(ifnt1);
827     IFont_Release(ifnt2);
828 }
829 
830 static void test_AddRefHfont(void)
831 {
832     FONTDESC fd;
833     IFont* ifnt1 = NULL;
834     IFont* ifnt2 = NULL;
835     IFont* ifnt3 = NULL;
836     HFONT hfnt1 = 0;
837     HFONT hfnt2 = 0;
838     HFONT hfnt3 = 0;
839     HRESULT hres;
840 
841     /* Basic font description */
842     fd.cbSizeofstruct = sizeof(FONTDESC);
843     fd.lpstrName      = system_font;
844     S(fd.cySize).Lo   = 100;
845     S(fd.cySize).Hi   = 100;
846     fd.sWeight        = 0;
847     fd.sCharset       = 0;
848     fd.fItalic        = FALSE;
849     fd.fUnderline     = FALSE;
850     fd.fStrikethrough = FALSE;
851 
852     /* Create HFONTs and IFONTs */
853     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt1);
854     IFont_get_hFont(ifnt1,&hfnt1);
855     fd.lpstrName = arial_font;
856     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2);
857     IFont_get_hFont(ifnt2,&hfnt2);
858 
859     /* Try invalid HFONT */
860     hres = IFont_AddRefHfont(ifnt1,NULL);
861     ok(hres == E_INVALIDARG,
862         "IFont_AddRefHfont: (Bad HFONT) Expected E_INVALIDARG but got 0x%08x\n",
863         hres);
864 
865     /* Try to add a bad HFONT */
866     hres = IFont_AddRefHfont(ifnt1,(HFONT)32);
867     ok(hres == S_FALSE,
868         "IFont_AddRefHfont: (Bad HFONT) Expected S_FALSE but got 0x%08x\n",
869         hres);
870 
871     /* Add simple IFONT HFONT pair */
872     hres = IFont_AddRefHfont(ifnt1,hfnt1);
873     ok(hres == S_OK,
874         "IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
875         hres);
876 
877     /* IFONT and HFONT do not have to be the same (always looks at HFONT) */
878     hres = IFont_AddRefHfont(ifnt2,hfnt1);
879     ok(hres == S_OK,
880         "IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
881         hres);
882 
883     /* Release all hfnt1 refs */
884     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
885     ok(hres == S_OK,
886         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
887         hres);
888 
889     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
890     ok(hres == S_OK,
891         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
892         hres);
893 
894     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
895     ok(hres == S_OK,
896         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
897         hres);
898 
899     /* Check if hfnt1 is empty */
900     hres = IFont_ReleaseHfont(ifnt1,hfnt1);
901     ok(hres == S_FALSE,
902         "IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
903         hres);
904 
905     /* Release all hfnt2 refs */
906     hres = IFont_ReleaseHfont(ifnt2,hfnt2);
907     ok(hres == S_OK,
908         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
909         hres);
910 
911     /* Check if hfnt2 is empty */
912     hres = IFont_ReleaseHfont(ifnt2,hfnt2);
913     ok(hres == S_FALSE,
914         "IFont_AddRefHfont: (Release ref) Expected S_FALSE but got 0x%08x\n",
915         hres);
916 
917     /* Show that releasing an IFONT does not always release it from the HFONT cache. */
918 
919     IFont_Release(ifnt1);
920 
921     /* Add a reference for destroyed hfnt1 */
922     hres = IFont_AddRefHfont(ifnt2,hfnt1);
923     ok(hres == S_OK,
924         "IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
925         hres);
926 
927     /* Decrement reference for destroyed hfnt1 */
928     hres = IFont_ReleaseHfont(ifnt2,hfnt1);
929     ok(hres == S_OK ||
930        hres == S_FALSE, /* <= win2k */
931         "IFont_AddRefHfont: (Release ref) Expected S_OK or S_FALSE but got 0x%08x\n",
932         hres);
933 
934     /* Shows that releasing all IFONT's does clear the HFONT cache. */
935 
936     IFont_Release(ifnt2);
937 
938     /* Need to make a new IFONT for testing */
939     fd.fUnderline = TRUE;
940     pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt3);
941     IFont_get_hFont(ifnt3,&hfnt3);
942 
943     /* Add a reference for destroyed hfnt1 */
944     hres = IFont_AddRefHfont(ifnt3,hfnt1);
945     ok(hres == S_FALSE,
946         "IFont_AddRefHfont: (Add ref) Expected S_OK but got 0x%08x\n",
947         hres);
948 
949     /* Decrement reference for destroyed hfnt1 */
950     hres = IFont_ReleaseHfont(ifnt3,hfnt1);
951     ok(hres == S_FALSE,
952         "IFont_AddRefHfont: (Release ref) Expected S_OK but got 0x%08x\n",
953         hres);
954 
955     IFont_Release(ifnt3);
956 }
957 
958 static void test_returns(void)
959 {
960     IFont *pFont;
961     FONTDESC fontdesc;
962     HRESULT hr;
963 
964     fontdesc.cbSizeofstruct = sizeof(fontdesc);
965     fontdesc.lpstrName = MSSansSerif_font;
966     fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
967     fontdesc.sWeight = FW_NORMAL;
968     fontdesc.sCharset = 0;
969     fontdesc.fItalic = FALSE;
970     fontdesc.fUnderline = FALSE;
971     fontdesc.fStrikethrough = FALSE;
972 
973     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&pFont);
974     EXPECT_HR(hr, S_OK);
975 
976     hr = IFont_put_Name(pFont, NULL);
977     EXPECT_HR(hr, CTL_E_INVALIDPROPERTYVALUE);
978 
979     hr = IFont_get_Name(pFont, NULL);
980     EXPECT_HR(hr, E_POINTER);
981 
982     hr = IFont_get_Size(pFont, NULL);
983     EXPECT_HR(hr, E_POINTER);
984 
985     hr = IFont_get_Bold(pFont, NULL);
986     EXPECT_HR(hr, E_POINTER);
987 
988     IFont_Release(pFont);
989 }
990 
991 static void test_hfont_lifetime(void)
992 {
993     IFont *font, *font2;
994     FONTDESC fontdesc;
995     HRESULT hr;
996     HFONT hfont, first_hfont = NULL;
997     CY size;
998     DWORD obj_type;
999     int i;
1000 
1001     fontdesc.cbSizeofstruct = sizeof(fontdesc);
1002     fontdesc.lpstrName = arial_font;
1003     fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
1004     fontdesc.sWeight = FW_NORMAL;
1005     fontdesc.sCharset = ANSI_CHARSET;
1006     fontdesc.fItalic = FALSE;
1007     fontdesc.fUnderline = FALSE;
1008     fontdesc.fStrikethrough = FALSE;
1009 
1010     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
1011     EXPECT_HR(hr, S_OK);
1012 
1013     hr = IFont_get_hFont(font, &hfont);
1014     EXPECT_HR(hr, S_OK);
1015 
1016     /* show that if the font is updated the old hfont is deleted when the
1017        new font is realized */
1018     for(i = 0; i < 100; i++)
1019     {
1020         HFONT last_hfont = hfont;
1021 
1022         size.int64 = (i + 10) * 20000;
1023 
1024         obj_type = GetObjectType(hfont);
1025         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1026 
1027         hr = IFont_put_Size(font, size);
1028         EXPECT_HR(hr, S_OK);
1029 
1030         /* put_Size doesn't cause the new font to be realized */
1031         obj_type = GetObjectType(last_hfont);
1032         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1033 
1034         hr = IFont_get_hFont(font, &hfont);
1035         EXPECT_HR(hr, S_OK);
1036 
1037         obj_type = GetObjectType(last_hfont);
1038         ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
1039     }
1040 
1041     /* now show that if we take a reference on the hfont, it persists
1042        until the font object is released */
1043     for(i = 0; i < 100; i++)
1044     {
1045         size.int64 = (i + 10) * 20000;
1046 
1047         obj_type = GetObjectType(hfont);
1048         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1049 
1050         hr = IFont_put_Size(font, size);
1051         EXPECT_HR(hr, S_OK);
1052 
1053         hr = IFont_get_hFont(font, &hfont);
1054         EXPECT_HR(hr, S_OK);
1055 
1056         hr = IFont_AddRefHfont(font, hfont);
1057         EXPECT_HR(hr, S_OK);
1058 
1059         if(i == 0) first_hfont = hfont;
1060         obj_type = GetObjectType(first_hfont);
1061         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1062     }
1063 
1064     IFont_Release(font);
1065 
1066     obj_type = GetObjectType(first_hfont);
1067     ok(obj_type == 0, "got obj type %d\n", obj_type);
1068 
1069     /* An AddRefHfont followed by a ReleaseHfont means the font doesn't not persist
1070        through re-realization */
1071 
1072     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
1073     EXPECT_HR(hr, S_OK);
1074 
1075     hr = IFont_get_hFont(font, &hfont);
1076     EXPECT_HR(hr, S_OK);
1077 
1078     for(i = 0; i < 100; i++)
1079     {
1080         HFONT last_hfont = hfont;
1081 
1082         size.int64 = (i + 10) * 20000;
1083 
1084         obj_type = GetObjectType(hfont);
1085         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1086 
1087         hr = IFont_put_Size(font, size);
1088         EXPECT_HR(hr, S_OK);
1089 
1090         /* put_Size doesn't cause the new font to be realized */
1091         obj_type = GetObjectType(last_hfont);
1092         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1093 
1094         hr = IFont_get_hFont(font, &hfont);
1095         EXPECT_HR(hr, S_OK);
1096 
1097         hr = IFont_AddRefHfont(font, hfont);
1098         EXPECT_HR(hr, S_OK);
1099 
1100         hr = IFont_ReleaseHfont(font, hfont);
1101         EXPECT_HR(hr, S_OK);
1102 
1103         obj_type = GetObjectType(last_hfont);
1104         ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
1105     }
1106 
1107     /* Interestingly if we release a nonexistent reference on the hfont,
1108      * it persists until the font object is released
1109      */
1110     for(i = 0; i < 100; i++)
1111     {
1112         size.int64 = (i + 10) * 20000;
1113 
1114         obj_type = GetObjectType(hfont);
1115         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1116 
1117         hr = IFont_put_Size(font, size);
1118         EXPECT_HR(hr, S_OK);
1119 
1120         hr = IFont_get_hFont(font, &hfont);
1121         EXPECT_HR(hr, S_OK);
1122 
1123         hr = IFont_ReleaseHfont(font, hfont);
1124         EXPECT_HR(hr, S_OK);
1125 
1126         if(i == 0) first_hfont = hfont;
1127         obj_type = GetObjectType(first_hfont);
1128         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1129     }
1130 
1131     IFont_Release(font);
1132 
1133     obj_type = GetObjectType(first_hfont);
1134     ok(obj_type == 0, "got obj type %d\n", obj_type);
1135 
1136     /* If we take two internal references on a hfont then we can release
1137        it twice.  So it looks like there's a total reference count
1138        that includes internal and external references */
1139 
1140     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
1141     EXPECT_HR(hr, S_OK);
1142     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font2);
1143     EXPECT_HR(hr, S_OK);
1144 
1145     hr = IFont_get_hFont(font, &hfont);
1146     EXPECT_HR(hr, S_OK);
1147     hr = IFont_get_hFont(font2, &first_hfont);
1148     EXPECT_HR(hr, S_OK);
1149 todo_wine
1150     ok(hfont == first_hfont, "fonts differ\n");
1151     hr = IFont_ReleaseHfont(font, hfont);
1152     EXPECT_HR(hr, S_OK);
1153     hr = IFont_ReleaseHfont(font, hfont);
1154 todo_wine
1155     EXPECT_HR(hr, S_OK);
1156     hr = IFont_ReleaseHfont(font, hfont);
1157     EXPECT_HR(hr, S_FALSE);
1158 
1159     obj_type = GetObjectType(hfont);
1160     ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1161 
1162     IFont_Release(font);
1163 
1164     obj_type = GetObjectType(hfont);
1165     ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
1166 
1167     IFont_Release(font2);
1168 
1169     obj_type = GetObjectType(hfont);
1170     ok(obj_type == 0, "got obj type %d\n", obj_type);
1171 }
1172 
1173 static void test_realization(void)
1174 {
1175     IFont *font;
1176     FONTDESC fontdesc;
1177     HRESULT hr;
1178     BSTR name;
1179     SHORT cs;
1180 
1181     /* Try to create a symbol only font (marlett) with charset
1182        set to ANSI.  This will result in another, ANSI, font
1183        being selected */
1184     fontdesc.cbSizeofstruct = sizeof(fontdesc);
1185     fontdesc.lpstrName = marlett_font;
1186     fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
1187     fontdesc.sWeight = FW_NORMAL;
1188     fontdesc.sCharset = ANSI_CHARSET;
1189     fontdesc.fItalic = FALSE;
1190     fontdesc.fUnderline = FALSE;
1191     fontdesc.fStrikethrough = FALSE;
1192 
1193     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
1194     EXPECT_HR(hr, S_OK);
1195 
1196     hr = IFont_get_Charset(font, &cs);
1197     EXPECT_HR(hr, S_OK);
1198     ok(cs == ANSI_CHARSET, "got charset %d\n", cs);
1199 
1200     IFont_Release(font);
1201 
1202     /* Now create an ANSI font and change the name to marlett */
1203 
1204     fontdesc.lpstrName = arial_font;
1205 
1206     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
1207     EXPECT_HR(hr, S_OK);
1208 
1209     hr = IFont_get_Charset(font, &cs);
1210     EXPECT_HR(hr, S_OK);
1211     ok(cs == ANSI_CHARSET, "got charset %d\n", cs);
1212 
1213     name = SysAllocString(marlett_font);
1214     hr = IFont_put_Name(font, name);
1215     EXPECT_HR(hr, S_OK);
1216     SysFreeString(name);
1217 
1218     hr = IFont_get_Name(font, &name);
1219     EXPECT_HR(hr, S_OK);
1220     ok(!lstrcmpiW(name, marlett_font), "got name %s\n", wine_dbgstr_w(name));
1221     SysFreeString(name);
1222 
1223     hr = IFont_get_Charset(font, &cs);
1224     EXPECT_HR(hr, S_OK);
1225     ok(cs == SYMBOL_CHARSET, "got charset %d\n", cs);
1226 
1227     IFont_Release(font);
1228 }
1229 
1230 static void test_OleCreateFontIndirect(void)
1231 {
1232     FONTDESC fontdesc;
1233     IUnknown *unk, *unk2;
1234     IFont *font;
1235     HRESULT hr;
1236 
1237     fontdesc.cbSizeofstruct = sizeof(fontdesc);
1238     fontdesc.lpstrName = arial_font;
1239     fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
1240     fontdesc.sWeight = FW_NORMAL;
1241     fontdesc.sCharset = ANSI_CHARSET;
1242     fontdesc.fItalic = FALSE;
1243     fontdesc.fUnderline = FALSE;
1244     fontdesc.fStrikethrough = FALSE;
1245 
1246     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
1247     EXPECT_HR(hr, S_OK);
1248     IFont_Release(font);
1249 
1250     /* play with cbSizeofstruct value */
1251     fontdesc.cbSizeofstruct = sizeof(fontdesc)-1;
1252     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
1253     EXPECT_HR(hr, S_OK);
1254     IFont_Release(font);
1255 
1256     fontdesc.cbSizeofstruct = sizeof(fontdesc)+1;
1257     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
1258     EXPECT_HR(hr, S_OK);
1259     IFont_Release(font);
1260 
1261     fontdesc.cbSizeofstruct = 0;
1262     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
1263     EXPECT_HR(hr, S_OK);
1264     IFont_Release(font);
1265 
1266     hr = OleInitialize(NULL);
1267     ok(hr == S_OK, "got 0x%08x\n", hr);
1268 
1269     hr = CoGetClassObject(&CLSID_StdFont, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)&unk);
1270     ok(hr == S_OK, "got 0x%08x\n", hr);
1271 
1272     hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void**)&unk2);
1273     ok(hr == S_OK, "got 0x%08x\n", hr);
1274 
1275     IUnknown_Release(unk);
1276     IUnknown_Release(unk2);
1277 
1278     OleUninitialize();
1279 }
1280 
1281 START_TEST(olefont)
1282 {
1283     hOleaut32 = GetModuleHandleA("oleaut32.dll");
1284     pOleCreateFontIndirect = (void*)GetProcAddress(hOleaut32, "OleCreateFontIndirect");
1285     if (!pOleCreateFontIndirect)
1286     {
1287         win_skip("OleCreateFontIndirect not available\n");
1288         return;
1289     }
1290 
1291     test_QueryInterface();
1292     test_type_info();
1293     test_ifont_sizes();
1294     test_font_events_disp();
1295     test_GetIDsOfNames();
1296     test_Invoke();
1297     test_IsEqual();
1298     test_ReleaseHfont();
1299     test_AddRefHfont();
1300     test_returns();
1301     test_hfont_lifetime();
1302     test_realization();
1303     test_OleCreateFontIndirect();
1304 }
1305