[OLEAUT32_WINETEST]
authorAmine Khaldi <amine.khaldi@reactos.org>
Wed, 12 Dec 2012 13:53:12 +0000 (13:53 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Wed, 12 Dec 2012 13:53:12 +0000 (13:53 +0000)
* Sync with Wine 1.5.19.

svn path=/trunk/; revision=57890

rostests/winetests/oleaut32/olefont.c
rostests/winetests/oleaut32/olepicture.c

index 7c0a112..2482554 100644 (file)
@@ -51,14 +51,14 @@ static HMODULE hOleaut32;
 
 static HRESULT (WINAPI *pOleCreateFontIndirect)(LPFONTDESC,REFIID,LPVOID*);
 
-#define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
+#define EXPECT_HR(hr,hr_exp) \
+    ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
 
 /* Create a font with cySize given by lo_size, hi_size,  */
 /* SetRatio to ratio_logical, ratio_himetric,            */
 /* check that resulting hfont has height hfont_height.   */
 /* Various checks along the way.                         */
-
-static void test_ifont_sizes(LONG lo_size, LONG hi_size,
+static void test_ifont_size(LONG lo_size, LONG hi_size,
        LONG ratio_logical, LONG ratio_himetric,
        LONG hfont_height, const char * test_name)
 {
@@ -69,9 +69,10 @@ static void test_ifont_sizes(LONG lo_size, LONG hi_size,
        LOGFONT lf;
        CY psize;
        HRESULT hres;
+        DWORD rtnval;
 
        fd.cbSizeofstruct = sizeof(FONTDESC);
-       fd.lpstrName      = system_font;
+       fd.lpstrName      = arial_font; /* using scalable instead of bitmap font reduces errors due to font realization */
        S(fd.cySize).Lo   = lo_size;
        S(fd.cySize).Hi   = hi_size;
        fd.sWeight        = 0;
@@ -87,32 +88,33 @@ static void test_ifont_sizes(LONG lo_size, LONG hi_size,
                test_name, hres);
        ok(pvObj != NULL,"%s: OCFI returns NULL.\n", test_name);
 
-       /* Read back size.  Hi part was ignored. */
+       /* If scaling ration specified, change ratio. */
+        if(ratio_logical && ratio_himetric)
+        {
+          hres = IFont_SetRatio(ifnt, ratio_logical, ratio_himetric);
+          ok(hres == S_OK,"%s: IFont_SetRatio returns 0x%08x instead of S_OK.\n",
+            test_name, hres);
+        }
+
+       /* Read back size. */
        hres = IFont_get_Size(ifnt, &psize);
        ok(hres == S_OK,"%s: IFont_get_size returns 0x%08x instead of S_OK.\n",
                test_name, hres);
-       ok(S(psize).Lo == lo_size && S(psize).Hi == 0,
-               "%s: get_Size: Lo=%d, Hi=%d; expected Lo=%d, Hi=0.\n",
-               test_name, S(psize).Lo, S(psize).Hi, lo_size);
 
-       /* Change ratio, check size unchanged.  Standard is 72, 2540. */
-       hres = IFont_SetRatio(ifnt, ratio_logical, ratio_himetric);
-       ok(hres == S_OK,"%s: IFont_SR returns 0x%08x instead of S_OK.\n",
-               test_name, hres);
-       hres = IFont_get_Size(ifnt, &psize);
-       ok(hres == S_OK,"%s: IFont_get_size returns 0x%08x instead of S_OK.\n",
-                test_name, hres);
-       ok(S(psize).Lo == lo_size && S(psize).Hi == 0,
-               "%s: gS after SR: Lo=%d, Hi=%d; expected Lo=%d, Hi=0.\n",
-               test_name, S(psize).Lo, S(psize).Hi, lo_size);
+        /* Check returned size - allow for errors due to rounding & font realization. */
+       ok((abs(S(psize).Lo - lo_size) < 10000) && S(psize).Hi == hi_size,
+               "%s: IFont_get_Size: Lo=%d, Hi=%d; expected Lo=%d, Hi=%d.\n",
+               test_name, S(psize).Lo, S(psize).Hi, lo_size, hi_size);
 
-       /* Check hFont size with this ratio.  This tests an important   */
-       /* conversion for which MSDN is very wrong.                     */
+       /* Check hFont size. */
        hres = IFont_get_hFont (ifnt, &hfont);
        ok(hres == S_OK, "%s: IFont_get_hFont returns 0x%08x instead of S_OK.\n",
                test_name, hres);
-       hres = GetObject (hfont, sizeof(LOGFONT), &lf);
-       ok(lf.lfHeight == hfont_height,
+       rtnval = GetObject (hfont, sizeof(LOGFONT), &lf);
+        ok(rtnval > 0, "GetObject(hfont) failed\n");
+
+        /* Since font scaling may encounter rounding errors, allow 1 pixel deviation. */
+       ok(abs(lf.lfHeight - hfont_height) <= 1,
                "%s: hFont has lf.lfHeight=%d, expected %d.\n",
                test_name, lf.lfHeight, hfont_height);
 
@@ -120,35 +122,68 @@ static void test_ifont_sizes(LONG lo_size, LONG hi_size,
        IFont_Release(ifnt);
 }
 
+static void test_ifont_sizes(void)
+{
+  /* Test various size operations and conversions. */
+  /* Add more as needed. */
+
+  /* Results of first 2 tests depend on display resolution. */
+  HDC hdc = GetDC(0);
+  LONG dpi = GetDeviceCaps(hdc, LOGPIXELSY); /* expected results depend on display DPI */
+  ReleaseDC(0, hdc);
+  if(dpi == 96) /* normal resolution display */
+  {
+    test_ifont_size(180000, 0, 0, 0, -24, "default");     /* normal font */
+    test_ifont_size(186000, 0, 0, 0, -25, "rounding");    /* test rounding */
+  } else if(dpi == 72) /* low resolution display */
+  {
+    test_ifont_size(180000, 0, 0, 0, -18, "default");     /* normal font */
+    test_ifont_size(186000, 0, 0, 0, -19, "rounding");    /* test rounding */
+  } else if(dpi == 120) /* high resolution display */
+  {
+    test_ifont_size(180000, 0, 0, 0, -30, "default");     /* normal font */
+    test_ifont_size(186000, 0, 0, 0, -31, "rounding");    /* test rounding */
+  } else
+    skip("Skipping resolution dependent font size tests - display resolution is %d\n", dpi);
+
+  /* Next 4 tests specify a scaling ratio, so display resolution is not a factor. */
+    test_ifont_size(180000, 0, 72,  2540, -18, "ratio1");  /* change ratio */
+    test_ifont_size(180000, 0, 144, 2540, -36, "ratio2");  /* another ratio */
+    test_ifont_size(180000, 0, 72,  1270, -36, "ratio3");  /* yet another ratio */
+    test_ifont_size(186000, 0, 72,  2540, -19, "rounding+ratio"); /* test rounding with ratio */
+}
+
 static void test_QueryInterface(void)
 {
-        LPVOID pvObj = NULL;
-        HRESULT hres;
-        IFont*  font = NULL;
-        LONG ret;
+    LPVOID pvObj = NULL;
+    HRESULT hr;
+    IFont*  font = NULL;
+    LONG ref;
+
+    hr = pOleCreateFontIndirect(NULL, &IID_IFont, NULL);
+    EXPECT_HR(hr, E_POINTER);
 
-        hres = pOleCreateFontIndirect(NULL, &IID_IFont, &pvObj);
-        font = pvObj;
+    hr = pOleCreateFontIndirect(NULL, &IID_IFont, &pvObj);
+    font = pvObj;
 
-        ok(hres == S_OK,"OCFI (NULL,..) does not return 0, but 0x%08x\n",hres);
-        ok(font != NULL,"OCFI (NULL,..) returns NULL, instead of !NULL\n");
+    EXPECT_HR(hr, S_OK);
+    ok(font != NULL,"OCFI (NULL,..) returns NULL, instead of !NULL\n");
 
-        pvObj = NULL;
-        hres = IFont_QueryInterface( font, &IID_IFont, &pvObj);
+    pvObj = NULL;
+    hr = IFont_QueryInterface( font, &IID_IFont, &pvObj);
+    EXPECT_HR(hr, S_OK);
 
-        /* Test if QueryInterface increments ref counter for IFONTs */
-        ret = IFont_AddRef(font);
-        ok(ret == 3 ||
-           broken(ret == 1), /* win95 */
-           "IFont_QI expected ref value 3 but instead got %d\n",ret);
-        IFont_Release(font);
+    /* Test if QueryInterface increments ref counter for IFONTs */
+    ref = IFont_AddRef(font);
+    ok(ref == 3 ||
+       broken(ref == 1), /* win95 */
+           "IFont_QI expected ref value 3 but instead got %d\n", ref);
+    IFont_Release(font);
 
-        ok(hres == S_OK,"IFont_QI does not return S_OK, but 0x%08x\n", hres);
-        ok(pvObj != NULL,"IFont_QI does return NULL, instead of a ptr\n");
+    ok(pvObj != NULL,"IFont_QI does return NULL, instead of a ptr\n");
 
-        /* Original ref and QueryInterface ref both have to be released */
-        IFont_Release(font);
-        IFont_Release(font);
+    IFont_Release(font);
+    IFont_Release(font);
 }
 
 static void test_type_info(void)
@@ -201,7 +236,7 @@ static HRESULT WINAPI FontEventsDisp_QueryInterface(
 {
     if (IsEqualIID(riid, &IID_IFontEventsDisp) || IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch))
     {
-        IUnknown_AddRef(iface);
+        IFontEventsDisp_AddRef(iface);
         *ppvObject = iface;
         return S_OK;
     }
@@ -284,26 +319,26 @@ static void test_font_events_disp(void)
     fontdesc.fStrikethrough = FALSE;
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&pFont);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_QueryInterface(pFont, &IID_IConnectionPointContainer, (void **)&pCPC);
-    ok_ole_success(hr, "IFont_QueryInterface");
+    EXPECT_HR(hr, S_OK);
 
     hr = IConnectionPointContainer_FindConnectionPoint(pCPC, &IID_IFontEventsDisp, &pCP);
-    ok_ole_success(hr, "IConnectionPointContainer_FindConnectionPoint");
+    EXPECT_HR(hr, S_OK);
     IConnectionPointContainer_Release(pCPC);
 
     hr = IConnectionPoint_Advise(pCP, (IUnknown *)&FontEventsDisp, &dwCookie);
-    ok_ole_success(hr, "IConnectionPoint_Advise");
+    EXPECT_HR(hr, S_OK);
     IConnectionPoint_Release(pCP);
 
     hr = IFont_put_Bold(pFont, TRUE);
-    ok_ole_success(hr, "IFont_put_Bold");
+    EXPECT_HR(hr, S_OK);
 
     ok(fonteventsdisp_invoke_called == 1, "IFontEventDisp::Invoke wasn't called once\n");
 
     hr = IFont_QueryInterface(pFont, &IID_IFontDisp, (void **)&pFontDisp);
-    ok_ole_success(hr, "IFont_QueryInterface");
+    EXPECT_HR(hr, S_OK);
 
     V_VT(&vararg) = VT_BOOL;
     V_BOOL(&vararg) = VARIANT_FALSE;
@@ -312,6 +347,7 @@ static void test_font_events_disp(void)
     dispparams.cArgs = 1;
     dispparams.rgvarg = &vararg;
     hr = IFontDisp_Invoke(pFontDisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
+    EXPECT_HR(hr, S_OK);
 
     IFontDisp_Release(pFontDisp);
 
@@ -319,11 +355,11 @@ static void test_font_events_disp(void)
         fonteventsdisp_invoke_called);
 
     hr = IFont_Clone(pFont, &pFont2);
-    ok_ole_success(hr, "IFont_Clone");
+    EXPECT_HR(hr, S_OK);
     IFont_Release(pFont);
 
     hr = IFont_put_Bold(pFont2, FALSE);
-    ok_ole_success(hr, "IFont_put_Bold");
+    EXPECT_HR(hr, S_OK);
 
     /* this test shows that the notification routine isn't called again */
     ok(fonteventsdisp_invoke_called == 2, "IFontEventDisp::Invoke was called %d times instead of twice\n",
@@ -450,7 +486,7 @@ static void test_Invoke(void)
     VARIANT varresult;
 
     hr = pOleCreateFontIndirect(NULL, &IID_IFontDisp, (void **)&fontdisp);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     V_VT(&vararg) = VT_BOOL;
     V_BOOL(&vararg) = VARIANT_FALSE;
@@ -459,32 +495,32 @@ static void test_Invoke(void)
     dispparams.cArgs = 1;
     dispparams.rgvarg = &vararg;
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_IFontDisp, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
-    ok(hr == DISP_E_UNKNOWNINTERFACE, "IFontDisp_Invoke should have returned DISP_E_UNKNOWNINTERFACE instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_UNKNOWNINTERFACE);
 
     dispparams.cArgs = 0;
     dispparams.rgvarg = NULL;
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
-    ok(hr == DISP_E_BADPARAMCOUNT, "IFontDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_BADPARAMCOUNT);
 
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYPUT, NULL, NULL, NULL, NULL);
-    ok(hr == DISP_E_PARAMNOTOPTIONAL, "IFontDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_PARAMNOTOPTIONAL);
 
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, NULL, NULL, NULL);
-    ok(hr == DISP_E_PARAMNOTOPTIONAL, "IFontDisp_Invoke should have returned DISP_E_PARAMNOTOPTIONAL instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_PARAMNOTOPTIONAL);
 
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
-    ok_ole_success(hr, "IFontDisp_Invoke");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_METHOD, NULL, &varresult, NULL, NULL);
-    ok(hr == DISP_E_MEMBERNOTFOUND, "IFontDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_MEMBERNOTFOUND);
 
     hr = IFontDisp_Invoke(fontdisp, 0xdeadbeef, &IID_NULL, 0, DISPATCH_PROPERTYGET, NULL, &varresult, NULL, NULL);
-    ok(hr == DISP_E_MEMBERNOTFOUND, "IFontDisp_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
+    EXPECT_HR(hr, DISP_E_MEMBERNOTFOUND);
 
     dispparams.cArgs = 1;
     dispparams.rgvarg = &vararg;
     hr = IFontDisp_Invoke(fontdisp, DISPID_FONT_BOLD, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL);
-    ok_ole_success(hr, "IFontDisp_Invoke");
+    EXPECT_HR(hr, S_OK);
 
     IFontDisp_Release(fontdisp);
 }
@@ -812,27 +848,19 @@ static void test_returns(void)
     fontdesc.fStrikethrough = FALSE;
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&pFont);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_put_Name(pFont, NULL);
-    ok(hr == CTL_E_INVALIDPROPERTYVALUE,
-       "IFont::put_Name: Expected CTL_E_INVALIDPROPERTYVALUE got 0x%08x\n",
-       hr);
+    EXPECT_HR(hr, CTL_E_INVALIDPROPERTYVALUE);
 
     hr = IFont_get_Name(pFont, NULL);
-    ok(hr == E_POINTER,
-       "IFont::get_Name: Expected E_POINTER got 0x%08x\n",
-       hr);
+    EXPECT_HR(hr, E_POINTER);
 
     hr = IFont_get_Size(pFont, NULL);
-    ok(hr == E_POINTER,
-       "IFont::get_Size: Expected E_POINTER got 0x%08x\n",
-       hr);
+    EXPECT_HR(hr, E_POINTER);
 
     hr = IFont_get_Bold(pFont, NULL);
-    ok(hr == E_POINTER,
-       "IFont::get_Bold: Expected E_POINTER got 0x%08x\n",
-       hr);
+    EXPECT_HR(hr, E_POINTER);
 
     IFont_Release(pFont);
 }
@@ -857,10 +885,10 @@ static void test_hfont_lifetime(void)
     fontdesc.fStrikethrough = FALSE;
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_get_hFont(font, &hfont);
-    ok_ole_success(hr, "get_hFont");
+    EXPECT_HR(hr, S_OK);
 
     /* show that if the font is updated the old hfont is deleted when the
        new font is realized */
@@ -874,14 +902,14 @@ static void test_hfont_lifetime(void)
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_put_Size(font, size);
-        ok_ole_success(hr, "put_Size");
+        EXPECT_HR(hr, S_OK);
 
         /* put_Size doesn't cause the new font to be realized */
         obj_type = GetObjectType(last_hfont);
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_get_hFont(font, &hfont);
-        ok_ole_success(hr, "get_hFont");
+        EXPECT_HR(hr, S_OK);
 
         obj_type = GetObjectType(last_hfont);
         ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
@@ -891,20 +919,19 @@ static void test_hfont_lifetime(void)
        until the font object is released */
     for(i = 0; i < 100; i++)
     {
-
         size.int64 = (i + 10) * 20000;
 
         obj_type = GetObjectType(hfont);
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_put_Size(font, size);
-        ok_ole_success(hr, "put_Size");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_get_hFont(font, &hfont);
-        ok_ole_success(hr, "get_hFont");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_AddRefHfont(font, hfont);
-        ok_ole_success(hr, "AddRefHfont");
+        EXPECT_HR(hr, S_OK);
 
         if(i == 0) first_hfont = hfont;
         obj_type = GetObjectType(first_hfont);
@@ -920,10 +947,10 @@ static void test_hfont_lifetime(void)
        through re-realization */
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_get_hFont(font, &hfont);
-    ok_ole_success(hr, "get_hFont");
+    EXPECT_HR(hr, S_OK);
 
     for(i = 0; i < 100; i++)
     {
@@ -935,20 +962,20 @@ static void test_hfont_lifetime(void)
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_put_Size(font, size);
-        ok_ole_success(hr, "put_Size");
+        EXPECT_HR(hr, S_OK);
 
         /* put_Size doesn't cause the new font to be realized */
         obj_type = GetObjectType(last_hfont);
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_get_hFont(font, &hfont);
-        ok_ole_success(hr, "get_hFont");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_AddRefHfont(font, hfont);
-        ok_ole_success(hr, "AddRefHfont");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_ReleaseHfont(font, hfont);
-        ok_ole_success(hr, "ReleaseHfont");
+        EXPECT_HR(hr, S_OK);
 
         obj_type = GetObjectType(last_hfont);
         ok(obj_type == 0, "%d: got obj type %d\n", i, obj_type);
@@ -965,13 +992,13 @@ static void test_hfont_lifetime(void)
         ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
 
         hr = IFont_put_Size(font, size);
-        ok_ole_success(hr, "put_Size");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_get_hFont(font, &hfont);
-        ok_ole_success(hr, "get_hFont");
+        EXPECT_HR(hr, S_OK);
 
         hr = IFont_ReleaseHfont(font, hfont);
-        ok_ole_success(hr, "ReleaseHfont");
+        EXPECT_HR(hr, S_OK);
 
         if(i == 0) first_hfont = hfont;
         obj_type = GetObjectType(first_hfont);
@@ -988,23 +1015,23 @@ static void test_hfont_lifetime(void)
        that includes internal and external references */
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font2);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_get_hFont(font, &hfont);
-    ok_ole_success(hr, "get_hFont");
+    EXPECT_HR(hr, S_OK);
     hr = IFont_get_hFont(font2, &first_hfont);
-    ok_ole_success(hr, "get_hFont");
+    EXPECT_HR(hr, S_OK);
 todo_wine
     ok(hfont == first_hfont, "fonts differ\n");
     hr = IFont_ReleaseHfont(font, hfont);
-    ok(hr == S_OK, "got %08x\n", hr);
+    EXPECT_HR(hr, S_OK);
     hr = IFont_ReleaseHfont(font, hfont);
 todo_wine
-    ok(hr == S_OK, "got %08x\n", hr);
+    EXPECT_HR(hr, S_OK);
     hr = IFont_ReleaseHfont(font, hfont);
-    ok(hr == S_FALSE, "got %08x\n", hr);
+    EXPECT_HR(hr, S_FALSE);
 
     obj_type = GetObjectType(hfont);
     ok(obj_type == OBJ_FONT, "got obj type %d\n", obj_type);
@@ -1041,10 +1068,10 @@ static void test_realization(void)
     fontdesc.fStrikethrough = FALSE;
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_get_Charset(font, &cs);
-    ok_ole_success(hr, "get_Charset");
+    EXPECT_HR(hr, S_OK);
     ok(cs == ANSI_CHARSET, "got charset %d\n", cs);
 
     IFont_Release(font);
@@ -1054,62 +1081,86 @@ static void test_realization(void)
     fontdesc.lpstrName = arial_font;
 
     hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void **)&font);
-    ok_ole_success(hr, "OleCreateFontIndirect");
+    EXPECT_HR(hr, S_OK);
 
     hr = IFont_get_Charset(font, &cs);
-    ok_ole_success(hr, "get_Charset");
+    EXPECT_HR(hr, S_OK);
     ok(cs == ANSI_CHARSET, "got charset %d\n", cs);
 
     name = SysAllocString(marlett_font);
     hr = IFont_put_Name(font, name);
-    ok_ole_success(hr, "put_Name");
+    EXPECT_HR(hr, S_OK);
     SysFreeString(name);
 
     hr = IFont_get_Name(font, &name);
-    ok_ole_success(hr, "get_Name");
+    EXPECT_HR(hr, S_OK);
     ok(!lstrcmpiW(name, marlett_font), "got name %s\n", wine_dbgstr_w(name));
     SysFreeString(name);
 
     hr = IFont_get_Charset(font, &cs);
-    ok_ole_success(hr, "get_Charset");
+    EXPECT_HR(hr, S_OK);
     ok(cs == SYMBOL_CHARSET, "got charset %d\n", cs);
 
     IFont_Release(font);
 }
 
+static void test_OleCreateFontIndirect(void)
+{
+    FONTDESC fontdesc;
+    IFont *font;
+    HRESULT hr;
+
+    fontdesc.cbSizeofstruct = sizeof(fontdesc);
+    fontdesc.lpstrName = arial_font;
+    fontdesc.cySize.int64 = 12 * 10000; /* 12 pt */
+    fontdesc.sWeight = FW_NORMAL;
+    fontdesc.sCharset = ANSI_CHARSET;
+    fontdesc.fItalic = FALSE;
+    fontdesc.fUnderline = FALSE;
+    fontdesc.fStrikethrough = FALSE;
+
+    hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
+    EXPECT_HR(hr, S_OK);
+    IFont_Release(font);
+
+    /* play with cbSizeofstruct value */
+    fontdesc.cbSizeofstruct = sizeof(fontdesc)-1;
+    hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
+    EXPECT_HR(hr, S_OK);
+    IFont_Release(font);
+
+    fontdesc.cbSizeofstruct = sizeof(fontdesc)+1;
+    hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
+    EXPECT_HR(hr, S_OK);
+    IFont_Release(font);
+
+    fontdesc.cbSizeofstruct = 0;
+    hr = pOleCreateFontIndirect(&fontdesc, &IID_IFont, (void**)&font);
+    EXPECT_HR(hr, S_OK);
+    IFont_Release(font);
+}
+
 START_TEST(olefont)
 {
-       hOleaut32 = GetModuleHandleA("oleaut32.dll");
-       pOleCreateFontIndirect = (void*)GetProcAddress(hOleaut32, "OleCreateFontIndirect");
-       if (!pOleCreateFontIndirect)
-       {
-           win_skip("OleCreateFontIndirect not available\n");
-           return;
-       }
-
-       test_QueryInterface();
-       test_type_info();
-
-       /* Test various size operations and conversions. */
-       /* Add more as needed. */
-       if (0) /* FIXME: failing tests */
-       {
-           test_ifont_sizes(180000, 0, 72, 2540, -18, "default");
-           test_ifont_sizes(180000, 0, 144, 2540, -36, "ratio1");              /* change ratio */
-           test_ifont_sizes(180000, 0, 72, 1270, -36, "ratio2");               /* 2nd part of ratio */
-
-           /* These depend on details of how IFont rounds sizes internally. */
-           test_ifont_sizes(0, 0, 72, 2540, 0, "zero size");          /* zero size */
-           test_ifont_sizes(186000, 0, 72, 2540, -19, "rounding");   /* test rounding */
-       }
-
-       test_font_events_disp();
-       test_GetIDsOfNames();
-       test_Invoke();
-       test_IsEqual();
-       test_ReleaseHfont();
-       test_AddRefHfont();
-       test_returns();
-        test_hfont_lifetime();
-        test_realization();
+    hOleaut32 = GetModuleHandleA("oleaut32.dll");
+    pOleCreateFontIndirect = (void*)GetProcAddress(hOleaut32, "OleCreateFontIndirect");
+    if (!pOleCreateFontIndirect)
+    {
+        win_skip("OleCreateFontIndirect not available\n");
+        return;
+    }
+
+    test_QueryInterface();
+    test_type_info();
+    test_ifont_sizes();
+    test_font_events_disp();
+    test_GetIDsOfNames();
+    test_Invoke();
+    test_IsEqual();
+    test_ReleaseHfont();
+    test_AddRefHfont();
+    test_returns();
+    test_hfont_lifetime();
+    test_realization();
+    test_OleCreateFontIndirect();
 }
index 9ed8700..3f64c67 100644 (file)
@@ -2,7 +2,7 @@
  * OLEPICTURE test program
  *
  * Copyright 2005 Marcus Meissner
- *
+ * Copyright 2012 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,6 +25,7 @@
 #include <float.h>
 
 #define COBJMACROS
+#define CONST_VTABLE
 #define NONAMELESSUNION
 
 #include "wine/test.h"
@@ -53,7 +54,7 @@
 static HMODULE hOleaut32;
 
 static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);
-static HRESULT (WINAPI *pOleCreatePictureIndirect)(PICTDESC*,REFIID,BOOL,LPVOID*);
+static HRESULT (WINAPI *pOleLoadPictureEx)(LPSTREAM,LONG,BOOL,REFIID,DWORD,DWORD,DWORD,LPVOID*);
 
 #define ok_ole_success(hr, func) ok(hr == S_OK, func " failed with error 0x%08x\n", hr)
 
@@ -169,17 +170,17 @@ static const unsigned char enhmetafile[] = {
 };
 
 
-struct NoStatStreamImpl
+typedef struct NoStatStreamImpl
 {
-       const IStreamVtbl       *lpVtbl;   
+       IStream                 IStream_iface;
        LONG                    ref;
 
        HGLOBAL                 supportHandle;
        ULARGE_INTEGER          streamSize;
        ULARGE_INTEGER          currentPosition;
-};
-typedef struct NoStatStreamImpl NoStatStreamImpl;
-static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal);
+} NoStatStreamImpl;
+
+static IStream* NoStatStream_Construct(HGLOBAL hGlobal);
 
 static void
 test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
@@ -219,7 +220,7 @@ test_pic_with_stream(LPSTREAM stream, unsigned int imgsize)
         if (handle)
         {
             BITMAP bmp;
-            GetObject((HGDIOBJ)handle, sizeof(BITMAP), &bmp);
+            GetObject(UlongToHandle(handle), sizeof(BITMAP), &bmp);
             todo_wine ok(bmp.bmBits != 0, "not a dib\n");
         }
 
@@ -282,7 +283,7 @@ test_pic(const unsigned char *imgdata, unsigned int imgsize)
        IStream_Release(stream);
 
        /* again with Non Statable and Non Seekable stream */
-       stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
+       stream = NoStatStream_Construct(hglob);
        hglob = 0;  /* Non-statable impl always deletes on release */
        test_pic_with_stream(stream, 0);
 
@@ -313,7 +314,7 @@ test_pic(const unsigned char *imgdata, unsigned int imgsize)
                IStream_Release(stream);
 
                /* again with Non Statable and Non Seekable stream */
-               stream = (LPSTREAM)NoStatStreamImpl_Construct(hglob);
+               stream = NoStatStream_Construct(hglob);
                hglob = 0;  /* Non-statable impl always deletes on release */
                test_pic_with_stream(stream, 0);
 
@@ -481,24 +482,26 @@ static void test_Invoke(void)
 
 static void test_OleCreatePictureIndirect(void)
 {
+    OLE_HANDLE handle;
     IPicture *pict;
     HRESULT hr;
     short type;
-    OLE_HANDLE handle;
 
-    if(!pOleCreatePictureIndirect)
-    {
-        win_skip("Skipping OleCreatePictureIndirect tests\n");
-        return;
-    }
+if (0)
+{
+    /* crashes on native */
+    OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, NULL);
+}
 
-    hr = pOleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
+    hr = OleCreatePictureIndirect(NULL, &IID_IPicture, TRUE, (void**)&pict);
     ok(hr == S_OK, "hr %08x\n", hr);
 
+    type = PICTYPE_NONE;
     hr = IPicture_get_Type(pict, &type);
     ok(hr == S_OK, "hr %08x\n", hr);
     ok(type == PICTYPE_UNINITIALIZED, "type %d\n", type);
 
+    handle = 0xdeadbeef;
     hr = IPicture_get_Handle(pict, &handle);
     ok(hr == S_OK, "hr %08x\n", hr);
     ok(handle == 0, "handle %08x\n", handle);
@@ -518,7 +521,7 @@ static void test_apm(void)
     short type;
 
     if(!winetest_interactive) {
-        skip("Bug 5000: oleaut_winetest:olepicture crashes with Page Fault.\n");
+        skip("ROSTESTS-2: oleaut_winetest:olepicture crashes with Page Fault.\n");
         return;
     }
 
@@ -527,7 +530,7 @@ static void test_apm(void)
     memcpy(data, apmdata, sizeof(apmdata));
 
     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
-    ole_check(OleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
+    ole_check(pOleLoadPictureEx(stream, sizeof(apmdata), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict));
 
     ole_check(IPicture_get_Handle(pict, &handle));
     ok(handle != 0, "handle is null\n");
@@ -562,7 +565,7 @@ static void test_metafile(void)
 
     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
     /* Windows does not load simple metafiles */
-    ole_expect(OleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
+    ole_expect(pOleLoadPictureEx(stream, sizeof(metafile), TRUE, &IID_IPicture, 100, 100, 0, (LPVOID *)&pict), E_FAIL);
 
     IStream_Release(stream);
 }
@@ -579,7 +582,7 @@ static void test_enhmetafile(void)
     short type;
 
     if(!winetest_interactive) {
-        skip("Bug 5000: oleaut_winetest:olepicture crashes with Page Fault.\n");
+        skip("ROSTESTS-2: oleaut_winetest:olepicture crashes with Page Fault.\n");
         return;
     }
 
@@ -588,7 +591,7 @@ static void test_enhmetafile(void)
     memcpy(data, enhmetafile, sizeof(enhmetafile));
 
     ole_check(CreateStreamOnHGlobal(hglob, TRUE, &stream));
-    ole_check(OleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
+    ole_check(pOleLoadPictureEx(stream, sizeof(enhmetafile), TRUE, &IID_IPicture, 10, 10, 0, (LPVOID *)&pict));
 
     ole_check(IPicture_get_Handle(pict, &handle));
     ok(handle != 0, "handle is null\n");
@@ -675,9 +678,9 @@ static void test_Render(void)
     IPicture_get_Width(pic, &pWidth);
     IPicture_get_Height(pic, &pHeight);
 
-    SetPixelV(hdc, 0, 0, 0x00F0F0F0);
-    SetPixelV(hdc, 5, 5, 0x00F0F0F0);
-    SetPixelV(hdc, 10, 10, 0x00F0F0F0);
+    SetPixelV(hdc, 0, 0, 0x00223344);
+    SetPixelV(hdc, 5, 5, 0x00223344);
+    SetPixelV(hdc, 10, 10, 0x00223344);
     expected = GetPixel(hdc, 0, 0);
 
     hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL);
@@ -800,9 +803,8 @@ static void test_OleLoadPicturePath(void)
     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, NULL, (void **)&pic);
     todo_wine
     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
-       hres == E_UNEXPECTED || /* NT4/Win95 */
-       hres == E_FAIL || /* Win95 OSR2 */
-       hres == E_OUTOFMEMORY, /* Win98/Win2k/Win2k3 */
+       broken(hres == E_UNEXPECTED) || /* NT4 */
+       broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
     ok(pic == NULL,
        "Expected the output interface pointer to be NULL, got %p\n", pic);
@@ -811,9 +813,8 @@ static void test_OleLoadPicturePath(void)
     hres = OleLoadPicturePath(emptyW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     todo_wine
     ok(hres == INET_E_UNKNOWN_PROTOCOL || /* XP/Vista+ */
-       hres == E_UNEXPECTED || /* NT4/Win95 */
-       hres == E_FAIL || /* Win95 OSR2 */
-       hres == E_OUTOFMEMORY, /* Win98/Win2k/Win2k3 */
+       broken(hres == E_UNEXPECTED) || /* NT4 */
+       broken(hres == E_OUTOFMEMORY), /* Win2k/Win2k3 */
        "Expected OleLoadPicturePath to return INET_E_UNKNOWN_PROTOCOL, got 0x%08x\n", hres);
     ok(pic == NULL,
        "Expected the output interface pointer to be NULL, got %p\n", pic);
@@ -831,7 +832,7 @@ static void test_OleLoadPicturePath(void)
     /* Try a normal DOS path. */
     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == S_OK ||
-       broken(hres == E_UNEXPECTED), /* NT4/Win95 */
+       broken(hres == E_UNEXPECTED), /* NT4 */
        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
     if (pic)
         IPicture_Release(pic);
@@ -839,7 +840,7 @@ static void test_OleLoadPicturePath(void)
     /* Try a DOS path with tacked on "file:". */
     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == S_OK ||
-       broken(hres == E_UNEXPECTED), /* NT4/Win95 */
+       broken(hres == E_UNEXPECTED), /* NT4 */
        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
     if (pic)
         IPicture_Release(pic);
@@ -849,14 +850,14 @@ static void test_OleLoadPicturePath(void)
     /* Try with a nonexistent file. */
     hres = OleLoadPicturePath(temp_fileW + 8, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
-       hres == E_UNEXPECTED || /* NT4/Win95 */
-       hres == E_FAIL, /* Win9x/Win2k */
+       broken(hres == E_UNEXPECTED) || /* NT4 */
+       broken(hres == E_FAIL), /*Win2k */
        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
 
     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
-       hres == E_UNEXPECTED || /* NT4/Win95 */
-       hres == E_FAIL, /* Win9x/Win2k */
+       broken(hres == E_UNEXPECTED) || /* NT4 */
+       broken(hres == E_FAIL), /* Win2k */
        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
 
     file = CreateFileA(temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
@@ -875,7 +876,7 @@ static void test_OleLoadPicturePath(void)
 
     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == S_OK ||
-       broken(hres == E_UNEXPECTED), /* NT4/Win95 */
+       broken(hres == E_UNEXPECTED), /* NT4 */
        "Expected OleLoadPicturePath to return S_OK, got 0x%08x\n", hres);
     if (pic)
         IPicture_Release(pic);
@@ -885,35 +886,267 @@ static void test_OleLoadPicturePath(void)
     /* Try with a nonexistent file. */
     hres = OleLoadPicturePath(temp_fileW, NULL, 0, 0, &IID_IPicture, (void **)&pic);
     ok(hres == INET_E_RESOURCE_NOT_FOUND || /* XP+ */
-       hres == E_UNEXPECTED || /* NT4/Win95 */
-       hres == E_FAIL, /* Win9x/Win2k */
+       broken(hres == E_UNEXPECTED) || /* NT4 */
+       broken(hres == E_FAIL), /* Win2k */
        "Expected OleLoadPicturePath to return INET_E_RESOURCE_NOT_FOUND, got 0x%08x\n", hres);
 }
 
+static void test_himetric(void)
+{
+    static const BYTE bmp_bits[1024];
+    OLE_XSIZE_HIMETRIC cx;
+    OLE_YSIZE_HIMETRIC cy;
+    IPicture *pic;
+    PICTDESC desc;
+    HBITMAP bmp;
+    HRESULT hr;
+    HICON icon;
+    HDC hdc;
+    INT d;
+
+    desc.cbSizeofstruct = sizeof(desc);
+    desc.picType = PICTYPE_BITMAP;
+    desc.u.bmp.hpal = NULL;
+
+    hdc = CreateCompatibleDC(0);
+
+    bmp = CreateBitmap(1.9 * GetDeviceCaps(hdc, LOGPIXELSX),
+                       1.9 * GetDeviceCaps(hdc, LOGPIXELSY), 1, 1, NULL);
+
+    desc.u.bmp.hbitmap = bmp;
+
+    /* size in himetric units reported rounded up to next integer value */
+    hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    cx = 0;
+    d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSX)), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
+    hr = IPicture_get_Width(pic, &cx);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cx == d, "got %d, expected %d\n", cx, d);
+
+    cy = 0;
+    d = MulDiv((INT)(1.9 * GetDeviceCaps(hdc, LOGPIXELSY)), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
+    hr = IPicture_get_Height(pic, &cy);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cy == d, "got %d, expected %d\n", cy, d);
+
+    DeleteObject(bmp);
+    IPicture_Release(pic);
+
+    /* same thing with icon */
+    icon = CreateIcon(NULL, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
+                      1, 1, bmp_bits, bmp_bits);
+    ok(icon != NULL, "failed to create icon\n");
+
+    desc.picType = PICTYPE_ICON;
+    desc.u.icon.hicon = icon;
+
+    hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    cx = 0;
+    d = MulDiv(GetSystemMetrics(SM_CXICON), 2540, GetDeviceCaps(hdc, LOGPIXELSX));
+    hr = IPicture_get_Width(pic, &cx);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cx == d, "got %d, expected %d\n", cx, d);
+
+    cy = 0;
+    d = MulDiv(GetSystemMetrics(SM_CYICON), 2540, GetDeviceCaps(hdc, LOGPIXELSY));
+    hr = IPicture_get_Height(pic, &cy);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cy == d, "got %d, expected %d\n", cy, d);
+
+    IPicture_Release(pic);
+    DestroyIcon(icon);
+
+    DeleteDC(hdc);
+}
+
+static void test_load_save_bmp(void)
+{
+    IPicture *pic;
+    PICTDESC desc;
+    short type;
+    OLE_HANDLE handle;
+    HGLOBAL hmem;
+    DWORD *mem;
+    IPersistStream *src_stream;
+    IStream *dst_stream;
+    HRESULT hr;
+
+    desc.cbSizeofstruct = sizeof(desc);
+    desc.picType = PICTYPE_BITMAP;
+    desc.u.bmp.hpal = 0;
+    desc.u.bmp.hbitmap = CreateBitmap(1, 1, 1, 1, NULL);
+    hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
+    ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
+
+    type = -1;
+    hr = IPicture_get_Type(pic, &type);
+    ok(hr == S_OK,"get_Type error %#8x\n", hr);
+    ok(type == PICTYPE_BITMAP,"expected picture type PICTYPE_BITMAP, got %d\n", type);
+
+    hr = IPicture_get_Handle(pic, &handle);
+    ok(hr == S_OK,"get_Handle error %#8x\n", hr);
+    ok(IntToPtr(handle) == desc.u.bmp.hbitmap, "get_Handle returned wrong handle %#x\n", handle);
+
+    hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
+    hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
+    ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
+
+    hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
+    ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+    hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
+    ok(hr == S_OK, "Save error %#x\n", hr);
+
+    IPersistStream_Release(src_stream);
+    IStream_Release(dst_stream);
+
+    mem = GlobalLock(hmem);
+    ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
+    ok(mem[1] == 66, "expected stream size 66, got %u\n", mem[1]);
+    ok(!memcmp(&mem[2], "BM", 2), "got wrong bmp header %04x\n", mem[2]);
+
+    GlobalUnlock(hmem);
+    GlobalFree(hmem);
+
+    DeleteObject(desc.u.bmp.hbitmap);
+    IPicture_Release(pic);
+}
+
+static void test_load_save_icon(void)
+{
+    IPicture *pic;
+    PICTDESC desc;
+    short type;
+    OLE_HANDLE handle;
+    HGLOBAL hmem;
+    DWORD *mem;
+    IPersistStream *src_stream;
+    IStream *dst_stream;
+    HRESULT hr;
+
+    desc.cbSizeofstruct = sizeof(desc);
+    desc.picType = PICTYPE_ICON;
+    desc.u.icon.hicon = LoadIcon(0, IDI_APPLICATION);
+    hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic);
+    ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
+
+    type = -1;
+    hr = IPicture_get_Type(pic, &type);
+    ok(hr == S_OK,"get_Type error %#8x\n", hr);
+    ok(type == PICTYPE_ICON,"expected picture type PICTYPE_ICON, got %d\n", type);
+
+    hr = IPicture_get_Handle(pic, &handle);
+    ok(hr == S_OK,"get_Handle error %#8x\n", hr);
+    ok(IntToPtr(handle) == desc.u.icon.hicon, "get_Handle returned wrong handle %#x\n", handle);
+
+    hmem = GlobalAlloc(GMEM_ZEROINIT, 8192);
+    hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
+    ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
+
+    hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
+    ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+    hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
+    ok(hr == S_OK, "Saveerror %#x\n", hr);
+
+    IPersistStream_Release(src_stream);
+    IStream_Release(dst_stream);
+
+    mem = GlobalLock(hmem);
+    ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
+todo_wine
+    ok(mem[1] == 766, "expected stream size 766, got %u\n", mem[1]);
+    ok(mem[2] == 0x00010000, "got wrong icon header %04x\n", mem[2]);
+
+    GlobalUnlock(hmem);
+    GlobalFree(hmem);
+
+    DestroyIcon(desc.u.icon.hicon);
+    IPicture_Release(pic);
+}
+
+static void test_load_save_empty_picture(void)
+{
+    IPicture *pic;
+    PICTDESC desc;
+    short type;
+    OLE_HANDLE handle;
+    HGLOBAL hmem;
+    DWORD *mem;
+    IPersistStream *src_stream;
+    IStream *dst_stream;
+    HRESULT hr;
+
+    memset(&pic, 0, sizeof(pic));
+    desc.cbSizeofstruct = sizeof(desc);
+    desc.picType = PICTYPE_NONE;
+    hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void **)&pic);
+    ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr);
+
+    type = -1;
+    hr = IPicture_get_Type(pic, &type);
+    ok(hr == S_OK,"get_Type error %#8x\n", hr);
+    ok(type == PICTYPE_NONE,"expected picture type PICTYPE_NONE, got %d\n", type);
+
+    handle = (OLE_HANDLE)0xdeadbeef;
+    hr = IPicture_get_Handle(pic, &handle);
+    ok(hr == S_OK,"get_Handle error %#8x\n", hr);
+    ok(!handle, "get_Handle returned wrong handle %#x\n", handle);
+
+    hmem = GlobalAlloc(GMEM_ZEROINIT, 4096);
+    hr = CreateStreamOnHGlobal(hmem, FALSE, &dst_stream);
+    ok(hr == S_OK, "createstreamonhglobal error %#x\n", hr);
+
+    hr = IPicture_QueryInterface(pic, &IID_IPersistStream, (void **)&src_stream);
+    ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+    hr = IPersistStream_Save(src_stream, dst_stream, TRUE);
+    ok(hr == S_OK, "Save error %#x\n", hr);
+
+    mem = GlobalLock(hmem);
+    ok(!memcmp(mem, "lt\0\0", 4), "got wrong stream header %04x\n", mem[0]);
+    ok(mem[1] == 0, "expected stream size 0, got %u\n", mem[1]);
+    GlobalUnlock(hmem);
+
+    IPersistStream_Release(src_stream);
+    IStream_Release(dst_stream);
+
+    GlobalFree(hmem);
+    IPicture_Release(pic);
+}
+
 START_TEST(olepicture)
 {
-       hOleaut32 = GetModuleHandleA("oleaut32.dll");
-       pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
-       pOleCreatePictureIndirect = (void*)GetProcAddress(hOleaut32, "OleCreatePictureIndirect");
-       if (!pOleLoadPicture)
-       {
-           win_skip("OleLoadPicture is not available\n");
-           return;
-       }
+    hOleaut32 = GetModuleHandleA("oleaut32.dll");
+    pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
+    pOleLoadPictureEx = (void*)GetProcAddress(hOleaut32, "OleLoadPictureEx");
+    if (!pOleLoadPicture)
+    {
+        win_skip("OleLoadPicture is not available\n");
+        return;
+    }
 
-       /* Test regular 1x1 pixel images of gif, jpg, bmp type */
-        test_pic(gifimage, sizeof(gifimage));
-       test_pic(jpgimage, sizeof(jpgimage));
-       test_pic(bmpimage, sizeof(bmpimage));
-        test_pic(gif4pixel, sizeof(gif4pixel));
-       /* FIXME: No PNG support in Windows... */
-       if (0) test_pic(pngimage, sizeof(pngimage));
-       test_empty_image();
-       test_empty_image_2();
+    /* Test regular 1x1 pixel images of gif, jpg, bmp type */
+    test_pic(gifimage, sizeof(gifimage));
+    test_pic(jpgimage, sizeof(jpgimage));
+    test_pic(bmpimage, sizeof(bmpimage));
+    test_pic(gif4pixel, sizeof(gif4pixel));
+    /* FIXME: No PNG support in Windows... */
+    if (0) test_pic(pngimage, sizeof(pngimage));
+    test_empty_image();
+    test_empty_image_2();
+    if (pOleLoadPictureEx)
+    {
         test_apm();
         test_metafile();
         test_enhmetafile();
-
+    }
+    else
+        win_skip("OleLoadPictureEx is not available\n");
     test_Invoke();
     test_OleCreatePictureIndirect();
     test_Render();
@@ -921,12 +1154,21 @@ START_TEST(olepicture)
     test_get_Handle();
     test_get_Type();
     test_OleLoadPicturePath();
+    test_himetric();
+    test_load_save_bmp();
+    test_load_save_icon();
+    test_load_save_empty_picture();
 }
 
 
 /* Helper functions only ... */
 
 
