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

svn path=/trunk/; revision=57892

12 files changed:
rostests/winetests/oleaut32/CMakeLists.txt
rostests/winetests/oleaut32/olefont.c
rostests/winetests/oleaut32/olepicture.c
rostests/winetests/oleaut32/safearray.c
rostests/winetests/oleaut32/tmarshal.c
rostests/winetests/oleaut32/tmarshal.idl
rostests/winetests/oleaut32/tmarshal_dispids.h
rostests/winetests/oleaut32/typelib.c
rostests/winetests/oleaut32/usrmarshal.c
rostests/winetests/oleaut32/varformat.c
rostests/winetests/oleaut32/vartest.c
rostests/winetests/oleaut32/vartype.c

index 763ecd4..c563581 100644 (file)
@@ -1,14 +1,9 @@
 
-add_definitions(
-    -D__ROS_LONG64__
-    -D_DLL -D__USE_CRTIMP)
-
+add_definitions(-D__ROS_LONG64__)
 include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
-
 add_typelib(test_reg.idl test_tlb.idl tmarshal.idl)
-
 add_idl_Headers(oleaut32_idlheaders test_reg.idl tmarshal.idl)
-generate_idl_iids(tmarshal.idl)
+generate_idl_iids(tmarshal.idl test_reg.idl)
 
 list(APPEND SOURCE
     dispatch.c
@@ -17,15 +12,15 @@ list(APPEND SOURCE
     safearray.c
     testlist.c
     tmarshal.c
-    tmarshal.rc
     typelib.c
     usrmarshal.c
     varformat.c
     vartest.c
     vartype.c
+    ${CMAKE_CURRENT_BINARY_DIR}/test_reg_i.c
     ${CMAKE_CURRENT_BINARY_DIR}/tmarshal_i.c)
 
-add_executable(oleaut32_winetest ${SOURCE})
+add_executable(oleaut32_winetest ${SOURCE} tmarshal.rc)
 target_link_libraries(oleaut32_winetest uuid wine)
 set_module_type(oleaut32_winetest win32cui)
 add_importlibs(oleaut32_winetest oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 msvcrt kernel32 ntdll)
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;
 }
 
 
index 29e8761..b689334 100644 (file)
@@ -25,6 +25,7 @@
 #include <float.h>
 
 #define COBJMACROS
+#define CONST_VTABLE
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
@@ -76,7 +77,7 @@ static BOOL HAVE_OLEAUT32_INT_PTR;
  */
 typedef struct IRecordInfoImpl
 {
-  const IRecordInfoVtbl *lpvtbl;
+  IRecordInfo IRecordInfo_iface;
   LONG ref;
   DWORD sizeCalled;
   DWORD clearCalled;
@@ -84,12 +85,17 @@ typedef struct IRecordInfoImpl
 
 static const IRecordInfoVtbl IRecordInfoImpl_VTable;
 
+static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface)
+{
+  return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface);
+}
+
 static IRecordInfoImpl *IRecordInfoImpl_Construct(void)
 {
   IRecordInfoImpl *rec;
 
   rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl));
-  rec->lpvtbl = &IRecordInfoImpl_VTable;
+  rec->IRecordInfo_iface.lpVtbl = &IRecordInfoImpl_VTable;
   rec->ref = START_REF_COUNT;
   rec->clearCalled = 0;
   rec->sizeCalled = 0;
@@ -98,32 +104,39 @@ static IRecordInfoImpl *IRecordInfoImpl_Construct(void)
 
 static ULONG CALLBACK IRecordInfoImpl_AddRef(IRecordInfo *iface)
 {
-  IRecordInfoImpl* This=(IRecordInfoImpl*)iface;
+  IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
   return InterlockedIncrement(&This->ref);
 }
 
 static ULONG CALLBACK IRecordInfoImpl_Release(IRecordInfo *iface)
 {
-  IRecordInfoImpl* This=(IRecordInfoImpl*)iface;
-  return InterlockedDecrement(&This->ref);
+  IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
+  ULONG ref = InterlockedDecrement(&This->ref);
+
+  if (!ref)
+      HeapFree(GetProcessHeap(), 0, This);
+
+  return ref;
 }
 
 static BOOL fail_GetSize; /* Whether to fail the GetSize call */
 
 static HRESULT CALLBACK IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting)
 {
-  IRecordInfoImpl* This=(IRecordInfoImpl*)iface;
+  IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
   This->clearCalled++;
   return S_OK;
 }
 
 static HRESULT CALLBACK IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG* size)
 {
-  IRecordInfoImpl* This=(IRecordInfoImpl*)iface;
+  IRecordInfoImpl* This = impl_from_IRecordInfo(iface);
   This->sizeCalled++;
-  *size = 17;
   if (fail_GetSize)
+  {
+    *size = RECORD_SIZE_FAIL;
     return E_UNEXPECTED;
+  }
   *size = RECORD_SIZE;
   return S_OK;
 }
@@ -211,9 +224,11 @@ static void check_for_VT_INT_PTR(void)
     bound.lLbound      = 0;
     a = SafeArrayCreate(VT_INT_PTR, 1, &bound);
     if (a) {
+        HRESULT hres;
         trace("VT_INT_PTR is supported\n");
         HAVE_OLEAUT32_INT_PTR = TRUE;
-        SafeArrayDestroy(a);
+        hres = SafeArrayDestroy(a);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
     }
     else {
         trace("VT_INT_PTR is not supported\n");
@@ -279,7 +294,7 @@ static void test_safearray(void)
        LONG            indices[2];
        HRESULT         hres;
        SAFEARRAYBOUND  bound, bounds[2];
-       VARIANT         v;
+       VARIANT         v,d;
        LPVOID          data;
        IID             iid;
        VARTYPE         vt;
@@ -318,7 +333,7 @@ static void test_safearray(void)
        ok(hres == S_OK || hres == E_OUTOFMEMORY,
           "SAR to a 0 elements dimension failed with hres %x\n", hres);
        hres = SafeArrayDestroy(a);
-       ok(hres == S_OK,"SAD of 0 dim array faild with hres %x\n", hres);
+       ok(hres == S_OK,"SAD of 0 dim array failed with hres %x\n", hres);
 
         SafeArrayAllocDescriptor(2, &a);
         a->rgsabound[0].cElements = 2;
@@ -355,7 +370,7 @@ static void test_safearray(void)
         ok(*(WORD *)ptr1 == 0x55aa, "Data not preserved when resizing array\n");
 
         hres = SafeArrayDestroy(a);
-        ok(hres == S_OK,"SAD faild with hres %x\n", hres);
+        ok(hres == S_OK,"SAD failed with hres %x\n", hres);
 
        bounds[0].cElements = 0;        bounds[0].lLbound =  1;
        bounds[1].cElements =  2;       bounds[1].lLbound = 23;
@@ -363,14 +378,14 @@ static void test_safearray(void)
        ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
 
         hres = SafeArrayDestroy(a);
-        ok(hres == S_OK,"SAD faild with hres %x\n", hres);
+        ok(hres == S_OK,"SAD failed with hres %x\n", hres);
        bounds[0].cElements = 1;        bounds[0].lLbound =  1;
        bounds[1].cElements = 0;        bounds[1].lLbound = 23;
        a = SafeArrayCreate(VT_I4,2,bounds);
        ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
 
         hres = SafeArrayDestroy(a);
-        ok(hres == S_OK,"SAD faild with hres %x\n", hres);
+        ok(hres == S_OK,"SAD failed with hres %x\n", hres);
 
        bounds[0].cElements = 42;       bounds[0].lLbound =  1;
        bounds[1].cElements =  2;       bounds[1].lLbound = 23;
@@ -455,7 +470,7 @@ static void test_safearray(void)
        ok(S_OK == hres, "SAUAD failed with 0x%x\n", hres);
 
        hres = SafeArrayDestroy(a);
-       ok(hres == S_OK,"SAD faild with hres %x\n", hres);
+       ok(hres == S_OK,"SAD failed with hres %x\n", hres);
 
        for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
        if ((i == VT_I8 || i == VT_UI8) && HAVE_OLEAUT32_I8)
@@ -520,7 +535,7 @@ static void test_safearray(void)
         }
 
                hres = SafeArrayDestroy(c);
-               ok(hres == S_OK,"SAD faild with hres %x\n", hres);
+               ok(hres == S_OK,"SAD failed with hres %x\n", hres);
 
                hres = SafeArrayDestroy(a);
                ok(hres == S_OK,"SAD of array with vt %d failed with hres %x\n", vttypes[i].vt, hres);
@@ -542,6 +557,15 @@ static void test_safearray(void)
        ok(V_BSTR(&v)[0] == 0x6548,"First letter are not 'He', but %x\n", V_BSTR(&v)[0]);
        VariantClear(&v);
 
+       VariantInit(&d);
+       V_VT(&v) = VT_BSTR;
+       V_BSTR(&v) = SysAllocStringLen(NULL, 0);
+       hres = VariantChangeTypeEx(&d, &v, 0, 0, VT_UI1|VT_ARRAY);
+       ok(hres==S_OK, "CTE VT_BSTR -> VT_UI1|VT_ARRAY failed with %x\n",hres);
+       ok(V_VT(&d) == (VT_UI1|VT_ARRAY),"CTE BSTR -> VT_UI1|VT_ARRAY did not return VT_UI1|VT_ARRAY, but %d.v\n",V_VT(&v));
+       VariantClear(&v);
+       VariantClear(&d);
+
        /* check locking functions */
        a = SafeArrayCreate(VT_I4, 1, &bound);
        ok(a!=NULL,"SAC should not fail\n");
@@ -580,9 +604,10 @@ static void test_safearray(void)
         ok(hres == E_INVALIDARG,"SafeArraySetIID of non IID capable safearray did not return E_INVALIDARG, but %x\n",hres);
 
         hres = SafeArrayAllocDescriptor(1,&a);
+        ok(hres == S_OK,"SafeArrayAllocDescriptor should return S_OK, but got %x\n",hres);
         ok((a->fFeatures & FADF_HAVEIID) == 0,"newly allocated descriptor with SAAD should not have FADF_HAVEIID\n");
         hres = pSafeArraySetIID(a,&iid);
-        ok(hres == E_INVALIDARG,"SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but %x\n",hres);
+        ok(hres == E_INVALIDARG,"SafeArraySetIID of newly allocated descriptor with SAAD should return E_INVALIDARG, but got %x\n",hres);
 
         hres = SafeArrayDestroyDescriptor(a);
         ok(hres == S_OK,"SADD failed with hres %x\n",hres);
@@ -594,6 +619,7 @@ static void test_safearray(void)
        for (i=0;i<sizeof(vttypes)/sizeof(vttypes[0]);i++) {
         a = NULL;
                hres = pSafeArrayAllocDescriptorEx(vttypes[i].vt,1,&a);
+               ok(hres == S_OK, "SafeArrayAllocDescriptorEx gave hres 0x%x\n", hres);
                ok(a->fFeatures == vttypes[i].expflags,"SAADE(%d) resulted with flags %x, expected %x\n", vttypes[i].vt, a->fFeatures, vttypes[i].expflags);
                if (a->fFeatures & FADF_HAVEIID) {
                        hres = pSafeArrayGetIID(a, &iid);
@@ -840,7 +866,10 @@ static void test_VectorCreateLockDestroy(void)
   int element;
 
   if (!pSafeArrayCreateVector)
+  {
+    win_skip("SafeArrayCreateVector not supported\n");
     return;
+  }
   sa = pSafeArrayCreateVector(VT_UI1, 0, 0);
   ok(sa != NULL, "SACV with 0 elements failed.\n");
 
@@ -933,7 +962,8 @@ test_LockUnlock_Vector:
           bVector ? "vector " : "\n", count, hres);
     }
 
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
   }
 
   if (bVector == FALSE && pSafeArrayCreateVector)
@@ -1068,7 +1098,8 @@ static void test_SafeArrayGetPutElement(void)
       }
     }
   }
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 static void test_SafeArrayGetPutElement_BSTR(void)
@@ -1102,21 +1133,33 @@ static void test_SafeArrayGetPutElement_BSTR(void)
   ok(hres == S_OK, "Failed to get bstr element at hres 0x%x\n", hres);
   if (hres == S_OK)
     ok(SysStringLen(value) == SysStringLen(gotvalue), "Got len %d instead of %d\n", SysStringLen(gotvalue), SysStringLen(value));
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
   SysFreeString(value);
   SysFreeString(gotvalue);
 }
 
-static int tunk_xref = 0;
-static HRESULT WINAPI tunk_QueryInterface(LPUNKNOWN punk,REFIID riid, LPVOID *x) {
-       return E_FAIL;
+struct xtunk_impl {
+  IUnknown IUnknown_iface;
+  LONG ref;
+};
+static const IUnknownVtbl xtunk_vtbl;
+
+static struct xtunk_impl xtunk = {{&xtunk_vtbl}, 0};
+
+static HRESULT WINAPI tunk_QueryInterface(IUnknown *punk, REFIID riid, void **x)
+{
+  return E_FAIL;
 }
-static ULONG WINAPI tunk_AddRef(LPUNKNOWN punk) {
-       return ++tunk_xref;
+
+static ULONG WINAPI tunk_AddRef(IUnknown *punk)
+{
+  return ++xtunk.ref;
 }
 
-static ULONG WINAPI tunk_Release(LPUNKNOWN punk) {
-       return --tunk_xref;
+static ULONG WINAPI tunk_Release(IUnknown *punk)
+{
+  return --xtunk.ref;
 }
 
 static const IUnknownVtbl xtunk_vtbl = {
@@ -1125,18 +1168,13 @@ static const IUnknownVtbl xtunk_vtbl = {
        tunk_Release
 };
 
-static struct xtunk_iface {
-       const IUnknownVtbl *lpvtbl;
-} xtunk_iface;
-
-
 static void test_SafeArrayGetPutElement_IUnknown(void)
 {
   SAFEARRAYBOUND sab;
   LONG indices[1];
   SAFEARRAY *sa;
   HRESULT hres;
-  LPUNKNOWN value = 0, gotvalue;
+  IUnknown *gotvalue;
 
   sab.lLbound = 1;
   sab.cElements = 1;
@@ -1150,21 +1188,19 @@ static void test_SafeArrayGetPutElement_IUnknown(void)
     return;
 
   indices[0] = sab.lLbound;
-  xtunk_iface.lpvtbl = &xtunk_vtbl;
-  value = (LPUNKNOWN)&xtunk_iface;
-  tunk_xref = 1;
-  ok (value != NULL, "Expected non-NULL\n");
-  hres = SafeArrayPutElement(sa, indices, value);
+  xtunk.ref = 1;
+  hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
   ok(hres == S_OK, "Failed to put bstr element hres 0x%x\n", hres);
-  ok(tunk_xref == 2,"Failed to increment refcount of iface.\n");
+  ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
   gotvalue = NULL;
   hres = SafeArrayGetElement(sa, indices, &gotvalue);
-  ok(tunk_xref == 3,"Failed to increment refcount of iface.\n");
+  ok(xtunk.ref == 3,"Failed to increment refcount of iface.\n");
   ok(hres == S_OK, "Failed to get bstr element at hres 0x%x\n", hres);
   if (hres == S_OK)
-    ok(value == gotvalue, "Got %p instead of %p\n", gotvalue, value);
-  SafeArrayDestroy(sa);
-  ok(tunk_xref == 2,"Failed to decrement refcount of iface.\n");
+    ok(gotvalue == &xtunk.IUnknown_iface, "Got %p instead of %p\n", gotvalue, &xtunk.IUnknown_iface);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+  ok(xtunk.ref == 2,"Failed to decrement refcount of iface.\n");
 }
 
 static void test_SafeArrayRedim_IUnknown(void)
@@ -1173,7 +1209,6 @@ static void test_SafeArrayRedim_IUnknown(void)
   LONG indices[1];
   SAFEARRAY *sa;
   HRESULT hres;
-  LPUNKNOWN value;
 
   sab.lLbound = 1;
   sab.cElements = 2;
@@ -1187,17 +1222,16 @@ static void test_SafeArrayRedim_IUnknown(void)
     return;
 
   indices[0] = 2;
-  xtunk_iface.lpvtbl = &xtunk_vtbl;
-  value = (LPUNKNOWN)&xtunk_iface;
-  tunk_xref = 1;
-  hres = SafeArrayPutElement(sa, indices, value);
+  xtunk.ref = 1;
+  hres = SafeArrayPutElement(sa, indices, &xtunk.IUnknown_iface);
   ok(hres == S_OK, "Failed to put IUnknown element hres 0x%x\n", hres);
-  ok(tunk_xref == 2,"Failed to increment refcount of iface.\n");
+  ok(xtunk.ref == 2,"Failed to increment refcount of iface.\n");
   sab.cElements = 1;
   hres = SafeArrayRedim(sa, &sab);
   ok(hres == S_OK, "Failed to shrink array hres 0x%x\n", hres);
-  ok(tunk_xref == 1, "Failed to decrement refcount\n");
-  SafeArrayDestroy(sa);
+  ok(xtunk.ref == 1, "Failed to decrement refcount\n");
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 static void test_SafeArrayGetPutElement_VARIANT(void)
@@ -1237,7 +1271,8 @@ static void test_SafeArrayGetPutElement_VARIANT(void)
     if (V_VT(&value) == V_VT(&gotvalue))
         ok(V_I4(&value) == V_I4(&gotvalue), "Got %d instead of %d\n", V_I4(&value), V_VT(&gotvalue));
   }
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 
@@ -1250,7 +1285,10 @@ static void test_SafeArrayCopyData(void)
   int dimension,size=1;
 
   if (!pSafeArrayCopyData)
+  {
+    win_skip("SafeArrayCopyData not supported\n");
     return;
+  }
 
   for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
   {
@@ -1309,7 +1347,8 @@ static void test_SafeArrayCopyData(void)
   ok(hres == E_INVALIDARG, "Smaller copy last dimension hres 0x%x\n", hres);
   sacopy->rgsabound[3].cElements += 1;
 
-  SafeArrayDestroy(sacopy);
+  hres = SafeArrayDestroy(sacopy);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
   sacopy = NULL;
   hres = pSafeArrayCopyData(sa, sacopy);
   ok(hres == E_INVALIDARG, "->Null copy hres 0x%x\n", hres);
@@ -1321,10 +1360,12 @@ static void test_SafeArrayCopyData(void)
     ok(SafeArrayGetElemsize(sa) == SafeArrayGetElemsize(sacopy),"elemsize wrong\n");
     ok(SafeArrayGetDim(sa) == SafeArrayGetDim(sacopy),"dimensions wrong\n");
     ok(!memcmp(sa->pvData, sacopy->pvData, size * sizeof(int)), "compared different\n");
-    SafeArrayDestroy(sacopy);
+    hres = SafeArrayDestroy(sacopy);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
   }
 
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 static void test_SafeArrayCreateEx(void)
@@ -1336,7 +1377,10 @@ static void test_SafeArrayCreateEx(void)
   int dimension;
 
   if (!pSafeArrayCreateEx)
+  {
+    win_skip("SafeArrayCreateEx not supported\n");
     return;
+  }
 
   for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++)
   {
@@ -1374,7 +1418,8 @@ static void test_SafeArrayCreateEx(void)
         ok(hres == S_OK && IsEqualGUID(&guid, &IID_IUnknown), "Set bad IID\n");
       }
     }
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
   }
 
   sa = pSafeArrayCreateEx(VT_DISPATCH, 1, sab, NULL);
@@ -1392,7 +1437,8 @@ static void test_SafeArrayCreateEx(void)
         ok(IsEqualGUID(&guid, &IID_IDispatch), "CreateEx (NULL) bad IID\n");
       }
     }
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
   }
 
   sa = pSafeArrayCreateEx(VT_UNKNOWN, 1, sab, NULL);
@@ -1410,12 +1456,13 @@ static void test_SafeArrayCreateEx(void)
         ok(IsEqualGUID(&guid, &IID_IUnknown), "CreateEx (NULL-Unk) bad IID\n");
       }
     }
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
   }
 
   /* VT_RECORD failure case */
   sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, NULL);
-  ok(sa == NULL, "CreateEx (NULL-Rec) succeded\n");
+  ok(sa == NULL, "CreateEx (NULL-Rec) succeeded\n");
 
   iRec = IRecordInfoImpl_Construct();
 
@@ -1429,8 +1476,10 @@ static void test_SafeArrayCreateEx(void)
   if (sa)
   {
     ok(sa->cbElements == RECORD_SIZE_FAIL, "Altered size to %d\n", sa->cbElements);
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
     ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
+    ok(iRec->ref == START_REF_COUNT, "got %d, expected %d\n", iRec->ref, START_REF_COUNT);
   }
 
   /* Test VT_RECORD array */
@@ -1449,18 +1498,26 @@ static void test_SafeArrayCreateEx(void)
     hres = pSafeArrayGetRecordInfo(sa, &saRec);
 
     ok(hres == S_OK,"GRI failed\n");
-    ok(saRec == (IRecordInfo*)iRec,"Different saRec\n");
+    ok(saRec == &iRec->IRecordInfo_iface, "Different saRec\n");
     ok(iRec->ref == START_REF_COUNT + 2, "Didn't AddRef %d\n", iRec->ref);
     if (iRec->ref == START_REF_COUNT + 2)
       IRecordInfo_Release(saRec);
 
     ok(sa->cbElements == RECORD_SIZE,"Elemsize is %d\n", sa->cbElements);
 
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
     ok(iRec->sizeCalled == 1, "Destroy->GetSize called %d times\n", iRec->sizeCalled);
     ok(iRec->clearCalled == sab[0].cElements, "Destroy->Clear called %d times\n", iRec->clearCalled);
     ok(iRec->ref == START_REF_COUNT, "Wrong iRec refcount %d\n", iRec->ref);
   }
+  else
+  {
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+  }
+
+  IRecordInfo_Release(&iRec->IRecordInfo_iface);
 }
 
 static void test_SafeArrayClear(void)
@@ -1499,7 +1556,8 @@ static void test_SafeArrayClear(void)
   hres = VariantClear(&v);
   ok(hres == DISP_E_BADVARTYPE, "VariantClear: hres 0x%x\n", hres);
 
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 static void test_SafeArrayCopy(void)
@@ -1535,22 +1593,43 @@ static void test_SafeArrayCopy(void)
      "VariantCopy: hres 0x%x, Type %d\n", hres, V_VT(&vDst));
   ok(V_ARRAY(&vDst) != sa, "VariantClear: Performed shallow copy\n");
 
-  SafeArrayDestroy(V_ARRAY(&vSrc));
-  SafeArrayDestroy(V_ARRAY(&vDst));
+  hres = SafeArrayDestroy(V_ARRAY(&vSrc));
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+  hres = SafeArrayDestroy(V_ARRAY(&vDst));
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+
+  hres = SafeArrayAllocDescriptor(1, &sa);
+  ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres);
+
+  sa->cbElements = 16;
+  hres = SafeArrayCopy(sa, &sa2);
+  ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08x\n", hres);
+  ok(sa != sa2, "SafeArrayCopy performed shallow copy\n");
+
+  hres = SafeArrayDestroy(sa2);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+
+  sa2 = (void*)0xdeadbeef;
+  hres = SafeArrayCopy(NULL, &sa2);
+  ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08x\n", hres);
+  ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
 
   hres = SafeArrayAllocDescriptor(1, &sa);
   ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres);
 
+  sa2 = (void*)0xdeadbeef;
   hres = SafeArrayCopy(sa, &sa2);
   ok(hres == E_INVALIDARG,
     "SafeArrayCopy with empty array should have failed with error E_INVALIDARG instead of 0x%08x\n",
     hres);
-  sa->cbElements = 16;
-  hres = SafeArrayCopy(sa, &sa2);
-  ok(hres == S_OK, "SafeArrayCopy failed with error 0x%08x\n", hres);
+  ok(!sa2, "SafeArrayCopy didn't return NULL for output array\n");
 
-  SafeArrayDestroy(sa2);
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa2);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
 }
 
 #define MKARRAY(low,num,typ) sab.lLbound = low; sab.cElements = num; \
@@ -1586,7 +1665,8 @@ static void test_SafeArrayChangeTypeEx(void)
   }
 
   /* VT_VECTOR|VT_UI1 -> VT_BSTR */
-  SafeArrayDestroy(sa);
+  hres = SafeArrayDestroy(sa);
+  ok(hres == S_OK, "got 0x%08x\n", hres);
   if (pSafeArrayCreateVector)
   {
     sa = pSafeArrayCreateVector(VT_UI1, 0, strlen(szHello)+1);
@@ -1616,16 +1696,33 @@ static void test_SafeArrayChangeTypeEx(void)
   }
 
   /* To/from BSTR only works with arrays of VT_UI1 */
-  for (vt = 0; vt <= VT_CLSID; vt++)
+  for (vt = VT_EMPTY; vt <= VT_CLSID; vt++)
   {
     if (vt == VT_UI1)
       continue;
 
-    MKARRAYCONT(0,1,vt);
+    sab.lLbound = 0;
+    sab.cElements = 1;
+    sa = SafeArrayCreate(vt, 1, &sab);
+    if (!sa) continue;
+
+    V_VT(&v) = VT_ARRAY|vt;
+    V_ARRAY(&v) = sa;
+    VariantInit(&v2);
+
     hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_BSTR);
-    ok(hres != S_OK, "CTE VT_ARRAY|VT %d->BSTR succeeded\n", vt);
+    if (vt == VT_INT_PTR || vt == VT_UINT_PTR)
+    {
+        ok(hres == DISP_E_BADVARTYPE, "expected DISP_E_BADVARTYPE, got 0x%08x\n", hres);
+        SafeArrayDestroy(sa);
+    }
+    else
+    {
+        ok(hres == DISP_E_TYPEMISMATCH, "got 0x%08x for vt=%d, instead of DISP_E_TYPEMISMATCH\n", hres, vt);
+        hres = VariantClear(&v);
+        ok(hres == S_OK, "expected S_OK, got 0x%08x\n", hres);
+    }
     VariantClear(&v2);
-    VariantClear(&v);
   }
 
   /* Can't change an array of one type into array of another type , even
@@ -1644,7 +1741,8 @@ static void test_SafeArrayChangeTypeEx(void)
     ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_I1 returned %x\n", hres);
 
     /* But can change to the same array type */
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
     sa = pSafeArrayCreateVector(VT_UI1, 0, 1);
     ok(sa != NULL, "CreateVector() failed.\n");
     if (!sa)
@@ -1653,7 +1751,8 @@ static void test_SafeArrayChangeTypeEx(void)
     V_ARRAY(&v) = sa;
     hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_ARRAY|VT_UI1);
     ok(hres == S_OK, "CTE VT_ARRAY|VT_UI1->VT_ARRAY|VT_UI1 returned %x\n", hres);
-    SafeArrayDestroy(sa);
+    hres = SafeArrayDestroy(sa);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
     VariantClear(&v2);
   }
 
@@ -1666,7 +1765,6 @@ static void test_SafeArrayChangeTypeEx(void)
   hres = VariantChangeTypeEx(&v2, &v, 0, 0, VT_EMPTY);
   ok(hres == DISP_E_TYPEMISMATCH, "CTE VT_ARRAY|VT_UI1 returned %x\n", hres);
   VariantClear(&v);
-
 }
 
 static void test_SafeArrayDestroyData (void)
@@ -1718,6 +1816,7 @@ START_TEST(safearray)
     GETPTR(SafeArrayGetVartype);
     GETPTR(SafeArrayCreateEx);
     GETPTR(SafeArrayCreateVector);
+    GETPTR(SafeArrayGetRecordInfo);
 
     check_for_VT_INT_PTR();
     test_safearray();
index f7df82f..9b90dce 100644 (file)
 #include "tmarshal.h"
 #include "tmarshal_dispids.h"
 
+static HRESULT (WINAPI *pVarAdd)(LPVARIANT,LPVARIANT,LPVARIANT);
+
+
 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", (unsigned long int)hr)
 
 /* ULL suffix is not portable */
 #define ULL_CONST(dw1, dw2) ((((ULONGLONG)dw1) << 32) | (ULONGLONG)dw2)
 
-const MYSTRUCT MYSTRUCT_BYVAL = {0x12345678, ULL_CONST(0xdeadbeef, 0x98765432)};
-const MYSTRUCT MYSTRUCT_BYPTR = {0x91827364, ULL_CONST(0x88776655, 0x44332211)};
+const MYSTRUCT MYSTRUCT_BYVAL = {0x12345678, ULL_CONST(0xdeadbeef, 0x98765432), {0,1,2,3,4,5,6,7}};
+const MYSTRUCT MYSTRUCT_BYPTR = {0x91827364, ULL_CONST(0x88776655, 0x44332211), {0,1,2,3,4,5,6,7}};
 const MYSTRUCT MYSTRUCT_ARRAY[5] = {
-    {0x1a1b1c1d, ULL_CONST(0x1e1f1011, 0x12131415)},
-    {0x2a2b2c2d, ULL_CONST(0x2e2f2021, 0x22232425)},
-    {0x3a3b3c3d, ULL_CONST(0x3e3f3031, 0x32333435)},
-    {0x4a4b4c4d, ULL_CONST(0x4e4f4041, 0x42434445)},
-    {0x5a5b5c5d, ULL_CONST(0x5e5f5051, 0x52535455)},
+    {0x1a1b1c1d, ULL_CONST(0x1e1f1011, 0x12131415), {0,1,2,3,4,5,6,7}},
+    {0x2a2b2c2d, ULL_CONST(0x2e2f2021, 0x22232425), {0,1,2,3,4,5,6,7}},
+    {0x3a3b3c3d, ULL_CONST(0x3e3f3031, 0x32333435), {0,1,2,3,4,5,6,7}},
+    {0x4a4b4c4d, ULL_CONST(0x4e4f4041, 0x42434445), {0,1,2,3,4,5,6,7}},
+    {0x5a5b5c5d, ULL_CONST(0x5e5f5051, 0x52535455), {0,1,2,3,4,5,6,7}},
 };
 
 
