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