+static inline NoStatStreamImpl *impl_from_IStream(IStream *iface)
+{
+  return CONTAINING_RECORD(iface, NoStatStreamImpl, IStream_iface);
+}
+
 static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
 {
   GlobalFree(This->supportHandle);
@@ -937,7 +1179,7 @@ static void NoStatStreamImpl_Destroy(NoStatStreamImpl* This)
 static ULONG WINAPI NoStatStreamImpl_AddRef(
                IStream* iface)
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   return InterlockedIncrement(&This->ref);
 }
 
@@ -946,7 +1188,7 @@ static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
                  REFIID         riid,        /* [in] */
                  void**         ppvObject)   /* [iid_is][out] */
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   if (ppvObject==0) return E_INVALIDARG;
   *ppvObject = 0;
   if (IsEqualIID(&IID_IUnknown, riid))
@@ -967,7 +1209,7 @@ static HRESULT WINAPI NoStatStreamImpl_QueryInterface(
 static ULONG WINAPI NoStatStreamImpl_Release(
                IStream* iface)
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   ULONG newRef = InterlockedDecrement(&This->ref);
   if (newRef==0)
     NoStatStreamImpl_Destroy(This);
@@ -980,7 +1222,7 @@ static HRESULT WINAPI NoStatStreamImpl_Read(
                  ULONG          cb,        /* [in] */
                  ULONG*         pcbRead)   /* [out] */
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   void* supportBuffer;
   ULONG bytesReadBuffer;
   ULONG bytesToReadFromBuffer;
@@ -1004,7 +1246,7 @@ static HRESULT WINAPI NoStatStreamImpl_Write(
                  ULONG          cb,          /* [in] */
                  ULONG*         pcbWritten)  /* [out] */
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   void*          supportBuffer;
   ULARGE_INTEGER newSize;
   ULONG          bytesWritten = 0;
@@ -1032,7 +1274,7 @@ static HRESULT WINAPI NoStatStreamImpl_Seek(
                  DWORD           dwOrigin,         /* [in] */
                  ULARGE_INTEGER* plibNewPosition) /* [out] */
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   ULARGE_INTEGER newPosition;
   switch (dwOrigin)
   {
@@ -1061,7 +1303,7 @@ static HRESULT WINAPI NoStatStreamImpl_SetSize(
                                     IStream*      iface,
                                     ULARGE_INTEGER  libNewSize)   /* [in] */
 {
-  NoStatStreamImpl* const This=(NoStatStreamImpl*)iface;
+  NoStatStreamImpl* const This = impl_from_IStream(iface);
   HGLOBAL supportHandle;
   if (libNewSize.u.HighPart != 0)
     return STG_E_INVALIDFUNCTION;
@@ -1174,14 +1416,14 @@ static const IStreamVtbl NoStatStreamImpl_Vtbl;
     In any case the object takes ownership of memory handle and will free it on
     object release.
  */
-static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
+static IStream* NoStatStream_Construct(HGLOBAL hGlobal)
 {
   NoStatStreamImpl* newStream;
 
   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(NoStatStreamImpl));
   if (newStream!=0)
   {
-    newStream->lpVtbl = &NoStatStreamImpl_Vtbl;
+    newStream->IStream_iface.lpVtbl = &NoStatStreamImpl_Vtbl;
     newStream->ref    = 1;
     newStream->supportHandle = hGlobal;
 
@@ -1193,7 +1435,7 @@ static NoStatStreamImpl* NoStatStreamImpl_Construct(HGLOBAL hGlobal)
     newStream->streamSize.u.HighPart = 0;
     newStream->streamSize.u.LowPart  = GlobalSize(newStream->supportHandle);
   }
-  return newStream;
+  return &newStream->IStream_iface;
 }