@@ -150,6 +153,35 @@ static void end_host_object(DWORD tid, HANDLE thread)
 
 static ItestDual TestDual, TestDualDisp;
 
+static HRESULT WINAPI TestSecondIface_QueryInterface(ITestSecondIface *iface, REFIID riid, void **ppv)
+{
+    return ItestDual_QueryInterface(&TestDual, riid, ppv);
+}
+
+static ULONG WINAPI TestSecondIface_AddRef(ITestSecondIface *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI TestSecondIface_Release(ITestSecondIface *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI TestSecondIface_test(ITestSecondIface *iface)
+{
+    return 1;
+}
+
+static const ITestSecondIfaceVtbl TestSecondIfaceVtbl = {
+    TestSecondIface_QueryInterface,
+    TestSecondIface_AddRef,
+    TestSecondIface_Release,
+    TestSecondIface_test
+};
+
+static ITestSecondIface TestSecondIface = { &TestSecondIfaceVtbl };
+
 static HRESULT WINAPI TestDual_QueryInterface(ItestDual *iface, REFIID riid, void **ppvObject)
 {
     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch)) {
@@ -158,6 +190,9 @@ static HRESULT WINAPI TestDual_QueryInterface(ItestDual *iface, REFIID riid, voi
     }else if(IsEqualGUID(riid, &IID_ItestDual)) {
         *ppvObject = &TestDual;
         return S_OK;
+    }else if(IsEqualGUID(riid, &IID_ITestSecondIface)) {
+        *ppvObject = &TestSecondIface;
+        return S_OK;
     }
 
     *ppvObject = NULL;
@@ -216,11 +251,16 @@ static ItestDual TestDualDisp = { &TestDualVtbl };
 
 typedef struct Widget
 {
-    const IWidgetVtbl *lpVtbl;
+    IWidget IWidget_iface;
     LONG refs;
     IUnknown *pDispatchUnknown;
 } Widget;
 
+static inline Widget *impl_from_IWidget(IWidget *iface)
+{
+    return CONTAINING_RECORD(iface, Widget, IWidget_iface);
+}
+
 static HRESULT WINAPI Widget_QueryInterface(
     IWidget *iface,
     /* [in] */ REFIID riid,
@@ -242,7 +282,7 @@ static HRESULT WINAPI Widget_QueryInterface(
 static ULONG WINAPI Widget_AddRef(
     IWidget *iface)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
 
     return InterlockedIncrement(&This->refs);
 }
@@ -250,7 +290,7 @@ static ULONG WINAPI Widget_AddRef(
 static ULONG WINAPI Widget_Release(
     IWidget *iface)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
     ULONG refs = InterlockedDecrement(&This->refs);
     if (!refs)
     {
@@ -267,7 +307,7 @@ static HRESULT WINAPI Widget_GetTypeInfoCount(
     IWidget *iface,
     /* [out] */ UINT __RPC_FAR *pctinfo)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
     IDispatch *pDispatch;
     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
     if (SUCCEEDED(hr))
@@ -284,7 +324,7 @@ static HRESULT WINAPI Widget_GetTypeInfo(
     /* [in] */ LCID lcid,
     /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
     IDispatch *pDispatch;
     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
     if (SUCCEEDED(hr))
@@ -303,7 +343,7 @@ static HRESULT WINAPI Widget_GetIDsOfNames(
     /* [in] */ LCID lcid,
     /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
     IDispatch *pDispatch;
     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
     if (SUCCEEDED(hr))
@@ -325,7 +365,7 @@ static HRESULT WINAPI Widget_Invoke(
     /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
     /* [out] */ UINT __RPC_FAR *puArgErr)
 {
-    Widget *This = (Widget *)iface;
+    Widget *This = impl_from_IWidget(iface);
     IDispatch *pDispatch;
     HRESULT hr = IUnknown_QueryInterface(This->pDispatchUnknown, &IID_IDispatch, (void **)&pDispatch);
     if (SUCCEEDED(hr))
@@ -470,6 +510,46 @@ static HRESULT WINAPI Widget_VariantArrayPtr(
     return S_OK;
 }
 
+static HRESULT WINAPI Widget_VariantCArray(
+    IWidget * iface,
+    ULONG count,
+    VARIANT values[])
+{
+    ULONG i;
+
+    trace("VariantCArray(%u,%p)\n", count, values);
+
+    ok(count == 2, "count is %d\n", count);
+    for (i = 0; i < count; i++)
+        ok(V_VT(&values[i]) == VT_I4, "values[%d] is not VT_I4\n", i);
+
+    if (pVarAdd)
+    {
+        VARIANT inc, res;
+        HRESULT hr;
+
+        V_VT(&inc) = VT_I4;
+        V_I4(&inc) = 1;
+        for (i = 0; i < count; i++) {
+            VariantInit(&res);
+            hr = pVarAdd(&values[i], &inc, &res);
+            if (FAILED(hr)) {
+                ok(0, "VarAdd failed at %u with error 0x%x\n", i, hr);
+                return hr;
+            }
+            hr = VariantCopy(&values[i], &res);
+            if (FAILED(hr)) {
+                ok(0, "VariantCopy failed at %u with error 0x%x\n", i, hr);
+                return hr;
+            }
+        }
+    }
+    else
+        win_skip("VarAdd is not available\n");
+
+    return S_OK;
+}
+
 static HRESULT WINAPI Widget_Variant(
     IWidget __RPC_FAR * iface,
     VARIANT var)
@@ -515,6 +595,17 @@ static HRESULT WINAPI Widget_VarArg(
     return S_OK;
 }
 
+
+static BOOL mystruct_uint_ordered(MYSTRUCT *mystruct)
+{
+    int i;
+    for (i = 0; i < sizeof(mystruct->uarr)/sizeof(mystruct->uarr[0]); i++)
+        if (mystruct->uarr[i] != i)
+            return 0;
+
+    return 1;
+}
+
 static HRESULT WINAPI Widget_StructArgs(
     IWidget * iface,
     MYSTRUCT byval,
@@ -523,14 +614,17 @@ static HRESULT WINAPI Widget_StructArgs(
 {
     int i, diff = 0;
     ok(byval.field1 == MYSTRUCT_BYVAL.field1 &&
-       byval.field2 == MYSTRUCT_BYVAL.field2,
+       byval.field2 == MYSTRUCT_BYVAL.field2 &&
+       mystruct_uint_ordered(&byval),
        "Struct parameter passed by value corrupted\n");
     ok(byptr->field1 == MYSTRUCT_BYPTR.field1 &&
-       byptr->field2 == MYSTRUCT_BYPTR.field2,
+       byptr->field2 == MYSTRUCT_BYPTR.field2 &&
+       mystruct_uint_ordered(byptr),
        "Struct parameter passed by pointer corrupted\n");
     for (i = 0; i < 5; i++)
         if (arr[i].field1 != MYSTRUCT_ARRAY[i].field1 ||
-            arr[i].field2 != MYSTRUCT_ARRAY[i].field2)
+            arr[i].field2 != MYSTRUCT_ARRAY[i].field2 ||
+            ! mystruct_uint_ordered(&arr[i]))
             diff++;
     ok(diff == 0, "Array of structs corrupted\n");
     return S_OK;
@@ -612,6 +706,20 @@ static HRESULT WINAPI Widget_put_prop_req_arg(
     return S_OK;
 }
 
+static HRESULT WINAPI Widget_do_restrict(IWidget* iface, INT *i)
+{
+    trace("restrict\n");
+    *i = DISPID_TM_RESTRICTED;
+    return S_OK;
+}
+
+static HRESULT WINAPI Widget_neg_restrict(IWidget* iface, INT *i)
+{
+    trace("neg_restrict\n");
+    *i = DISPID_TM_NEG_RESTRICTED;
+    return S_OK;
+}
+
 static const struct IWidgetVtbl Widget_VTable =
 {
     Widget_QueryInterface,
@@ -635,6 +743,7 @@ static const struct IWidgetVtbl Widget_VTable =
     Widget_Value,
     Widget_Array,
     Widget_VariantArrayPtr,
+    Widget_VariantCArray,
     Widget_Variant,
     Widget_VarArg,
     Widget_StructArgs,
@@ -647,6 +756,8 @@ static const struct IWidgetVtbl Widget_VTable =
     Widget_ByRefUInt,
     Widget_put_prop_opt_arg,
     Widget_put_prop_req_arg,
+    Widget_do_restrict,
+    Widget_neg_restrict
 };
 
 static HRESULT WINAPI StaticWidget_QueryInterface(IStaticWidget *iface, REFIID riid, void **ppvObject)
@@ -703,11 +814,17 @@ static HRESULT WINAPI StaticWidget_Invoke(IStaticWidget *iface, DISPID dispIdMem
 static HRESULT WINAPI StaticWidget_TestDual(IStaticWidget *iface, ItestDual *p)
 {
     trace("TestDual()\n");
-    todo_wine
     ok(p == &TestDual, "wrong ItestDual\n");
     return S_OK;
 }
 
+static HRESULT WINAPI StaticWidget_TestSecondIface(IStaticWidget *iface, ITestSecondIface *p)
+{
+    trace("TestSecondIface()\n");
+    ok(p == &TestSecondIface, "wrong ItestSecondIface\n");
+    return S_OK;
+}
+
 static const IStaticWidgetVtbl StaticWidgetVtbl = {
     StaticWidget_QueryInterface,
     StaticWidget_AddRef,
@@ -716,17 +833,23 @@ static const IStaticWidgetVtbl StaticWidgetVtbl = {
     StaticWidget_GetTypeInfo,
     StaticWidget_GetIDsOfNames,
     StaticWidget_Invoke,
-    StaticWidget_TestDual
+    StaticWidget_TestDual,
+    StaticWidget_TestSecondIface
 };
 
 static IStaticWidget StaticWidget = { &StaticWidgetVtbl };
 
 typedef struct KindaEnum
 {
-    const IKindaEnumWidgetVtbl *lpVtbl;
+    IKindaEnumWidget IKindaEnumWidget_iface;
     LONG refs;
 } KindaEnum;
 
+static inline KindaEnum *impl_from_IKindaEnumWidget(IKindaEnumWidget *iface)
+{
+    return CONTAINING_RECORD(iface, KindaEnum, IKindaEnumWidget_iface);
+}
+
 static HRESULT register_current_module_typelib(void)
 {
     WCHAR path[MAX_PATH];
@@ -777,16 +900,17 @@ static IWidget *Widget_Create(void)
         return NULL;
 
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
-    This->lpVtbl = &Widget_VTable;
+    This->IWidget_iface.lpVtbl = &Widget_VTable;
     This->refs = 1;
     This->pDispatchUnknown = NULL;
 
-    hr = CreateStdDispatch((IUnknown *)&This->lpVtbl, This, pTypeInfo, &This->pDispatchUnknown);
+    hr = CreateStdDispatch((IUnknown *)&This->IWidget_iface, This, pTypeInfo,
+                           &This->pDispatchUnknown);
     ok_ole_success(hr, CreateStdDispatch);
     ITypeInfo_Release(pTypeInfo);
 
     if (SUCCEEDED(hr))
-        return (IWidget *)&This->lpVtbl;
+        return &This->IWidget_iface;
     else
     {
         HeapFree(GetProcessHeap(), 0, This);
@@ -815,7 +939,7 @@ static HRESULT WINAPI KindaEnum_QueryInterface(
 static ULONG WINAPI KindaEnum_AddRef(
     IKindaEnumWidget *iface)
 {
-    KindaEnum *This = (KindaEnum *)iface;
+    KindaEnum *This = impl_from_IKindaEnumWidget(iface);
 
     return InterlockedIncrement(&This->refs);
 }
@@ -823,7 +947,7 @@ static ULONG WINAPI KindaEnum_AddRef(
 static ULONG WINAPI KindaEnum_Release(
     IKindaEnumWidget *iface)
 {
-    KindaEnum *This = (KindaEnum *)iface;
+    KindaEnum *This = impl_from_IKindaEnumWidget(iface);
     ULONG refs = InterlockedDecrement(&This->refs);
     if (!refs)
     {
@@ -883,9 +1007,9 @@ static IKindaEnumWidget *KindaEnumWidget_Create(void)
 
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
     if (!This) return NULL;
-    This->lpVtbl = &KindaEnumWidget_VTable;
+    This->IKindaEnumWidget_iface.lpVtbl = &KindaEnumWidget_VTable;
     This->refs = 1;
-    return (IKindaEnumWidget *)This;
+    return &This->IKindaEnumWidget_iface;
 }
 
 static HRESULT WINAPI NonOleAutomation_QueryInterface(INonOleAutomation *iface, REFIID riid, void **ppv)
@@ -989,7 +1113,14 @@ static void test_typelibmarshal(void)
 
     IKindaEnumWidget_Release(pKEW);
 
+    /* call GetTypeInfoCount (direct) */
+    hr = IWidget_GetTypeInfoCount(pWidget, &uval);
+    ok_ole_success(hr, IWidget_GetTypeInfoCount);
+    hr = IWidget_GetTypeInfoCount(pWidget, &uval);
+    ok_ole_success(hr, IWidget_GetTypeInfoCount);
+
     hr = IWidget_QueryInterface(pWidget, &IID_IDispatch, (void **)&pDispatch);
+    ok_ole_success(hr, IWidget_QueryInterface);
 
     /* call put_Name */
     VariantInit(&vararg[0]);
@@ -1026,7 +1157,7 @@ static void test_typelibmarshal(void)
     VariantClear(&varresult);
 
     /* call get_Name (direct) */
-    bstr = NULL;
+    bstr = (void *)0xdeadbeef;
     hr = IWidget_get_Name(pWidget, &bstr);
     ok_ole_success(hr, IWidget_get_Name);
     ok(!lstrcmpW(bstr, szCat), "IWidget_get_Name should have returned string \"Cat\" instead of %s\n", wine_dbgstr_w(bstr));
@@ -1088,6 +1219,7 @@ static void test_typelibmarshal(void)
     ok(V_VT(&varresult) == VT_BSTR, "Return value should be of type BSTR instead of %d\n", V_VT(&varresult));
     ok(!lstrcmpW(V_BSTR(&varresult), szTestTest), "Return value should have been \"TestTest\" instead of %s\n", wine_dbgstr_w(V_BSTR(&varresult)));
     VariantClear(&varresult);
+    SysFreeString(bstr);
 
     /* call SetOleColor with large negative VT_I4 param */
     VariantInit(&vararg[0]);
@@ -1211,6 +1343,18 @@ static void test_typelibmarshal(void)
     ok_ole_success(hr, IDispatch_Invoke);
     VariantClear(&varresult);
 
+    /* call VariantCArray - test marshaling of variant arrays */
+    V_VT(&vararg[0]) = VT_I4;
+    V_I4(&vararg[0]) = 1;
+    V_VT(&vararg[1]) = VT_I4;
+    V_I4(&vararg[1]) = 2;
+    hr = IWidget_VariantCArray(pWidget, 2, vararg);
+    ok_ole_success(hr, IWidget_VariantCArray);
+    todo_wine
+    ok(V_VT(&vararg[0]) == VT_I4 && V_I4(&vararg[0]) == 2, "vararg[0] = %d[%d]\n", V_VT(&vararg[0]), V_I4(&vararg[0]));
+    todo_wine
+    ok(V_VT(&vararg[1]) == VT_I4 && V_I4(&vararg[1]) == 3, "vararg[1] = %d[%d]\n", V_VT(&vararg[1]), V_I4(&vararg[1]));
+
     /* call VarArg */
     VariantInit(&vararg[3]);
     V_VT(&vararg[3]) = VT_I4;
@@ -1436,6 +1580,28 @@ static void test_typelibmarshal(void)
     ok_ole_success(hr, ITypeInfo_Invoke);
     VariantClear(&varresult);
 
+    /* restricted member */
+    dispparams.cNamedArgs = 0;
+    dispparams.rgdispidNamedArgs = NULL;
+    dispparams.cArgs = 0;
+    dispparams.rgvarg = NULL;
+    VariantInit(&varresult);
+    hr = IDispatch_Invoke(pDispatch, DISPID_TM_RESTRICTED, &IID_NULL, 0x40c, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
+    ok( hr == DISP_E_MEMBERNOTFOUND, "got %08x\n", hr );
+    VariantClear(&varresult);
+
+    /* restricted member with -ve memid (not restricted) */
+    dispparams.cNamedArgs = 0;
+    dispparams.rgdispidNamedArgs = NULL;
+    dispparams.cArgs = 0;
+    dispparams.rgvarg = NULL;
+    VariantInit(&varresult);
+    hr = IDispatch_Invoke(pDispatch, DISPID_TM_NEG_RESTRICTED, &IID_NULL, 0x40c, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
+    ok( hr == S_OK, "got %08x\n", hr );
+    ok(V_VT(&varresult) == VT_I4, "got %x\n", V_VT(&varresult));
+    ok(V_I4(&varresult) == DISPID_TM_NEG_RESTRICTED, "got %x\n", V_I4(&varresult));
+    VariantClear(&varresult);
+
     IDispatch_Release(pDispatch);
     IWidget_Release(pWidget);
 
@@ -1498,6 +1664,20 @@ static void test_StaticWidget(void)
     ok(V_VT(&varresult) == VT_EMPTY, "vt %x\n", V_VT(&varresult));
     VariantClear(&varresult);
 
+    /* call TestSecondIface */
+    dispparams.cNamedArgs = 0;
+    dispparams.cArgs = 1;
+    dispparams.rgdispidNamedArgs = NULL;
+    dispparams.rgvarg = vararg;
+    V_VT(vararg) = VT_DISPATCH;
+    V_DISPATCH(vararg) = (IDispatch*)&TestDualDisp;
+    VariantInit(&varresult);
+    hr = ITypeInfo_Invoke(type_info, &StaticWidget, DISPID_TM_TESTSECONDIFACE, DISPATCH_METHOD,
+            &dispparams, &varresult, &excepinfo, NULL);
+    ok_ole_success(hr, IDispatch_Invoke);
+    ok(V_VT(&varresult) == VT_EMPTY, "vt %x\n", V_VT(&varresult));
+    VariantClear(&varresult);
+
     ITypeInfo_Release(type_info);
 }
 
@@ -1527,11 +1707,18 @@ static void test_libattr(void)
 START_TEST(tmarshal)
 {
     HRESULT hr;
+    HANDLE hOleaut32 = GetModuleHandleA("oleaut32.dll");
+    pVarAdd = (void*)GetProcAddress(hOleaut32, "VarAdd");
 
     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 
     hr = register_current_module_typelib();
-    ok_ole_success(hr, register_current_module_typelib);
+    if (FAILED(hr))
+    {
+        CoUninitialize();
+        win_skip("Registration of the test typelib failed, skipping tests\n");
+        return;
+    }
 
     test_typelibmarshal();
     test_DispCallFunc();
index 7616789..a421011 100644 (file)
@@ -39,6 +39,7 @@ library TestTypelib
     {
         INT field1;
         ULONGLONG field2;
+        UINT uarr[8];
     } MYSTRUCT;
 
     coclass ApplicationObject2;
@@ -63,6 +64,15 @@ library TestTypelib
         HRESULT test();
     }
 
+    [
+        odl,
+        uuid(3f7e06fe-0bce-46f0-8b7d-3a68393c7968)
+    ]
+    interface ITestSecondIface : IUnknown
+    {
+        HRESULT test();
+    }
+
     [
         odl,
         uuid(a1f8cae3-c947-4c5f-b57d-c87b9b5f3586),
@@ -111,6 +121,9 @@ library TestTypelib
         [id(DISPID_TM_VARARRAYPTR)]
         HRESULT VariantArrayPtr([in] SAFEARRAY(VARIANT) *values);
 
+        [id(DISPID_TM_VARCARRAY)]
+        HRESULT VariantCArray([in] ULONG count, [in, out] VARIANT values[2]);
+
         [id(DISPID_TM_VARIANT)]
         HRESULT Variant([in] VARIANT var);
 
@@ -146,6 +159,12 @@ library TestTypelib
 
         [id(DISPID_TM_PROP_REQ_ARG), propput]
         HRESULT prop_req_arg([in] INT req, [in] INT i);
+
+        [id(DISPID_TM_RESTRICTED), restricted]
+        HRESULT do_restrict([out, retval] INT *i);
+
+        [id(DISPID_TM_NEG_RESTRICTED), restricted]
+        HRESULT neg_restrict([out, retval] INT *i);
     }
 
     [
@@ -158,6 +177,9 @@ library TestTypelib
     {
         [id(DISPID_TM_TESTDUAL)]
         HRESULT TestDual([in] ItestDual *p);
+
+        [id(DISPID_TM_TESTSECONDIFACE)]
+        HRESULT TestSecondIface([in] ITestSecondIface *p);
     }
 
     [
index 376162b..879d974 100644 (file)
 #define DISPID_TM_BYREF_UINT 21
 #define DISPID_TM_PROP_OPT_ARG 22
 #define DISPID_TM_PROP_REQ_ARG 23
+#define DISPID_TM_VARCARRAY 24
+#define DISPID_TM_RESTRICTED 25
+#define DISPID_TM_NEG_RESTRICTED -26
+#define DISPID_TM_TESTSECONDIFACE 27
 
 #define DISPID_NOA_BSTRRET 1
 #define DISPID_NOA_ERROR 2
index 0df3e4d..dab2aaa 100644 (file)
@@ -31,7 +31,6 @@
 #include "ocidl.h"
 #include "shlwapi.h"
 #include "tmarshal.h"
-#include "initguid.h"
 
 #include "test_reg.h"
 
@@ -60,6 +59,10 @@ static HRESULT (WINAPI *pRegisterTypeLibForUser)(ITypeLib*,OLECHAR*,OLECHAR*);
 static HRESULT (WINAPI *pUnRegisterTypeLibForUser)(REFGUID,WORD,WORD,LCID,SYSKIND);
 
 static const WCHAR wszStdOle2[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
+static WCHAR wszGUID[] = {'G','U','I','D',0};
+static WCHAR wszguid[] = {'g','u','i','d',0};
+
+static const int is_win64 = sizeof(void *) > sizeof(int);
 
 static void init_function_pointers(void)
 {
@@ -108,18 +111,19 @@ static void test_TypeComp(void)
     BINDPTR bindptr;
     ITypeInfo *pTypeInfo;
     ITypeInfo *pFontTypeInfo;
+    ITypeComp *pTypeComp_tmp;
     static WCHAR wszStdFunctions[] = {'S','t','d','F','u','n','c','t','i','o','n','s',0};
     static WCHAR wszSavePicture[] = {'S','a','v','e','P','i','c','t','u','r','e',0};
     static WCHAR wszOLE_TRISTATE[] = {'O','L','E','_','T','R','I','S','T','A','T','E',0};
     static WCHAR wszUnchecked[] = {'U','n','c','h','e','c','k','e','d',0};
     static WCHAR wszIUnknown[] = {'I','U','n','k','n','o','w','n',0};
     static WCHAR wszFont[] = {'F','o','n','t',0};
-    static WCHAR wszGUID[] = {'G','U','I','D',0};
     static WCHAR wszStdPicture[] = {'S','t','d','P','i','c','t','u','r','e',0};
     static WCHAR wszOLE_COLOR[] = {'O','L','E','_','C','O','L','O','R',0};
     static WCHAR wszClone[] = {'C','l','o','n','e',0};
     static WCHAR wszclone[] = {'c','l','o','n','e',0};
     static WCHAR wszJunk[] = {'J','u','n','k',0};
+    static WCHAR wszAddRef[] = {'A','d','d','R','e','f',0};
 
     hr = LoadTypeLib(wszStdOle2, &pTypeLib);
     ok_ole_success(hr, LoadTypeLib);
@@ -253,6 +257,52 @@ static void test_TypeComp(void)
     ok(!pTypeInfo, "pTypeInfo should have been set to NULL\n");
     ok(!bindptr.lptcomp, "bindptr should have been set to NULL\n");
 
+    /* test basic BindType argument handling */
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszGUID);
+    hr = ITypeComp_BindType(pTypeComp, wszGUID, ulHash, NULL, NULL);
+    ok(hr == E_INVALIDARG, "Got %08x\n", hr);
+
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszGUID);
+    pTypeInfo = (void*)0xdeadbeef;
+    hr = ITypeComp_BindType(pTypeComp, wszGUID, ulHash, &pTypeInfo, NULL);
+    ok(hr == E_INVALIDARG, "Got %08x\n", hr);
+    ok(pTypeInfo == (void*)0xdeadbeef, "Got %p\n", pTypeInfo);
+
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszGUID);
+    pTypeComp_tmp = (void*)0xdeadbeef;
+    hr = ITypeComp_BindType(pTypeComp, wszGUID, ulHash, NULL, &pTypeComp_tmp);
+    ok(hr == E_INVALIDARG, "Got %08x\n", hr);
+    ok(pTypeComp_tmp == (void*)0xdeadbeef, "Got %p\n", pTypeComp_tmp);
+
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszGUID);
+    pTypeComp_tmp = (void*)0xdeadbeef;
+    pTypeInfo = (void*)0xdeadbeef;
+    hr = ITypeComp_BindType(pTypeComp, NULL, ulHash, &pTypeInfo, &pTypeComp_tmp);
+    ok(hr == E_INVALIDARG, "Got %08x\n", hr);
+    ok(pTypeInfo == (void*)0xdeadbeef, "Got %p\n", pTypeInfo);
+    ok(pTypeComp_tmp == (void*)0xdeadbeef, "Got %p\n", pTypeComp_tmp);
+
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszGUID);
+    pTypeComp_tmp = (void*)0xdeadbeef;
+    pTypeInfo = (void*)0xdeadbeef;
+    hr = ITypeComp_BindType(pTypeComp, wszGUID, ulHash, &pTypeInfo, &pTypeComp_tmp);
+    ok_ole_success(hr, ITypeComp_BindType);
+    ok(pTypeInfo != NULL, "Got NULL pTypeInfo\n");
+    todo_wine ok(pTypeComp_tmp == NULL, "Got pTypeComp_tmp %p\n", pTypeComp_tmp);
+    ITypeInfo_Release(pTypeInfo);
+    if(pTypeComp_tmp) ITypeComp_Release(pTypeComp_tmp); /* fixme */
+
+    /* test BindType case-insensitivity */
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszguid);
+    pTypeComp_tmp = (void*)0xdeadbeef;
+    pTypeInfo = (void*)0xdeadbeef;
+    hr = ITypeComp_BindType(pTypeComp, wszguid, ulHash, &pTypeInfo, &pTypeComp_tmp);
+    ok_ole_success(hr, ITypeComp_BindType);
+    ok(pTypeInfo != NULL, "Got NULL pTypeInfo\n");
+    todo_wine ok(pTypeComp_tmp == NULL, "Got pTypeComp_tmp %p\n", pTypeComp_tmp);
+    ITypeInfo_Release(pTypeInfo);
+    if(pTypeComp_tmp) ITypeComp_Release(pTypeComp_tmp); /* fixme */
+
     ITypeComp_Release(pTypeComp);
 
     /* tests for ITypeComp on an interface */
@@ -295,7 +345,7 @@ static void test_TypeComp(void)
     ITypeInfo_ReleaseFuncDesc(pTypeInfo, bindptr.lpfuncdesc);
     ITypeInfo_Release(pTypeInfo);
 
-    /* tests non-existent members */
+    /* tests nonexistent members */
     desckind = 0xdeadbeef;
     bindptr.lptcomp = (ITypeComp*)0xdeadbeef;
     pTypeInfo = (ITypeInfo*)0xdeadbeef;
@@ -306,6 +356,19 @@ static void test_TypeComp(void)
     ok(pTypeInfo == NULL, "pTypeInfo should have been NULL, was: %p\n", pTypeInfo);
     ok(bindptr.lptcomp == NULL, "bindptr should have been NULL, was: %p\n", bindptr.lptcomp);
 
+    /* tests inherited members */
+    desckind = 0xdeadbeef;
+    bindptr.lpfuncdesc = NULL;
+    pTypeInfo = NULL;
+    ulHash = LHashValOfNameSys(SYS_WIN32, LOCALE_NEUTRAL, wszAddRef);
+    hr = ITypeComp_Bind(pTypeComp, wszAddRef, ulHash, 0, &pTypeInfo, &desckind, &bindptr);
+    ok_ole_success(hr, ITypeComp_Bind);
+    ok(desckind == DESCKIND_FUNCDESC, "desckind should have been DESCKIND_FUNCDESC, was: %d\n", desckind);
+    ok(pTypeInfo != NULL, "pTypeInfo should not have been NULL, was: %p\n", pTypeInfo);
+    ok(bindptr.lpfuncdesc != NULL, "bindptr should not have been NULL, was: %p\n", bindptr.lpfuncdesc);
+    ITypeInfo_ReleaseFuncDesc(pTypeInfo, bindptr.lpfuncdesc);
+    ITypeInfo_Release(pTypeInfo);
+
     ITypeComp_Release(pTypeComp);
     ITypeInfo_Release(pFontTypeInfo);
     ITypeLib_Release(pTypeLib);
@@ -487,10 +550,34 @@ static void test_TypeInfo(void)
     DISPPARAMS dispparams;
     GUID bogusguid = {0x806afb4f,0x13f7,0x42d2,{0x89,0x2c,0x6c,0x97,0xc3,0x6a,0x36,0xc1}};
     VARIANT var;
+    UINT count;
+    TYPEKIND kind;
 
     hr = LoadTypeLib(wszStdOle2, &pTypeLib);
     ok_ole_success(hr, LoadTypeLib);
 
+    count = ITypeLib_GetTypeInfoCount(pTypeLib);
+    ok(count > 0, "got %d\n", count);
+
+    /* invalid index */
+    hr = ITypeLib_GetTypeInfo(pTypeLib, count, &pTypeInfo);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_GetTypeInfo(pTypeLib, 0, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_GetLibAttr(pTypeLib, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_GetTypeInfoType(pTypeLib, count, &kind);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_GetTypeInfoType(pTypeLib, count, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_GetTypeInfoType(pTypeLib, 0, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
     hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_IFont, &pTypeInfo);
     ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid); 
 
@@ -530,9 +617,9 @@ static void test_TypeInfo(void)
     dispparams.cNamedArgs = 0;
     hr = ITypeInfo_Invoke(pTypeInfo, (void *)0xdeadbeef, dispidMember, DISPATCH_PROPERTYGET, &dispparams, NULL, NULL, NULL);
     ok(hr == DISP_E_MEMBERNOTFOUND, "ITypeInfo_Invoke should have returned DISP_E_MEMBERNOTFOUND instead of 0x%08x\n", hr);
-    /* correct member id -- correct flags -- cNamedArgs not bigger than cArgs
+    /* correct member id -- correct flags -- cNamedArgs not bigger than cArgs */
     hr = ITypeInfo_Invoke(pTypeInfo, (void *)0xdeadbeef, dispidMember, DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
-    ok(hr == 0x8002000e, "ITypeInfo_Invoke should have returned 0x8002000e instead of 0x%08x\n", hr); */
+    ok(hr == DISP_E_BADPARAMCOUNT, "ITypeInfo_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr);
 
     /* correct member id -- wrong flags -- cNamedArgs bigger than cArgs */
     dispparams.cNamedArgs = 1;
@@ -629,6 +716,191 @@ static void test_TypeInfo(void)
     ITypeLib_Release(pTypeLib);
 }
 
+static int WINAPI int_func( int a0, int a1, int a2, int a3, int a4 )
+{
+    ok( a0 == 1, "wrong arg0 %x\n", a0 );
+    ok( a1 == -1, "wrong arg1 %x\n", a1 );
+    ok( a2 == (0x55550000 | 1234), "wrong arg2 %x\n", a2 );
+    ok( a3 == 0xdeadbeef, "wrong arg3 %x\n", a3 );
+    ok( a4 == 0x555555fd, "wrong arg4 %x\n", a4 );
+    return 4321;
+}
+
+static double WINAPI double_func( double a0, float a1, double a2, int a3 )
+{
+    ok( a0 == 1.2, "wrong arg0 %f\n", (double)a0 );
+    ok( a1 == 3.25, "wrong arg1 %f\n", (double)a1 );
+    ok( a2 == 1.2e12, "wrong arg2 %f\n", (double)a2);
+    ok( a3 == -4433.0, "wrong arg3 %f\n", (double)a3 );
+    return 4321;
+}
+
+static LONGLONG WINAPI longlong_func( LONGLONG a0, CY a1 )
+{
+    ok( a0 == (((ULONGLONG)0xdead << 32) | 0xbeef), "wrong arg0 %08x%08x\n", (DWORD)(a0 >> 32), (DWORD)a0);
+    ok( a1.int64 == ((ULONGLONG)10000 * 12345678), "wrong arg1 %08x%08x\n",
+        (DWORD)(a1.int64 >> 32), (DWORD)a1.int64 );
+    return ((ULONGLONG)4321 << 32) | 8765;
+}
+
+static VARIANT WINAPI variant_func( int a0, BOOL a1, DECIMAL a2, VARIANT a3 )
+{
+    VARIANT var;
+    ok( a0 == 2233, "wrong arg0 %x\n", a0 );
+    ok( a1 == 1 || broken(a1 == 0x55550001), "wrong arg1 %x\n", a1 );
+    V_VT(&var) = VT_LPWSTR;
+    V_UI4(&var) = 0xbabe;
+    ok( a2.Hi32 == 1122, "wrong arg2.Hi32 %x\n", a2.Hi32 );
+    ok( U1(a2).Lo64 == 3344, "wrong arg2.Lo64 %08x%08x\n", (DWORD)(U1(a2).Lo64 >> 32), (DWORD)U1(a2).Lo64 );
+    ok( V_VT(&a3) == VT_EMPTY, "wrong arg3 type %x\n", V_VT(&a3) );
+    ok( V_UI4(&a3) == 0xdeadbeef, "wrong arg3 value %x\n", V_UI4(&a3) );
+    return var;
+}
+
+static int CDECL void_func( int a0, int a1 )
+{
+    if (is_win64)  /* VT_EMPTY is passed as real arg on win64 */
+    {
+        ok( a0 == 0x55555555, "wrong arg0 %x\n", a0 );
+        ok( a1 == 1111, "wrong arg1 %x\n", a1 );
+    }
+    else
+    {
+        ok( a0 == 1111, "wrong arg0 %x\n", a0 );
+        ok( a1 == 0, "wrong arg1 %x\n", a1 );
+    }
+    return 12;
+}
+
+static int WINAPI stdcall_func( int a )
+{
+    return 0;
+}
+
+static int WINAPI inst_func( void *inst, int a )
+{
+    ok( (*(void ***)inst)[3] == inst_func, "wrong ptr %p\n", inst );
+    ok( a == 3, "wrong arg %x\n", a );
+    return a * 2;
+}
+
+static const void *vtable[] = { NULL, NULL, NULL, inst_func };
+
+static void test_DispCallFunc(void)
+{
+    const void **inst = vtable;
+    HRESULT res;
+    VARIANT result, args[5];
+    VARIANTARG *pargs[5];
+    VARTYPE types[5];
+    int i;
+
+    for (i = 0; i < 5; i++) pargs[i] = &args[i];
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_UI4;
+    V_UI4(&args[0]) = 1;
+    types[1] = VT_I4;
+    V_I4(&args[1]) = -1;
+    types[2] = VT_I2;
+    V_I2(&args[2]) = 1234;
+    types[3] = VT_UI4;
+    V_UI4(&args[3]) = 0xdeadbeef;
+    types[4] = VT_UI4;
+    V_I1(&args[4]) = -3;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( NULL, (ULONG_PTR)int_func, CC_STDCALL, VT_UI4, 5, types, pargs, &result );
+    ok( res == S_OK, "DispCallFunc failed %x\n", res );
+    ok( V_VT(&result) == VT_UI4, "wrong result type %d\n", V_VT(&result) );
+    ok( V_UI4(&result) == 4321, "wrong result %u\n", V_UI4(&result) );
+
+    /* the function checks the argument sizes for stdcall */
+    if (!is_win64)  /* no stdcall on 64-bit */
+    {
+        res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 0, types, pargs, &result );
+        ok( res == DISP_E_BADCALLEE, "DispCallFunc wrong error %x\n", res );
+        res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 1, types, pargs, &result );
+        ok( res == S_OK, "DispCallFunc failed %x\n", res );
+        res = DispCallFunc( NULL, (ULONG_PTR)stdcall_func, CC_STDCALL, VT_UI4, 2, types, pargs, &result );
+        ok( res == DISP_E_BADCALLEE, "DispCallFunc wrong error %x\n", res );
+    }
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_R8;
+    V_R8(&args[0]) = 1.2;
+    types[1] = VT_R4;
+    V_R4(&args[1]) = 3.25;
+    types[2] = VT_R8;
+    V_R8(&args[2]) = 1.2e12;
+    types[3] = VT_I4;
+    V_I4(&args[3]) = -4433;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( NULL, (ULONG_PTR)double_func, CC_STDCALL, VT_R8, 4, types, pargs, &result );
+    ok( res == S_OK, "DispCallFunc failed %x\n", res );
+    ok( V_VT(&result) == VT_R8, "wrong result type %d\n", V_VT(&result) );
+    ok( V_R8(&result) == 4321, "wrong result %f\n", V_R8(&result) );
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_I8;
+    V_I8(&args[0]) = ((ULONGLONG)0xdead << 32) | 0xbeef;
+    types[1] = VT_CY;
+    V_CY(&args[1]).int64 = (ULONGLONG)10000 * 12345678;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( NULL, (ULONG_PTR)longlong_func, CC_STDCALL, VT_I8, 2, types, pargs, &result );
+    ok( res == S_OK || broken(res == E_INVALIDARG),  /* longlong not supported on <= win2k */
+        "DispCallFunc failed %x\n", res );
+    if (res == S_OK)
+    {
+        ok( V_VT(&result) == VT_I8, "wrong result type %d\n", V_VT(&result) );
+        ok( V_I8(&result) == (((ULONGLONG)4321 << 32) | 8765), "wrong result %08x%08x\n",
+            (DWORD)(V_I8(&result) >> 32), (DWORD)V_I8(&result) );
+    }
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_I4;
+    V_I4(&args[0]) = 2233;
+    types[1] = VT_BOOL;
+    V_BOOL(&args[1]) = 1;
+    types[2] = VT_DECIMAL;
+    V_DECIMAL(&args[2]).Hi32 = 1122;
+    U1(V_DECIMAL(&args[2])).Lo64 = 3344;
+    types[3] = VT_VARIANT;
+    V_VT(&args[3]) = VT_EMPTY;
+    V_UI4(&args[3]) = 0xdeadbeef;
+    types[4] = VT_EMPTY;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( NULL, (ULONG_PTR)variant_func, CC_STDCALL, VT_VARIANT, 5, types, pargs, &result );
+    ok( res == S_OK, "DispCallFunc failed %x\n", res );
+    ok( V_VT(&result) == VT_LPWSTR, "wrong result type %d\n", V_VT(&result) );
+    ok( V_UI4(&result) == 0xbabe, "wrong result %08x\n", V_UI4(&result) );
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_EMPTY;
+    types[1] = VT_I4;
+    V_I4(&args[1]) = 1111;
+    types[2] = VT_EMPTY;
+    types[3] = VT_I4;
+    V_I4(&args[3]) = 0;
+    types[4] = VT_EMPTY;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( NULL, (ULONG_PTR)void_func, CC_CDECL, VT_EMPTY, 5, types, pargs, &result );
+    ok( res == S_OK, "DispCallFunc failed %x\n", res );
+    ok( V_VT(&result) == VT_EMPTY, "wrong result type %d\n", V_VT(&result) );
+    if (is_win64)
+        ok( V_UI4(&result) == 12, "wrong result %08x\n", V_UI4(&result) );
+    else
+        ok( V_UI4(&result) == 0xcccccccc, "wrong result %08x\n", V_UI4(&result) );
+
+    memset( args, 0x55, sizeof(args) );
+    types[0] = VT_I4;
+    V_I4(&args[0]) = 3;
+    memset( &result, 0xcc, sizeof(result) );
+    res = DispCallFunc( &inst, 3 * sizeof(void*), CC_STDCALL, VT_I4, 1, types, pargs, &result );
+    ok( res == S_OK, "DispCallFunc failed %x\n", res );
+    ok( V_VT(&result) == VT_I4, "wrong result type %d\n", V_VT(&result) );
+    ok( V_I4(&result) == 6, "wrong result %08x\n", V_I4(&result) );
+}
+
 /* RegDeleteTreeW from dlls/advapi32/registry.c */
 static LSTATUS myRegDeleteTreeW(HKEY hKey, LPCWSTR lpszSubKey)
 {
@@ -693,10 +965,10 @@ cleanup:
     return ret;
 }
 
-static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL remove)
+static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, DWORD arch, LPCWSTR base, BOOL remove)
 {
     static const WCHAR typelibW[] = {'T','y','p','e','l','i','b','\\',0};
-    static const WCHAR formatW[] = {'\\','%','u','.','%','u','\\','0','\\','w','i','n','3','2',0};
+    static const WCHAR formatW[] = {'\\','%','u','.','%','u','\\','0','\\','w','i','n','%','u',0};
     static const WCHAR format2W[] = {'%','s','_','%','u','_','%','u','.','d','l','l',0};
     WCHAR buf[128];
     HKEY hkey;
@@ -712,7 +984,7 @@ static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL
         return TRUE;
     }
 
-    wsprintfW(buf + lstrlenW(buf), formatW, maj, min );
+    wsprintfW(buf + lstrlenW(buf), formatW, maj, min, arch);
 
     SetLastError(0xdeadbeef);
     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, buf, 0, NULL, 0,
@@ -725,7 +997,7 @@ static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL
 
     if (res != ERROR_SUCCESS)
     {
-        trace("RegCreateKeyExW failed\n");
+        trace("RegCreateKeyExW failed: %u\n", res);
         return FALSE;
     }
 
@@ -740,7 +1012,7 @@ static BOOL do_typelib_reg_key(GUID *uid, WORD maj, WORD min, LPCWSTR base, BOOL
     return ret;
 }
 
-static void test_QueryPathOfRegTypeLib(void)
+static void test_QueryPathOfRegTypeLib(DWORD arch)
 {
     static const struct test_data
     {
@@ -761,6 +1033,7 @@ static void test_QueryPathOfRegTypeLib(void)
         { 4, 0, TYPE_E_LIBNOTREGISTERED, { 0 } }
     };
     static const WCHAR base[] = {'f','a','k','e',0};
+    static const WCHAR wrongW[] = {'w','r','o','n','g',0};
     UINT i;
     RPC_STATUS status;
     GUID uid;
@@ -774,10 +1047,11 @@ static void test_QueryPathOfRegTypeLib(void)
     StringFromGUID2(&uid, uid_str, 40);
     /*trace("GUID: %s\n", wine_dbgstr_w(uid_str));*/
 
-    if (!do_typelib_reg_key(&uid, 3, 0, base, 0)) return;
-    if (!do_typelib_reg_key(&uid, 3, 1, base, 0)) return;
-    if (!do_typelib_reg_key(&uid, 3, 37, base, 0)) return;
-    if (!do_typelib_reg_key(&uid, 5, 37, base, 0)) return;
+    if (!do_typelib_reg_key(&uid, 3, 0, arch, base, 0)) return;
+    if (!do_typelib_reg_key(&uid, 3, 1, arch, base, 0)) return;
+    if (!do_typelib_reg_key(&uid, 3, 37, arch, base, 0)) return;
+    if (!do_typelib_reg_key(&uid, 5, 37, arch, base, 0)) return;
+    if (arch == 64 && !do_typelib_reg_key(&uid, 5, 37, 32, wrongW, 0)) return;
 
     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
     {
@@ -790,7 +1064,7 @@ static void test_QueryPathOfRegTypeLib(void)
         }
     }
 
-    do_typelib_reg_key(&uid, 0, 0, NULL, 1);
+    do_typelib_reg_key(&uid, 0, 0, arch, NULL, 1);
 }
 
 static void test_inheritance(void)
@@ -838,6 +1112,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -872,6 +1147,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -906,6 +1182,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -935,6 +1212,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -968,6 +1246,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -1004,6 +1283,7 @@ if(use_midl_tlb) {
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
     ok(hr == S_OK, "hr %08x\n", hr);
     hr = ITypeInfo_GetTypeAttr(pTI_p, &pTA);
+    ok(hr == S_OK, "got %08x\n", hr);
     ok(IsEqualGUID(&pTA->guid, &IID_IDispatch), "guid {%08x-....\n", pTA->guid.Data1);
     ITypeInfo_ReleaseTypeAttr(pTI_p, pTA);
     ITypeInfo_Release(pTI_p);
@@ -1023,7 +1303,7 @@ if(use_midl_tlb) {
     href = U(pFD->lprgelemdescParam[0].tdesc).hreftype;
     ok((href & 0xff000000) == 0x04000000, "href 0x%08x\n", href);
     hr = ITypeInfo_GetRefTypeInfo(pTI, href, &pTI_p);
-    ok(SUCCEEDED(hr), "hr %08x\n", hr);
+    ok(hr == S_OK, "hr %08x\n", hr);
     if (SUCCEEDED(hr)) ITypeInfo_Release(pTI_p);
     ITypeInfo_ReleaseFuncDesc(pTI, pFD);
 }
@@ -1072,15 +1352,18 @@ static void test_CreateTypeLib(void) {
     static OLECHAR dualW[] = {'d','u','a','l',0};
     static OLECHAR coclassW[] = {'c','o','c','l','a','s','s',0};
     static WCHAR defaultW[] = {'d','e','f','a','u','l','t',0x3213,0};
+    static WCHAR defaultQW[] = {'d','e','f','a','u','l','t','?',0};
     static OLECHAR func1W[] = {'f','u','n','c','1',0};
     static OLECHAR func2W[] = {'f','u','n','c','2',0};
     static OLECHAR prop1W[] = {'P','r','o','p','1',0};
     static OLECHAR param1W[] = {'p','a','r','a','m','1',0};
     static OLECHAR param2W[] = {'p','a','r','a','m','2',0};
+    static OLECHAR asdfW[] = {'A','s','d','f',0};
     static OLECHAR *names1[] = {func1W, param1W, param2W};
     static OLECHAR *names2[] = {func2W, param1W, param2W};
     static OLECHAR *propname[] = {prop1W, param1W};
     static const GUID custguid = {0xbf611abe,0x5b38,0x11df,{0x91,0x5c,0x08,0x02,0x79,0x79,0x94,0x70}};
+    static const GUID bogusguid = {0xbf611abe,0x5b38,0x11df,{0x91,0x5c,0x08,0x02,0x79,0x79,0x94,0x71}};
 
     char filename[MAX_PATH];
     WCHAR filenameW[MAX_PATH];
@@ -1090,8 +1373,8 @@ static void test_CreateTypeLib(void) {
     ITypeLib *tl, *stdole;
     ITypeInfo *interface1, *interface2, *dual, *unknown, *dispatch, *ti;
     ITypeInfo2 *ti2;
-    FUNCDESC funcdesc;
-    ELEMDESC elemdesc[5];
+    FUNCDESC funcdesc, *pfuncdesc;
+    ELEMDESC elemdesc[5], *edesc;
     PARAMDESCEX paramdescex;
     TYPEDESC typedesc1, typedesc2;
     TYPEATTR *typeattr;
@@ -1102,6 +1385,7 @@ static void test_CreateTypeLib(void) {
     int impltypeflags;
     VARIANT cust_data;
     HRESULT hres;
+    TYPEKIND kind;
 
     trace("CreateTypeLib tests\n");
 
@@ -1120,9 +1404,24 @@ static void test_CreateTypeLib(void) {
     hres = CreateTypeLib2(SYS_WIN32, filenameW, &createtl);
     ok(hres == S_OK, "got %08x\n", hres);
 
-    hres = ICreateTypeLib_QueryInterface(createtl, &IID_ITypeLib, (void**)&tl);
+    hres = ICreateTypeLib2_QueryInterface(createtl, &IID_ITypeLib, (void**)&tl);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeLib_GetTypeInfo(tl, 0, NULL);
+    ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
+
+    hres = ITypeLib_GetTypeInfoType(tl, 0, &kind);
+    ok(hres == TYPE_E_ELEMENTNOTFOUND, "got 0x%08x\n", hres);
+
+    hres = ITypeLib_GetTypeInfoType(tl, 0, NULL);
+    ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
+
+    hres = ITypeLib_GetTypeInfoType(tl, 0, NULL);
+    ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
+
+    hres = ITypeLib_GetLibAttr(tl, NULL);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
     hres = ITypeLib_GetLibAttr(tl, &libattr);
     ok(hres == S_OK, "got %08x\n", hres);
 
@@ -1144,10 +1443,10 @@ static void test_CreateTypeLib(void) {
     hres = ITypeLib_GetDocumentation(tl, 0, &name, NULL, NULL, NULL);
     ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
 
-    hres = ICreateTypeLib_SetName(createtl, typelibW);
+    hres = ICreateTypeLib2_SetName(createtl, typelibW);
     ok(hres == S_OK, "got %08x\n", hres);
 
-    hres = ICreateTypeLib_SetHelpFileName(createtl, helpfileW);
+    hres = ICreateTypeLib2_SetHelpFileName(createtl, helpfileW);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ITypeLib_GetDocumentation(tl, -1, NULL, NULL, NULL, NULL);
@@ -1161,7 +1460,17 @@ static void test_CreateTypeLib(void) {
     SysFreeString(name);
     SysFreeString(helpfile);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, &createti);
+    /* invalid parameters */
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, NULL, TKIND_INTERFACE, &createti);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, NULL);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, NULL, TKIND_INTERFACE, NULL);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, &createti);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo_QueryInterface(createti, &IID_ITypeInfo, (void**)&interface1);
@@ -1223,6 +1532,8 @@ static void test_CreateTypeLib(void) {
     hres = ITypeInfo_GetRefTypeOfImplType(interface1, -1, &hreftype);
     ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
 
+    ICreateTypeInfo_QueryInterface(createti, &IID_ITypeInfo2, (void**)&ti2);
+
     memset(&funcdesc, 0, sizeof(FUNCDESC));
     funcdesc.funckind = FUNC_PUREVIRTUAL;
     funcdesc.invkind = INVOKE_PROPERTYGET;
@@ -1239,6 +1550,32 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 0, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 0, NULL);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 0, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam == NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_PROPERTYGET, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 0, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 12 ||
+            broken(pfuncdesc->oVft == 24) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_BSTR, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     hres = ICreateTypeInfo_SetFuncHelpContext(createti, 0, 0xabcdefab);
     ok(hres == S_OK, "got %08x\n", hres);
 
@@ -1265,6 +1602,12 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_SetFuncHelpContext(createti, 1, 0xabcdefab);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 0, propname, 0);
+    ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
+
+    hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 0, NULL, 1);
+    ok(hres == E_INVALIDARG, "got %08x\n", hres);
+
     hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 0, propname, 1);
     ok(hres == S_OK, "got %08x\n", hres);
 
@@ -1274,6 +1617,30 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 1, propname, 2);
     ok(hres == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_PROPERTYPUT, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 16 ||
+            broken(pfuncdesc->oVft == 28) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).idldesc.wIDLFlags == IDLFLAG_FIN, "got: %x\n", U(*edesc).idldesc.wIDLFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
 
     funcdesc.invkind = INVOKE_PROPERTYPUTREF;
     hres = ICreateTypeInfo_AddFuncDesc(createti, 0, &funcdesc);
@@ -1292,6 +1659,26 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 1, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 1, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 1, "got %d\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam == NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 0, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 16 ||
+            broken(pfuncdesc->oVft == 28), /* xp64 */
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     funcdesc.memid = MEMBERID_NIL;
     hres = ICreateTypeInfo_AddFuncDesc(createti, 1, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
@@ -1304,12 +1691,68 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 4, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 4, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010004, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 28 ||
+            broken(pfuncdesc->oVft == 40) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_PTR, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FIN, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex == NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(edesc->tdesc).lptdesc != NULL, "got: %p\n", U(edesc->tdesc).lptdesc);
+    ok(U(edesc->tdesc).lptdesc->vt == VT_BSTR, "got: %d\n", U(edesc->tdesc).lptdesc->vt);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     U(elemdesc[0].tdesc).lptdesc = &typedesc2;
     typedesc2.vt = VT_PTR;
     U(typedesc2).lptdesc = &typedesc1;
     hres = ICreateTypeInfo_AddFuncDesc(createti, 4, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 4, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010007, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 28 ||
+            broken(pfuncdesc->oVft == 40) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_PTR, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FIN, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex == NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(edesc->tdesc).lptdesc != NULL, "got: %p\n", U(edesc->tdesc).lptdesc);
+    ok(U(edesc->tdesc).lptdesc->vt == VT_PTR, "got: %d\n", U(edesc->tdesc).lptdesc->vt);
+    ok(U(*U(edesc->tdesc).lptdesc).lptdesc != NULL, "got: %p\n", U(*U(edesc->tdesc).lptdesc).lptdesc);
+    ok(U(*U(edesc->tdesc).lptdesc).lptdesc->vt == VT_BSTR, "got: %d\n", U(*U(edesc->tdesc).lptdesc).lptdesc->vt);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     elemdesc[0].tdesc.vt = VT_INT;
     U(elemdesc[0]).paramdesc.wParamFlags = PARAMFLAG_FHASDEFAULT;
     U(elemdesc[0]).paramdesc.pparamdescex = &paramdescex;
@@ -1318,6 +1761,37 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010003, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_INT, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex != NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(*edesc).paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            U(*edesc).paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == VT_I4, "got: %d\n",
+            V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+    ok(V_I4(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == 0x123, "got: 0x%x\n",
+            V_I4(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     U(elemdesc[0]).idldesc.dwReserved = 0;
     U(elemdesc[0]).idldesc.wIDLFlags = IDLFLAG_FIN;
     elemdesc[1].tdesc.vt = VT_UI2;
@@ -1329,6 +1803,42 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
 
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010009, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 2, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_INT, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FIN, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex == NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+
+    edesc = pfuncdesc->lprgelemdescParam + 1;
+    ok(edesc->tdesc.vt == VT_UI2, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex != NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(*edesc).paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            U(*edesc).paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == VT_UI2, "got: %d\n",
+            V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+    ok(V_UI2(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == 0xFFFF, "got: 0x%x\n",
+            V_UI2(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
     U(elemdesc[0]).paramdesc.wParamFlags = PARAMFLAG_FHASDEFAULT;
     U(elemdesc[0]).paramdesc.pparamdescex = &paramdescex;
     elemdesc[1].tdesc.vt = VT_INT;
@@ -1343,6 +1853,90 @@ static void test_CreateTypeLib(void) {
     V_BSTR(&paramdescex.varDefaultValue) = SysAllocString(defaultW);
     hres = ICreateTypeInfo_AddFuncDesc(createti, 3, &funcdesc);
     ok(hres == S_OK, "got %08x\n", hres);
+    SysFreeString(V_BSTR(&paramdescex.varDefaultValue));
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 3, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x6001000b, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 2, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 24 ||
+            broken(pfuncdesc->oVft == 36) /* xp64 */,
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex != NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(*edesc).paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            U(*edesc).paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == VT_BSTR, "got: %d\n",
+            V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+    ok(!lstrcmpW(V_BSTR(&U(*edesc).paramdesc.pparamdescex->varDefaultValue), defaultQW),
+            "got: %s\n",
+            wine_dbgstr_w(V_BSTR(&U(*edesc).paramdesc.pparamdescex->varDefaultValue)));
+
+    edesc = pfuncdesc->lprgelemdescParam + 1;
+    ok(edesc->tdesc.vt == VT_BSTR, "got: %d\n", edesc->tdesc.vt);
+    ok(U(*edesc).paramdesc.wParamFlags == PARAMFLAG_FHASDEFAULT, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(U(*edesc).paramdesc.pparamdescex != NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(*edesc).paramdesc.pparamdescex->cBytes == sizeof(PARAMDESCEX), "got: %d\n",
+            U(*edesc).paramdesc.pparamdescex->cBytes);
+    ok(V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue) == VT_BSTR, "got: %d\n",
+            V_VT(&U(*edesc).paramdesc.pparamdescex->varDefaultValue));
+    ok(!lstrcmpW(V_BSTR(&U(*edesc).paramdesc.pparamdescex->varDefaultValue), defaultQW),
+            "got: %s\n",
+            wine_dbgstr_w(V_BSTR(&U(*edesc).paramdesc.pparamdescex->varDefaultValue)));
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
+
+    elemdesc[0].tdesc.vt = VT_USERDEFINED;
+    U(elemdesc[0].tdesc).hreftype = hreftype;
+    U(elemdesc[0]).paramdesc.pparamdescex = NULL;
+    U(elemdesc[0]).paramdesc.wParamFlags = 0;
+
+    funcdesc.lprgelemdescParam = elemdesc;
+    funcdesc.invkind = INVOKE_FUNC;
+    funcdesc.cParams = 1;
+    funcdesc.elemdescFunc.tdesc.vt = VT_VOID;
+
+    hres = ICreateTypeInfo_AddFuncDesc(createti, 5, &funcdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    hres = ITypeInfo2_GetFuncDesc(ti2, 5, &pfuncdesc);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(pfuncdesc->memid == 0x60010005, "got %x\n", pfuncdesc->memid);
+    ok(pfuncdesc->lprgscode == NULL, "got %p\n", pfuncdesc->lprgscode);
+    ok(pfuncdesc->lprgelemdescParam != NULL, "got %p\n", pfuncdesc->lprgelemdescParam);
+    ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got 0x%x\n", pfuncdesc->funckind);
+    ok(pfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", pfuncdesc->invkind);
+    ok(pfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", pfuncdesc->callconv);
+    ok(pfuncdesc->cParams == 1, "got %d\n", pfuncdesc->cParams);
+    ok(pfuncdesc->cParamsOpt == 0, "got %d\n", pfuncdesc->cParamsOpt);
+    todo_wine ok(pfuncdesc->oVft == 32 ||
+            broken(pfuncdesc->oVft == 44), /* xp64 */
+            "got %d\n", pfuncdesc->oVft);
+    ok(pfuncdesc->cScodes == 0, "got %d\n", pfuncdesc->cScodes);
+    ok(pfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", pfuncdesc->elemdescFunc.tdesc.vt);
+    ok(pfuncdesc->wFuncFlags == 0, "got 0x%x\n", pfuncdesc->wFuncFlags);
+
+    edesc = pfuncdesc->lprgelemdescParam;
+    ok(U(*edesc).paramdesc.pparamdescex == NULL, "got: %p\n", U(*edesc).paramdesc.pparamdescex);
+    ok(U(*edesc).paramdesc.wParamFlags == 0, "got: 0x%x\n", U(*edesc).paramdesc.wParamFlags);
+    ok(edesc->tdesc.vt == VT_USERDEFINED, "got: %d\n", edesc->tdesc.vt);
+    ok(U(edesc->tdesc).hreftype == hreftype, "got: 0x%x\n", U(edesc->tdesc).hreftype);
+
+    ITypeInfo2_ReleaseFuncDesc(ti2, pfuncdesc);
 
     hres = ITypeInfo_GetDocumentation(interface1, 0, &name, &docstring, &helpcontext, &helpfile);
     ok(hres == S_OK, "got %08x\n", hres);
@@ -1380,12 +1974,13 @@ static void test_CreateTypeLib(void) {
     hres = ICreateTypeInfo_SetFuncAndParamNames(createti, 3, names1, 3);
     ok(hres == TYPE_E_AMBIGUOUSNAME, "got %08x\n", hres);
 
+    ITypeInfo2_Release(ti2);
     ICreateTypeInfo_Release(createti);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, &createti);
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, interface1W, TKIND_INTERFACE, &createti);
     ok(hres == TYPE_E_NAMECONFLICT, "got %08x\n", hres);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, interface2W, TKIND_INTERFACE, &createti);
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, interface2W, TKIND_INTERFACE, &createti);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo_QueryInterface(createti, &IID_ITypeInfo, (void**)&interface2);
@@ -1435,7 +2030,7 @@ static void test_CreateTypeLib(void) {
 
     VariantInit(&cust_data);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, interface3W, TKIND_INTERFACE, &createti);
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, interface3W, TKIND_INTERFACE, &createti);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo_QueryInterface(createti, &IID_ICreateTypeInfo2, (void**)&createti2);
@@ -1445,15 +2040,12 @@ static void test_CreateTypeLib(void) {
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ITypeInfo2_GetCustData(ti2, NULL, NULL);
-    todo_wine
     ok(hres == E_INVALIDARG, "got %08x\n", hres);
 
     hres = ITypeInfo2_GetCustData(ti2, &custguid, NULL);
-    todo_wine
     ok(hres == E_INVALIDARG, "got %08x\n", hres);
 
     hres = ITypeInfo2_GetCustData(ti2, &custguid, &cust_data);
-    todo_wine
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo2_SetCustData(createti2, NULL, NULL);
@@ -1475,12 +2067,9 @@ static void test_CreateTypeLib(void) {
     V_VT(&cust_data) = VT_EMPTY;
 
     hres = ITypeInfo2_GetCustData(ti2, &custguid, &cust_data);
-    todo_wine
     ok(hres == S_OK, "got %08x\n", hres);
 
-    todo_wine
     ok(V_VT(&cust_data) == VT_UI4, "got %d\n", V_VT(&cust_data));
-    todo_wine
     ok(V_I4(&cust_data) == 0xdeadbeef, "got 0x%08x\n", V_I4(&cust_data));
 
     V_VT(&cust_data) = VT_UI4;
@@ -1493,19 +2082,41 @@ static void test_CreateTypeLib(void) {
     V_VT(&cust_data) = VT_EMPTY;
 
     hres = ITypeInfo2_GetCustData(ti2, &custguid, &cust_data);
-    todo_wine
     ok(hres == S_OK, "got %08x\n", hres);
 
-    todo_wine
     ok(V_VT(&cust_data) == VT_UI4, "got %d\n", V_VT(&cust_data));
-    todo_wine
     ok(V_I4(&cust_data) == 12345678, "got 0x%08x\n", V_I4(&cust_data));
 
+    V_VT(&cust_data) = VT_BSTR;
+    V_BSTR(&cust_data) = SysAllocString(asdfW);
+
+    hres = ICreateTypeInfo2_SetCustData(createti2, &custguid, &cust_data);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    SysFreeString(V_BSTR(&cust_data));
+    V_I4(&cust_data) = 0;
+    V_VT(&cust_data) = VT_EMPTY;
+
+    hres = ITypeInfo2_GetCustData(ti2, &custguid, &cust_data);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(V_VT(&cust_data) == VT_BSTR, "got %d\n", V_VT(&cust_data));
+    ok(!lstrcmpW(V_BSTR(&cust_data), asdfW), "got %s\n", wine_dbgstr_w(V_BSTR(&cust_data)));
+    SysFreeString(V_BSTR(&cust_data));
+
+    V_VT(&cust_data) = VT_UI4;
+    V_UI4(&cust_data) = 17;
+
+    hres = ITypeInfo2_GetCustData(ti2, &bogusguid, &cust_data);
+    ok(hres == S_OK, "got %08x\n", hres);
+
+    ok(V_VT(&cust_data) == VT_EMPTY, "got: %d\n", V_VT(&cust_data));
+
     ITypeInfo2_Release(ti2);
     ICreateTypeInfo2_Release(createti2);
     ICreateTypeInfo_Release(createti);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, coclassW, TKIND_COCLASS, &createti);
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, coclassW, TKIND_COCLASS, &createti);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo_AddRefTypeInfo(createti, interface1, &hreftype);
@@ -1572,7 +2183,7 @@ static void test_CreateTypeLib(void) {
 
     ICreateTypeInfo_Release(createti);
 
-    hres = ICreateTypeLib_CreateTypeInfo(createtl, dualW, TKIND_INTERFACE, &createti);
+    hres = ICreateTypeLib2_CreateTypeInfo(createtl, dualW, TKIND_INTERFACE, &createti);
     ok(hres == S_OK, "got %08x\n", hres);
 
     hres = ICreateTypeInfo_SetTypeFlags(createti, TYPEFLAG_FDUAL);
@@ -1636,10 +2247,10 @@ static void test_CreateTypeLib(void) {
     ok(hres == S_OK, "got %08x\n", hres);
     ok(typeattr->cbSizeInstance == 4, "cbSizeInstance = %d\n", typeattr->cbSizeInstance);
     ok(typeattr->typekind == 3, "typekind = %d\n", typeattr->typekind);
-    ok(typeattr->cFuncs == 11, "cFuncs = %d\n", typeattr->cFuncs);
+    ok(typeattr->cFuncs == 12, "cFuncs = %d\n", typeattr->cFuncs);
     ok(typeattr->cVars == 0, "cVars = %d\n", typeattr->cVars);
     ok(typeattr->cImplTypes == 1, "cImplTypes = %d\n", typeattr->cImplTypes);
-    ok(typeattr->cbSizeVft == 56 || broken(typeattr->cbSizeVft == 3 * sizeof(void *) + 44), /* xp64 */
+    ok(typeattr->cbSizeVft == 60 || broken(typeattr->cbSizeVft == 3 * sizeof(void *) + 48), /* xp64 */
        "cbSizeVft = %d\n", typeattr->cbSizeVft);
     ok(typeattr->cbAlignment == 4, "cbAlignment = %d\n", typeattr->cbAlignment);
     ok(typeattr->wTypeFlags == 0, "wTypeFlags = %d\n", typeattr->wTypeFlags);
@@ -2152,6 +2763,8 @@ static void test_create_typelib_lcid(LCID lcid)
     ok(hr == S_OK, "got %08x\n", hr);
 
     hr = ICreateTypeLib2_SaveAllChanges(tl);
+    ok(hr == S_OK, "got %08x\n", hr);
+
     ICreateTypeLib2_Release(tl);
 
     file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
@@ -2228,7 +2841,7 @@ static void test_register_typelib(BOOL system_registration)
     MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filename, MAX_PATH);
 
     hr = LoadTypeLibEx(filename, REGKIND_NONE, &typelib);
-    ok(SUCCEEDED(hr), "got %08x\n", hr);
+    ok(hr == S_OK, "got %08x\n", hr);
 
     if (system_registration)
         hr = RegisterTypeLib(typelib, filename, NULL);
@@ -2241,7 +2854,7 @@ static void test_register_typelib(BOOL system_registration)
         DeleteFileA(filenameA);
         return;
     }
-    ok(SUCCEEDED(hr), "got %08x\n", hr);
+    ok(hr == S_OK, "got %08x\n", hr);
 
     count = ITypeLib_GetTypeInfoCount(typelib);
     ok(count == 11, "got %d\n", count);
@@ -2252,10 +2865,10 @@ static void test_register_typelib(BOOL system_registration)
         TYPEATTR *attr;
 
         hr = ITypeLib_GetTypeInfo(typelib, i, &typeinfo);
-        ok(SUCCEEDED(hr), "got %08x\n", hr);
+        ok(hr == S_OK, "got %08x\n", hr);
 
         hr = ITypeInfo_GetTypeAttr(typeinfo, &attr);
-        ok(SUCCEEDED(hr), "got %08x\n", hr);
+        ok(hr == S_OK, "got %08x\n", hr);
 
         ok(attr->typekind == attrs[i].kind, "%d: got kind %d\n", i, attr->typekind);
         ok(attr->wTypeFlags == attrs[i].flags, "%d: got flags %04x\n", i, attr->wTypeFlags);
@@ -2267,13 +2880,13 @@ static void test_register_typelib(BOOL system_registration)
             TYPEATTR *dual_attr;
 
             hr = ITypeInfo_GetRefTypeOfImplType(typeinfo, -1, &reftype);
-            ok(SUCCEEDED(hr), "got %08x\n", hr);
+            ok(hr == S_OK, "got %08x\n", hr);
 
             hr = ITypeInfo_GetRefTypeInfo(typeinfo, reftype, &dual_info);
-            ok(SUCCEEDED(hr), "got %08x\n", hr);
+            ok(hr == S_OK, "got %08x\n", hr);
 
             hr = ITypeInfo_GetTypeAttr(dual_info, &dual_attr);
-            ok(SUCCEEDED(hr), "got %08x\n", hr);
+            ok(hr == S_OK, "got %08x\n", hr);
 
             ok(dual_attr->typekind == TKIND_INTERFACE, "%d: got kind %d\n", i, dual_attr->typekind);
             ok(dual_attr->wTypeFlags == (TYPEFLAG_FDISPATCHABLE | TYPEFLAG_FOLEAUTOMATION | TYPEFLAG_FDUAL), "%d: got flags %04x\n", i, dual_attr->wTypeFlags);
@@ -2304,15 +2917,274 @@ static void test_register_typelib(BOOL system_registration)
     }
 
     if (system_registration)
-        hr = UnRegisterTypeLib(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32);
+        hr = UnRegisterTypeLib(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, is_win64 ? SYS_WIN64 : SYS_WIN32);
     else
-        hr = pUnRegisterTypeLibForUser(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, sizeof(void*) == 8 ? SYS_WIN64 : SYS_WIN32);
-    ok(SUCCEEDED(hr), "got %08x\n", hr);
+        hr = pUnRegisterTypeLibForUser(&LIBID_register_test, 1, 0, LOCALE_NEUTRAL, is_win64 ? SYS_WIN64 : SYS_WIN32);
+    ok(hr == S_OK, "got %08x\n", hr);
 
     ITypeLib_Release(typelib);
     DeleteFileA( filenameA );
 }
 
+static void test_LoadTypeLib(void)
+{
+    ITypeLib *tl;
+    HRESULT hres;
+
+    static const WCHAR kernel32_dllW[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
+
+    hres = LoadTypeLib(kernel32_dllW, &tl);
+    ok(hres == TYPE_E_CANTLOADLIBRARY, "LoadTypeLib returned: %08x, expected TYPE_E_CANTLOADLIBRARY\n", hres);
+}
+
+static void test_SetVarHelpContext(void)
+{
+    static OLECHAR nameW[] = {'n','a','m','e',0};
+    CHAR filenameA[MAX_PATH];
+    WCHAR filenameW[MAX_PATH];
+    ICreateTypeLib2 *ctl;
+    ICreateTypeInfo *cti;
+    VARDESC desc;
+    HRESULT hr;
+    VARIANT v;
+
+    GetTempFileNameA(".", "tlb", 0, filenameA);
+    MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filenameW, MAX_PATH);
+
+    hr = CreateTypeLib2(SYS_WIN32, filenameW, &ctl);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeLib2_CreateTypeInfo(ctl, nameW, TKIND_ENUM, &cti);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarHelpContext(cti, 0, 0);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr);
+
+    memset(&desc, 0, sizeof(desc));
+    desc.elemdescVar.tdesc.vt = VT_INT;
+    desc.varkind = VAR_CONST;
+
+    V_VT(&v) = VT_INT;
+    V_INT(&v) = 1;
+    U(desc).lpvarValue = &v;
+    hr = ICreateTypeInfo_AddVarDesc(cti, 0, &desc);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarHelpContext(cti, 0, 0);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    /* another time */
+    hr = ICreateTypeInfo_SetVarHelpContext(cti, 0, 1);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    /* wrong index now */
+    hr = ICreateTypeInfo_SetVarHelpContext(cti, 1, 0);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr);
+
+    ICreateTypeInfo_Release(cti);
+    ICreateTypeLib2_Release(ctl);
+    DeleteFileA(filenameA);
+}
+
+static void test_SetFuncAndParamNames(void)
+{
+    static OLECHAR nameW[] = {'n','a','m','e',0};
+    static OLECHAR prop[] = {'p','r','o','p',0};
+    static OLECHAR *propW[] = {prop};
+    CHAR filenameA[MAX_PATH];
+    WCHAR filenameW[MAX_PATH];
+    ICreateTypeLib2 *ctl;
+    ICreateTypeInfo *cti;
+    FUNCDESC funcdesc;
+    ELEMDESC edesc;
+    HRESULT hr;
+
+    GetTempFileNameA(".", "tlb", 0, filenameA);
+    MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filenameW, MAX_PATH);
+
+    hr = CreateTypeLib2(SYS_WIN32, filenameW, &ctl);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeLib2_CreateTypeInfo(ctl, nameW, TKIND_DISPATCH, &cti);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    /* get method */
+    memset(&funcdesc, 0, sizeof(FUNCDESC));
+    funcdesc.funckind = FUNC_DISPATCH;
+    funcdesc.callconv = CC_STDCALL;
+    funcdesc.elemdescFunc.tdesc.vt = VT_VOID;
+    funcdesc.wFuncFlags = FUNCFLAG_FBINDABLE;
+
+    /* put method */
+    memset(&edesc, 0, sizeof(edesc));
+    edesc.tdesc.vt = VT_BSTR;
+    U(edesc).idldesc.dwReserved = 0;
+    U(edesc).idldesc.wIDLFlags = IDLFLAG_FIN;
+
+    funcdesc.lprgelemdescParam = &edesc;
+    funcdesc.invkind = INVOKE_PROPERTYPUT;
+    funcdesc.cParams = 1;
+
+    hr = ICreateTypeInfo_AddFuncDesc(cti, 0, &funcdesc);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* setter name */
+    hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 0, propW, 1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* putref method */
+    funcdesc.invkind = INVOKE_PROPERTYPUTREF;
+    hr = ICreateTypeInfo_AddFuncDesc(cti, 1, &funcdesc);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* putref name */
+    hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 1, propW, 1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    funcdesc.invkind = INVOKE_PROPERTYGET;
+    funcdesc.cParams = 0;
+    hr = ICreateTypeInfo_AddFuncDesc(cti, 2, &funcdesc);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* getter name */
+    hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 2, propW, 1);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ICreateTypeInfo_Release(cti);
+    ICreateTypeLib2_Release(ctl);
+    DeleteFileA(filenameA);
+}
+
+static void test_SetVarDocString(void)
+{
+    static OLECHAR nameW[] = {'n','a','m','e',0};
+    static OLECHAR doc1W[] = {'d','o','c','1',0};
+    static OLECHAR doc2W[] = {'d','o','c','2',0};
+    CHAR filenameA[MAX_PATH];
+    WCHAR filenameW[MAX_PATH];
+    ICreateTypeLib2 *ctl;
+    ICreateTypeInfo *cti;
+    VARDESC desc;
+    HRESULT hr;
+    VARIANT v;
+
+    GetTempFileNameA(".", "tlb", 0, filenameA);
+    MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filenameW, MAX_PATH);
+
+    hr = CreateTypeLib2(SYS_WIN32, filenameW, &ctl);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeLib2_CreateTypeInfo(ctl, nameW, TKIND_ENUM, &cti);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarDocString(cti, 0, doc1W);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarDocString(cti, 0, NULL);
+    ok(hr == E_INVALIDARG, "got %08x\n", hr);
+
+    memset(&desc, 0, sizeof(desc));
+    desc.elemdescVar.tdesc.vt = VT_INT;
+    desc.varkind = VAR_CONST;
+
+    V_VT(&v) = VT_INT;
+    V_INT(&v) = 1;
+    U(desc).lpvarValue = &v;
+    hr = ICreateTypeInfo_AddVarDesc(cti, 0, &desc);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarDocString(cti, 0, NULL);
+    ok(hr == E_INVALIDARG, "got %08x\n", hr);
+
+    hr = ICreateTypeInfo_SetVarDocString(cti, 0, doc1W);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    /* already set */
+    hr = ICreateTypeInfo_SetVarDocString(cti, 0, doc2W);
+    ok(hr == S_OK, "got %08x\n", hr);
+
+    /* wrong index now */
+    hr = ICreateTypeInfo_SetVarDocString(cti, 1, doc1W);
+    ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr);
+
+    ICreateTypeInfo_Release(cti);
+    ICreateTypeLib2_Release(ctl);
+    DeleteFileA(filenameA);
+}
+
+static void test_FindName(void)
+{
+    static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
+    WCHAR buffW[100];
+    MEMBERID memid;
+    ITypeInfo *ti;
+    ITypeLib *tl;
+    HRESULT hr;
+    UINT16 c;
+
+    hr = LoadTypeLib(wszStdOle2, &tl);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = ITypeLib_FindName(tl, NULL, 0, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    lstrcpyW(buffW, wszGUID);
+    hr = ITypeLib_FindName(tl, buffW, 0, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    c = 0;
+    ti = (void*)0xdeadbeef;
+    hr = ITypeLib_FindName(tl, buffW, 0, &ti, NULL, &c);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(c == 0, "got %d\n", c);
+    ok(ti == (void*)0xdeadbeef, "got %p\n", ti);
+
+    c = 1;
+    ti = (void*)0xdeadbeef;
+    hr = ITypeLib_FindName(tl, buffW, 0, &ti, NULL, &c);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    ok(c == 1, "got %d\n", c);
+    ok(ti == (void*)0xdeadbeef, "got %p\n", ti);
+
+    c = 1;
+    memid = 0;
+    ti = (void*)0xdeadbeef;
+    hr = ITypeLib_FindName(tl, buffW, 0, &ti, &memid, &c);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+todo_wine
+    ok(memid == -1, "got %d\n", memid);
+    ok(!lstrcmpW(buffW, wszGUID), "got %s\n", wine_dbgstr_w(buffW));
+    ok(c == 1, "got %d\n", c);
+    ITypeInfo_Release(ti);
+
+    c = 1;
+    memid = 0;
+    lstrcpyW(buffW, wszguid);
+    ti = (void*)0xdeadbeef;
+    hr = ITypeLib_FindName(tl, buffW, 0, &ti, &memid, &c);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+todo_wine {
+    ok(memid == -1, "got %d\n", memid);
+    ok(!lstrcmpW(buffW, wszGUID), "got %s\n", wine_dbgstr_w(buffW));
+    ok(c == 1, "got %d\n", c);
+}
+    if (c == 1)
+        ITypeInfo_Release(ti);
+
+    c = 1;
+    memid = -1;
+    lstrcpyW(buffW, invalidW);
+    ti = (void*)0xdeadbeef;
+    hr = ITypeLib_FindName(tl, buffW, 0, &ti, &memid, &c);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(memid == -1, "got %d\n", memid);
+    ok(!lstrcmpW(buffW, invalidW), "got %s\n", wine_dbgstr_w(buffW));
+    ok(c == 0, "got %d\n", c);
+    ok(ti == (void*)0xdeadbeef, "got %p\n", ti);
+
+    ITypeLib_Release(tl);
+}
+
 START_TEST(typelib)
 {
     const char *filename;
@@ -2323,9 +3195,16 @@ START_TEST(typelib)
     test_TypeComp();
     test_CreateDispTypeInfo();
     test_TypeInfo();
-    test_QueryPathOfRegTypeLib();
+    test_DispCallFunc();
+    test_QueryPathOfRegTypeLib(32);
+    if(sizeof(void*) == 8)
+        test_QueryPathOfRegTypeLib(64);
     test_inheritance();
     test_CreateTypeLib();
+    test_SetVarHelpContext();
+    test_SetFuncAndParamNames();
+    test_SetVarDocString();
+    test_FindName();
 
     if ((filename = create_test_typelib(2)))
     {
@@ -2336,5 +3215,5 @@ START_TEST(typelib)
     test_register_typelib(TRUE);
     test_register_typelib(FALSE);
     test_create_typelibs();
-
+    test_LoadTypeLib();
 }
index 9275837..4f7b843 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #define COBJMACROS
+#define CONST_VTABLE
 
 #include <stdarg.h>
 
 # define V_U2(A)  (*(A))
 #endif
 
-#define LPSAFEARRAY_UNMARSHAL_WORKS 1
-#define BSTR_UNMARSHAL_WORKS 1
-#define VARIANT_UNMARSHAL_WORKS 1
+static HRESULT (WINAPI *pSafeArrayGetIID)(SAFEARRAY*,GUID*);
+static HRESULT (WINAPI *pSafeArrayGetVartype)(SAFEARRAY*,VARTYPE*);
+static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG);
 
 static inline SF_TYPE get_union_type(SAFEARRAY *psa)
 {
     VARTYPE vt;
     HRESULT hr;
 
-    hr = SafeArrayGetVartype(psa, &vt);
+    hr = pSafeArrayGetVartype(psa, &vt);
     if (FAILED(hr))
     {
         if(psa->fFeatures & FADF_VARIANT) return SF_VARIANT;
@@ -120,9 +121,11 @@ static DWORD elem_wire_size(LPSAFEARRAY lpsa, SF_TYPE sftype)
 static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
 {
     unsigned char *wiresa = buffer;
+    const SAFEARRAYBOUND *bounds;
     VARTYPE vt;
     SF_TYPE sftype;
     ULONG cell_count;
+    int i;
 
     if(!lpsa)
     {
@@ -130,7 +133,10 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
         return;
     }
 
-    if(FAILED(SafeArrayGetVartype(lpsa, &vt)))
+    if (!pSafeArrayGetVartype || !pSafeArrayGetIID)
+        return;
+
+    if(FAILED(pSafeArrayGetVartype(lpsa, &vt)))
         vt = 0;
 
     sftype = get_union_type(lpsa);
@@ -159,11 +165,22 @@ static void check_safearray(void *buffer, LPSAFEARRAY lpsa)
     if(sftype == SF_HAVEIID)
     {
         GUID guid;
-        SafeArrayGetIID(lpsa, &guid);
+        pSafeArrayGetIID(lpsa, &guid);
         ok(IsEqualGUID(&guid, wiresa), "guid mismatch\n");
         wiresa += sizeof(GUID);
     }
-    ok(!memcmp(wiresa, lpsa->rgsabound, sizeof(lpsa->rgsabound[0]) * lpsa->cDims), "bounds mismatch\n");
+
+    /* bounds are marshaled in natural dimensions order */
+    bounds = (SAFEARRAYBOUND*)wiresa;
+    for(i=0; i<lpsa->cDims; i++)
+    {
+        ok(memcmp(bounds, &lpsa->rgsabound[lpsa->cDims-i-1], sizeof(SAFEARRAYBOUND)) == 0,
+           "bounds mismatch for dimension %d, got (%d,%d), expected (%d,%d)\n", i,
+            bounds->lLbound, bounds->cElements, lpsa->rgsabound[lpsa->cDims-i-1].lLbound,
+            lpsa->rgsabound[lpsa->cDims-i-1].cElements);
+        bounds++;
+    }
+
     wiresa += sizeof(lpsa->rgsabound[0]) * lpsa->cDims;
 
     ok(*(DWORD *)wiresa == cell_count, "wiresa + 0x28 should be %u instead of %u\n", cell_count, *(DWORD*)wiresa);
@@ -209,57 +226,105 @@ static void test_marshal_LPSAFEARRAY(void)
     ULONG size, expected;
     LPSAFEARRAY lpsa;
     LPSAFEARRAY lpsa2 = NULL;
-    SAFEARRAYBOUND sab;
+    SAFEARRAYBOUND sab[2];
     RPC_MESSAGE rpc_msg;
     MIDL_STUB_MESSAGE stub_msg;
     USER_MARSHAL_CB umcb;
     HRESULT hr;
-    VARTYPE vt;
+    VARTYPE vt, vt2;
     OLECHAR *values[10];
     int expected_bstr_size;
     int i;
     LONG indices[1];
 
-    sab.lLbound = 5;
-    sab.cElements = 10;
+    sab[0].lLbound = 5;
+    sab[0].cElements = 10;
 
-    lpsa = SafeArrayCreate(VT_I2, 1, &sab);
+    lpsa = SafeArrayCreate(VT_I2, 1, sab);
     *(DWORD *)lpsa->pvData = 0xcafebabe;
 
     lpsa->cLocks = 7;
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
     expected = (44 + 1 + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1);
-    expected += sab.cElements * sizeof(USHORT);
+    expected += sab[0].cElements * sizeof(USHORT);
+    ok(size == expected || size == expected + 12, /* win64 */
+       "size should be %u bytes, not %u\n", expected, size);
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
+    expected = 44 + sab[0].cElements * sizeof(USHORT);
+    ok(size == expected || size == expected + 12, /* win64 */
+       "size should be %u bytes, not %u\n", expected, size);
+    buffer = HeapAlloc(GetProcessHeap(), 0, size);
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
+    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
+    ok(lpsa->cLocks == 7, "got lock count %u\n", lpsa->cLocks);
+
+    check_safearray(buffer, lpsa);
+
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
+    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
+    if (pSafeArrayGetVartype)
+    {
+        pSafeArrayGetVartype(lpsa, &vt);
+        pSafeArrayGetVartype(lpsa2, &vt2);
+        ok(vt == vt2, "vts differ %x %x\n", vt, vt2);
+    }
+    ok(lpsa2->cLocks == 0, "got lock count %u, expected 0\n", lpsa2->cLocks);
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
+    HeapFree(GetProcessHeap(), 0, buffer);
+    lpsa->cLocks = 0;
+    hr = SafeArrayDestroy(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    /* use two dimensions */
+    sab[0].lLbound = 5;
+    sab[0].cElements = 10;
+    sab[1].lLbound = 1;
+    sab[1].cElements = 2;
+
+    lpsa = SafeArrayCreate(VT_I2, 2, sab);
+    *(DWORD *)lpsa->pvData = 0xcafebabe;
+
+    lpsa->cLocks = 7;
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
+    expected = (44 + 1 + +sizeof(SAFEARRAYBOUND) + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1);
+    expected += max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT);
     ok(size == expected || size == expected + 12, /* win64 */
        "size should be %u bytes, not %u\n", expected, size);
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
-    expected = 44 + sab.cElements * sizeof(USHORT);
+    expected = 52 + max(sab[0].cElements, sab[1].cElements) * lpsa->cDims * sizeof(USHORT);
     ok(size == expected || size == expected + 12, /* win64 */
        "size should be %u bytes, not %u\n", expected, size);
     buffer = HeapAlloc(GetProcessHeap(), 0, size);
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
     next = LPSAFEARRAY_UserMarshal(&umcb.Flags, buffer, &lpsa);
     ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
+    ok(lpsa->cLocks == 7, "got lock count %u\n", lpsa->cLocks);
 
     check_safearray(buffer, lpsa);
 
-    if (LPSAFEARRAY_UNMARSHAL_WORKS)
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
+    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
+    if (pSafeArrayGetVartype)
     {
-        VARTYPE vt, vt2;
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
-        ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal\n");
-        SafeArrayGetVartype(lpsa, &vt);
-        SafeArrayGetVartype(lpsa2, &vt2);
+        pSafeArrayGetVartype(lpsa, &vt);
+        pSafeArrayGetVartype(lpsa2, &vt2);
         ok(vt == vt2, "vts differ %x %x\n", vt, vt2);
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
     }
+    ok(lpsa2->cLocks == 0, "got lock count %u, expected 0\n", lpsa2->cLocks);
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
     HeapFree(GetProcessHeap(), 0, buffer);
     lpsa->cLocks = 0;
-    SafeArrayDestroy(lpsa);
+    hr = SafeArrayDestroy(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
     /* test NULL safe array */
     lpsa = NULL;
@@ -274,32 +339,29 @@ static void test_marshal_LPSAFEARRAY(void)
     ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
     check_safearray(buffer, lpsa);
 
-    if (LPSAFEARRAY_UNMARSHAL_WORKS)
-    {
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
-        ok(lpsa2 == NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
-    }
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
+    ok(lpsa2 == NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
     HeapFree(GetProcessHeap(), 0, buffer);
 
-    sab.lLbound = 5;
-    sab.cElements = 10;
+    sab[0].lLbound = 5;
+    sab[0].cElements = 10;
 
-    lpsa = SafeArrayCreate(VT_R8, 1, &sab);
+    lpsa = SafeArrayCreate(VT_R8, 1, sab);
     *(double *)lpsa->pvData = 3.1415;
 
     lpsa->cLocks = 7;
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
     expected = (44 + 1 + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
-    expected += sab.cElements * sizeof(double);
+    expected += sab[0].cElements * sizeof(double);
     ok(size == expected || size == expected + 16, /* win64 */
        "size should be %u bytes, not %u\n", expected, size);
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     expected = (44 + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
-    expected += sab.cElements * sizeof(double);
+    expected += sab[0].cElements * sizeof(double);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
     ok(size == expected || size == expected + 8, /* win64 */
        "size should be %u bytes, not %u\n", expected, size);
@@ -313,7 +375,8 @@ static void test_marshal_LPSAFEARRAY(void)
 
     HeapFree(GetProcessHeap(), 0, buffer);
     lpsa->cLocks = 0;
-    SafeArrayDestroy(lpsa);
+    hr = SafeArrayDestroy(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
     /* VARTYPE-less arrays can be marshaled if cbElements is 1,2,4 or 8 as type SF_In */
     hr = SafeArrayAllocDescriptor(1, &lpsa);
@@ -324,8 +387,11 @@ static void test_marshal_LPSAFEARRAY(void)
     hr = SafeArrayAllocData(lpsa);
     ok(hr == S_OK, "saad failed %08x\n", hr);
 
-    hr = SafeArrayGetVartype(lpsa, &vt);
-    ok(hr == E_INVALIDARG, "ret %08x\n", hr);
+    if (pSafeArrayGetVartype)
+    {
+        hr = pSafeArrayGetVartype(lpsa, &vt);
+        ok(hr == E_INVALIDARG, "ret %08x\n", hr);
+    }
 
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
@@ -340,23 +406,25 @@ static void test_marshal_LPSAFEARRAY(void)
             "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
     check_safearray(buffer, lpsa);
     HeapFree(GetProcessHeap(), 0, buffer);
-    SafeArrayDestroyData(lpsa);
-    SafeArrayDestroyDescriptor(lpsa);
+    hr = SafeArrayDestroyData(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = SafeArrayDestroyDescriptor(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
     /* Test an array of VT_BSTR */
-    sab.lLbound = 3;
-    sab.cElements = sizeof(values) / sizeof(values[0]);
+    sab[0].lLbound = 3;
+    sab[0].cElements = sizeof(values) / sizeof(values[0]);
 
-    lpsa = SafeArrayCreate(VT_BSTR, 1, &sab);
+    lpsa = SafeArrayCreate(VT_BSTR, 1, sab);
     expected_bstr_size = 0;
-    for (i = 0; i < sab.cElements; i++)
+    for (i = 0; i < sab[0].cElements; i++)
     {
         int j;
         WCHAR buf[128];
         for (j = 0; j <= i; j++)
             buf[j] = 'a' + j;
         buf[j] = 0;
-        indices[0] = i + sab.lLbound;
+        indices[0] = i + sab[0].lLbound;
         values[i] = SysAllocString(buf);
         hr = SafeArrayPutElement(lpsa, indices, values[i]);
         ok(hr == S_OK, "Failed to put bstr element hr 0x%x\n", hr);
@@ -367,7 +435,7 @@ static void test_marshal_LPSAFEARRAY(void)
 
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 1, &lpsa);
-    expected = 44 + (sab.cElements * sizeof(DWORD)) + expected_bstr_size;
+    expected = 44 + (sab[0].cElements * sizeof(DWORD)) + expected_bstr_size;
     todo_wine
     ok(size == expected + sizeof(DWORD) || size  == (expected + sizeof(DWORD) + 12 /* win64 */),
             "size should be %u bytes, not %u\n", expected + (ULONG) sizeof(DWORD), size);
@@ -386,14 +454,11 @@ static void test_marshal_LPSAFEARRAY(void)
     check_safearray(buffer, lpsa);
 
     lpsa2 = NULL;
-    if (LPSAFEARRAY_UNMARSHAL_WORKS)
-    {
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        next = LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
-        todo_wine
-        ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
-        ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal, result %p\n", next);
-    }
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = LPSAFEARRAY_UserUnmarshal(&umcb.Flags, buffer, &lpsa2);
+    todo_wine
+    ok(next - buffer == expected, "Marshaled %u bytes, expected %u\n", (ULONG) (next - buffer), expected);
+    ok(lpsa2 != NULL, "LPSAFEARRAY didn't unmarshal, result %p\n", next);
 
     for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
     {
@@ -401,12 +466,13 @@ static void test_marshal_LPSAFEARRAY(void)
 
         if (lpsa2)
         {
-            indices[0] = i + sab.lLbound;
+            indices[0] = i + sab[0].lLbound;
             hr = SafeArrayGetElement(lpsa2, indices, &gotvalue);
             ok(hr == S_OK, "Failed to get bstr element at hres 0x%x\n", hr);
             if (hr == S_OK)
             {
-                ok(VarBstrCmp(values[i], gotvalue, 0, 0) == VARCMP_EQ, "String %d does not match\n", i);
+                if (pVarBstrCmp)
+                    ok(pVarBstrCmp(values[i], gotvalue, 0, 0) == VARCMP_EQ, "String %d does not match\n", i);
                 SysFreeString(gotvalue);
             }
         }
@@ -414,15 +480,12 @@ static void test_marshal_LPSAFEARRAY(void)
         SysFreeString(values[i]);
     }
 
-    if (LPSAFEARRAY_UNMARSHAL_WORKS)
-    {
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
-    }
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    LPSAFEARRAY_UserFree(&umcb.Flags, &lpsa2);
 
     HeapFree(GetProcessHeap(), 0, buffer);
-    SafeArrayDestroy(lpsa);
-
+    hr = SafeArrayDestroy(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
     /* VARTYPE-less arrays with FADF_VARIANT */
     hr = SafeArrayAllocDescriptor(1, &lpsa);
@@ -434,8 +497,11 @@ static void test_marshal_LPSAFEARRAY(void)
     hr = SafeArrayAllocData(lpsa);
     ok(hr == S_OK, "saad failed %08x\n", hr);
 
-    hr = SafeArrayGetVartype(lpsa, &vt);
-    ok(hr == E_INVALIDARG, "ret %08x\n", hr);
+    if (pSafeArrayGetVartype)
+    {
+        hr = pSafeArrayGetVartype(lpsa, &vt);
+        ok(hr == E_INVALIDARG, "ret %08x\n", hr);
+    }
 
     init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
     size = LPSAFEARRAY_UserSize(&umcb.Flags, 0, &lpsa);
@@ -452,8 +518,10 @@ static void test_marshal_LPSAFEARRAY(void)
     lpsa->cbElements = 16;  /* VARIANT wire size */
     check_safearray(buffer, lpsa);
     HeapFree(GetProcessHeap(), 0, buffer);
-    SafeArrayDestroyData(lpsa);
-    SafeArrayDestroyDescriptor(lpsa);
+    hr = SafeArrayDestroyData(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    hr = SafeArrayDestroyDescriptor(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 }
 
 static void check_bstr(void *buffer, BSTR b)
@@ -508,17 +576,14 @@ static void test_marshal_BSTR(void)
     ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
     check_bstr(buffer, b);
 
-    if (BSTR_UNMARSHAL_WORKS)
-    {
-        b2 = NULL;
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
-        ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
-        ok(b2 != NULL, "BSTR didn't unmarshal\n");
-        ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n");
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        BSTR_UserFree(&umcb.Flags, &b2);
-    }
+    b2 = NULL;
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
+    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
+    ok(b2 != NULL, "BSTR didn't unmarshal\n");
+    ok(!memcmp(b, b2, (len + 1) * 2), "strings differ\n");
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    BSTR_UserFree(&umcb.Flags, &b2);
 
     HeapFree(GetProcessHeap(), 0, buffer);
     SysFreeString(b);
@@ -534,16 +599,13 @@ static void test_marshal_BSTR(void)
     ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
 
     check_bstr(buffer, b);
-    if (BSTR_UNMARSHAL_WORKS)
-    {
-        b2 = NULL;
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
-        ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
-        ok(b2 == NULL, "NULL BSTR didn't unmarshal\n");
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        BSTR_UserFree(&umcb.Flags, &b2);
-    }
+    b2 = NULL;
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
+    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
+    ok(b2 == NULL, "NULL BSTR didn't unmarshal\n");
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    BSTR_UserFree(&umcb.Flags, &b2);
     HeapFree(GetProcessHeap(), 0, buffer);
 
     b = SysAllocStringByteLen("abc", 3);
@@ -565,17 +627,14 @@ static void test_marshal_BSTR(void)
     check_bstr(buffer, b);
     ok(buffer[15] == 'd', "buffer[15] %02x\n", buffer[15]);
 
-    if (BSTR_UNMARSHAL_WORKS)
-    {
-        b2 = NULL;
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
-        ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
-        ok(b2 != NULL, "BSTR didn't unmarshal\n");
-        ok(!memcmp(b, b2, len), "strings differ\n");
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        BSTR_UserFree(&umcb.Flags, &b2);
-    }
+    b2 = NULL;
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
+    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
+    ok(b2 != NULL, "BSTR didn't unmarshal\n");
+    ok(!memcmp(b, b2, len), "strings differ\n");
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    BSTR_UserFree(&umcb.Flags, &b2);
     HeapFree(GetProcessHeap(), 0, buffer);
     SysFreeString(b);
 
@@ -595,28 +654,30 @@ static void test_marshal_BSTR(void)
     ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
     check_bstr(buffer, b);
 
-    if (BSTR_UNMARSHAL_WORKS)
-    {
-        b2 = NULL;
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
-        next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
-        ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
-        ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
-        len = SysStringByteLen(b2);
-        ok(len == 0, "byte len %d\n", len);
-        init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
-        BSTR_UserFree(&umcb.Flags, &b2);
-    }
+    b2 = NULL;
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, MSHCTX_DIFFERENTMACHINE);
+    next = BSTR_UserUnmarshal(&umcb.Flags, buffer, &b2);
+    ok(next == buffer + size, "got %p expect %p\n", next, buffer + size);
+    ok(b2 != NULL, "NULL LPSAFEARRAY didn't unmarshal\n");
+    len = SysStringByteLen(b2);
+    ok(len == 0, "byte len %d\n", len);
+    init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_DIFFERENTMACHINE);
+    BSTR_UserFree(&umcb.Flags, &b2);
     HeapFree(GetProcessHeap(), 0, buffer);
     SysFreeString(b);
 }
 
 typedef struct
 {
-    const IUnknownVtbl *lpVtbl;
+    IUnknown IUnknown_iface;
     ULONG refs;
 } HeapUnknown;
 
+static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
+}
+
 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
 {
     if (IsEqualIID(riid, &IID_IUnknown))
@@ -631,13 +692,13 @@ static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, v
 
 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
 {
-    HeapUnknown *This = (HeapUnknown *)iface;
+    HeapUnknown *This = impl_from_IUnknown(iface);
     return InterlockedIncrement((LONG*)&This->refs);
 }
 
 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
 {
-    HeapUnknown *This = (HeapUnknown *)iface;
+    HeapUnknown *This = impl_from_IUnknown(iface);
     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
     if (!refs) HeapFree(GetProcessHeap(), 0, This);
     return refs;
@@ -686,7 +747,7 @@ static void *alloc_aligned(SIZE_T size, void **buf)
 
 static void test_marshal_VARIANT(void)
 {
-    VARIANT v, v2;
+    VARIANT v, v2, v3;
     MIDL_STUB_MESSAGE stubMsg = { 0 };
     RPC_MESSAGE rpcMsg = { 0 };
     USER_MARSHAL_CB umcb = { 0 };
@@ -695,6 +756,7 @@ static void test_marshal_VARIANT(void)
     ULONG ul;
     short s;
     double d;
+    void *mem;
     DWORD *wirev;
     BSTR b;
     WCHAR str[] = {'m','a','r','s','h','a','l',' ','t','e','s','t',0};
@@ -703,6 +765,9 @@ static void test_marshal_VARIANT(void)
     DECIMAL dec, dec2;
     HeapUnknown *heap_unknown;
     DWORD expected;
+    HRESULT hr;
+    LONG bound, bound2;
+    VARTYPE vt, vt2;
 
     stubMsg.RpcMsg = &rpcMsg;
 
@@ -740,17 +805,14 @@ static void test_marshal_VARIANT(void)
     check_variant_header(wirev, &v, stubMsg.BufferLength);
     wirev += 5;
     ok(*(char*)wirev == V_I1(&v), "wv[5] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_I1(&v) == V_I1(&v2), "got i1 %x expect %x\n", V_I1(&v), V_I1(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_I1(&v) == V_I1(&v2), "got i1 %x expect %x\n", V_I1(&v), V_I1(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** I2 ***/
@@ -770,17 +832,14 @@ static void test_marshal_VARIANT(void)
     check_variant_header(wirev, &v, stubMsg.BufferLength);
     wirev += 5;
     ok(*(short*)wirev == V_I2(&v), "wv[5] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_I2(&v) == V_I2(&v2), "got i2 %x expect %x\n", V_I2(&v), V_I2(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_I2(&v) == V_I2(&v2), "got i2 %x expect %x\n", V_I2(&v), V_I2(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** I2 BYREF ***/
@@ -803,21 +862,17 @@ static void test_marshal_VARIANT(void)
     ok(*wirev == 0x4, "wv[5] %08x\n", *wirev);
     wirev++;
     ok(*(short*)wirev == s, "wv[6] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        void *mem;
-        VariantInit(&v2);
-        V_VT(&v2) = VT_I2 | VT_BYREF;
-        V_BYREF(&v2) = mem = CoTaskMemAlloc(sizeof(V_I2(&v2)));
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_BYREF(&v2) == mem, "didn't reuse existing memory\n");
-        ok(*V_I2REF(&v) == *V_I2REF(&v2), "got i2 ref %x expect ui4 ref %x\n", *V_I2REF(&v), *V_I2REF(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    V_VT(&v2) = VT_I2 | VT_BYREF;
+    V_BYREF(&v2) = mem = CoTaskMemAlloc(sizeof(V_I2(&v2)));
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_BYREF(&v2) == mem, "didn't reuse existing memory\n");
+    ok(*V_I2REF(&v) == *V_I2REF(&v2), "got i2 ref %x expect ui4 ref %x\n", *V_I2REF(&v), *V_I2REF(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** I4 ***/
@@ -838,17 +893,14 @@ static void test_marshal_VARIANT(void)
     wirev += 5;
     ok(*wirev == V_I4(&v), "wv[5] %08x\n", *wirev);
 
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_I4(&v) == V_I4(&v2), "got i4 %x expect %x\n", V_I4(&v), V_I4(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_I4(&v) == V_I4(&v2), "got i4 %x expect %x\n", V_I4(&v), V_I4(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** UI4 ***/
@@ -868,17 +920,14 @@ static void test_marshal_VARIANT(void)
     check_variant_header(wirev, &v, stubMsg.BufferLength);
     wirev += 5;
     ok(*wirev == 0x1234, "wv[5] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_UI4(&v) == V_UI4(&v2), "got ui4 %x expect %x\n", V_UI4(&v), V_UI4(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_UI4(&v) == V_UI4(&v2), "got ui4 %x expect %x\n", V_UI4(&v), V_UI4(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** UI4 BYREF ***/
@@ -902,17 +951,14 @@ static void test_marshal_VARIANT(void)
     wirev++;
     ok(*wirev == ul, "wv[6] %08x\n", *wirev);
 
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(*V_UI4REF(&v) == *V_UI4REF(&v2), "got ui4 ref %x expect ui4 ref %x\n", *V_UI4REF(&v), *V_UI4REF(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(*V_UI4REF(&v) == *V_UI4REF(&v2), "got ui4 ref %x expect ui4 ref %x\n", *V_UI4REF(&v), *V_UI4REF(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** R4 ***/
@@ -932,17 +978,14 @@ static void test_marshal_VARIANT(void)
     check_variant_header(wirev, &v, stubMsg.BufferLength);
     wirev += 5;
     ok(*(float*)wirev == V_R4(&v), "wv[5] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_R4(&v) == V_R4(&v2), "got r4 %f expect %f\n", V_R4(&v), V_R4(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_R4(&v) == V_R4(&v2), "got r4 %f expect %f\n", V_R4(&v), V_R4(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** R8 ***/
@@ -965,17 +1008,14 @@ static void test_marshal_VARIANT(void)
     ok(*wirev == 0xcccccccc, "wv[5] %08x\n", *wirev); /* pad */
     wirev++;
     ok(*(double*)wirev == V_R8(&v), "wv[6] %08x, wv[7] %08x\n", *wirev, *(wirev+1));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_R8(&v) == V_R8(&v2), "got r8 %f expect %f\n", V_R8(&v), V_R8(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_R8(&v) == V_R8(&v2), "got r8 %f expect %f\n", V_R8(&v), V_R8(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** R8 BYREF ***/
@@ -998,17 +1038,14 @@ static void test_marshal_VARIANT(void)
     ok(*wirev == 8, "wv[5] %08x\n", *wirev);
     wirev++;
     ok(*(double*)wirev == d, "wv[6] %08x wv[7] %08x\n", *wirev, *(wirev+1));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(*V_R8REF(&v) == *V_R8REF(&v2), "got r8 ref %f expect %f\n", *V_R8REF(&v), *V_R8REF(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(*V_R8REF(&v) == *V_R8REF(&v2), "got r8 ref %f expect %f\n", *V_R8REF(&v), *V_R8REF(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** VARIANT_BOOL ***/
@@ -1028,17 +1065,14 @@ static void test_marshal_VARIANT(void)
     check_variant_header(wirev, &v, stubMsg.BufferLength);
     wirev += 5;
     ok(*(short*)wirev == V_BOOL(&v), "wv[5] %04x\n", *(WORD*)wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(V_BOOL(&v) == V_BOOL(&v2), "got bool %x expect %x\n", V_BOOL(&v), V_BOOL(&v2));
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(V_BOOL(&v) == V_BOOL(&v2), "got bool %x expect %x\n", V_BOOL(&v), V_BOOL(&v2));
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** DECIMAL ***/
@@ -1066,17 +1100,14 @@ static void test_marshal_VARIANT(void)
     dec2.wReserved = VT_DECIMAL;
     ok(!memcmp(wirev, &dec2, sizeof(dec2)), "wirev[6] %08x wirev[7] %08x wirev[8] %08x wirev[9] %08x\n",
        *wirev, *(wirev + 1), *(wirev + 2), *(wirev + 3));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(!memcmp(&V_DECIMAL(&v), & V_DECIMAL(&v2), sizeof(DECIMAL)), "decimals differ\n");
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(!memcmp(&V_DECIMAL(&v), & V_DECIMAL(&v2), sizeof(DECIMAL)), "decimals differ\n");
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** DECIMAL BYREF ***/
@@ -1098,24 +1129,21 @@ static void test_marshal_VARIANT(void)
     ok(*wirev == 16, "wv[5] %08x\n", *wirev);
     wirev++;
     ok(!memcmp(wirev, &dec, sizeof(dec)), "wirev[6] %08x wirev[7] %08x wirev[8] %08x wirev[9] %08x\n", *wirev, *(wirev + 1), *(wirev + 2), *(wirev + 3));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        /* check_variant_header tests wReserved[123], so initialize to unique values.
-         * (Could probably also do this by setting the variant to a known DECIMAL.)
-         */
-        V_U2(&v2).wReserved1 = 0x0123;
-        V_U2(&v2).wReserved2 = 0x4567;
-        V_U2(&v2).wReserved3 = 0x89ab;
-
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(!memcmp(V_DECIMALREF(&v), V_DECIMALREF(&v2), sizeof(DECIMAL)), "decimals differ\n");
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    /* check_variant_header tests wReserved[123], so initialize to unique values.
+     * (Could probably also do this by setting the variant to a known DECIMAL.)
+     */
+    V_U2(&v2).wReserved1 = 0x0123;
+    V_U2(&v2).wReserved2 = 0x4567;
+    V_U2(&v2).wReserved3 = 0x89ab;
+
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(!memcmp(V_DECIMALREF(&v), V_DECIMALREF(&v2), sizeof(DECIMAL)), "decimals differ\n");
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** EMPTY ***/
@@ -1132,16 +1160,13 @@ static void test_marshal_VARIANT(void)
     wirev = (DWORD*)buffer;
 
     check_variant_header(wirev, &v, stubMsg.BufferLength);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
 
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** NULL ***/
@@ -1158,16 +1183,13 @@ static void test_marshal_VARIANT(void)
     wirev = (DWORD*)buffer;
 
     check_variant_header(wirev, &v, stubMsg.BufferLength);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
 
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** BSTR ***/
@@ -1189,18 +1211,15 @@ static void test_marshal_VARIANT(void)
     ok(*wirev, "wv[5] %08x\n", *wirev); /* win2k: this is b. winxp: this is (char*)b + 1 */
     wirev++;
     check_bstr(wirev, V_BSTR(&v));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(SysStringByteLen(V_BSTR(&v)) == SysStringByteLen(V_BSTR(&v2)), "bstr string lens differ\n");
-        ok(!memcmp(V_BSTR(&v), V_BSTR(&v2), SysStringByteLen(V_BSTR(&v))), "bstrs differ\n");
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(SysStringByteLen(V_BSTR(&v)) == SysStringByteLen(V_BSTR(&v2)), "bstr string lens differ\n");
+    ok(!memcmp(V_BSTR(&v), V_BSTR(&v2), SysStringByteLen(V_BSTR(&v))), "bstrs differ\n");
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** BSTR BYREF ***/
@@ -1223,18 +1242,15 @@ static void test_marshal_VARIANT(void)
     ok(*wirev, "wv[6] %08x\n", *wirev); /* win2k: this is b. winxp: this is (char*)b + 1 */
     wirev++;
     check_bstr(wirev, b);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(SysStringByteLen(*V_BSTRREF(&v)) == SysStringByteLen(*V_BSTRREF(&v2)), "bstr string lens differ\n");
-        ok(!memcmp(*V_BSTRREF(&v), *V_BSTRREF(&v2), SysStringByteLen(*V_BSTRREF(&v))), "bstrs differ\n");
-
-        VARIANT_UserFree(&umcb.Flags, &v2);
-    }
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(SysStringByteLen(*V_BSTRREF(&v)) == SysStringByteLen(*V_BSTRREF(&v2)), "bstr string lens differ\n");
+    ok(!memcmp(*V_BSTRREF(&v), *V_BSTRREF(&v2), SysStringByteLen(*V_BSTRREF(&v))), "bstrs differ\n");
+
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
     SysFreeString(b);
 
@@ -1265,27 +1281,25 @@ static void test_marshal_VARIANT(void)
     ok(*wirev, "wv[5] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */
     wirev++;
     check_safearray(wirev, lpsa);
-    if (VARIANT_UNMARSHAL_WORKS)
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(SafeArrayGetDim(V_ARRAY(&v)) == SafeArrayGetDim(V_ARRAY(&v2)), "array dims differ\n");
+    SafeArrayGetLBound(V_ARRAY(&v), 1, &bound);
+    SafeArrayGetLBound(V_ARRAY(&v2), 1, &bound2);
+    ok(bound == bound2, "array lbounds differ\n");
+    SafeArrayGetUBound(V_ARRAY(&v), 1, &bound);
+    SafeArrayGetUBound(V_ARRAY(&v2), 1, &bound2);
+    ok(bound == bound2, "array ubounds differ\n");
+    if (pSafeArrayGetVartype)
     {
-        LONG bound, bound2;
-        VARTYPE vt, vt2;
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(SafeArrayGetDim(V_ARRAY(&v)) == SafeArrayGetDim(V_ARRAY(&v)), "array dims differ\n");  
-        SafeArrayGetLBound(V_ARRAY(&v), 1, &bound);
-        SafeArrayGetLBound(V_ARRAY(&v2), 1, &bound2);
-        ok(bound == bound2, "array lbounds differ\n");
-        SafeArrayGetUBound(V_ARRAY(&v), 1, &bound);
-        SafeArrayGetUBound(V_ARRAY(&v2), 1, &bound2);
-        ok(bound == bound2, "array ubounds differ\n");
-        SafeArrayGetVartype(V_ARRAY(&v), &vt);
-        SafeArrayGetVartype(V_ARRAY(&v2), &vt2);
+        pSafeArrayGetVartype(V_ARRAY(&v), &vt);
+        pSafeArrayGetVartype(V_ARRAY(&v2), &vt2);
         ok(vt == vt2, "array vts differ %x %x\n", vt, vt2);
-        VARIANT_UserFree(&umcb.Flags, &v2);
     }
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** ARRAY BYREF ***/
@@ -1310,29 +1324,28 @@ static void test_marshal_VARIANT(void)
     ok(*wirev, "wv[6] %08x\n", *wirev); /* win2k: this is lpsa. winxp: this is (char*)lpsa + 1 */
     wirev++;
     check_safearray(wirev, lpsa);
-    if (VARIANT_UNMARSHAL_WORKS)
+    VariantInit(&v2);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
+    ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
+    ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
+    ok(SafeArrayGetDim(*V_ARRAYREF(&v)) == SafeArrayGetDim(*V_ARRAYREF(&v2)), "array dims differ\n");
+    SafeArrayGetLBound(*V_ARRAYREF(&v), 1, &bound);
+    SafeArrayGetLBound(*V_ARRAYREF(&v2), 1, &bound2);
+    ok(bound == bound2, "array lbounds differ\n");
+    SafeArrayGetUBound(*V_ARRAYREF(&v), 1, &bound);
+    SafeArrayGetUBound(*V_ARRAYREF(&v2), 1, &bound2);
+    ok(bound == bound2, "array ubounds differ\n");
+    if (pSafeArrayGetVartype)
     {
-        LONG bound, bound2;
-        VARTYPE vt, vt2;
-        VariantInit(&v2);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v2);
-        ok(next == buffer + expected, "got %p expect %p\n", next, buffer + expected);
-        ok(V_VT(&v) == V_VT(&v2), "got vt %d expect %d\n", V_VT(&v), V_VT(&v2));
-        ok(SafeArrayGetDim(*V_ARRAYREF(&v)) == SafeArrayGetDim(*V_ARRAYREF(&v)), "array dims differ\n");  
-        SafeArrayGetLBound(*V_ARRAYREF(&v), 1, &bound);
-        SafeArrayGetLBound(*V_ARRAYREF(&v2), 1, &bound2);
-        ok(bound == bound2, "array lbounds differ\n");
-        SafeArrayGetUBound(*V_ARRAYREF(&v), 1, &bound);
-        SafeArrayGetUBound(*V_ARRAYREF(&v2), 1, &bound2);
-        ok(bound == bound2, "array ubounds differ\n");
-        SafeArrayGetVartype(*V_ARRAYREF(&v), &vt);
-        SafeArrayGetVartype(*V_ARRAYREF(&v2), &vt2);
+        pSafeArrayGetVartype(*V_ARRAYREF(&v), &vt);
+        pSafeArrayGetVartype(*V_ARRAYREF(&v2), &vt2);
         ok(vt == vt2, "array vts differ %x %x\n", vt, vt2);
-        VARIANT_UserFree(&umcb.Flags, &v2);
     }
+    VARIANT_UserFree(&umcb.Flags, &v2);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
-    SafeArrayDestroy(lpsa);
+    hr = SafeArrayDestroy(lpsa);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
     /*** VARIANT BYREF ***/
     VariantInit(&v);
@@ -1364,29 +1377,25 @@ static void test_marshal_VARIANT(void)
     ok(*wirev == 0xcccccccc, "wv[13] %08x\n", *wirev); /* pad for VT_R8 */
     wirev++;
     ok(*(double*)wirev == V_R8(&v2), "wv[6] %08x wv[7] %08x\n", *wirev, *(wirev+1));
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VARIANT v3;
-        VariantInit(&v3);
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
-        ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
-        ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
-        ok(V_VT(V_VARIANTREF(&v)) == V_VT(V_VARIANTREF(&v3)), "vts differ %x %x\n",
-           V_VT(V_VARIANTREF(&v)), V_VT(V_VARIANTREF(&v3))); 
-        ok(V_R8(V_VARIANTREF(&v)) == V_R8(V_VARIANTREF(&v3)), "r8s differ\n"); 
-        VARIANT_UserFree(&umcb.Flags, &v3);
-    }
+    VariantInit(&v3);
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
+    ok(next == buffer + stubMsg.BufferLength, "got %p expect %p\n", next, buffer + stubMsg.BufferLength);
+    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
+    ok(V_VT(V_VARIANTREF(&v)) == V_VT(V_VARIANTREF(&v3)), "vts differ %x %x\n",
+       V_VT(V_VARIANTREF(&v)), V_VT(V_VARIANTREF(&v3))); 
+    ok(V_R8(V_VARIANTREF(&v)) == V_R8(V_VARIANTREF(&v3)), "r8s differ\n"); 
+    VARIANT_UserFree(&umcb.Flags, &v3);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** UNKNOWN ***/
     heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown));
-    heap_unknown->lpVtbl = &HeapUnknown_Vtbl;
+    heap_unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
     heap_unknown->refs = 1;
     VariantInit(&v);
     VariantInit(&v2);
     V_VT(&v) = VT_UNKNOWN;
-    V_UNKNOWN(&v) = (IUnknown *)heap_unknown;
+    V_UNKNOWN(&v) = &heap_unknown->IUnknown_iface;
 
     rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
     ok(stubMsg.BufferLength > 32, "size %d\n", stubMsg.BufferLength);
@@ -1410,21 +1419,17 @@ static void test_marshal_VARIANT(void)
     wirev++;
     todo_wine
     ok(*wirev == 0x574f454d, "wv[8] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VARIANT v3;
-        VariantInit(&v3);
-        V_VT(&v3) = VT_UNKNOWN;
-        V_UNKNOWN(&v3) = (IUnknown *)heap_unknown;
-        IUnknown_AddRef(V_UNKNOWN(&v3));
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
-        ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
-        ok(V_UNKNOWN(&v) == V_UNKNOWN(&v3), "got %p expect %p\n", V_UNKNOWN(&v), V_UNKNOWN(&v3));
-        VARIANT_UserFree(&umcb.Flags, &v3);
-        ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
-        IUnknown_Release((IUnknown *)heap_unknown);
-    }
+    VariantInit(&v3);
+    V_VT(&v3) = VT_UNKNOWN;
+    V_UNKNOWN(&v3) = &heap_unknown->IUnknown_iface;
+    IUnknown_AddRef(V_UNKNOWN(&v3));
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
+    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
+    ok(V_UNKNOWN(&v) == V_UNKNOWN(&v3), "got %p expect %p\n", V_UNKNOWN(&v), V_UNKNOWN(&v3));
+    VARIANT_UserFree(&umcb.Flags, &v3);
+    ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
+    IUnknown_Release(&heap_unknown->IUnknown_iface);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 
     /*** NULL UNKNOWN ***/
@@ -1453,7 +1458,7 @@ static void test_marshal_VARIANT(void)
 
     /*** UNKNOWN BYREF ***/
     heap_unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*heap_unknown));
-    heap_unknown->lpVtbl = &HeapUnknown_Vtbl;
+    heap_unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
     heap_unknown->refs = 1;
     VariantInit(&v);
     VariantInit(&v2);
@@ -1484,27 +1489,34 @@ static void test_marshal_VARIANT(void)
     wirev++;
     todo_wine
     ok(*wirev == 0x574f454d, "wv[9] %08x\n", *wirev);
-    if (VARIANT_UNMARSHAL_WORKS)
-    {
-        VARIANT v3;
-        VariantInit(&v3);
-        V_VT(&v3) = VT_UNKNOWN;
-        V_UNKNOWN(&v3) = (IUnknown *)heap_unknown;
-        IUnknown_AddRef(V_UNKNOWN(&v3));
-        stubMsg.Buffer = buffer;
-        next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
-        ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
-        ok(*V_UNKNOWNREF(&v) == *V_UNKNOWNREF(&v3), "got %p expect %p\n", *V_UNKNOWNREF(&v), *V_UNKNOWNREF(&v3));
-        VARIANT_UserFree(&umcb.Flags, &v3);
-        ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
-        IUnknown_Release((IUnknown *)heap_unknown);
-    }
+
+    VariantInit(&v3);
+    V_VT(&v3) = VT_UNKNOWN;
+    V_UNKNOWN(&v3) = &heap_unknown->IUnknown_iface;
+    IUnknown_AddRef(V_UNKNOWN(&v3));
+    stubMsg.Buffer = buffer;
+    next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
+    ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
+    ok(*V_UNKNOWNREF(&v) == *V_UNKNOWNREF(&v3), "got %p expect %p\n", *V_UNKNOWNREF(&v), *V_UNKNOWNREF(&v3));
+    VARIANT_UserFree(&umcb.Flags, &v3);
+    ok(heap_unknown->refs == 1, "%d refcounts of IUnknown leaked\n", heap_unknown->refs - 1);
+    IUnknown_Release(&heap_unknown->IUnknown_iface);
     HeapFree(GetProcessHeap(), 0, oldbuffer);
 }
 
 
 START_TEST(usrmarshal)
 {
+    HANDLE hOleaut32 = GetModuleHandleA("oleaut32.dll");
+#define GETPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func)
+    GETPTR(SafeArrayGetIID);
+    GETPTR(SafeArrayGetVartype);
+    GETPTR(VarBstrCmp);
+#undef GETPTR
+
+    if (!pSafeArrayGetIID || !pSafeArrayGetVartype)
+        win_skip("SafeArrayGetIID and/or SafeArrayGetVartype is not available, some tests will be skipped\n");
+
     CoInitialize(NULL);
 
     test_marshal_LPSAFEARRAY();
index 2d4ef62..0354d19 100644 (file)
@@ -39,6 +39,7 @@
 
 static HMODULE hOleaut32;
 
+static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG);
 static HRESULT (WINAPI *pVarFormatNumber)(LPVARIANT,int,int,int,int,ULONG,BSTR*);
 static HRESULT (WINAPI *pVarFormat)(LPVARIANT,LPOLESTR,int,int,ULONG,BSTR*);
 static HRESULT (WINAPI *pVarWeekdayName)(int,int,int,ULONG,BSTR*);
@@ -51,7 +52,7 @@ static HRESULT (WINAPI *pVarWeekdayName)(int,int,int,ULONG,BSTR*);
 
 /* Get a conversion function ptr, return if function not available */
 #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \
-  if (!p##func) { trace("function " # func " not available, not testing it\n"); return; }
+  if (!p##func) { win_skip("function " # func " not available, not testing it\n"); return; }
 
 static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 )
 {
@@ -212,7 +213,17 @@ static const FMTDATERES VarFormat_date_results[] =
   { 2.525, "hh :mm:mm", "12 :36:01" },
   { 2.525, "dd :mm:mm", "01 :01:01" },
   { 2.525, "dd :mm:nn", "01 :01:36" },
-  { 2.725, "hh:nn:ss A/P", "05:24:00 P" }
+  { 2.725, "hh:nn:ss A/P", "05:24:00 P" },
+  { 40531.0, "dddd", "Sunday" },
+  { 40531.0, "ddd", "Sun" }
+};
+
+/* The following tests require that the time separator is a colon (:) */
+static const FMTDATERES VarFormat_namedtime_results[] =
+{
+  { 2.525, "short time", "12:36" },
+  { 2.525, "medium time", "12:36 PM" },
+  { 2.525, "long time", "12:36:00 PM" }
 };
 
 #define VNUMFMT(vt,v) \
@@ -245,7 +256,7 @@ static void test_VarFormat(void)
 
   if (PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID())) != LANG_ENGLISH)
   {
-    skip("Skipping VarFormat tests for non english language\n");
+    skip("Skipping VarFormat tests for non English language\n");
     return;
   }
   GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char));
@@ -299,6 +310,23 @@ static void test_VarFormat(void)
            VarFormat_date_results[i].res);
   }
 
+  /* Named time formats */
+  GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, buff, sizeof(buff)/sizeof(char));
+  if (strcmp(buff, "h:mm:ss tt"))
+  {
+    skip("Skipping named time tests as time format is '%s'\n", buff);
+  }
+  else
+  {
+    for (i = 0; i < sizeof(VarFormat_namedtime_results)/sizeof(FMTDATERES); i++)
+    {
+      fd = 0;
+      VARFMT(VT_DATE,V_DATE,VarFormat_namedtime_results[i].val,
+             VarFormat_namedtime_results[i].fmt,S_OK,
+             VarFormat_namedtime_results[i].res);
+    }
+  }
+
   /* Strings */
   bstrin = SysAllocString(szTesting);
   VARFMT(VT_BSTR,V_BSTR,bstrin,"",S_OK,"testing");
@@ -498,28 +526,30 @@ static void test_VarWeekdayName(void)
      "Null pointer: expected E_INVALIDARG, got 0x%08x\n", hres);
 
   /* Check all combinations */
-  for (iWeekday = 1; iWeekday <= 7; ++iWeekday)
-  {
-    for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev)
+  pVarBstrCmp = (void*)GetProcAddress(hOleaut32, "VarBstrCmp");
+  if (pVarBstrCmp)
+    for (iWeekday = 1; iWeekday <= 7; ++iWeekday)
     {
-      /* 0 = Default, 1 = Sunday, 2 = Monday, .. */
-      for (iFirstDay = 0; iFirstDay <= 7; ++iFirstDay)
+      for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev)
       {
-        VARWDN_O(iWeekday, fAbbrev, iFirstDay, 0);
-        if (iFirstDay == 0)
-          firstDay = defaultFirstDay;
-        else
-          /* Translate from 0=Sunday to 0=Monday in the modulo 7 space */
-          firstDay = iFirstDay - 2;
-        day = (7 + iWeekday - 1 + firstDay) % 7;
-        ok(VARCMP_EQ == VarBstrCmp(out, dayNames[day][fAbbrev],
-                                   LOCALE_USER_DEFAULT, 0),
-           "VarWeekdayName(%d,%d,%d): got wrong dayname: '%s'\n",
-           iWeekday, fAbbrev, iFirstDay, buff);
-        SysFreeString(out);
+        /* 0 = Default, 1 = Sunday, 2 = Monday, .. */
+        for (iFirstDay = 0; iFirstDay <= 7; ++iFirstDay)
+        {
+          VARWDN_O(iWeekday, fAbbrev, iFirstDay, 0);
+          if (iFirstDay == 0)
+            firstDay = defaultFirstDay;
+          else
+            /* Translate from 0=Sunday to 0=Monday in the modulo 7 space */
+            firstDay = iFirstDay - 2;
+          day = (7 + iWeekday - 1 + firstDay) % 7;
+          ok(VARCMP_EQ == pVarBstrCmp(out, dayNames[day][fAbbrev],
+                                      LOCALE_USER_DEFAULT, 0),
+             "VarWeekdayName(%d,%d,%d): got wrong dayname: '%s'\n",
+             iWeekday, fAbbrev, iFirstDay, buff);
+          SysFreeString(out);
+        }
       }
     }
-  }
 
   /* Cleanup */
   for (day = 0; day <= 6; ++day)
index 8203510..c7b46db 100644 (file)
@@ -24,6 +24,8 @@
 #include <math.h>
 #include <float.h>
 
+#define CONST_VTABLE
+
 #include "windef.h"
 #include "winbase.h"
 #include "winsock.h"
@@ -53,7 +55,7 @@ static WCHAR sz12_true[32];
 
 /* Get a conversion function ptr, return if function not available */
 #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \
-  if (!p##func) { trace("function " # func " not available, not testing it\n"); return; }
+  if (!p##func) { win_skip("function " # func " not available, not testing it\n"); return; }
 
 /* Have IRecordInfo data type? */
 static int HAVE_OLEAUT32_RECORD = 0;
@@ -104,7 +106,7 @@ static void init(void)
     HRESULT res;
 
     res = VarBstrFromBool(VARIANT_TRUE, LANG_USER_DEFAULT, VAR_LOCALBOOL, &bstr);
-    ok(SUCCEEDED(res) && (lstrlenW(bstr) > 0),
+    ok(res == S_OK && (lstrlenW(bstr) > 0),
         "Expected localized string for 'True'\n");
     /* lstrcpyW / lstrcatW do not work on win95 */
     memcpy(sz12_true, sz12, sizeof(sz12));
@@ -112,7 +114,7 @@ static void init(void)
     SysFreeString(bstr);
 
     res = VarBstrFromBool(VARIANT_FALSE, LANG_USER_DEFAULT, VAR_LOCALBOOL, &bstr);
-    ok(SUCCEEDED(res) && (lstrlenW(bstr) > 0),
+    ok(res == S_OK && (lstrlenW(bstr) > 0),
         "Expected localized string for 'False'\n");
     memcpy(sz12_false, sz12, sizeof(sz12));
     if (bstr) memcpy(&sz12_false[2], bstr, SysStringByteLen(bstr) + sizeof(WCHAR));
@@ -343,6 +345,20 @@ static void test_var_call2( int line, HRESULT (WINAPI *func)(LPVARIANT,LPVARIANT
     VariantClear( &result );
 }
 
+static int strcmp_wa(const WCHAR *strw, const char *stra)
+{
+    WCHAR buf[512];
+    MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(buf[0]));
+    return lstrcmpW(strw, buf);
+}
+
+#define test_bstr_var(a,b) _test_bstr_var(__LINE__,a,b)
+static void _test_bstr_var(unsigned line, const VARIANT *v, const char *str)
+{
+    ok_(__FILE__,line)(V_VT(v) == VT_BSTR, "unexpected vt=%d\n", V_VT(v));
+    if(V_VT(v) == VT_BSTR)
+        ok(!strcmp_wa(V_BSTR(v), str), "v=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), str);
+}
 
 static void test_VariantInit(void)
 {
@@ -399,26 +415,31 @@ static int IsValidVariantClearVT(VARTYPE vt, VARTYPE extraFlags)
 
 typedef struct
 {
-    const IUnknownVtbl *lpVtbl;
-    LONG               ref;
-    LONG               events;
+    IUnknown IUnknown_iface;
+    LONG     ref;
+    LONG     events;
 } test_VariantClearImpl;
 
+static inline test_VariantClearImpl *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, test_VariantClearImpl, IUnknown_iface);
+}
+
 static HRESULT WINAPI VC_QueryInterface(LPUNKNOWN iface,REFIID riid,LPVOID *ppobj)
 {
-    test_VariantClearImpl *This = (test_VariantClearImpl *)iface;
+    test_VariantClearImpl *This = impl_from_IUnknown(iface);
     This->events |= 0x1;
     return E_NOINTERFACE;
 }
 
 static ULONG WINAPI VC_AddRef(LPUNKNOWN iface) {
-    test_VariantClearImpl *This = (test_VariantClearImpl *)iface;
+    test_VariantClearImpl *This = impl_from_IUnknown(iface);
     This->events |= 0x2;
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI VC_Release(LPUNKNOWN iface) {
-    test_VariantClearImpl *This = (test_VariantClearImpl *)iface;
+    test_VariantClearImpl *This = impl_from_IUnknown(iface);
     /* static class, won't be  freed */
     This->events |= 0x4;
     return InterlockedDecrement(&This->ref);
@@ -430,7 +451,7 @@ static const IUnknownVtbl test_VariantClear_vtbl = {
     VC_Release,
 };
 
-static test_VariantClearImpl test_myVariantClearImpl = {&test_VariantClear_vtbl, 1, 0};
+static test_VariantClearImpl test_myVariantClearImpl = {{&test_VariantClear_vtbl}, 1, 0};
 
 static void test_VariantClear(void)
 {
@@ -442,7 +463,8 @@ static void test_VariantClear(void)
   IUnknown *punk;
 
   /* Crashes: Native does not test input for NULL, so neither does Wine */
-  if (0) hres = VariantClear(NULL);
+  if (0)
+      VariantClear(NULL);
 
   /* Only the type field is set, to VT_EMPTY */
   V_VT(&v) = VT_UI4;
@@ -509,17 +531,17 @@ static void test_VariantClear(void)
 
   /* UNKNOWN */
   V_VT(&v) = VT_UNKNOWN;
-  V_UNKNOWN(&v) = (IUnknown*)&test_myVariantClearImpl;
+  V_UNKNOWN(&v) = &test_myVariantClearImpl.IUnknown_iface;
   test_myVariantClearImpl.events = 0;
   hres = VariantClear(&v);
   ok(hres == S_OK, "ret %08x\n", hres);
   ok(V_VT(&v) == 0, "vt %04x\n", V_VT(&v));
-  ok(V_UNKNOWN(&v) == (IUnknown*)&test_myVariantClearImpl, "unknown %p\n", V_UNKNOWN(&v));
+  ok(V_UNKNOWN(&v) == &test_myVariantClearImpl.IUnknown_iface, "unknown %p\n", V_UNKNOWN(&v));
   /* Check that Release got called, but nothing else */
   ok(test_myVariantClearImpl.events ==  0x4, "Unexpected call. events %08x\n", test_myVariantClearImpl.events);
 
   /* UNKNOWN BYREF */
-  punk = (IUnknown*)&test_myVariantClearImpl;
+  punk = &test_myVariantClearImpl.IUnknown_iface;
   V_VT(&v) = VT_UNKNOWN | VT_BYREF;
   V_UNKNOWNREF(&v) = &punk;
   test_myVariantClearImpl.events = 0;
@@ -542,7 +564,7 @@ static void test_VariantClear(void)
   ok(test_myVariantClearImpl.events ==  0x4, "Unexpected call. events %08x\n", test_myVariantClearImpl.events);
 
   /* DISPATCH BYREF */
-  punk = (IUnknown*)&test_myVariantClearImpl;
+  punk = &test_myVariantClearImpl.IUnknown_iface;
   V_VT(&v) = VT_DISPATCH | VT_BYREF;
   V_DISPATCHREF(&v) = (IDispatch**)&punk;
   test_myVariantClearImpl.events = 0;
@@ -854,6 +876,7 @@ static void test_VariantCopyInd(void)
   VariantInit(&vDst);
 
   hres = VariantCopyInd(&vDst, &vSrc);
+  ok(hres == S_OK, "VariantCopyInd failed: 0x%08x\n", hres);
   ok(V_VT(&vDst) == VT_UI1 && V_UI1(&vDst) == 0x77,
      "CopyInd(deref): expected dst vt = VT_UI1, val 0x77, got %d|0x%X, 0x%2X\n",
       V_VT(&vDst) & VT_TYPEMASK, V_VT(&vDst) & ~VT_TYPEMASK, V_UI1(&vDst));
@@ -866,6 +889,7 @@ static void test_VariantCopyInd(void)
   VariantInit(&vDst);
 
   hres = VariantCopyInd(&vDst, &vSrc);
+  ok(hres == S_OK, "VariantCopyInd failed: 0x%08x\n", hres);
   ok(V_VT(&vDst) == VT_UI1 && V_UI1(&vDst) == 0x88,
      "CopyInd(deref): expected dst vt = VT_UI1, val 0x77, got %d|0x%X, 0x%2X\n",
       V_VT(&vDst) & VT_TYPEMASK, V_VT(&vDst) & ~VT_TYPEMASK, V_UI1(&vDst));
@@ -1575,15 +1599,13 @@ static void test_UdateFromDate( int line, DATE dt, ULONG flags, HRESULT r, WORD
 
     memset(&ud, 0, sizeof(ud));
     res = pVarUdateFromDate(dt, flags, &ud);
-    ok_(__FILE__,line)(r == res, "Wrong result %x/%x\n", r, res);
-    if (SUCCEEDED(res))
-        ok_(__FILE__,line)(ud.st.wYear == y && ud.st.wMonth == m && ud.st.wDay == d &&
-                           ud.st.wHour == h && ud.st.wMinute == mn && ud.st.wSecond == s &&
-                           ud.st.wMilliseconds == ms && ud.st.wDayOfWeek == dw && ud.wDayOfYear == dy,
-                           "%.16g expected %d,%d,%d,%d,%d,%d,%d  %d %d, got %d,%d,%d,%d,%d,%d,%d  %d %d\n",
-                           dt, d, m, y, h, mn, s, ms, dw, dy,
-                           ud.st.wDay, ud.st.wMonth, ud.st.wYear, ud.st.wHour, ud.st.wMinute,
-                           ud.st.wSecond, ud.st.wMilliseconds, ud.st.wDayOfWeek, ud.wDayOfYear );
+    ok_(__FILE__,line)(r == res && (res != S_OK || (ud.st.wYear == y && ud.st.wMonth == m && ud.st.wDay == d &&
+                       ud.st.wHour == h && ud.st.wMinute == mn && ud.st.wSecond == s &&
+                       ud.st.wMilliseconds == ms && ud.st.wDayOfWeek == dw && ud.wDayOfYear == dy)),
+                       "%.16g expected res(%x) %d,%d,%d,%d,%d,%d,%d  %d %d, got res(%x) %d,%d,%d,%d,%d,%d,%d  %d %d\n",
+                       dt, r, d, m, y, h, mn, s, ms, dw, dy,
+                       res, ud.st.wDay, ud.st.wMonth, ud.st.wYear, ud.st.wHour, ud.st.wMinute,
+                       ud.st.wSecond, ud.st.wMilliseconds, ud.st.wDayOfWeek, ud.wDayOfYear );
 }
 #define DT2UD(dt,flags,r,d,m,y,h,mn,s,ms,dw,dy) test_UdateFromDate(__LINE__,dt,flags,r,d,m,y,h,mn,s,ms,dw,dy)
 
@@ -1609,6 +1631,15 @@ static void test_VarUdateFromDate(void)
   DT2UD(29221.5,0,S_OK,1,1,1980,12,0,0,0,2,1);           /* 12 AM */
   DT2UD(29221.9888884444,0,S_OK,1,1,1980,23,44,0,0,2,1); /* 11:44 PM */
   DT2UD(29221.7508765432,0,S_OK,1,1,1980,18,1,16,0,2,1); /* 6:18:02 PM */
+
+  /* Test handling of times on dates prior to the epoch */
+  DT2UD(-5.25,0,S_OK,25,12,1899,6,0,0,0,1,359);
+  DT2UD(-5.9999884259259,0,S_OK,25,12,1899,23,59,59,0,1,359);
+  /* This just demonstrates the non-linear nature of values prior to the epoch */
+  DT2UD(-4.0,0,S_OK,26,12,1899,0,0,0,0,2,360);
+  /* Numerical oddity: for 0.0 < x < 1.0, x and -x represent the same datetime */
+  DT2UD(-0.25,0,S_OK,30,12,1899,6,0,0,0,6,364);
+  DT2UD(0.25,0,S_OK,30,12,1899,6,0,0,0,6,364);
 }
 
 
@@ -1629,7 +1660,7 @@ static void test_DateFromUDate( int line, WORD d, WORD m, WORD y, WORD h, WORD m
     ud.st.wDayOfWeek = dw;
     ud.wDayOfYear = dy;
     res = pVarDateFromUdate(&ud, flags, &out);
-    ok_(__FILE__,line)(r == res && (FAILED(r) || EQ_DOUBLE(out, dt)),
+    ok_(__FILE__,line)(r == res && (r != S_OK || EQ_DOUBLE(out, dt)),
                        "expected %x, %.16g, got %x, %.16g\n", r, dt, res, out);
 }
 #define UD2T(d,m,y,h,mn,s,ms,dw,dy,flags,r,dt) test_DateFromUDate(__LINE__,d,m,y,h,mn,s,ms,dw,dy,flags,r,dt)
@@ -1672,6 +1703,15 @@ static void test_VarDateFromUdate(void)
   UD2T(1,1,-1,18,1,16,0,0,0,0,S_OK,36161.75087962963);               /* Test year -1 = 1999 */
   UD2T(1,-1,1980,18,1,16,0,0,0,0,S_OK,29160.7508796296);             /* Test month -1 = 11 */
   UD2T(1,13,1980,0,0,0,0,2,1,0,S_OK,29587.0);                        /* Rolls fwd to 1/1/1981 */
+
+  /* Test handling of times on dates prior to the epoch */
+  UD2T(25,12,1899,6,0,0,0,1,359,0,S_OK,-5.25);
+  UD2T(25,12,1899,23,59,59,0,1,359,0,S_OK,-5.9999884259259);
+  /* This just demonstrates the non-linear nature of values prior to the epoch */
+  UD2T(26,12,1899,0,0,0,0,2,360,0,S_OK,-4.0);
+  /* for DATE values 0.0 < x < 1.0, x and -x represent the same datetime */
+  /* but when converting to DATE, prefer the positive versions */
+  UD2T(30,12,1899,6,0,0,0,6,364,0,S_OK,0.25);
 }
 
 static void test_st2dt(int line, WORD d, WORD m, WORD y, WORD h, WORD mn,
@@ -1702,7 +1742,10 @@ static void test_SystemTimeToVariantTime(void)
   ST2DT(2,1,1980,0,0,0,0,TRUE,29222.0);
   ST2DT(0,1,1980,0,0,0,0,TRUE,29220.0);   /* Rolls back to 31 Dec 1899 */
   ST2DT(1,13,1980,0,0,0,0,FALSE,29587.0); /* Fails on invalid month */
-  ST2DT(31,12,90,0,0,0,0,TRUE,33238.0);   /* year < 100 is 1900+year! */
+  ST2DT(31,12,90,0,0,0,0,TRUE,33238.0);   /* 30 <= year < 100 is 1900+year */
+  ST2DT(1,1,30,0,0,0,0,TRUE,10959.0);     /* 30 <= year < 100 is 1900+year */
+  ST2DT(1,1,29,0,0,0,0,TRUE,47119.0);     /* 0 <= year < 30 is 2000+year */
+  ST2DT(1,1,0,0,0,0,0,TRUE,36526.0);      /* 0 <= year < 30 is 2000+year */
 }
 
 static void test_dt2st(int line, double dt, INT r, WORD d, WORD m, WORD y,
@@ -1964,6 +2007,8 @@ static void test_VarNot(void)
 {
     static const WCHAR szNum0[] = {'0','\0' };
     static const WCHAR szNum1[] = {'1','\0' };
+    static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
+    static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
     HRESULT hres;
     VARIANT v, exp, vDst;
     DECIMAL *pdec = &V_DECIMAL(&v);
@@ -2059,6 +2104,8 @@ static void test_VarNot(void)
     ok(V_VT(&v) == VT_BSTR && V_BSTR(&v) == szNum0, "VarNot(0): changed input\n");
     VARNOT(BSTR,(BSTR)szNum1,I4,-2);
     ok(V_VT(&v) == VT_BSTR && V_BSTR(&v) == szNum1, "VarNot(1): changed input\n");
+    VARNOT(BSTR, (BSTR)szTrue, BOOL, VARIANT_FALSE);
+    VARNOT(BSTR, (BSTR)szFalse, BOOL, VARIANT_TRUE);
 
     V_VT(&v) = VT_DECIMAL;
     S(U(*pdec)).sign = DECIMAL_NEG;
@@ -2129,7 +2176,6 @@ static void test_VarSub(void)
                 if (rightvt == VT_BSTR)
                     V_BSTR(&right) = rbstr;
                 V_VT(&result) = VT_EMPTY;
-                resvt = VT_ERROR;
 
                 /* All extra flags produce errors */
                 if (ExtraFlags[i] == (VT_VECTOR|VT_BYREF|VT_RESERVED) ||
@@ -2273,7 +2319,7 @@ static void test_VarSub(void)
     V_BSTR(&left) = lbstr;
     V_VT(&right) = VT_BSTR;
     V_BSTR(&right) = rbstr;
-    hres = VarSub(&left, &right, &result);
+    hres = pVarSub(&left, &right, &result);
     ok(hres == S_OK && V_VT(&result) == VT_R8,
         "VarSub: expected coerced type VT_R8, got %s!\n", vtstr(V_VT(&result)));
     ok(hres == S_OK && EQ_DOUBLE(V_R8(&result), 0),
@@ -2293,14 +2339,14 @@ static void test_VarSub(void)
     V_VT(&right) = VT_UI1;
     V_UI1(&right) = 9;
 
-    hres = VarSub(&cy, &right, &result);
+    hres = pVarSub(&cy, &right, &result);
     ok(hres == S_OK && V_VT(&result) == VT_CY,
         "VarSub: expected coerced type VT_CY, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromCy(V_CY(&result), &r);
     ok(hres == S_OK && EQ_DOUBLE(r, 4702),
         "VarSub: CY value %f, expected %f\n", r, (double)4720);
 
-    hres = VarSub(&left, &dec, &result);
+    hres = pVarSub(&left, &dec, &result);
     ok(hres == S_OK && V_VT(&result) == VT_DECIMAL,
         "VarSub: expected coerced type VT_DECIMAL, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromDec(&V_DECIMAL(&result), &r);
@@ -3194,6 +3240,32 @@ static void test_Round( int line, VARIANT *arg, int deci, VARIANT *expected )
     V_VT(&exp) = VT_##rvt; V_##rvt(&exp) = rval; \
     test_Round( __LINE__, &v, deci, &exp )
 
+struct decimal_t {
+    BYTE scale;
+    BYTE sign;
+    ULONG Hi32;
+    ULONG Mid32;
+    ULONG Lo32;
+};
+
+struct decimal_round_t {
+    struct decimal_t source;
+    struct decimal_t ret;
+    int dec;
+};
+
+static const struct decimal_round_t decimal_round_data[] = {
+    {{ 0, DECIMAL_NEG, 0, 0, 1 }, { 0, DECIMAL_NEG, 0, 0, 1 }, 0},
+    {{ 0, 0, 0, 0, 1 }, { 0, 0, 0, 0, 1 }, 0},
+    {{ 2, 0, 0, 0, 155 }, { 0, 0, 0, 0, 16 }, 1},
+    {{ 2, 0, 0, 0, 155 }, { 1, 0, 0, 0, 2 }, 0},
+    {{ 2, 0, 0, 0, 199 }, { 1, 0, 0, 0, 20 }, 1},
+    {{ 2, 0, 0, 0, 199 }, { 2, 0, 0, 0, 199 }, 2},
+    {{ 2, DECIMAL_NEG, 0, 0, 199 }, { 2, DECIMAL_NEG, 0, 0, 199 }, 2},
+    {{ 2, DECIMAL_NEG, 0, 0, 55 },  { 2, DECIMAL_NEG, 0, 0, 6 }, 1},
+    {{ 2, 0, 0, 0, 55 },  { 2, 0, 0, 0, 6 }, 1}
+};
+
 static void test_VarRound(void)
 {
     static WCHAR szNumMin[] = {'-','1','.','4','4','9','\0' };
@@ -3202,6 +3274,7 @@ static void test_VarRound(void)
     VARIANT v, exp, vDst;
     CY *pcy = &V_CY(&v);
     char buff[8];
+    int i;
 
     CHECKPTR(VarRound);
 
@@ -3278,30 +3351,38 @@ static void test_VarRound(void)
     ok(hres == S_OK && V_VT(&vDst) == VT_NULL,
         "VarRound: expected 0x0,%d got 0x%X,%d\n", VT_NULL, hres, V_VT(&vDst));
 
-    /* not yet implemented so no use testing yet
-    todo_wine {
-        DECIMAL *pdec = &V_DECIMAL(&v);
+    /* VT_DECIMAL */
+    for (i = 0; i < sizeof(decimal_round_data)/sizeof(struct decimal_round_t); i++)
+    {
+        const struct decimal_round_t *ptr = &decimal_round_data[i];
+        DECIMAL *pdec;
+
+        pdec = &V_DECIMAL(&v);
         V_VT(&v) = VT_DECIMAL;
-        S(U(*pdec)).sign = DECIMAL_NEG;
-        S(U(*pdec)).scale = 0;
-        pdec->Hi32 = 0;
-        S1(U1(*pdec)).Mid32 = 0;
-        S1(U1(*pdec)).Lo32 = 1;
-        hres = pVarRound(&v,0,&vDst);
-        ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-            S(U(V_DECIMAL(&vDst))).sign == 0,
-            "VarRound: expected 0x0,%d,0x00, got 0x%X,%d,%02x\n", VT_DECIMAL,
-            hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);
-
-        S(U(*pdec)).sign = 0;
-        hres = pVarRound(&v,0,&vDst);
-        ok(hres == S_OK && V_VT(&vDst) == VT_DECIMAL &&
-            S(U(V_DECIMAL(&vDst))).sign == DECIMAL_NEG,
-            "VarRound: expected 0x0,%d,0x7f, got 0x%X,%d,%02x\n", VT_DECIMAL,
-            hres, V_VT(&vDst), S(U(V_DECIMAL(&vDst))).sign);
-    }
-    */
+        S(U(*pdec)).sign = ptr->source.sign;
+        S(U(*pdec)).scale = ptr->source.scale;
+        pdec->Hi32 = ptr->source.Hi32;
+        S1(U1(*pdec)).Mid32 = ptr->source.Mid32;
+        S1(U1(*pdec)).Lo32 = ptr->source.Lo32;
+        VariantInit(&vDst);
+        hres = pVarRound(&v, ptr->dec, &vDst);
+    todo_wine
+        ok(hres == S_OK, "%d: got 0x%08x\n", i, hres);
+        if (hres == S_OK)
+        {
+            ok(V_VT(&vDst) == VT_DECIMAL, "%d: got VT %d, expected VT_DECIMAL\n", i, V_VT(&vDst));
+            ok(S(U(V_DECIMAL(&vDst))).sign == ptr->ret.sign, "%d: got sign 0x%02x, expected 0x%02x\n",
+                i, S(U(V_DECIMAL(&vDst))).sign, ptr->ret.sign);
+            ok(V_DECIMAL(&vDst).Hi32 == ptr->ret.Hi32, "%d: got Hi32 %d, expected %d\n",
+                i, V_DECIMAL(&vDst).Hi32, ptr->ret.Hi32);
+            ok(S1(U1(V_DECIMAL(&vDst))).Mid32 == ptr->ret.Mid32, "%d: got Mid32 %d, expected %d\n",
+               i, S1(U1(V_DECIMAL(&vDst))).Mid32,  ptr->ret.Mid32);
+            ok(S1(U1(V_DECIMAL(&vDst))).Lo32 == ptr->ret.Lo32, "%d: got Lo32 %d, expected %d\n",
+                i, S1(U1(V_DECIMAL(&vDst))).Lo32, ptr->ret.Lo32);
+        }
+    }
 
+    /* VT_CY */
     V_VT(&v) = VT_CY;
     pcy->int64 = 10000;
     hres = pVarRound(&v,0,&vDst);
@@ -5081,12 +5162,12 @@ static void test_VarMul(void)
     V_VT(&right) = VT_UI1;
     V_UI1(&right) = 9;
 
-    hres = VarMul(&cy, &right, &result);
+    hres = pVarMul(&cy, &right, &result);
     ok(hres == S_OK && V_VT(&result) == VT_CY, "VarMul: expected coerced type VT_CY, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromCy(V_CY(&result), &r);
     ok(hres == S_OK && EQ_DOUBLE(r, 42399), "VarMul: CY value %f, expected %f\n", r, (double)42399);
 
-    hres = VarMul(&left, &dec, &result);
+    hres = pVarMul(&left, &dec, &result);
     ok(hres == S_OK && V_VT(&result) == VT_DECIMAL, "VarMul: expected coerced type VT_DECIMAL, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromDec(&V_DECIMAL(&result), &r);
     ok(hres == S_OK && EQ_DOUBLE(r, 46.2), "VarMul: DECIMAL value %f, expected %f\n", r, (double)46.2);
@@ -5252,7 +5333,7 @@ static void test_VarAdd(void)
     V_BSTR(&left) = lbstr;
     V_VT(&right) = VT_BSTR;
     V_BSTR(&right) = rbstr;
-    hres = VarAdd(&left, &right, &result);
+    hres = pVarAdd(&left, &right, &result);
     ok(hres == S_OK && V_VT(&result) == VT_BSTR, "VarAdd: expected coerced type VT_BSTR, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromStr(V_BSTR(&result), 0, 0, &r);
     ok(hres == S_OK && EQ_DOUBLE(r, 1212), "VarAdd: BSTR value %f, expected %f\n", r, (double)1212);
@@ -5272,12 +5353,12 @@ static void test_VarAdd(void)
     V_VT(&right) = VT_UI1;
     V_UI1(&right) = 9;
 
-    hres = VarAdd(&cy, &right, &result);
+    hres = pVarAdd(&cy, &right, &result);
     ok(hres == S_OK && V_VT(&result) == VT_CY, "VarAdd: expected coerced type VT_CY, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromCy(V_CY(&result), &r);
     ok(hres == S_OK && EQ_DOUBLE(r, 4720), "VarAdd: CY value %f, expected %f\n", r, (double)4720);
 
-    hres = VarAdd(&left, &dec, &result);
+    hres = pVarAdd(&left, &dec, &result);
     ok(hres == S_OK && V_VT(&result) == VT_DECIMAL, "VarAdd: expected coerced type VT_DECIMAL, got %s!\n", vtstr(V_VT(&result)));
     hres = VarR8FromDec(&V_DECIMAL(&result), &r);
     ok(hres == S_OK && EQ_DOUBLE(r, -15.2), "VarAdd: DECIMAL value %f, expected %f\n", r, (double)-15.2);
@@ -5287,6 +5368,9 @@ static void test_VarAdd(void)
     SysFreeString(rbstr);
 }
 
+static HRESULT (WINAPI *pVarCmp)(LPVARIANT,LPVARIANT,LCID,ULONG);
+static HRESULT (WINAPI *pVarCat)(LPVARIANT,LPVARIANT,LPVARIANT);
+
 static void test_VarCat(void)
 {
     LCID lcid;
@@ -5303,6 +5387,8 @@ static void test_VarCat(void)
     HRESULT hres;
     HRESULT expected_error_num;
 
+    CHECKPTR(VarCat);
+
     /* Set date format for testing */
     lcid = LOCALE_USER_DEFAULT;
     GetLocaleInfo(lcid,LOCALE_SSHORTDATE,orig_date_format,128);
@@ -5419,7 +5505,7 @@ static void test_VarCat(void)
                 V_I8(&right) = 0;
             }
 
-            hres = VarCat(&left, &right, &result);
+            hres = pVarCat(&left, &right, &result);
 
             /* Determine the error code for the vt combination */
             ok(hres == expected_error_num,
@@ -5446,10 +5532,11 @@ static void test_VarCat(void)
     V_BSTR(&left) = SysAllocString(sz12);
     V_BSTR(&right) = SysAllocString(sz34);
     V_BSTR(&expected) = SysAllocString(sz1234);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
-        "VarCat: VT_BSTR concat with VT_BSTR failed to return correct result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
+           "VarCat: VT_BSTR concat with VT_BSTR failed to return correct result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5459,7 +5546,7 @@ static void test_VarCat(void)
     V_VT(&left) = VT_ERROR;
     V_VT(&right) = VT_BSTR;
     V_BSTR(&right) = SysAllocString(sz1234);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == DISP_E_TYPEMISMATCH, "VarCat should have returned DISP_E_TYPEMISMATCH instead of 0x%08x\n", hres);
     ok(V_VT(&result) == VT_EMPTY,
         "VarCat: VT_ERROR concat with VT_BSTR should have returned VT_EMPTY\n");
@@ -5471,7 +5558,7 @@ static void test_VarCat(void)
     V_VT(&left) = VT_BSTR;
     V_VT(&right) = VT_ERROR;
     V_BSTR(&left) = SysAllocString(sz1234);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == DISP_E_TYPEMISMATCH, "VarCat should have returned DISP_E_TYPEMISMATCH instead of 0x%08x\n", hres);
     ok(V_VT(&result) == VT_EMPTY,
         "VarCat: VT_BSTR concat with VT_ERROR should have returned VT_EMPTY\n");
@@ -5488,11 +5575,14 @@ static void test_VarCat(void)
     V_INT(&left) = 12;
     V_BOOL(&right) = TRUE;
     V_BSTR(&expected) = SysAllocString(sz12_true);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    hres = VarCmp(&result,&expected,lcid,0);
-    ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n",
-        hres, variantstr(&result), variantstr(&expected));
+    if (pVarCmp)
+    {
+        hres = pVarCmp(&result,&expected,lcid,0);
+        ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n",
+           hres, variantstr(&result), variantstr(&expected));
+    }
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5505,11 +5595,14 @@ static void test_VarCat(void)
     V_INT(&left) = 12;
     V_BOOL(&right) = FALSE;
     V_BSTR(&expected) = SysAllocString(sz12_false);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    hres = VarCmp(&result,&expected,lcid,0);
-    ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n",
-        hres, variantstr(&result), variantstr(&expected));
+    if (pVarCmp)
+    {
+        hres = pVarCmp(&result,&expected,lcid,0);
+        ok(hres == VARCMP_EQ, "Expected VARCMP_EQ, got %08x for %s, %s\n",
+           hres, variantstr(&result), variantstr(&expected));
+    }
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5523,10 +5616,11 @@ static void test_VarCat(void)
     V_INT(&left)  = 12;
     V_INT(&right) = 34;
     V_BSTR(&expected) = SysAllocString(sz1234);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
-        "VarCat: NUMBER concat with NUMBER returned incorrect result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
+           "VarCat: NUMBER concat with NUMBER returned incorrect result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5537,10 +5631,11 @@ static void test_VarCat(void)
     V_VT(&right) = VT_BSTR;
     V_INT(&left) = 12;
     V_BSTR(&right) = SysAllocString(sz34);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
-        "VarCat: NUMBER concat with VT_BSTR, incorrect result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
+           "VarCat: NUMBER concat with VT_BSTR, incorrect result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5550,10 +5645,11 @@ static void test_VarCat(void)
     V_VT(&right) = VT_INT;
     V_BSTR(&left) = SysAllocString(sz12);
     V_INT(&right) = 34;
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
-        "VarCat: VT_BSTR concat with NUMBER, incorrect result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ,
+           "VarCat: VT_BSTR concat with NUMBER, incorrect result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5569,11 +5665,12 @@ static void test_VarCat(void)
     V_DATE(&right) = 29494.0;
     V_BSTR(&expected)= SysAllocString(sz12_date);
     V_BSTR(&expected_broken)= SysAllocString(sz12_date_broken);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ ||
-        broken(VarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */
-        "VarCat: VT_BSTR concat with VT_DATE returned incorrect result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ ||
+           broken(pVarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */
+           "VarCat: VT_BSTR concat with VT_DATE returned incorrect result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5589,11 +5686,12 @@ static void test_VarCat(void)
     V_BSTR(&right) = SysAllocString(sz12);
     V_BSTR(&expected)= SysAllocString(date_sz12);
     V_BSTR(&expected_broken)= SysAllocString(date_sz12_broken);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ ||
-        broken(VarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */
-        "VarCat: VT_DATE concat with VT_BSTR returned incorrect result\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&expected,lcid,0) == VARCMP_EQ ||
+           broken(pVarCmp(&result,&expected_broken,lcid,0) == VARCMP_EQ), /* Some W98 and NT4 (intermittent) */
+           "VarCat: VT_DATE concat with VT_BSTR returned incorrect result\n");
 
     VariantClear(&left);
     VariantClear(&right);
@@ -5608,10 +5706,11 @@ static void test_VarCat(void)
     V_BSTR(&left) = SysAllocString(sz_empty);
     V_BSTR(&right) = SysAllocString(sz_empty);
     V_BSTR(&expected)= SysAllocString(sz_empty);
-    hres = VarCat(&left,&right,&result);
+    hres = pVarCat(&left,&right,&result);
     ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
-    ok(VarCmp(&result,&left,lcid,0) == VARCMP_EQ,
-        "VarCat: EMPTY concat with EMPTY did not return empty VT_BSTR\n");
+    if (pVarCmp)
+        ok(pVarCmp(&result,&left,lcid,0) == VARCMP_EQ,
+           "VarCat: EMPTY concat with EMPTY did not return empty VT_BSTR\n");
 
     /* Restore original date format settings */
     SetLocaleInfo(lcid,LOCALE_SSHORTDATE,orig_date_format);
@@ -5620,6 +5719,30 @@ static void test_VarCat(void)
     VariantClear(&right);
     VariantClear(&result);
     VariantClear(&expected);
+
+    /* Test boolean conversion */
+    V_VT(&left) = VT_BOOL;
+    V_BOOL(&left) = VARIANT_TRUE;
+    V_VT(&right) = VT_BSTR;
+    V_BSTR(&right) = SysAllocStringLen(NULL,0);
+    hres = pVarCat(&left, &right, &result);
+    ok(hres == S_OK, "VarCat failed: %08x\n", hres);
+    if(!strcmp_wa(V_BSTR(&result), "True")) {
+        V_VT(&right) = VT_BOOL;
+        V_BOOL(&right) = 100;
+        hres = pVarCat(&left, &right, &result);
+        ok(hres == S_OK, "VarCat failed: %08x\n", hres);
+        test_bstr_var(&result, "TrueTrue");
+        VariantClear(&result);
+
+        V_BOOL(&right) = VARIANT_FALSE;
+        hres = pVarCat(&left, &right, &result);
+        ok(hres == S_OK, "VarCat failed: %08x\n", hres);
+        test_bstr_var(&result, "TrueFalse");
+        VariantClear(&result);
+    }else {
+        skip("Got %s as True, assuming non-English locale\n", wine_dbgstr_w(V_BSTR(&result)));
+    }
 }
 
 static HRESULT (WINAPI *pVarAnd)(LPVARIANT,LPVARIANT,LPVARIANT);
@@ -6300,12 +6423,12 @@ static void test_VarAnd(void)
     SysFreeString(false_str);
 }
 
-static HRESULT (WINAPI *pVarCmp)(LPVARIANT,LPVARIANT,LCID,ULONG);
-
 static void test_cmp( int line, LCID lcid, UINT flags, VARIANT *left, VARIANT *right, HRESULT result )
 {
     HRESULT hres;
 
+    CHECKPTR(VarCmp);
+
     hres = pVarCmp(left,right,lcid,flags);
     ok_(__FILE__,line)(hres == result, "VarCmp(%s,%s): expected 0x%x, got hres=0x%x\n",
                        variantstr(left), variantstr(right), result, hres );
@@ -7973,7 +8096,7 @@ static void test_VarIdiv(void)
     V_VT(&right) = VT_I8;
     V_UI1(&right) = 2;
 
-    hres = VarIdiv(&cy, &cy, &result);
+    hres = pVarIdiv(&cy, &cy, &result);
     ok(hres == S_OK && V_VT(&result) == VT_I4,
         "VARIDIV: expected coerced hres 0x%X type VT_I4, got hres 0x%X type %s!\n",
         S_OK, hres, vtstr(V_VT(&result)));
@@ -7982,7 +8105,7 @@ static void test_VarIdiv(void)
 
     if (HAVE_OLEAUT32_I8)
     {
-        hres = VarIdiv(&cy, &right, &result);
+        hres = pVarIdiv(&cy, &right, &result);
         ok(hres == S_OK && V_VT(&result) == VT_I8,
             "VARIDIV: expected coerced hres 0x%X type VT_I8, got hres 0x%X type %s!\n",
             S_OK, hres, vtstr(V_VT(&result)));
@@ -7991,21 +8114,21 @@ static void test_VarIdiv(void)
            (DWORD)(V_I8(&result) >>32), (DWORD)V_I8(&result), 5000);
     }
 
-    hres = VarIdiv(&left, &cy, &result);
+    hres = pVarIdiv(&left, &cy, &result);
     ok(hres == S_OK && V_VT(&result) == VT_I4,
         "VARIDIV: expected coerced hres 0x%X type VT_I4, got hres 0x%X type %s!\n",
         S_OK, hres, vtstr(V_VT(&result)));
     ok(hres == S_OK && V_I4(&result) == 0,
         "VARIDIV: CY value %d, expected %d\n", V_I4(&result), 0);
 
-    hres = VarIdiv(&left, &dec, &result);
+    hres = pVarIdiv(&left, &dec, &result);
     ok(hres == S_OK && V_VT(&result) == VT_I4,
         "VARIDIV: expected coerced hres 0x%X type VT_I4, got hres 0x%X type %s!\n",
         S_OK, hres, vtstr(V_VT(&result)));
     ok(hres == S_OK && V_I4(&result) == 50,
         "VARIDIV: DECIMAL value %d, expected %d\n", V_I4(&result), 50);
 
-    hres = VarIdiv(&dec, &dec, &result);
+    hres = pVarIdiv(&dec, &dec, &result);
     ok(hres == S_OK && V_VT(&result) == VT_I4,
         "VARIDIV: expected coerced hres 0x%X type VT_I4, got hres 0x%X type %s!\n",
         S_OK, hres, vtstr(V_VT(&result)));
@@ -8014,7 +8137,7 @@ static void test_VarIdiv(void)
 
     if (HAVE_OLEAUT32_I8)
     {
-        hres = VarIdiv(&dec, &right, &result);
+        hres = pVarIdiv(&dec, &right, &result);
         ok(hres == S_OK && V_VT(&result) == VT_I8,
             "VARIDIV: expected coerced hres 0x%X type VT_I8, got hres 0x%X type %s!\n",
             S_OK, hres, vtstr(V_VT(&result)));
@@ -8637,8 +8760,8 @@ START_TEST(vartest)
   test_VarEqv();
   test_VarMul();
   test_VarAdd();
+  test_VarCmp(); /* Before test_VarCat() which needs VarCmp() */
   test_VarCat();
-  test_VarCmp();
   test_VarAnd();
   test_VarDiv();
   test_VarIdiv();
index 361342e..58b30b1 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#define CONST_VTABLE
+
 #include "wine/test.h"
 #include "oleauto.h"
 #include <math.h>
@@ -70,17 +72,18 @@ static HMODULE hOleaut32;
 /* Macros for converting and testing results */
 #define CONVVARS(typ) HRESULT hres; CONV_TYPE out; typ in
 
+#define _EXPECT_NO_OUT(res)     ok(hres == res, "expected " #res ", got hres=0x%08x\n", hres)
+#define EXPECT_OVERFLOW _EXPECT_NO_OUT(DISP_E_OVERFLOW)
+#define EXPECT_MISMATCH _EXPECT_NO_OUT(DISP_E_TYPEMISMATCH)
+#define EXPECT_BADVAR   _EXPECT_NO_OUT(DISP_E_BADVARTYPE)
+#define EXPECT_INVALID  _EXPECT_NO_OUT(E_INVALIDARG)
+#define EXPECT_LT       _EXPECT_NO_OUT(VARCMP_LT)
+#define EXPECT_GT       _EXPECT_NO_OUT(VARCMP_GT)
+#define EXPECT_EQ       _EXPECT_NO_OUT(VARCMP_EQ)
+
 #define _EXPECTRES(res, x, fs) \
-  ok((hres == S_OK && out == (CONV_TYPE)(x)) || ((HRESULT)res != S_OK && hres == (HRESULT)res), \
-     "expected " #x ", got " fs "; hres=0x%08x\n", out, hres)
+  ok(hres == S_OK && out == (CONV_TYPE)(x), "expected " #x ", got " fs "; hres=0x%08x\n", out, hres)
 #define EXPECT(x)       EXPECTRES(S_OK, (x))
-#define EXPECT_OVERFLOW EXPECTRES(DISP_E_OVERFLOW, DISP_E_OVERFLOW)
-#define EXPECT_MISMATCH EXPECTRES(DISP_E_TYPEMISMATCH,DISP_E_TYPEMISMATCH)
-#define EXPECT_BADVAR   EXPECTRES(DISP_E_BADVARTYPE, DISP_E_BADVARTYPE)
-#define EXPECT_INVALID  EXPECTRES(E_INVALIDARG, E_INVALIDARG)
-#define EXPECT_LT       EXPECTRES(VARCMP_LT, VARCMP_LT)
-#define EXPECT_GT       EXPECTRES(VARCMP_GT, VARCMP_GT)
-#define EXPECT_EQ       EXPECTRES(VARCMP_EQ, VARCMP_EQ)
 #define EXPECT_DBL(x)   \
   ok(hres == S_OK && fabs(out-(x))<=1e-14*(x), "expected %16.16g, got %16.16g; hres=0x%08x\n", (x), out, hres)
 
@@ -149,8 +152,8 @@ static HMODULE hOleaut32;
   ok(hres == S_OK && V_VT(&vDst) == typ && (CONV_TYPE)res == in, \
      "hres=0x%X, type=%d (should be %d(" #typ ")), value=%d (should be 1)\n", \
       hres, V_VT(&vDst), typ, (int)res);
-#define BADVAR(typ)   CHANGETYPEEX(typ); out = (CONV_TYPE)hres; EXPECT_BADVAR
-#define MISMATCH(typ) CHANGETYPEEX(typ); out = (CONV_TYPE)hres; EXPECT_MISMATCH
+#define BADVAR(typ)   CHANGETYPEEX(typ); EXPECT_BADVAR
+#define MISMATCH(typ) CHANGETYPEEX(typ); EXPECT_MISMATCH
 
 #define INITIAL_TYPETEST(vt, val, fs) \
   VariantInit(&vSrc); \
@@ -501,6 +504,7 @@ static HRESULT (WINAPI *pVarBstrFromDate)(DATE,LCID,ULONG,BSTR*);
 static HRESULT (WINAPI *pVarBstrFromCy)(CY,LCID,ULONG,BSTR*);
 static HRESULT (WINAPI *pVarBstrFromDec)(DECIMAL*,LCID,ULONG,BSTR*);
 static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG);
+static HRESULT (WINAPI *pVarBstrCat)(BSTR,BSTR,BSTR*);
 
 static INT (WINAPI *pSystemTimeToVariantTime)(LPSYSTEMTIME,double*);
 static void (WINAPI *pClearCustData)(LPCUSTDATA);
@@ -514,7 +518,7 @@ typedef struct tagINTERNAL_BSTR
 
 typedef struct
 {
-  const IDispatchVtbl *lpVtbl;
+  IDispatch IDispatch_iface;
   LONG ref;
   VARTYPE vt;
   BOOL bFailInvoke;
@@ -522,16 +526,25 @@ typedef struct
 
 static DummyDispatch dispatch;
 
+static inline DummyDispatch *impl_from_IDispatch(IDispatch *iface)
+{
+  return CONTAINING_RECORD(iface, DummyDispatch, IDispatch_iface);
+}
+
 static ULONG WINAPI DummyDispatch_AddRef(LPDISPATCH iface)
 {
+  DummyDispatch *This = impl_from_IDispatch(iface);
+
   trace("AddRef(%p)\n", iface);
-  return InterlockedIncrement(&((DummyDispatch*)iface)->ref);
+  return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI DummyDispatch_Release(LPDISPATCH iface)
 {
+  DummyDispatch *This = impl_from_IDispatch(iface);
+
   trace("Release(%p)\n", iface);
-  return InterlockedDecrement(&((DummyDispatch*)iface)->ref);
+  return InterlockedDecrement(&This->ref);
 }
 
 static HRESULT WINAPI DummyDispatch_QueryInterface(LPDISPATCH iface,
@@ -592,7 +605,7 @@ static const IDispatchVtbl DummyDispatch_VTable =
   DummyDispatch_Invoke
 };
 
-static DummyDispatch dispatch = { &DummyDispatch_VTable, 1, 0, 0 };
+static DummyDispatch dispatch = { { &DummyDispatch_VTable }, 1, 0, 0 };
 
 /*
  * VT_I1/VT_UI1
@@ -836,7 +849,8 @@ static void test_VarI1Copy(void)
 
 static void test_VarI1ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  signed char in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -1094,11 +1108,11 @@ static void test_VarUI1FromDisp(void)
   VariantInit(&vDst);
 
   V_VT(&vSrc) = VT_DISPATCH;
-  V_DISPATCH(&vSrc) = (IDispatch*)&dispatch;
+  V_DISPATCH(&vSrc) = &dispatch.IDispatch_iface;
   dispatch.vt = VT_UI1;
   dispatch.bFailInvoke = FALSE;
 
-  hres = pVarUI1FromDisp((IDispatch*)&dispatch, in, &out);
+  hres = pVarUI1FromDisp(&dispatch.IDispatch_iface, in, &out);
   trace("0x%08x\n", hres);
 
   hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1);
@@ -1106,7 +1120,7 @@ static void test_VarUI1FromDisp(void)
 
   dispatch.bFailInvoke = TRUE;
 
-  hres = pVarUI1FromDisp((IDispatch*)&dispatch, in, &out);
+  hres = pVarUI1FromDisp(&dispatch.IDispatch_iface, in, &out);
   trace("0x%08x\n", hres);
 
   hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1);
@@ -1120,7 +1134,8 @@ static void test_VarUI1Copy(void)
 
 static void test_VarUI1ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  BYTE in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -1136,8 +1151,6 @@ static void test_VarUI1ChangeTypeEx(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE SHORT
-#undef EXPECTRES
-#define EXPECTRES(res, x) _EXPECTRES(res, x, "%d")
 
 static void test_VarI2FromI1(void)
 {
@@ -1369,7 +1382,8 @@ static void test_VarI2Copy(void)
 
 static void test_VarI2ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  SHORT in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -1608,7 +1622,8 @@ static void test_VarUI2Copy(void)
 
 static void test_VarUI2ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  USHORT in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -1627,9 +1642,6 @@ static void test_VarUI2ChangeTypeEx(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE LONG
-#undef EXPECTRES
-#define EXPECTRES(res, x) _EXPECTRES(res, x, "%d")
-
 
 static void test_VarI4FromI1(void)
 {
@@ -1863,7 +1875,8 @@ static void test_VarI4Copy(void)
 
 static void test_VarI4ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  LONG in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -2097,7 +2110,8 @@ static void test_VarUI4Copy(void)
 
 static void test_VarUI4ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  ULONG in;
   VARIANTARG vSrc, vDst;
 
   in = 1;
@@ -2116,10 +2130,6 @@ static void test_VarUI4ChangeTypeEx(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE LONG64
-#undef EXPECTRES
-#define EXPECTRES(res, x) \
-  ok(hres == S_OK || ((HRESULT)res != S_OK && hres == (HRESULT)res), \
-     "expected hres " #x ", got hres=0x%08x\n", hres)
 
 #define EXPECTI8(x) \
   ok((hres == S_OK && out == (CONV_TYPE)(x)), \
@@ -2374,7 +2384,8 @@ static void test_VarI8Copy(void)
 
 static void test_VarI8ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  LONG64 in;
   VARIANTARG vSrc, vDst;
 
   if (!HAVE_OLEAUT32_I8)
@@ -2524,7 +2535,10 @@ static void test_VarUI8FromBool(void)
   int i;
 
   CHECKPTR(VarUI8FromBool);
-  CONVERTRANGE(VarUI8FromBool, -32768, 32768);
+  for (i = -32768; i < 32768; i++)
+  {
+    CONVERT(VarUI8FromBool, i); EXPECTI8(i);
+  }
 }
 
 static void test_VarUI8FromI8(void)
@@ -2588,10 +2602,13 @@ static void test_VarUI8FromStr(void)
 
   CHECKPTR(VarUI8FromStr);
 
-  CONVERT_STR(VarUI8FromStr,NULL,0);         EXPECT_MISMATCH;
-  CONVERT_STR(VarUI8FromStr,"0",0);          EXPECTI8(0);
-  CONVERT_STR(VarUI8FromStr,"-1",0);         EXPECT_OVERFLOW;
-  CONVERT_STR(VarUI8FromStr,"2147483647",0); EXPECTI8(2147483647);
+  CONVERT_STR(VarUI8FromStr,NULL,0);                    EXPECT_MISMATCH;
+  CONVERT_STR(VarUI8FromStr,"0",0);                     EXPECTI8(0);
+  CONVERT_STR(VarUI8FromStr,"-1",0);                    EXPECT_OVERFLOW;
+  CONVERT_STR(VarUI8FromStr,"2147483647",0);            EXPECTI8(2147483647);
+  CONVERT_STR(VarUI8FromStr,"18446744073709551614",0);  EXPECTI864(0xFFFFFFFF,0xFFFFFFFE);
+  CONVERT_STR(VarUI8FromStr,"18446744073709551615",0);  EXPECTI864(0xFFFFFFFF,0xFFFFFFFF);
+  CONVERT_STR(VarUI8FromStr,"18446744073709551616",0);  EXPECT_OVERFLOW;
 
   CONVERT_STR(VarUI8FromStr,"-1.5",LOCALE_NOUSEROVERRIDE); EXPECT_OVERFLOW;
   CONVERT_STR(VarUI8FromStr,"-0.6",LOCALE_NOUSEROVERRIDE); EXPECT_OVERFLOW;
@@ -2636,7 +2653,8 @@ static void test_VarUI8Copy(void)
 
 static void test_VarUI8ChangeTypeEx(void)
 {
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  ULONG64 in;
   VARIANTARG vSrc, vDst;
 
   if (!HAVE_OLEAUT32_I8)
@@ -2844,7 +2862,8 @@ static void test_VarR4Copy(void)
 static void test_VarR4ChangeTypeEx(void)
 {
 #ifdef HAS_UINT64_TO_FLOAT
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  float in;
   VARIANTARG vSrc, vDst;
 
   in = 1.0f;
@@ -2860,8 +2879,6 @@ static void test_VarR4ChangeTypeEx(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE double
-#undef EXPECTRES
-#define EXPECTRES(res, x) _EXPECTRES(res, x, "%15.15f")
 
 static void test_VarR8FromI1(void)
 {
@@ -3055,7 +3072,8 @@ static void test_VarR8Copy(void)
 static void test_VarR8ChangeTypeEx(void)
 {
 #ifdef HAS_UINT64_TO_FLOAT
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  double in;
   VARIANTARG vSrc, vDst;
 
   in = 1.0;
@@ -3433,6 +3451,8 @@ static void test_VarDateFromStr(void)
   DFS("1 2 1970");        EXPECT_DBL(25570.0);
   DFS("1/2/1970");        EXPECT_DBL(25570.0);
   DFS("1-2-1970");        EXPECT_DBL(25570.0);
+  DFS("13-1-1970");       EXPECT_DBL(25581.0);
+  DFS("1970-1-13");       EXPECT_DBL(25581.0);
   /* Native fails "1999 January 3, 9AM". I consider that a bug in native */
 
   /* test a non-english data string */
@@ -3440,6 +3460,11 @@ static void test_VarDateFromStr(void)
   DFS("02.01.1970 00:00:00"); EXPECT_MISMATCH;
   lcid = MAKELCID(MAKELANGID(LANG_GERMAN,SUBLANG_GERMAN),SORT_DEFAULT);
   DFS("02.01.1970"); EXPECT_DBL(25570.0);
+  DFS("02.13.1970"); EXPECT_DBL(25612.0);
+  DFS("02-13-1970"); EXPECT_DBL(25612.0);
+  DFS("2020-01-11"); EXPECT_DBL(43841.0);
+  DFS("2173-10-14"); EXPECT_DBL(100000.0);
+
   DFS("02.01.1970 00:00:00"); EXPECT_DBL(25570.0);
   lcid = MAKELCID(MAKELANGID(LANG_SPANISH,SUBLANG_SPANISH),SORT_DEFAULT);
   DFS("02.01.1970"); EXPECT_MISMATCH;
@@ -3467,7 +3492,8 @@ static void test_VarDateChangeTypeEx(void)
           '1','/','2','/','7','0','\0' };
   static const WCHAR sz25570Nls[] = {
     '1','/','2','/','1','9','7','0',' ','1','2',':','0','0',':','0','0',' ','A','M','\0' };
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  DATE in;
   VARIANTARG vSrc, vDst;
   LCID lcid;
 
@@ -3507,10 +3533,6 @@ static void test_VarDateChangeTypeEx(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE CY
-#undef EXPECTRES
-#define EXPECTRES(res, x) \
-  ok(hres == S_OK || ((HRESULT)res != S_OK && hres == (HRESULT)res), \
-     "expected hres " #x ", got hres=0x%08x\n", hres)
 
 #define EXPECTCY(x) \
   ok((hres == S_OK && out.int64 == (LONGLONG)(x*CY_MULTIPLIER)), \
@@ -3699,7 +3721,9 @@ static void test_VarCyFromUI8(void)
   CONVERT(VarCyFromUI8, 0); EXPECTCY(0);
   CONVERT(VarCyFromUI8, 1); EXPECTCY(1);
   CONVERT_I8(VarCyFromUI8, 214748, 1566804068); EXPECTCY64(2147483647ul, 4294951488ul);
-  CONVERT_I8(VarCyFromUI8, 214748, 1566804069); EXPECT_OVERFLOW;
+  CONVERT_I8(VarCyFromUI8, 214748, 1566804069); EXPECTCY64(2147483647ul, 4294961488ul);
+  CONVERT_I8(VarCyFromUI8, 214748, 1566804070); EXPECT_OVERFLOW;
+  CONVERT_I8(VarCyFromUI8, 214749, 1566804068); EXPECT_OVERFLOW;
 }
 
 static void test_VarCyFromDec(void)
@@ -3715,7 +3739,9 @@ static void test_VarCyFromDec(void)
   CONVERT_DEC(VarCyFromDec,0,0,0,1);    EXPECTCY(1);
 
   CONVERT_DEC64(VarCyFromDec,0,0,0,214748, 1566804068); EXPECTCY64(2147483647ul, 4294951488ul);
-  CONVERT_DEC64(VarCyFromDec,0,0,0,214748, 1566804069); EXPECT_OVERFLOW;
+  CONVERT_DEC64(VarCyFromDec,0,0,0,214748, 1566804069); EXPECTCY64(2147483647ul, 4294961488ul);
+  CONVERT_DEC64(VarCyFromDec,0,0,0,214748, 1566804070); EXPECT_OVERFLOW;
+  CONVERT_DEC64(VarCyFromDec,0,0,0,214749, 1566804068); EXPECT_OVERFLOW;
 
   CONVERT_DEC(VarCyFromDec,2,0,0,100);     EXPECTCY(1);
   CONVERT_DEC(VarCyFromDec,2,0x80,0,100);  EXPECTCY(-1);
@@ -3872,11 +3898,13 @@ static void test_VarCyMulI8(void)
 }
 
 #define MATHCMP(l, r) left = l; right = r; pVarCyFromR8(left, &cyLeft); pVarCyFromR8(right, &cyRight); \
-  hres = pVarCyCmp(cyLeft, cyRight); out.int64 = hres
+  hres = pVarCyCmp(cyLeft, cyRight)
 
 static void test_VarCyCmp(void)
 {
-  MATHVARS2;
+  HRESULT hres;
+  double left = 0.0, right = 0.0;
+  CY cyLeft, cyRight;
 
   CHECKPTR(VarCyCmp);
   MATHCMP(-1.0, -1.0); EXPECT_EQ;
@@ -3893,11 +3921,13 @@ static void test_VarCyCmp(void)
 }
 
 #define MATHCMPR8(l, r) left = l; right = r; pVarCyFromR8(left, &cyLeft); \
-  hres = pVarCyCmpR8(cyLeft, right); out.int64 = hres
+  hres = pVarCyCmpR8(cyLeft, right);
 
 static void test_VarCyCmpR8(void)
 {
-  MATHVARS1;
+  HRESULT hres;
+  double left = 0.0;
+  CY cyLeft;
   double right;
 
   CHECKPTR(VarCyCmpR8);
@@ -4006,10 +4036,6 @@ static void test_VarCyInt(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE DECIMAL
-#undef EXPECTRES
-#define EXPECTRES(res, x) \
-  ok(hres == S_OK || ((HRESULT)res != S_OK && hres == (HRESULT)res), \
-     "expected hres " #x ", got hres=0x%08x\n", hres)
 
 #define EXPECTDEC(scl, sgn, hi, lo) ok(hres == S_OK && \
   S(U(out)).scale == (BYTE)(scl) && S(U(out)).sign == (BYTE)(sgn) && \
@@ -4534,10 +4560,6 @@ static void test_VarDecCmp(void)
 
 #undef CONV_TYPE
 #define CONV_TYPE VARIANT_BOOL
-#undef _EXPECTRES
-#define _EXPECTRES(res, x, fs) \
-  ok((hres == S_OK && out == (CONV_TYPE)(x)) || ((HRESULT)res != S_OK && hres == (HRESULT)res), \
-     "expected " #x ", got " fs "; hres=0x%08x\n", out, hres)
 #undef EXPECTRES
 #define EXPECTRES(res, x) _EXPECTRES(res, x, "%d")
 #undef CONVERTRANGE
@@ -4794,7 +4816,8 @@ static void test_VarBoolChangeTypeEx(void)
   static const WCHAR szTrue[] = { 'T','r','u','e','\0' };
   static const WCHAR szFalse[] = { 'F','a','l','s','e','\0' };
   static const WCHAR szFaux[] = { 'F','a','u','x','\0' };
-  CONVVARS(CONV_TYPE);
+  HRESULT hres;
+  VARIANT_BOOL in;
   VARIANTARG vSrc, vDst;
   LCID lcid;
 
@@ -4896,23 +4919,30 @@ static void test_VarBstrFromR4(void)
   }
 }
 
-#define BSTR_DATE(dt,str) \
-  bstr = NULL; \
-  hres = pVarBstrFromDate(dt,lcid,LOCALE_NOUSEROVERRIDE,&bstr); \
-  if (bstr) {WideCharToMultiByte(CP_ACP, 0, bstr, -1, buff, sizeof(buff), 0, 0); SysFreeString(bstr);} \
-  else buff[0] = 0; \
-  ok(hres == S_OK && !strcmp(str,buff), "Expected '%s', got '%s', hres = 0x%08x\n", \
-     str, buff, hres)
-
-static void test_VarBstrFromDate(void)
+static void _BSTR_DATE(DATE dt, const char *str, int line)
 {
+  LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
   char buff[256];
-  LCID lcid;
+  BSTR bstr = NULL;
   HRESULT hres;
-  BSTR bstr;
+
+  hres = pVarBstrFromDate(dt, lcid, LOCALE_NOUSEROVERRIDE, &bstr);
+  if (bstr)
+  {
+    WideCharToMultiByte(CP_ACP, 0, bstr, -1, buff, sizeof(buff), 0, 0);
+    SysFreeString(bstr);
+  }
+  else
+    buff[0] = 0;
+  ok_(__FILE__, line)(hres == S_OK && !strcmp(str, buff),
+      "Expected '%s', got '%s', hres = 0x%08x\n", str, buff, hres);
+}
+
+static void test_VarBstrFromDate(void)
+{
+#define BSTR_DATE(dt,str) _BSTR_DATE(dt,str,__LINE__)
 
   CHECKPTR(VarBstrFromDate);
-  lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
 
   BSTR_DATE(0.0, "12:00:00 AM");
   BSTR_DATE(3.34, "1/2/1900 8:09:36 AM");
@@ -4923,174 +4953,146 @@ static void test_VarBstrFromDate(void)
   BSTR_DATE(1461.5, "12/31/1903 12:00:00 PM");
   todo_wine { BSTR_DATE(-657434.0, "1/1/100"); }
   BSTR_DATE(2958465.0, "12/31/9999");
-}
 
-#define BSTR_CY(l, a, b, e) \
-  S(l).Lo = b; S(l).Hi = a; \
-  hres = pVarBstrFromCy(l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\
-  ok(hres == S_OK, "got hres 0x%08x\n", hres);\
-  if (hres== S_OK && bstr)\
-  {\
-    ok(lstrcmpW(bstr, e) == 0, "invalid number (got %s)\n", wtoascii(bstr));\
-    SysFreeString(bstr);\
-  }
+#undef BSTR_DATE
+}
 
-static void test_VarBstrFromCy(void)
+static void _BSTR_CY(LONG a, LONG b, const char *str, LCID lcid, int line)
 {
-  LCID lcid;
-  HRESULT hres;
+  HRESULT hr;
   BSTR bstr = NULL;
+  char buff[256];
   CY l;
 
-  static const WCHAR szZero[] = {'0', '\0'};
-  static const WCHAR szOne[] = {'1', '\0'};
-  static const WCHAR szOnePointFive[] = {'1','.','5','\0'};
-  static const WCHAR szMinusOnePointFive[] = {'-','1','.','5','\0'};
-  static const WCHAR szBigNum1[] = {'4','2','9','4','9','6','.','7','2','9','5','\0'};    /* (1 << 32) - 1 / 1000 */
-  static const WCHAR szBigNum2[] = {'4','2','9','4','9','6','.','7','2','9','6','\0'};    /* (1 << 32) / 1000 */
-  static const WCHAR szBigNum3[] = {'9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','.','5','8','0','7','\0'};    /* ((1 << 63) - 1)/10000 */
-
-  static const WCHAR szSmallNumber_English[] = {'0','.','0','0','0','9','\0'};
-  static const WCHAR szSmallNumber_Spanish[] = {'0',',','0','0','0','9','\0'};
-
-  CHECKPTR(VarBstrFromCy);
-  lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
-
-  /* check zero */
-  BSTR_CY(l, 0,0, szZero);
-
-  /* check one */
-  BSTR_CY(l, 0, 10000, szOne);
+  S(l).Lo = b;
+  S(l).Hi = a;
+  hr = pVarBstrFromCy(l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);
+  ok(hr == S_OK, "got hr 0x%08x\n", hr);
 
-  /* check one point five */
-  BSTR_CY(l, 0, 15000, szOnePointFive);
-
-  /* check minus one point five */
-  BSTR_CY(l, 0xffffffff, ((15000)^0xffffffff)+1, szMinusOnePointFive);
+  if(bstr)
+  {
+    WideCharToMultiByte(CP_ACP, 0, bstr, -1, buff, sizeof(buff), 0, 0);
+    SysFreeString(bstr);
+  }
+  else
+    buff[0] = 0;
 
-  /* check bignum (1) */
-  BSTR_CY(l, 0, 0xffffffff, szBigNum1);
+  if(hr == S_OK)
+  {
+    ok_(__FILE__, line)(!strcmp(str, buff), "Expected '%s', got '%s'\n", str, buff);
+  }
+}
 
-  /* check bignum (2) */
-  BSTR_CY(l, 1,0, szBigNum2);
+static void test_VarBstrFromCy(void)
+{
+#define BSTR_CY(a, b, str, lcid) _BSTR_CY(a, b, str, lcid, __LINE__)
 
-  /* check bignum (3) */
-  BSTR_CY(l, 0x7fffffff,0xffffffff, szBigNum3);
+  LCID en_us, sp;
 
-  /* check leading zeros and decimal sep. for English locale */
-  BSTR_CY(l, 0,9, szSmallNumber_English);
+  CHECKPTR(VarBstrFromCy);
 
-  lcid = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT);
+  en_us = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
+  sp = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT);
+
+  BSTR_CY(0, 0, "0", en_us);
+  BSTR_CY(0, 10000, "1", en_us);
+  BSTR_CY(0, 15000, "1.5", en_us);
+  BSTR_CY(0xffffffff, ((15000)^0xffffffff)+1, "-1.5", en_us);
+  /* (1 << 32) - 1 / 1000 */
+  BSTR_CY(0, 0xffffffff, "429496.7295", en_us);
+  /* (1 << 32) / 1000 */
+  BSTR_CY(1, 0, "429496.7296", en_us);
+  /* ((1 << 63) - 1)/10000 */
+  BSTR_CY(0x7fffffff, 0xffffffff, "922337203685477.5807", en_us);
+  BSTR_CY(0, 9, "0.0009", en_us);
+  BSTR_CY(0, 9, "0,0009", sp);
 
-  /* check leading zeros and decimal sep. for Spanish locale */
-  BSTR_CY(l, 0,9, szSmallNumber_Spanish);
+#undef BSTR_CY
 }
 
-#undef BSTR_CY
+static void _BSTR_DEC(BYTE scale, BYTE sign, ULONG hi, ULONG mid, ULONGLONG lo, const char *str,
+    LCID lcid, int line)
+{
+  char buff[256];
+  HRESULT hr;
+  BSTR bstr = NULL;
+  DECIMAL dec;
+
+  SETDEC64(dec, scale, sign, hi, mid, lo);
+  hr = pVarBstrFromDec(&dec, lcid, LOCALE_NOUSEROVERRIDE, &bstr);
+  ok_(__FILE__, line)(hr == S_OK, "got hr 0x%08x\n", hr);
 
-#define BSTR_DEC(l, a, b, c, d, e) \
-  SETDEC(l, a,b,c,d);\
-  hres = pVarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\
-  ok(hres == S_OK, "got hres 0x%08x\n", hres);\
-  if (hres== S_OK && bstr)\
-  {\
-    ok(lstrcmpW(bstr, e) == 0, "invalid number (got %s)\n", wtoascii(bstr));\
-    SysFreeString(bstr);\
+  if(bstr)
+  {
+    WideCharToMultiByte(CP_ACP, 0, bstr, -1, buff, sizeof(buff), 0, 0);
+    SysFreeString(bstr);
   }
+  else
+    buff[0] = 0;
 
-#define BSTR_DEC64(l, a, b, c, x, d, e) \
-  SETDEC64(l, a,b,c,x,d);\
-  hres = pVarBstrFromDec(&l, lcid, LOCALE_NOUSEROVERRIDE, &bstr);\
-  ok(hres == S_OK, "got hres 0x%08x\n", hres);\
-  if (hres== S_OK && bstr)\
-  {\
-    ok(lstrcmpW(bstr, e) == 0, "invalid number (got %s)\n", wtoascii(bstr));\
-    SysFreeString(bstr);\
+  if(hr == S_OK)
+  {
+    ok_(__FILE__, line)(!strcmp(str, buff), "Expected '%s', got '%s'\n", str, buff);
   }
+}
 
 static void test_VarBstrFromDec(void)
 {
-  LCID lcid;
-  HRESULT hres;
-  BSTR bstr = NULL;
-  DECIMAL l;
+#define BSTR_DEC(scale, sign, hi, lo, str, lcid) _BSTR_DEC(scale, sign, hi, 0, lo, str, lcid, __LINE__)
+#define BSTR_DEC64(scale, sign, hi, mid, lo, str, lcid) _BSTR_DEC(scale, sign, hi, mid, lo, str, lcid, __LINE__)
 
-  static const WCHAR szZero[] = {'0', '\0'};
-  static const WCHAR szOne[] = {'1', '\0'};
-  static const WCHAR szOnePointFive[] = {'1','.','5','\0'};
-  static const WCHAR szMinusOnePointFive[] = {'-','1','.','5','\0'};
-  static const WCHAR szBigNum1[] = {'4','2','9','4','9','6','7','2','9','5','\0'};    /* (1 << 32) - 1 */
-  static const WCHAR szBigNum2[] = {'4','2','9','4','9','6','7','2','9','6','\0'};    /* (1 << 32) */
-  static const WCHAR szBigNum3[] = {'1','8','4','4','6','7','4','4','0','7','3','7','0','9','5','5','1','6','1','5','\0'};    /* (1 << 64) - 1 */
-  static const WCHAR szBigNum4[] = {'1','8','4','4','6','7','4','4','0','7','3','7','0','9','5','5','1','6','1','6','\0'};    /* (1 << 64) */
-  static const WCHAR szBigNum5[] = {'7','9','2','2','8','1','6','2','5','1','4','2','6','4','3','3','7','5','9','3','5','4','3','9','5','0','3','3','5','\0'};    /* (1 << 96) - 1 */
-  static const WCHAR szBigScale1[] = {'0','.','0','0','0','0','0','0','0','0','0','1','\0'};    /* 1 * 10^-10 */
-  static const WCHAR szBigScale2[] = {'7','9','2','2','8','1','6','2','5','1','4','2','6','4','3','3','7','5','9','.','3','5','4','3','9','5','0','3','3','5','\0'};    /* ((1 << 96) - 1) * 10^-10 */
-  static const WCHAR szBigScale3[] = {'7','.','9','2','2','8','1','6','2','5','1','4','2','6','4','3','3','7','5','9','3','5','4','3','9','5','0','3','3','5','\0'};    /* ((1 << 96) - 1) * 10^-28 */
-
-  static const WCHAR szSmallNumber_English[] = {'0','.','0','0','0','9','\0'};
-  static const WCHAR szSmallNumber_Spanish[] = {'0',',','0','0','0','9','\0'};
+  LCID en_us, sp;
 
   CHECKPTR(VarBstrFromDec);
-  lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
-
-  /* check zero */
-  BSTR_DEC(l, 0,0,0,0, szZero);
-  
-  /* check one */
-  BSTR_DEC(l, 0,0,0,1, szOne);
-  BSTR_DEC(l, 1,0,0,10,szOne);
-  BSTR_DEC(l, 2,0,0,100,szOne);
-  BSTR_DEC(l, 3,0,0,1000,szOne);
 
-  /* check one point five */
-  BSTR_DEC(l, 1,0,0,15, szOnePointFive);
-  BSTR_DEC(l, 2,0,0,150, szOnePointFive);
-  BSTR_DEC(l, 3,0,0,1500, szOnePointFive);
-
-  /* check minus one point five */
-  BSTR_DEC(l, 1,0x80,0,15, szMinusOnePointFive);
-
-  /* check bignum (1) */
-  BSTR_DEC(l, 0,0,0,0xffffffff, szBigNum1);
-
-  /* check bignum (2) */
-  BSTR_DEC64(l, 0,0,0,1,0, szBigNum2);
-
-  /* check bignum (3) */
-  BSTR_DEC64(l, 0,0,0,0xffffffff,0xffffffff, szBigNum3);
-
-  /* check bignum (4) */
-  BSTR_DEC(l, 0,0,1,0, szBigNum4);
-
-  /* check bignum (5) */
-  BSTR_DEC64(l, 0,0,0xffffffff,0xffffffff,0xffffffff, szBigNum5);
-
-  /* check bigscale (1) */
-  BSTR_DEC(l, 10,0,0,1, szBigScale1);
-
-  /* check bigscale (2) */
-  BSTR_DEC64(l, 10,0,0xffffffffUL,0xffffffff,0xffffffff, szBigScale2);
-
-  /* check bigscale (3) */
-  BSTR_DEC64(l, 28,0,0xffffffffUL,0xffffffff,0xffffffff, szBigScale3);
+  en_us = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
+  sp = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT);
+
+  BSTR_DEC(0,0,0,0, "0", en_us);
+
+  BSTR_DEC(0,0,0,1,   "1", en_us);
+  BSTR_DEC(1,0,0,10,  "1", en_us);
+  BSTR_DEC(2,0,0,100, "1", en_us);
+  BSTR_DEC(3,0,0,1000,"1", en_us);
+
+  BSTR_DEC(1,0,0,15,  "1.5", en_us);
+  BSTR_DEC(2,0,0,150, "1.5", en_us);
+  BSTR_DEC(3,0,0,1500,"1.5", en_us);
+
+  BSTR_DEC(1,0x80,0,15, "-1.5", en_us);
+
+  /* (1 << 32) - 1 */
+  BSTR_DEC(0,0,0,0xffffffff, "4294967295", en_us);
+  /* (1 << 32) */
+  BSTR_DEC64(0,0,0,1,0, "4294967296", en_us);
+  /* (1 << 64) - 1 */
+  BSTR_DEC64(0,0,0,0xffffffff,0xffffffff, "18446744073709551615", en_us);
+  /* (1 << 64) */
+  BSTR_DEC(0,0,1,0, "18446744073709551616", en_us);
+  /* (1 << 96) - 1 */
+  BSTR_DEC64(0,0,0xffffffff,0xffffffff,0xffffffff, "79228162514264337593543950335", en_us);
+  /* 1 * 10^-10 */
+  BSTR_DEC(10,0,0,1, "0.0000000001", en_us);
+  /* ((1 << 96) - 1) * 10^-10 */
+  BSTR_DEC64(10,0,0xffffffffUL,0xffffffff,0xffffffff, "7922816251426433759.3543950335", en_us);
+  /* ((1 << 96) - 1) * 10^-28 */
+  BSTR_DEC64(28,0,0xffffffffUL,0xffffffff,0xffffffff, "7.9228162514264337593543950335", en_us);
 
   /* check leading zeros and decimal sep. for English locale */
-  BSTR_DEC(l, 4,0,0,9, szSmallNumber_English);
-  BSTR_DEC(l, 5,0,0,90, szSmallNumber_English);
-  BSTR_DEC(l, 6,0,0,900, szSmallNumber_English);
-  BSTR_DEC(l, 7,0,0,9000, szSmallNumber_English);
-  
-  lcid = MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), SORT_DEFAULT);
+  BSTR_DEC(4,0,0,9, "0.0009", en_us);
+  BSTR_DEC(5,0,0,90, "0.0009", en_us);
+  BSTR_DEC(6,0,0,900, "0.0009", en_us);
+  BSTR_DEC(7,0,0,9000, "0.0009", en_us);
   
   /* check leading zeros and decimal sep. for Spanish locale */
-  BSTR_DEC(l, 4,0,0,9, szSmallNumber_Spanish);
-  BSTR_DEC(l, 5,0,0,90, szSmallNumber_Spanish);
-  BSTR_DEC(l, 6,0,0,900, szSmallNumber_Spanish);
-  BSTR_DEC(l, 7,0,0,9000, szSmallNumber_Spanish);
-}
+  BSTR_DEC(4,0,0,9, "0,0009", sp);
+  BSTR_DEC(5,0,0,90, "0,0009", sp);
+  BSTR_DEC(6,0,0,900, "0,0009", sp);
+  BSTR_DEC(7,0,0,9000, "0,0009", sp);
+
 #undef BSTR_DEC
 #undef BSTR_DEC64
+}
 
 #define _VARBSTRCMP(left,right,lcid,flags,result) \
         hres = pVarBstrCmp(left,right,lcid,flags); \
@@ -5151,7 +5153,7 @@ static void test_VarBstrCmp(void)
     SysFreeString(bstr);
 
     bstr = SysAllocStringByteLen(sbchr0, sizeof(sbchr0));
-    bstr2 = SysAllocStringByteLen(sbchr0, sizeof(sbchr00));
+    bstr2 = SysAllocStringByteLen(sbchr00, sizeof(sbchr00));
     VARBSTRCMP(bstr,bstrempty,0,VARCMP_GT);
     VARBSTRCMP(bstrempty,bstr,0,VARCMP_LT);
     VARBSTRCMP(bstr2,bstrempty,0,VARCMP_GT);
@@ -5170,7 +5172,7 @@ static void test_VarBstrCmp(void)
     SysFreeString(bstr);
 
     bstr = SysAllocStringByteLen(sbchr0, sizeof(sbchr0));
-    bstr2 = SysAllocStringByteLen(sbchr0, sizeof(sbchr00));
+    bstr2 = SysAllocStringByteLen(sbchr00, sizeof(sbchr00));
     VARBSTRCMP(bstr,bstrempty,0,VARCMP_GT);
     VARBSTRCMP(bstrempty,bstr,0,VARCMP_LT);
     VARBSTRCMP(bstr2,bstrempty,0,VARCMP_GT);
@@ -5492,14 +5494,16 @@ static void test_VarBstrCat(void)
     BSTR str1, str2, res;
     UINT len;
 
+    CHECKPTR(VarBstrCat);
+
 if (0)
 {
     /* Crash */
-    ret = VarBstrCat(NULL, NULL, NULL);
+    pVarBstrCat(NULL, NULL, NULL);
 }
 
     /* Concatenation of two NULL strings works */
-    ret = VarBstrCat(NULL, NULL, &res);
+    ret = pVarBstrCat(NULL, NULL, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == 0, "Expected a 0-length string\n");
@@ -5508,13 +5512,13 @@ if (0)
     str1 = SysAllocString(sz1);
 
     /* Concatenation with one NULL arg */
-    ret = VarBstrCat(NULL, str1, &res);
+    ret = pVarBstrCat(NULL, str1, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == SysStringLen(str1), "Unexpected length\n");
     ok(!memcmp(res, sz1, SysStringLen(str1)), "Unexpected value\n");
     SysFreeString(res);
-    ret = VarBstrCat(str1, NULL, &res);
+    ret = pVarBstrCat(str1, NULL, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == SysStringLen(str1), "Unexpected length\n");
@@ -5523,7 +5527,7 @@ if (0)
 
     /* Concatenation of two zero-terminated strings */
     str2 = SysAllocString(sz2);
-    ret = VarBstrCat(str1, str2, &res);
+    ret = pVarBstrCat(str1, str2, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == sizeof(sz1sz2) / sizeof(WCHAR) - 1,
@@ -5538,7 +5542,7 @@ if (0)
     str1 = SysAllocStringLen(s1, sizeof(s1) / sizeof(WCHAR));
     str2 = SysAllocStringLen(s2, sizeof(s2) / sizeof(WCHAR));
 
-    ret = VarBstrCat(str1, str2, &res);
+    ret = pVarBstrCat(str1, str2, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == sizeof(s1s2) / sizeof(WCHAR),
@@ -5557,7 +5561,7 @@ if (0)
     len = SysStringLen(str2);
     ok(len == (sizeof(str2A)-1)/sizeof(WCHAR), "got length %u\n", len);
 
-    ret = VarBstrCat(str1, str2, &res);
+    ret = pVarBstrCat(str1, str2, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     len = (sizeof(str1A) + sizeof(str2A) - 2)/sizeof(WCHAR);
@@ -5576,7 +5580,7 @@ if (0)
     len = SysStringLen(str2);
     ok(len == 0, "got length %u\n", len);
 
-    ret = VarBstrCat(str1, str2, &res);
+    ret = pVarBstrCat(str1, str2, &res);
     ok(ret == S_OK, "VarBstrCat failed: %08x\n", ret);
     ok(res != NULL, "Expected a string\n");
     ok(SysStringLen(res) == 1, "got %d, expected 1\n", SysStringLen(res));
@@ -5593,12 +5597,12 @@ static void test_IUnknownClear(void)
 {
   HRESULT hres;
   VARIANTARG v;
-  DummyDispatch u = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IUnknown* pu = (IUnknown*)&u;
+  DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IUnknown* pu = (IUnknown*)&u.IDispatch_iface;
 
   /* Test that IUnknown_Release is called on by-value */
   V_VT(&v) = VT_UNKNOWN;
-  V_UNKNOWN(&v) = (IUnknown*)&u;
+  V_UNKNOWN(&v) = (IUnknown*)&u.IDispatch_iface;
   hres = VariantClear(&v);
   ok(hres == S_OK && u.ref == 0 && V_VT(&v) == VT_EMPTY,
      "clear unknown: expected 0x%08x, %d, %d, got 0x%08x, %d, %d\n",
@@ -5618,8 +5622,8 @@ static void test_IUnknownCopy(void)
 {
   HRESULT hres;
   VARIANTARG vSrc, vDst;
-  DummyDispatch u = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IUnknown* pu = (IUnknown*)&u;
+  DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IUnknown* pu = (IUnknown*)&u.IDispatch_iface;
 
   /* AddRef is called on by-value copy */
   VariantInit(&vDst);
@@ -5666,8 +5670,8 @@ static void test_IUnknownChangeTypeEx(void)
   VARIANTARG vSrc, vDst;
   LCID lcid;
   VARTYPE vt;
-  DummyDispatch u = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IUnknown* pu = (IUnknown*)&u;
+  DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IUnknown* pu = (IUnknown*)&u.IDispatch_iface;
 
   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
 
@@ -5734,8 +5738,8 @@ static void test_IDispatchClear(void)
 {
   HRESULT hres;
   VARIANTARG v;
-  DummyDispatch d = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IDispatch* pd = (IDispatch*)&d;
+  DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IDispatch* pd = &d.IDispatch_iface;
 
   /* As per IUnknown */
 
@@ -5759,8 +5763,8 @@ static void test_IDispatchCopy(void)
 {
   HRESULT hres;
   VARIANTARG vSrc, vDst;
-  DummyDispatch d = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IDispatch* pd = (IDispatch*)&d;
+  DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IDispatch* pd = &d.IDispatch_iface;
 
   /* As per IUnknown */
 
@@ -5804,8 +5808,8 @@ static void test_IDispatchChangeTypeEx(void)
   HRESULT hres;
   VARIANTARG vSrc, vDst;
   LCID lcid;
-  DummyDispatch d = { &DummyDispatch_VTable, 1, VT_UI1, FALSE };
-  IDispatch* pd = (IDispatch*)&d;
+  DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE };
+  IDispatch* pd = &d.IDispatch_iface;
 
   lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
 
@@ -6064,7 +6068,7 @@ static void test_ChangeType_keep_dst(void)
      V_INT(&v2) = 4;
      hres = VariantChangeTypeEx(&v2, &v1, 0, 0, VT_INT);
      ok(hres == DISP_E_TYPEMISMATCH, "VariantChangeTypeEx returns %08x\n", hres);
-     ok(V_VT(&v2) == VT_INT && V_INT(&v2) == 4, "VariantChangeTypeEx changed dst variant\n");     
+     ok(V_VT(&v2) == VT_INT && V_INT(&v2) == 4, "VariantChangeTypeEx changed dst variant\n");
      SysFreeString(bstr);
 }
 
@@ -6072,7 +6076,7 @@ START_TEST(vartype)
 {
   hOleaut32 = GetModuleHandleA("oleaut32.dll");
 
-  trace("LCID's: System=0x%08x, User=0x%08x\n", GetSystemDefaultLCID(),
+  trace("LCIDs: System=0x%08x, User=0x%08x\n", GetSystemDefaultLCID(),
         GetUserDefaultLCID());
 
   test_VarI1FromI2();