From 559ca8b24eaef2d8d801dc99da34e269d2f04814 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Thu, 24 Apr 2014 15:13:22 +0000 Subject: [PATCH] [OLEAUT32_WINETEST] * Sync with Wine 1.7.17. CORE-8080 svn path=/trunk/; revision=62943 --- rostests/winetests/oleaut32/CMakeLists.txt | 10 +- rostests/winetests/oleaut32/dispatch.c | 70 +++ rostests/winetests/oleaut32/olefont.c | 255 +++++--- rostests/winetests/oleaut32/olepicture.c | 183 +++++- rostests/winetests/oleaut32/safearray.c | 413 ++++++++++--- rostests/winetests/oleaut32/test_reg.idl | 7 + rostests/winetests/oleaut32/test_tlb.idl | 12 + rostests/winetests/oleaut32/tmarshal.c | 27 +- rostests/winetests/oleaut32/tmarshal.idl | 3 + rostests/winetests/oleaut32/typelib.c | 640 ++++++++++++++++++--- rostests/winetests/oleaut32/vartest.c | 295 +++++++++- rostests/winetests/oleaut32/vartype.c | 574 ++++++++++++++---- 12 files changed, 2103 insertions(+), 386 deletions(-) diff --git a/rostests/winetests/oleaut32/CMakeLists.txt b/rostests/winetests/oleaut32/CMakeLists.txt index 0c85ba32052..2de2a00eace 100644 --- a/rostests/winetests/oleaut32/CMakeLists.txt +++ b/rostests/winetests/oleaut32/CMakeLists.txt @@ -2,8 +2,8 @@ add_definitions(-DUSE_WINE_TODOS) 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 test_reg.idl) +add_idl_Headers(oleaut32_idlheaders test_reg.idl test_tlb.idl tmarshal.idl) +generate_idl_iids(test_reg.idl test_tlb.idl tmarshal.idl) list(APPEND SOURCE dispatch.c @@ -18,6 +18,7 @@ list(APPEND SOURCE vartest.c vartype.c ${CMAKE_CURRENT_BINARY_DIR}/test_reg_i.c + ${CMAKE_CURRENT_BINARY_DIR}/test_tlb_i.c ${CMAKE_CURRENT_BINARY_DIR}/tmarshal_i.c) set(tmarshal.rc_DEPS @@ -30,6 +31,9 @@ set_source_files_properties(tmarshal.rc PROPERTIES OBJECT_DEPENDS "${tmarshal.rc add_executable(oleaut32_winetest ${SOURCE} tmarshal.rc) target_link_libraries(oleaut32_winetest uuid) set_module_type(oleaut32_winetest win32cui) -add_importlibs(oleaut32_winetest oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 msvcrt kernel32 ntdll) +add_importlibs(oleaut32_winetest oleaut32 ole32 rpcrt4 user32 gdi32 advapi32 msvcrt kernel32) +if(MSVC) + add_importlibs(oleaut32_winetest ntdll) +endif() add_dependencies(oleaut32_winetest stdole2 oleaut32_typelibs oleaut32_idlheaders) add_cd_file(TARGET oleaut32_winetest DESTINATION reactos/bin FOR all) diff --git a/rostests/winetests/oleaut32/dispatch.c b/rostests/winetests/oleaut32/dispatch.c index cd531287adb..d5ac4f0383e 100644 --- a/rostests/winetests/oleaut32/dispatch.c +++ b/rostests/winetests/oleaut32/dispatch.c @@ -22,6 +22,9 @@ #define _INC_WINDOWS #define COM_NO_WINDOWS_H +#define COBJMACROS +#define CONST_VTABLE + #include //#include //#include @@ -273,7 +276,74 @@ static void test_DispGetParam(void) VariantClear(&result); } +static HRESULT WINAPI unk_QI(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + return S_OK; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } +} + +static ULONG WINAPI unk_AddRef(IUnknown *iface) +{ + return 2; +} + +static ULONG WINAPI unk_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl unkvtbl = +{ + unk_QI, + unk_AddRef, + unk_Release +}; + +static IUnknown test_unk = { &unkvtbl }; + +static void test_CreateStdDispatch(void) +{ + static const WCHAR stdole2W[] = {'s','t','d','o','l','e','2','.','t','l','b',0}; + ITypeLib *tl; + ITypeInfo *ti; + IUnknown *unk; + HRESULT hr; + + hr = CreateStdDispatch(NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + + hr = CreateStdDispatch(NULL, NULL, NULL, &unk); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + + hr = LoadTypeLib(stdole2W, &tl); + ok(hr == S_OK, "got %08x\n", hr); + hr = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IUnknown, &ti); + ok(hr == S_OK, "got %08x\n", hr); + ITypeLib_Release(tl); + + hr = CreateStdDispatch(NULL, &test_unk, NULL, &unk); + ok(hr == E_INVALIDARG, "got %08x\n", hr); + + hr = CreateStdDispatch(NULL, NULL, ti, &unk); + ok(hr == E_INVALIDARG, "got %08x\n", hr); + + hr = CreateStdDispatch(NULL, &test_unk, ti, &unk); + ok(hr == S_OK, "got %08x\n", hr); + IUnknown_Release(unk); + + ITypeInfo_Release(ti); +} + START_TEST(dispatch) { test_DispGetParam(); + test_CreateStdDispatch(); } diff --git a/rostests/winetests/oleaut32/olefont.c b/rostests/winetests/oleaut32/olefont.c index 3a20f2fae4e..634b1c781eb 100644 --- a/rostests/winetests/oleaut32/olefont.c +++ b/rostests/winetests/oleaut32/olefont.c @@ -71,7 +71,7 @@ static void test_ifont_size(LONG lo_size, LONG hi_size, LPVOID pvObj = NULL; IFont* ifnt = NULL; HFONT hfont; - LOGFONT lf; + LOGFONTA lf; CY psize; HRESULT hres; DWORD rtnval; @@ -82,9 +82,9 @@ static void test_ifont_size(LONG lo_size, LONG hi_size, S(fd.cySize).Hi = hi_size; fd.sWeight = 0; fd.sCharset = 0; - fd.fItalic = 0; - fd.fUnderline = 0; - fd.fStrikethrough = 0; + fd.fItalic = FALSE; + fd.fUnderline = FALSE; + fd.fStrikethrough = FALSE; /* Create font, test that it worked. */ hres = pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj); @@ -93,13 +93,10 @@ static void test_ifont_size(LONG lo_size, LONG hi_size, test_name, hres); ok(pvObj != NULL,"%s: OCFI returns NULL.\n", test_name); - /* 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); - } + /* Change the scaling ratio */ + hres = IFont_SetRatio(ifnt, ratio_logical, ratio_himetric); + ok((ratio_logical && ratio_himetric) ? hres == S_OK : hres == E_FAIL, + "%s: IFont_SetRatio unexpectedly returned 0x%08x.\n", test_name, hres); /* Read back size. */ hres = IFont_get_Size(ifnt, &psize); @@ -115,7 +112,7 @@ static void test_ifont_size(LONG lo_size, LONG hi_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); - rtnval = GetObject (hfont, sizeof(LOGFONT), &lf); + rtnval = GetObjectA(hfont, sizeof(LOGFONTA), &lf); ok(rtnval > 0, "GetObject(hfont) failed\n"); /* Since font scaling may encounter rounding errors, allow 1 pixel deviation. */ @@ -156,6 +153,41 @@ static void test_ifont_sizes(void) 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 */ + + /* test various combinations of logical == himetric */ + test_ifont_size(180000, 0, 10, 10, -635, "identical ratio 1"); + test_ifont_size(240000, 0, 10, 10, -848, "identical ratio 2"); + test_ifont_size(300000, 0, 10, 10, -1058, "identical ratio 3"); + + /* test various combinations of logical and himetric both set to 1 */ + test_ifont_size(180000, 0, 1, 1, -24, "1:1 ratio 1"); + test_ifont_size(240000, 0, 1, 1, -32, "1:1 ratio 2"); + test_ifont_size(300000, 0, 1, 1, -40, "1:1 ratio 3"); + + /* test various combinations of logical set to 1 */ + test_ifont_size(180000, 0, 1, 0, -24, "1:0 ratio 1"); + test_ifont_size(240000, 0, 1, 0, -32, "1:0 ratio 2"); + test_ifont_size(300000, 0, 1, 0, -40, "1:0 ratio 3"); + + /* test various combinations of himetric set to 1 */ + test_ifont_size(180000, 0, 0, 1, -24, "0:1 ratio 1"); + test_ifont_size(240000, 0, 0, 1, -32, "0:1 ratio 2"); + test_ifont_size(300000, 0, 0, 1, -40, "0:1 ratio 3"); + + /* test various combinations of 2:1 logical:himetric */ + test_ifont_size(180000, 0, 2, 1, -1270, "2:1 ratio 1"); + test_ifont_size(240000, 0, 2, 1, -1694, "2:1 ratio 2"); + test_ifont_size(300000, 0, 2, 1, -2117, "2:1 ratio 3"); + + /* test various combinations of 1:2 logical:himetric */ + test_ifont_size(180000, 0, 1, 2, -318, "1:2 ratio 1"); + test_ifont_size(240000, 0, 1, 2, -424, "1:2 ratio 2"); + test_ifont_size(300000, 0, 1, 2, -529, "1:2 ratio 3"); + + /* test various combinations of logical and himetric both set to 2 */ + test_ifont_size(180000, 0, 2, 2, -635, "2:2 ratio 1"); + test_ifont_size(240000, 0, 2, 2, -848, "2:2 ratio 2"); + test_ifont_size(300000, 0, 2, 2, -1058, "2:2 ratio 3"); } static void test_QueryInterface(void) @@ -234,10 +266,7 @@ static void test_type_info(void) IFontDisp_Release(fontdisp); } -static HRESULT WINAPI FontEventsDisp_QueryInterface( - IFontEventsDisp *iface, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) +static HRESULT WINAPI FontEventsDisp_QueryInterface(IFontEventsDisp *iface, REFIID riid, void **ppvObject) { if (IsEqualIID(riid, &IID_IFontEventsDisp) || IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch)) { @@ -264,26 +293,48 @@ static ULONG WINAPI FontEventsDisp_Release( return 1; } -static int fonteventsdisp_invoke_called = 0; +static HRESULT WINAPI FontEventsDisp_GetTypeInfoCount(IFontEventsDisp *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI FontEventsDisp_GetTypeInfo(IFontEventsDisp *iface, UINT itinfo, LCID lcid, ITypeInfo **pptinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI FontEventsDisp_GetIDsOfNames(IFontEventsDisp *iface, REFIID riid, LPOLESTR *names, UINT cNames, LCID lcid, + DISPID *dispid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static int fonteventsdisp_invoke_called; +static BSTR fonteventsdisp_invoke_arg0; static HRESULT WINAPI FontEventsDisp_Invoke( - IFontEventsDisp __RPC_FAR * iface, - /* [in] */ DISPID dispIdMember, - /* [in] */ REFIID riid, - /* [in] */ LCID lcid, - /* [in] */ WORD wFlags, - /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, - /* [out] */ VARIANT __RPC_FAR *pVarResult, - /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, - /* [out] */ UINT __RPC_FAR *puArgErr) + IFontEventsDisp *iface, + DISPID dispid, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) { - static const WCHAR wszBold[] = {'B','o','l','d',0}; - ok(wFlags == INVOKE_FUNC, "invoke flags should have been INVOKE_FUNC instead of 0x%x\n", wFlags); - ok(dispIdMember == DISPID_FONT_CHANGED, "dispIdMember should have been DISPID_FONT_CHANGED instead of 0x%x\n", dispIdMember); - ok(pDispParams->cArgs == 1, "pDispParams->cArgs should have been 1 instead of %d\n", pDispParams->cArgs); - ok(V_VT(&pDispParams->rgvarg[0]) == VT_BSTR, "VT of first param should have been VT_BSTR instead of %d\n", V_VT(&pDispParams->rgvarg[0])); - ok(!lstrcmpW(V_BSTR(&pDispParams->rgvarg[0]), wszBold), "String in first param should have been \"Bold\"\n"); + VARIANTARG *arg0 = &pDispParams->rgvarg[0]; + ok(dispid == DISPID_FONT_CHANGED, "expected DISPID_FONT_CHANGED instead of 0x%x\n", dispid); + ok(IsEqualGUID(riid, &GUID_NULL), "got riid %s\n", wine_dbgstr_guid(riid)); + ok(wFlags == INVOKE_FUNC, "expected INVOKE_FUNC instead of 0x%x\n", wFlags); + ok(pDispParams->cArgs == 1, "expected arg count 1, got %d\n", pDispParams->cArgs); + ok(V_VT(arg0) == VT_BSTR, "expected VT_BSTR, got %d\n", V_VT(arg0)); + + fonteventsdisp_invoke_arg0 = SysAllocString(V_BSTR(arg0)); fonteventsdisp_invoke_called++; return S_OK; } @@ -293,16 +344,43 @@ static IFontEventsDispVtbl FontEventsDisp_Vtbl = FontEventsDisp_QueryInterface, FontEventsDisp_AddRef, FontEventsDisp_Release, - NULL, - NULL, - NULL, + FontEventsDisp_GetTypeInfoCount, + FontEventsDisp_GetTypeInfo, + FontEventsDisp_GetIDsOfNames, FontEventsDisp_Invoke }; static IFontEventsDisp FontEventsDisp = { &FontEventsDisp_Vtbl }; + struct font_dispid + { + DISPID dispid; + const WCHAR *name; + }; + static void test_font_events_disp(void) { + static const WCHAR nameW[] = {'N','a','m','e',0}; + static const WCHAR sizeW[] = {'S','i','z','e',0}; + static const WCHAR boldW[] = {'B','o','l','d',0}; + static const WCHAR italicW[] = {'I','t','a','l','i','c',0}; + static const WCHAR underlineW[] = {'U','n','d','e','r','l','i','n','e',0}; + static const WCHAR strikeW[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0}; + static const WCHAR weightW[] = {'W','e','i','g','h','t',0}; + static const WCHAR charsetW[] = {'C','h','a','r','s','e','t',0}; + + static const struct font_dispid font_dispids[] = + { + { DISPID_FONT_NAME, nameW }, + { DISPID_FONT_SIZE, sizeW }, + { DISPID_FONT_BOLD, boldW }, + { DISPID_FONT_ITALIC, italicW }, + { DISPID_FONT_UNDER, underlineW }, + { DISPID_FONT_STRIKE, strikeW }, + { DISPID_FONT_WEIGHT, weightW }, + { DISPID_FONT_CHARSET, charsetW } + }; + IFont *pFont; IFont *pFont2; IConnectionPointContainer *pCPC; @@ -313,6 +391,7 @@ static void test_font_events_disp(void) IFontDisp *pFontDisp; DISPPARAMS dispparams; VARIANTARG vararg; + INT i; fontdesc.cbSizeofstruct = sizeof(fontdesc); fontdesc.lpstrName = MSSansSerif_font; @@ -337,6 +416,7 @@ static void test_font_events_disp(void) EXPECT_HR(hr, S_OK); IConnectionPoint_Release(pCP); + fonteventsdisp_invoke_called = 0; hr = IFont_put_Bold(pFont, TRUE); EXPECT_HR(hr, S_OK); @@ -345,30 +425,73 @@ static void test_font_events_disp(void) hr = IFont_QueryInterface(pFont, &IID_IFontDisp, (void **)&pFontDisp); EXPECT_HR(hr, S_OK); - V_VT(&vararg) = VT_BOOL; - V_BOOL(&vararg) = VARIANT_FALSE; - dispparams.cNamedArgs = 0; - dispparams.rgdispidNamedArgs = NULL; - 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); + for (i = 0; i < sizeof(font_dispids)/sizeof(font_dispids[0]); i++) + { + switch (font_dispids[i].dispid) + { + case DISPID_FONT_NAME: + { + static const WCHAR arialW[] = {'A','r','i','a','l',0}; + V_VT(&vararg) = VT_BSTR; + V_BSTR(&vararg) = SysAllocString(arialW); + break; + } + case DISPID_FONT_SIZE: + V_VT(&vararg) = VT_CY; + S(V_CY(&vararg)).Lo = 25; + S(V_CY(&vararg)).Hi = 0; + break; + case DISPID_FONT_BOLD: + V_VT(&vararg) = VT_BOOL; + V_BOOL(&vararg) = VARIANT_FALSE; + break; + case DISPID_FONT_ITALIC: + case DISPID_FONT_UNDER: + case DISPID_FONT_STRIKE: + V_VT(&vararg) = VT_BOOL; + V_BOOL(&vararg) = VARIANT_TRUE; + break; + case DISPID_FONT_WEIGHT: + V_VT(&vararg) = VT_I2; + V_I2(&vararg) = FW_BLACK; + break; + case DISPID_FONT_CHARSET: + V_VT(&vararg) = VT_I2; + V_I2(&vararg) = 1; + break; + default: + ; + } + + dispparams.cNamedArgs = 0; + dispparams.rgdispidNamedArgs = NULL; + dispparams.cArgs = 1; + dispparams.rgvarg = &vararg; + fonteventsdisp_invoke_called = 0; + hr = IFontDisp_Invoke(pFontDisp, font_dispids[i].dispid, &IID_NULL, 0, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL); + ok(hr == S_OK, "dispid=%d, got 0x%08x\n", font_dispids[i].dispid, hr); + ok(fonteventsdisp_invoke_called == 1, "dispid=%d, DISPID_FONT_CHANGED not called, got %d\n", font_dispids[i].dispid, + fonteventsdisp_invoke_called); + if (hr == S_OK) + { + ok(!lstrcmpW(font_dispids[i].name, fonteventsdisp_invoke_arg0), "dispid=%d, got %s, expected %s\n", + font_dispids[i].dispid, wine_dbgstr_w(fonteventsdisp_invoke_arg0), wine_dbgstr_w(font_dispids[i].name)); + SysFreeString(fonteventsdisp_invoke_arg0); + } + VariantClear(&vararg); + } IFontDisp_Release(pFontDisp); - ok(fonteventsdisp_invoke_called == 2, "IFontEventDisp::Invoke was called %d times instead of twice\n", - fonteventsdisp_invoke_called); - hr = IFont_Clone(pFont, &pFont2); EXPECT_HR(hr, S_OK); IFont_Release(pFont); + /* this test shows that the notification routine isn't called again */ + fonteventsdisp_invoke_called = 0; hr = IFont_put_Bold(pFont2, FALSE); 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", - fonteventsdisp_invoke_called); + ok(fonteventsdisp_invoke_called == 0, "got %d\n", fonteventsdisp_invoke_called); IFont_Release(pFont2); } @@ -544,9 +667,9 @@ static void test_IsEqual(void) S(fd.cySize).Hi = 100; fd.sWeight = 0; fd.sCharset = 0; - fd.fItalic = 0; - fd.fUnderline = 0; - fd.fStrikethrough = 0; + fd.fItalic = FALSE; + fd.fUnderline = FALSE; + fd.fStrikethrough = FALSE; /* Create font */ pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt); @@ -609,30 +732,30 @@ static void test_IsEqual(void) IFont_Release(ifnt2); /* Test italic setting */ - fd.fItalic = 1; + fd.fItalic = TRUE; pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2); hres = IFont_IsEqual(ifnt,ifnt2); ok(hres == S_FALSE, "IFont_IsEqual: (Italic) Expected S_FALSE but got 0x%08x\n",hres); - fd.fItalic = 0; + fd.fItalic = FALSE; IFont_Release(ifnt2); /* Test underline setting */ - fd.fUnderline = 1; + fd.fUnderline = TRUE; pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2); hres = IFont_IsEqual(ifnt,ifnt2); ok(hres == S_FALSE, "IFont_IsEqual: (Underline) Expected S_FALSE but got 0x%08x\n",hres); - fd.fUnderline = 0; + fd.fUnderline = FALSE; IFont_Release(ifnt2); /* Test strikethrough setting */ - fd.fStrikethrough = 1; + fd.fStrikethrough = TRUE; pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt2); hres = IFont_IsEqual(ifnt,ifnt2); ok(hres == S_FALSE, "IFont_IsEqual: (Strikethrough) Expected S_FALSE but got 0x%08x\n",hres); - fd.fStrikethrough = 0; + fd.fStrikethrough = FALSE; IFont_Release(ifnt2); /* Free IFont. */ @@ -657,9 +780,9 @@ static void test_ReleaseHfont(void) S(fd.cySize).Hi = 100; fd.sWeight = 0; fd.sCharset = 0; - fd.fItalic = 0; - fd.fUnderline = 0; - fd.fStrikethrough = 0; + fd.fItalic = FALSE; + fd.fUnderline = FALSE; + fd.fStrikethrough = FALSE; /* Create HFONTs and IFONTs */ pOleCreateFontIndirect(&fd, &IID_IFont, &pvObj1); @@ -727,9 +850,9 @@ static void test_AddRefHfont(void) S(fd.cySize).Hi = 100; fd.sWeight = 0; fd.sCharset = 0; - fd.fItalic = 0; - fd.fUnderline = 0; - fd.fStrikethrough = 0; + fd.fItalic = FALSE; + fd.fUnderline = FALSE; + fd.fStrikethrough = FALSE; /* Create HFONTs and IFONTs */ pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt1); @@ -818,7 +941,7 @@ static void test_AddRefHfont(void) IFont_Release(ifnt2); /* Need to make a new IFONT for testing */ - fd.fUnderline = 1; + fd.fUnderline = TRUE; pOleCreateFontIndirect(&fd, &IID_IFont, (void **)&ifnt3); IFont_get_hFont(ifnt3,&hfnt3); diff --git a/rostests/winetests/oleaut32/olepicture.c b/rostests/winetests/oleaut32/olepicture.c index 40118a5ad8d..df995477891 100644 --- a/rostests/winetests/oleaut32/olepicture.c +++ b/rostests/winetests/oleaut32/olepicture.c @@ -224,7 +224,7 @@ test_pic_with_stream(LPSTREAM stream, unsigned int imgsize) if (handle) { BITMAP bmp; - GetObject(UlongToHandle(handle), sizeof(BITMAP), &bmp); + GetObjectA(UlongToHandle(handle), sizeof(BITMAP), &bmp); todo_wine ok(bmp.bmBits != 0, "not a dib\n"); } @@ -416,12 +416,14 @@ static void test_Invoke(void) { IPictureDisp *picdisp; HRESULT hr; - VARIANTARG vararg; + VARIANTARG vararg, args[10]; DISPPARAMS dispparams; VARIANT varresult; IStream *stream; HGLOBAL hglob; void *data; + HDC hdc; + int i; hglob = GlobalAlloc (0, sizeof(gifimage)); data = GlobalLock(hglob); @@ -481,6 +483,44 @@ static void test_Invoke(void) hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_HPAL, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varresult, NULL, NULL); ok(hr == DISP_E_BADPARAMCOUNT, "IPictureDisp_Invoke should have returned DISP_E_BADPARAMCOUNT instead of 0x%08x\n", hr); + /* DISPID_PICT_RENDER */ + hdc = GetDC(0); + + for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) + V_VT(&args[i]) = VT_I4; + + V_I4(&args[0]) = 0; + V_I4(&args[1]) = 10; + V_I4(&args[2]) = 10; + V_I4(&args[3]) = 0; + V_I4(&args[4]) = 0; + V_I4(&args[5]) = 10; + V_I4(&args[6]) = 10; + V_I4(&args[7]) = 0; + V_I4(&args[8]) = 0; + V_I4(&args[9]) = HandleToLong(hdc); + + dispparams.rgvarg = args; + dispparams.rgdispidNamedArgs = NULL; + dispparams.cArgs = 10; + dispparams.cNamedArgs = 0; + + V_VT(&varresult) = VT_EMPTY; + hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL); + ok(hr == S_OK, "got 0x%08x\n", hr); + + /* Try with one argument set to VT_I2, it'd still work if coerced. */ + V_VT(&args[3]) = VT_I2; + hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL); + ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hr); + V_VT(&args[3]) = VT_I4; + + /* Wrong argument count */ + dispparams.cArgs = 9; + hr = IPictureDisp_Invoke(picdisp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, &dispparams, &varresult, NULL, NULL); + ok(hr == DISP_E_BADPARAMCOUNT, "got 0x%08x\n", hr); + + ReleaseDC(NULL, hdc); IPictureDisp_Release(picdisp); } @@ -616,6 +656,55 @@ static void test_enhmetafile(void) IStream_Release(stream); } +static HRESULT picture_render(IPicture *iface, HDC hdc, LONG x, LONG y, LONG cx, LONG cy, + OLE_XPOS_HIMETRIC xSrc, + OLE_YPOS_HIMETRIC ySrc, + OLE_XSIZE_HIMETRIC cxSrc, + OLE_YSIZE_HIMETRIC cySrc, + const RECT *bounds) +{ + VARIANT ret, args[10]; + HRESULT hr, hr_disp; + DISPPARAMS params; + IDispatch *disp; + int i; + + hr = IPicture_Render(iface, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, bounds); + + IPicture_QueryInterface(iface, &IID_IDispatch, (void**)&disp); + + /* This is broken on 64 bits - accepted pointer argument type is still VT_I4 */ + for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) + V_VT(&args[i]) = VT_I4; + + /* pack arguments and call */ + V_INT_PTR(&args[0]) = (INT_PTR)bounds; + V_I4(&args[1]) = cySrc; + V_I4(&args[2]) = cxSrc; + V_I4(&args[3]) = ySrc; + V_I4(&args[4]) = xSrc; + V_I4(&args[5]) = cy; + V_I4(&args[6]) = cx; + V_I4(&args[7]) = y; + V_I4(&args[8]) = x; + V_I4(&args[9]) = HandleToLong(hdc); + + params.rgvarg = args; + params.rgdispidNamedArgs = NULL; + params.cArgs = 10; + params.cNamedArgs = 0; + + V_VT(&ret) = VT_EMPTY; + hr_disp = IDispatch_Invoke(disp, DISPID_PICT_RENDER, &GUID_NULL, 0, DISPATCH_METHOD, + ¶ms, &ret, NULL, NULL); + ok(hr == hr_disp, "DISPID_PICT_RENDER returned wrong code, 0x%08x, expected 0x%08x\n", + hr_disp, hr); + + IDispatch_Release(disp); + + return hr; +} + static void test_Render(void) { IPicture *pic; @@ -633,28 +722,28 @@ static void test_Render(void) ok(hres == S_OK, "IPicture_get_Type does not return S_OK, but 0x%08x\n", hres); ok(type == PICTYPE_UNINITIALIZED, "Expected type = PICTYPE_UNINITIALIZED, got = %d\n", type); /* zero dimensions */ - hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); /* nonzero dimensions, PICTYPE_UNINITIALIZED */ - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 10, NULL); ole_expect(hres, S_OK); IPicture_Release(pic); desc.cbSizeofstruct = sizeof(PICTDESC); desc.picType = PICTYPE_ICON; - desc.u.icon.hicon = LoadIcon(NULL, IDI_APPLICATION); + desc.u.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); if(!desc.u.icon.hicon){ win_skip("LoadIcon failed. Skipping...\n"); ReleaseDC(NULL, hdc); @@ -663,19 +752,19 @@ static void test_Render(void) OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE, (VOID**)&pic); /* zero dimensions, PICTYPE_ICON */ - hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 0, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 10, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 10, 0, 0, 0, 0, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 10, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 10, 0, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); - hres = IPicture_Render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); + hres = picture_render(pic, hdc, 0, 0, 0, 0, 0, 0, 10, 10, NULL); ole_expect(hres, CTL_E_INVALIDPROPERTYVALUE); /* Check if target size and position is respected */ @@ -687,7 +776,7 @@ static void test_Render(void) SetPixelV(hdc, 10, 10, 0x00223344); expected = GetPixel(hdc, 0, 0); - hres = IPicture_Render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL); + hres = picture_render(pic, hdc, 1, 1, 9, 9, 0, 0, pWidth, -pHeight, NULL); ole_expect(hres, S_OK); if(hres != S_OK) { @@ -1034,7 +1123,7 @@ static void test_load_save_icon(void) desc.cbSizeofstruct = sizeof(desc); desc.picType = PICTYPE_ICON; - desc.u.icon.hicon = LoadIcon(0, IDI_APPLICATION); + desc.u.icon.hicon = LoadIconA(NULL, (LPCSTR)IDI_APPLICATION); hr = OleCreatePictureIndirect(&desc, &IID_IPicture, FALSE, (void**)&pic); ok(hr == S_OK, "OleCreatePictureIndirect error %#x\n", hr); @@ -1082,7 +1171,8 @@ static void test_load_save_empty_picture(void) HGLOBAL hmem; DWORD *mem; IPersistStream *src_stream; - IStream *dst_stream; + IStream *dst_stream, *stream; + LARGE_INTEGER offset; HRESULT hr; memset(&pic, 0, sizeof(pic)); @@ -1117,10 +1207,57 @@ static void test_load_save_empty_picture(void) GlobalUnlock(hmem); IPersistStream_Release(src_stream); + IPicture_Release(pic); + + /* first with statable and seekable stream */ + offset.QuadPart = 0; + hr = IStream_Seek(dst_stream, offset, SEEK_SET, NULL); + ok(hr == S_OK, "IStream_Seek %#x\n", hr); + + pic = NULL; + hr = pOleLoadPicture(dst_stream, 0, FALSE, &IID_IPicture, (void **)&pic); + ok(hr == S_OK, "OleLoadPicture error %#x\n", hr); + ok(pic != NULL,"picture should not be not NULL\n"); + if (pic != NULL) + { + 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); + + IPicture_Release(pic); + } IStream_Release(dst_stream); - GlobalFree(hmem); - IPicture_Release(pic); + /* again with non-statable and non-seekable stream */ + stream = NoStatStream_Construct(hmem); + ok(stream != NULL, "failed to create empty image stream\n"); + + pic = NULL; + hr = pOleLoadPicture(stream, 0, FALSE, &IID_IPicture, (void **)&pic); + ok(hr == S_OK, "OleLoadPicture error %#x\n", hr); + ok(pic != NULL,"picture should not be not NULL\n"); + if (pic != NULL) + { + 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); + + IPicture_Release(pic); + } + /* Non-statable impl always deletes on release */ + IStream_Release(stream); } START_TEST(olepicture) diff --git a/rostests/winetests/oleaut32/safearray.c b/rostests/winetests/oleaut32/safearray.c index 859deb319a7..ae687ff7248 100644 --- a/rostests/winetests/oleaut32/safearray.c +++ b/rostests/winetests/oleaut32/safearray.c @@ -43,6 +43,10 @@ //#include "wtypes.h" #include +#ifndef FADF_CREATEVECTOR + const USHORT FADF_CREATEVECTOR = 0x2000; +#endif + static HMODULE hOleaut32; static HRESULT (WINAPI *pSafeArrayAllocDescriptorEx)(VARTYPE,UINT,SAFEARRAY**); @@ -61,6 +65,14 @@ static BOOL has_i8; /* Has INT_PTR/UINT_PTR type? */ static BOOL has_int_ptr; +static const USHORT ignored_copy_features[] = + { + FADF_AUTO, + FADF_STATIC, + FADF_EMBEDDED, + FADF_FIXEDSIZE + }; + #define START_REF_COUNT 1 #define RECORD_SIZE 64 #define RECORD_SIZE_FAIL 17 @@ -71,36 +83,38 @@ typedef struct IRecordInfoImpl { IRecordInfo IRecordInfo_iface; LONG ref; - DWORD sizeCalled; - DWORD clearCalled; + unsigned int sizeCalled; + unsigned int clearCalled; + unsigned int recordcopy; } 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) +static HRESULT WINAPI RecordInfo_QueryInterface(IRecordInfo *iface, REFIID riid, void **obj) { - IRecordInfoImpl *rec; + *obj = NULL; - rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl)); - rec->IRecordInfo_iface.lpVtbl = &IRecordInfoImpl_VTable; - rec->ref = START_REF_COUNT; - rec->clearCalled = 0; - rec->sizeCalled = 0; - return rec; + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IRecordInfo)) + { + *obj = iface; + IRecordInfo_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; } -static ULONG CALLBACK IRecordInfoImpl_AddRef(IRecordInfo *iface) +static ULONG WINAPI RecordInfo_AddRef(IRecordInfo *iface) { IRecordInfoImpl* This = impl_from_IRecordInfo(iface); return InterlockedIncrement(&This->ref); } -static ULONG CALLBACK IRecordInfoImpl_Release(IRecordInfo *iface) +static ULONG WINAPI RecordInfo_Release(IRecordInfo *iface) { IRecordInfoImpl* This = impl_from_IRecordInfo(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -111,16 +125,41 @@ static ULONG CALLBACK IRecordInfoImpl_Release(IRecordInfo *iface) return ref; } +static HRESULT WINAPI RecordInfo_RecordInit(IRecordInfo *iface, PVOID pvNew) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + static BOOL fail_GetSize; /* Whether to fail the GetSize call */ -static HRESULT CALLBACK IRecordInfoImpl_RecordClear(IRecordInfo *iface, PVOID pvExisting) +static HRESULT WINAPI RecordInfo_RecordClear(IRecordInfo *iface, PVOID pvExisting) { IRecordInfoImpl* This = impl_from_IRecordInfo(iface); This->clearCalled++; return S_OK; } -static HRESULT CALLBACK IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG* size) +static HRESULT WINAPI RecordInfo_RecordCopy(IRecordInfo *iface, PVOID pvExisting, PVOID pvNew) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + This->recordcopy++; + return S_OK; +} + +static HRESULT WINAPI RecordInfo_GetGuid(IRecordInfo *iface, GUID *pguid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetName(IRecordInfo *iface, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetSize(IRecordInfo *iface, ULONG* size) { IRecordInfoImpl* This = impl_from_IRecordInfo(iface); This->sizeCalled++; @@ -133,37 +172,107 @@ static HRESULT CALLBACK IRecordInfoImpl_GetSize(IRecordInfo *iface, ULONG* size) return S_OK; } -static HRESULT CALLBACK IRecordInfoImpl_Dummy(IRecordInfo *iface) +static HRESULT WINAPI RecordInfo_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo) { - trace("Called an unexpected IRecordInfo method - please report!\n"); - /* Quit because we'll just crash anyway */ - fflush(NULL); - exit(255); + ok(0, "unexpected call\n"); + return E_NOTIMPL; } -static const IRecordInfoVtbl IRecordInfoImpl_VTable = +static HRESULT WINAPI RecordInfo_GetField(IRecordInfo *iface, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField) { - (PVOID)IRecordInfoImpl_Dummy, - IRecordInfoImpl_AddRef, - IRecordInfoImpl_Release, - (PVOID)IRecordInfoImpl_Dummy, - IRecordInfoImpl_RecordClear, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - IRecordInfoImpl_GetSize, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy, - (PVOID)IRecordInfoImpl_Dummy + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags, + PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetFieldNames(IRecordInfo *iface, ULONG *pcNames, + BSTR *rgBstrNames) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static BOOL WINAPI RecordInfo_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static PVOID WINAPI RecordInfo_RecordCreate(IRecordInfo *iface) +{ + ok(0, "unexpected call\n"); + return NULL; +} + +static HRESULT WINAPI RecordInfo_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource, + PVOID *ppvDest) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_RecordDestroy(IRecordInfo *iface, PVOID pvRecord) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IRecordInfoVtbl RecordInfoVtbl = +{ + RecordInfo_QueryInterface, + RecordInfo_AddRef, + RecordInfo_Release, + RecordInfo_RecordInit, + RecordInfo_RecordClear, + RecordInfo_RecordCopy, + RecordInfo_GetGuid, + RecordInfo_GetName, + RecordInfo_GetSize, + RecordInfo_GetTypeInfo, + RecordInfo_GetField, + RecordInfo_GetFieldNoCopy, + RecordInfo_PutField, + RecordInfo_PutFieldNoCopy, + RecordInfo_GetFieldNames, + RecordInfo_IsMatchingType, + RecordInfo_RecordCreate, + RecordInfo_RecordCreateCopy, + RecordInfo_RecordDestroy }; +static IRecordInfoImpl *IRecordInfoImpl_Construct(void) +{ + IRecordInfoImpl *rec; + + rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl)); + rec->IRecordInfo_iface.lpVtbl = &RecordInfoVtbl; + rec->ref = START_REF_COUNT; + rec->clearCalled = 0; + rec->sizeCalled = 0; + return rec; +} + static DWORD SAFEARRAY_GetVTSize(VARTYPE vt) { switch (vt) @@ -957,10 +1066,11 @@ test_LockUnlock_Vector: static void test_SafeArrayGetPutElement(void) { SAFEARRAYBOUND sab[4]; - LONG indices[NUM_DIMENSIONS]; + LONG indices[NUM_DIMENSIONS], index; SAFEARRAY *sa; HRESULT hres; int value = 0, gotvalue, dimension; + IRecordInfoImpl *irec; unsigned int x,y,z,a; for (dimension = 0; dimension < NUM_DIMENSIONS; dimension++) @@ -974,8 +1084,6 @@ static void test_SafeArrayGetPutElement(void) return; /* Some early versions can't handle > 3 dims */ ok(sa->cbElements == sizeof(value), "int size mismatch\n"); - if (sa->cbElements != sizeof(value)) - return; /* Failure cases */ for (x = 0; x < NUM_DIMENSIONS; x++) @@ -1079,6 +1187,34 @@ static void test_SafeArrayGetPutElement(void) } hres = SafeArrayDestroy(sa); ok(hres == S_OK, "got 0x%08x\n", hres); + + /* VT_RECORD array */ + irec = IRecordInfoImpl_Construct(); + irec->ref = 1; + + sab[0].lLbound = 0; + sab[0].cElements = 8; + + sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &irec->IRecordInfo_iface); + ok(sa != NULL, "failed to create array\n"); + ok(irec->ref == 2, "got %d\n", irec->ref); + + index = 0; + irec->recordcopy = 0; + hres = SafeArrayPutElement(sa, &index, (void*)0xdeadbeef); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy); + + index = 0; + irec->recordcopy = 0; + hres = SafeArrayGetElement(sa, &index, (void*)0xdeadbeef); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(irec->recordcopy == 1, "got %d\n", irec->recordcopy); + + hres = SafeArrayDestroy(sa); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(irec->ref == 1, "got %d\n", irec->ref); + IRecordInfo_Release(&irec->IRecordInfo_iface); } static void test_SafeArrayGetPutElement_BSTR(void) @@ -1099,8 +1235,6 @@ static void test_SafeArrayGetPutElement_BSTR(void) return; ok(sa->cbElements == sizeof(BSTR), "BSTR size mismatch\n"); - if (sa->cbElements != sizeof(BSTR)) - return; indices[0] = sab.lLbound; value = SysAllocString(szTest); @@ -1163,8 +1297,6 @@ static void test_SafeArrayGetPutElement_IUnknown(void) return; ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n"); - if (sa->cbElements != sizeof(LPUNKNOWN)) - return; indices[0] = sab.lLbound; xtunk.ref = 1; @@ -1197,8 +1329,6 @@ static void test_SafeArrayRedim_IUnknown(void) return; ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n"); - if (sa->cbElements != sizeof(LPUNKNOWN)) - return; indices[0] = 2; xtunk.ref = 1; @@ -1229,8 +1359,6 @@ static void test_SafeArrayGetPutElement_VARIANT(void) return; ok(sa->cbElements == sizeof(VARIANT), "VARIANT size mismatch\n"); - if (sa->cbElements != sizeof(VARIANT)) - return; indices[0] = sab.lLbound; V_VT(&value) = VT_I4; @@ -1254,14 +1382,13 @@ static void test_SafeArrayGetPutElement_VARIANT(void) ok(hres == S_OK, "got 0x%08x\n", hres); } - static void test_SafeArrayCopyData(void) { SAFEARRAYBOUND sab[4]; SAFEARRAY *sa; SAFEARRAY *sacopy; HRESULT hres; - int dimension,size=1; + int dimension, size = 1, i; if (!pSafeArrayCopyData) { @@ -1285,8 +1412,6 @@ static void test_SafeArrayCopyData(void) return; ok(sa->cbElements == sizeof(int), "int size mismatch\n"); - if (sa->cbElements != sizeof(int)) - return; /* Fill the source array with some data; it doesn't matter what */ for (dimension = 0; dimension < size; dimension++) @@ -1334,17 +1459,58 @@ static void test_SafeArrayCopyData(void) hres = SafeArrayCopy(sa, &sacopy); ok(hres == S_OK, "copy failed hres 0x%x\n", hres); - if (hres == S_OK) + 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"); + hres = SafeArrayDestroy(sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); + + sacopy = SafeArrayCreate(VT_INT, NUM_DIMENSIONS, sab); + ok(sacopy != NULL, "Copy test couldn't create copy array\n"); + ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures); + + for (i = 0; i < sizeof(ignored_copy_features)/sizeof(USHORT); i++) { - 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"); - hres = SafeArrayDestroy(sacopy); - ok(hres == S_OK, "got 0x%08x\n", hres); + USHORT feature = ignored_copy_features[i]; + USHORT orig = sacopy->fFeatures; + + sa->fFeatures |= feature; + hres = SafeArrayCopyData(sa, sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(sacopy->fFeatures == orig && orig == FADF_HAVEVARTYPE, "got features 0x%04x\n", sacopy->fFeatures); + sa->fFeatures &= ~feature; } + hres = SafeArrayDestroy(sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); hres = SafeArrayDestroy(sa); ok(hres == S_OK, "got 0x%08x\n", hres); + + /* copy data from a vector */ + sa = SafeArrayCreateVector(VT_UI1, 0, 2); + + sacopy = SafeArrayCreateVector(VT_UI1, 0, 2); + ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) || + broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */), + "got 0x%08x\n", sa->fFeatures); + ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) || + broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */), + "got 0x%08x\n", sacopy->fFeatures); + hres = SafeArrayCopyData(sa, sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(sacopy->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) || + broken(sacopy->fFeatures == FADF_CREATEVECTOR /* W2k */), + "got 0x%04x\n", sacopy->fFeatures); + SafeArrayDestroy(sacopy); + + sacopy = SafeArrayCreate(VT_UI1, NUM_DIMENSIONS, sab); + ok(sacopy != NULL, "Copy test couldn't create copy array\n"); + ok(sacopy->fFeatures == FADF_HAVEVARTYPE, "0x%04x\n", sacopy->fFeatures); + hres = SafeArrayCopyData(sa, sacopy); + ok(hres == E_INVALIDARG, "got 0x%08x\n", hres); + SafeArrayDestroy(sacopy); + + SafeArrayDestroy(sa); } static void test_SafeArrayCreateEx(void) @@ -1447,7 +1613,7 @@ static void test_SafeArrayCreateEx(void) /* Win32 doesn't care if GetSize fails */ fail_GetSize = TRUE; - sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, iRec); + sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface); ok(sa != NULL, "CreateEx (Fail Size) failed\n"); ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref); ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled); @@ -1466,7 +1632,7 @@ static void test_SafeArrayCreateEx(void) iRec->ref = START_REF_COUNT; iRec->sizeCalled = 0; iRec->clearCalled = 0; - sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, iRec); + sa = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface); ok(sa != NULL, "CreateEx (Rec) failed\n"); ok(iRec->ref == START_REF_COUNT + 1, "Wrong iRec refcount %d\n", iRec->ref); ok(iRec->sizeCalled == 1, "GetSize called %d times\n", iRec->sizeCalled); @@ -1474,19 +1640,34 @@ static void test_SafeArrayCreateEx(void) if (sa && pSafeArrayGetRecordInfo) { IRecordInfo* saRec = NULL; - hres = pSafeArrayGetRecordInfo(sa, &saRec); + SAFEARRAY *sacopy; + hres = pSafeArrayGetRecordInfo(sa, &saRec); ok(hres == S_OK,"GRI failed\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); + IRecordInfo_Release(saRec); ok(sa->cbElements == RECORD_SIZE,"Elemsize is %d\n", sa->cbElements); + /* try to copy record based arrays */ + sacopy = pSafeArrayCreateEx(VT_RECORD, 1, sab, &iRec->IRecordInfo_iface); + iRec->recordcopy = 0; + iRec->clearCalled = 0; + /* array copy code doesn't explicitely clear a record */ + hres = SafeArrayCopyData(sa, sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(iRec->recordcopy == sab[0].cElements, "got %d\n", iRec->recordcopy); + ok(iRec->clearCalled == 0, "got %d\n", iRec->clearCalled); + + hres = SafeArrayDestroy(sacopy); + ok(hres == S_OK, "got 0x%08x\n", hres); + + iRec->clearCalled = 0; + iRec->sizeCalled = 0; 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->sizeCalled == 0, "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); } @@ -1545,6 +1726,7 @@ static void test_SafeArrayCopy(void) SAFEARRAY *sa, *sa2; VARIANTARG vSrc, vDst; HRESULT hres; + int i; sab.lLbound = 0; sab.cElements = 10; @@ -1609,6 +1791,41 @@ static void test_SafeArrayCopy(void) ok(hres == S_OK, "got 0x%08x\n", hres); hres = SafeArrayDestroy(sa); ok(hres == S_OK, "got 0x%08x\n", hres); + + /* test feature copy */ + hres = SafeArrayAllocDescriptor(1, &sa); + ok(hres == S_OK, "SafeArrayAllocDescriptor failed with error 0x%08x\n", hres); + ok(sa->fFeatures == 0, "got src features 0x%04x\n", sa->fFeatures); + sa->cbElements = 16; + + for (i = 0; i < sizeof(ignored_copy_features)/sizeof(USHORT); i++) + { + USHORT feature = ignored_copy_features[i]; + + sa->fFeatures |= feature; + hres = SafeArrayCopy(sa, &sa2); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(sa2->fFeatures == 0, "got features 0x%04x\n", sa2->fFeatures); + hres = SafeArrayDestroy(sa2); + ok(hres == S_OK, "got 0x%08x\n", hres); + sa->fFeatures &= ~feature; + } + + SafeArrayDestroy(sa); + + /* copy from a vector */ + sa = SafeArrayCreateVector(VT_UI1, 0, 2); + ok(sa->fFeatures == (FADF_HAVEVARTYPE|FADF_CREATEVECTOR) || + broken(sa->fFeatures == FADF_CREATEVECTOR /* W2k */), + "got 0x%08x\n", sa->fFeatures); + hres = SafeArrayCopy(sa, &sa2); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(sa2->fFeatures == FADF_HAVEVARTYPE || + broken(!sa2->fFeatures /* W2k */), "got 0x%04x\n", + sa2->fFeatures); + + SafeArrayDestroy(sa2); + SafeArrayDestroy(sa); } #define MKARRAY(low,num,typ) sab.lLbound = low; sab.cElements = num; \ @@ -1753,7 +1970,7 @@ static void test_SafeArrayDestroyData (void) HRESULT hres; int value = 0xdeadbeef; LONG index[1]; - void HUGEP *temp_pvData; + void *temp_pvData; sab.lLbound = 0; sab.cElements = 10; @@ -1784,6 +2001,63 @@ static void test_SafeArrayDestroyData (void) ok(hres == S_OK, "SAD failed, error code %x.\n", hres); } +static void test_safearray_layout(void) +{ + IRecordInfoImpl *irec; + IRecordInfo *record; + GUID guid, *guidptr; + SAFEARRAYBOUND sab; + SAFEARRAY *sa; + DWORD *dwptr; + HRESULT hr; + + sab.lLbound = 0; + sab.cElements = 10; + + /* GUID field */ + sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab); + ok(sa != NULL, "got %p\n", sa); + + guidptr = (GUID*)sa - 1; + ok(IsEqualIID(guidptr, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(guidptr)); + + hr = SafeArraySetIID(sa, &IID_IDispatch); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualIID(guidptr, &IID_IDispatch), "got %s\n", wine_dbgstr_guid(guidptr)); + + memcpy(guidptr, &IID_IUnknown, sizeof(GUID)); + hr = SafeArrayGetIID(sa, &guid); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualIID(&guid, &IID_IUnknown), "got %s\n", wine_dbgstr_guid(&guid)); + + hr = SafeArrayDestroy(sa); + ok(hr == S_OK, "got 0x%08x\n", hr); + + /* VARTYPE field */ + sa = SafeArrayCreate(VT_UI1, 1, &sab); + ok(sa != NULL, "got %p\n", sa); + + dwptr = (DWORD*)sa - 1; + ok(*dwptr == VT_UI1, "got %d\n", *dwptr); + + hr = SafeArrayDestroy(sa); + ok(hr == S_OK, "got 0x%08x\n", hr); + + /* IRecordInfo pointer */ + irec = IRecordInfoImpl_Construct(); + irec->ref = 1; + + sa = pSafeArrayCreateEx(VT_RECORD, 1, &sab, &irec->IRecordInfo_iface); + ok(sa != NULL, "failed to create array\n"); + + record = *((IRecordInfo**)sa - 1); + ok(record == &irec->IRecordInfo_iface, "got %p\n", record); + + hr = SafeArrayDestroy(sa); + ok(hr == S_OK, "got 0x%08x\n", hr); + IRecordInfo_Release(&irec->IRecordInfo_iface); +} + START_TEST(safearray) { hOleaut32 = GetModuleHandleA("oleaut32.dll"); @@ -1816,4 +2090,5 @@ START_TEST(safearray) test_SafeArrayGetPutElement_IUnknown(); test_SafeArrayRedim_IUnknown(); test_SafeArrayGetPutElement_VARIANT(); + test_safearray_layout(); } diff --git a/rostests/winetests/oleaut32/test_reg.idl b/rostests/winetests/oleaut32/test_reg.idl index 7f73b2502e9..ff32a1c508d 100644 --- a/rostests/winetests/oleaut32/test_reg.idl +++ b/rostests/winetests/oleaut32/test_reg.idl @@ -18,6 +18,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#pragma makedep ident +#pragma makedep typelib + import "oaidl.idl"; /* needed by widl */ [ @@ -134,5 +137,9 @@ library register_test { [propget, id(DISPID_VALUE)] LONG test([in] LONG i); + [propputref, id(1)] + LONG testprop([in] LONG *i); + [propputref, id(2)] + LONG testprop2([in] IUnknown *i); } } diff --git a/rostests/winetests/oleaut32/test_tlb.idl b/rostests/winetests/oleaut32/test_tlb.idl index 91b6a7680af..59425be7628 100644 --- a/rostests/winetests/oleaut32/test_tlb.idl +++ b/rostests/winetests/oleaut32/test_tlb.idl @@ -18,6 +18,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#pragma makedep ident +#pragma makedep typelib + import "oaidl.idl"; /* needed by widl */ [uuid(8b05fe77-4a6c-4133-b9cd-8f81747af784)] @@ -36,4 +39,13 @@ library Test { HRESULT test(); } + + [uuid(4029f190-ca4a-4611-aeb9-673983cb96dd)] + struct test_struct + { + HRESULT hr; + VARIANT_BOOL b; + IDispatch *disp; + BSTR bstr; + }; } diff --git a/rostests/winetests/oleaut32/tmarshal.c b/rostests/winetests/oleaut32/tmarshal.c index 68361c63ba4..5222d0e4b59 100644 --- a/rostests/winetests/oleaut32/tmarshal.c +++ b/rostests/winetests/oleaut32/tmarshal.c @@ -41,7 +41,7 @@ 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) +#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr) /* ULL suffix is not portable */ #define ULL_CONST(dw1, dw2) ((((ULONGLONG)dw1) << 32) | (ULONGLONG)dw2) @@ -89,11 +89,11 @@ static DWORD CALLBACK host_object_proc(LPVOID p) ok_ole_success(hr, CoMarshalInterface); /* force the message queue to be created before signaling parent thread */ - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); SetEvent(data->marshal_event); - while (GetMessage(&msg, NULL, 0, 0)) + while (GetMessageA(&msg, NULL, 0, 0)) { if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA) { @@ -102,7 +102,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p) SetEvent((HANDLE)msg.lParam); } else - DispatchMessage(&msg); + DispatchMessageA(&msg); } HeapFree(GetProcessHeap(), 0, data); @@ -115,7 +115,7 @@ static DWORD CALLBACK host_object_proc(LPVOID p) static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread) { DWORD tid = 0; - HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL); + HANDLE marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL); struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data)); data->stream = stream; @@ -144,8 +144,8 @@ static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, M * same thread that marshaled the interface in the first place. */ static void release_host_object(DWORD tid) { - HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); - PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event); + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL); + PostThreadMessageA(tid, RELEASEMARSHALDATA, 0, (LPARAM)event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } @@ -153,7 +153,7 @@ static void release_host_object(DWORD tid) static void end_host_object(DWORD tid, HANDLE thread) { - BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0); + BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0); ok(ret, "PostThreadMessage failed with error %d\n", GetLastError()); /* be careful of races - don't return until hosting thread has terminated */ WaitForSingleObject(thread, INFINITE); @@ -730,9 +730,8 @@ 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; + return FALSE; + return TRUE; } static HRESULT WINAPI Widget_StructArgs( @@ -835,7 +834,7 @@ static HRESULT WINAPI Widget_put_prop_req_arg( return S_OK; } -static HRESULT WINAPI Widget_do_restrict(IWidget* iface, INT *i) +static HRESULT WINAPI Widget__restrict(IWidget* iface, INT *i) { trace("restrict\n"); *i = DISPID_TM_RESTRICTED; @@ -885,7 +884,7 @@ static const struct IWidgetVtbl Widget_VTable = Widget_ByRefUInt, Widget_put_prop_opt_arg, Widget_put_prop_req_arg, - Widget_do_restrict, + Widget__restrict, Widget_neg_restrict }; @@ -1204,7 +1203,7 @@ static void test_typelibmarshal(void) { static const WCHAR szCat[] = { 'C','a','t',0 }; static const WCHAR szTestTest[] = { 'T','e','s','t','T','e','s','t',0 }; - static WCHAR szSuperman[] = { 'S','u','p','e','r','m','a','n',0 }; + static const WCHAR szSuperman[] = { 'S','u','p','e','r','m','a','n',0 }; HRESULT hr; IKindaEnumWidget *pKEW = KindaEnumWidget_Create(); IWidget *pWidget; diff --git a/rostests/winetests/oleaut32/tmarshal.idl b/rostests/winetests/oleaut32/tmarshal.idl index 92b54357752..60854db2fcb 100644 --- a/rostests/winetests/oleaut32/tmarshal.idl +++ b/rostests/winetests/oleaut32/tmarshal.idl @@ -17,6 +17,9 @@ * */ +#pragma makedep ident +#pragma makedep typelib + #include "tmarshal_dispids.h" import "ocidl.idl"; diff --git a/rostests/winetests/oleaut32/typelib.c b/rostests/winetests/oleaut32/typelib.c index bb99aa68147..f515bc6c646 100644 --- a/rostests/winetests/oleaut32/typelib.c +++ b/rostests/winetests/oleaut32/typelib.c @@ -41,17 +41,19 @@ #include #include +#include #define expect_eq(expr, value, type, format) { type _ret = (expr); ok((value) == _ret, #expr " expected " format " got " format "\n", value, _ret); } #define expect_int(expr, value) expect_eq(expr, (int)(value), int, "%d") #define expect_hex(expr, value) expect_eq(expr, (int)(value), int, "0x%x") #define expect_null(expr) expect_eq(expr, NULL, const void *, "%p") +#define expect_guid(expected, guid) { ok(IsEqualGUID(expected, guid), "got wrong guid\n"); } #define expect_wstr_acpval(expr, value) \ { \ CHAR buf[260]; \ expect_eq(!WideCharToMultiByte(CP_ACP, 0, (expr), -1, buf, 260, NULL, NULL), 0, int, "%d"); \ - ok(lstrcmp(value, buf) == 0, #expr " expected \"%s\" got \"%s\"\n", value, buf); \ + ok(strcmp(value, buf) == 0, #expr " expected \"%s\" got \"%s\"\n", value, buf); \ } #define ole_expect(expr, expect) { \ @@ -83,7 +85,7 @@ 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 const BOOL is_win64 = sizeof(void *) > sizeof(int); static HRESULT WINAPI invoketest_QueryInterface(IInvokeTest *iface, REFIID riid, void **ret) { @@ -140,6 +142,16 @@ static LONG WINAPI invoketest_get_test(IInvokeTest *iface, LONG i) return i+1; } +static LONG WINAPI invoketest_putref_testprop(IInvokeTest *iface, LONG *i) +{ + return *i+2; +} + +static LONG WINAPI invoketest_putref_testprop2(IInvokeTest *iface, IUnknown *i) +{ + return 6; +} + static const IInvokeTestVtbl invoketestvtbl = { invoketest_QueryInterface, invoketest_AddRef, @@ -148,7 +160,9 @@ static const IInvokeTestVtbl invoketestvtbl = { invoketest_GetTypeInfo, invoketest_GetIDsOfNames, invoketest_Invoke, - invoketest_get_test + invoketest_get_test, + invoketest_putref_testprop, + invoketest_putref_testprop2 }; static IInvokeTest invoketest = { &invoketestvtbl }; @@ -635,14 +649,14 @@ static void write_typelib(int res_no, const char *filename) HRSRC res; void *ptr; - file = CreateFile( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + file = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" ); if (file == INVALID_HANDLE_VALUE) return; - res = FindResource( GetModuleHandle(0), MAKEINTRESOURCE(res_no), "TYPELIB" ); + res = FindResourceA( GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(res_no), "TYPELIB" ); ok( res != 0, "couldn't find resource\n" ); - ptr = LockResource( LoadResource( GetModuleHandle(0), res )); - WriteFile( file, ptr, SizeofResource( GetModuleHandle(0), res ), &written, NULL ); - ok( written == SizeofResource( GetModuleHandle(0), res ), "couldn't write resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); CloseHandle( file ); } @@ -658,7 +672,7 @@ static const char *create_test_typelib(int res_no) static void test_TypeInfo(void) { ITypeLib *pTypeLib; - ITypeInfo *pTypeInfo; + ITypeInfo *pTypeInfo, *ti; ITypeInfo2 *pTypeInfo2; HRESULT hr; static WCHAR wszBogus[] = { 'b','o','g','u','s',0 }; @@ -675,6 +689,8 @@ static void test_TypeInfo(void) TYPEKIND kind; const char *filenameA; WCHAR filename[MAX_PATH]; + TYPEATTR *attr; + LONG l; hr = LoadTypeLib(wszStdOle2, &pTypeLib); ok_ole_success(hr, LoadTypeLib); @@ -772,8 +788,6 @@ static void test_TypeInfo(void) ITypeInfo_Release(pTypeInfo); - - hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_IDispatch, &pTypeInfo); ok_ole_success(hr, ITypeLib_GetTypeInfoOfGuid); @@ -799,6 +813,23 @@ static void test_TypeInfo(void) VariantClear(&var); } + /* Check instance size for IDispatch, typelib is loaded using system SYS_WIN* kind so it always matches + system bitness. */ + hr = ITypeInfo_GetTypeAttr(pTypeInfo, &attr); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(attr->cbSizeInstance == sizeof(void*), "got size %d\n", attr->cbSizeInstance); + ok(attr->typekind == TKIND_INTERFACE, "got typekind %d\n", attr->typekind); + ITypeInfo_ReleaseTypeAttr(pTypeInfo, attr); + + /* same size check with some general interface */ + hr = ITypeLib_GetTypeInfoOfGuid(pTypeLib, &IID_IEnumVARIANT, &ti); + ok(hr == S_OK, "got 0x%08x\n", hr); + hr = ITypeInfo_GetTypeAttr(ti, &attr); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(attr->cbSizeInstance == sizeof(void*), "got size %d\n", attr->cbSizeInstance); + ITypeInfo_ReleaseTypeAttr(ti, attr); + ITypeInfo_Release(ti); + /* test invoking a method with a [restricted] keyword */ /* correct member id -- wrong flags -- cNamedArgs not bigger than cArgs */ @@ -854,8 +885,6 @@ static void test_TypeInfo(void) V_VT(&args[0]) = VT_I4; V_I4(&args[0]) = 0; - V_VT(&res) = VT_EMPTY; - i = 0; V_VT(&res) = VT_EMPTY; V_I4(&res) = 0; @@ -881,6 +910,48 @@ static void test_TypeInfo(void) ok(V_VT(&res) == VT_I4, "got %d\n", V_VT(&res)); ok(V_I4(&res) == 1, "got %d\n", V_I4(&res)); + /* DISPATCH_PROPERTYPUTREF */ + l = 1; + V_VT(&args[0]) = VT_I4|VT_BYREF; + V_I4REF(&args[0]) = &l; + + dispidMember = DISPID_PROPERTYPUT; + dispparams.cArgs = 1; + dispparams.cNamedArgs = 1; + dispparams.rgdispidNamedArgs = &dispidMember; + dispparams.rgvarg = args; + + i = 0; + V_VT(&res) = VT_EMPTY; + V_I4(&res) = 0; + hr = ITypeInfo_Invoke(pTypeInfo, &invoketest, 1, DISPATCH_PROPERTYPUTREF, &dispparams, &res, NULL, &i); + ok(hr == S_OK, "got 0x%08x, %d\n", hr, i); + ok(V_VT(&res) == VT_I4, "got %d\n", V_VT(&res)); + ok(V_I4(&res) == 3, "got %d\n", V_I4(&res)); + + i = 0; + V_VT(&res) = VT_EMPTY; + V_I4(&res) = 0; + hr = ITypeInfo_Invoke(pTypeInfo, &invoketest, 1, DISPATCH_PROPERTYPUT, &dispparams, &res, NULL, &i); + ok(hr == DISP_E_MEMBERNOTFOUND, "got 0x%08x, %d\n", hr, i); + + i = 0; + V_VT(&args[0]) = VT_UNKNOWN; + V_UNKNOWN(&args[0]) = NULL; + + V_VT(&res) = VT_EMPTY; + V_I4(&res) = 0; + hr = ITypeInfo_Invoke(pTypeInfo, &invoketest, 2, DISPATCH_PROPERTYPUTREF, &dispparams, &res, NULL, &i); + ok(hr == S_OK, "got 0x%08x, %d\n", hr, i); + ok(V_VT(&res) == VT_I4, "got %d\n", V_VT(&res)); + ok(V_I4(&res) == 6, "got %d\n", V_I4(&res)); + + i = 0; + V_VT(&res) = VT_EMPTY; + V_I4(&res) = 0; + hr = ITypeInfo_Invoke(pTypeInfo, &invoketest, 2, DISPATCH_PROPERTYPUT, &dispparams, &res, NULL, &i); + ok(hr == DISP_E_MEMBERNOTFOUND, "got 0x%08x, %d\n", hr, i); + ITypeInfo_Release(pTypeInfo); ITypeLib_Release(pTypeLib); DeleteFileA(filenameA); @@ -1265,7 +1336,7 @@ static void test_inheritance(void) CHAR pathA[MAX_PATH]; static const WCHAR tl_path[] = {'.','\\','m','i','d','l','_','t','m','a','r','s','h','a','l','.','t','l','b',0}; - BOOL use_midl_tlb = 0; + BOOL use_midl_tlb = FALSE; GetModuleFileNameA(NULL, pathA, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH); @@ -1529,7 +1600,6 @@ if(use_midl_tlb) { } static void test_CreateTypeLib(SYSKIND sys) { - static const WCHAR stdoleW[] = {'s','t','d','o','l','e','2','.','t','l','b',0}; static OLECHAR typelibW[] = {'t','y','p','e','l','i','b',0}; static OLECHAR helpfileW[] = {'C',':','\\','b','o','g','u','s','.','h','l','p',0}; static OLECHAR interface1W[] = {'i','n','t','e','r','f','a','c','e','1',0}; @@ -1537,8 +1607,8 @@ static void test_CreateTypeLib(SYSKIND sys) { static OLECHAR interface3W[] = {'i','n','t','e','r','f','a','c','e','3',0}; 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 const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0x3213,0}; + static const 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}; @@ -1546,6 +1616,7 @@ static void test_CreateTypeLib(SYSKIND sys) { static OLECHAR param2W[] = {'p','a','r','a','m','2',0}; static OLECHAR asdfW[] = {'A','s','d','f',0}; static OLECHAR aliasW[] = {'a','l','i','a','s',0}; + static OLECHAR invokeW[] = {'I','n','v','o','k','e',0}; static OLECHAR *names1[] = {func1W, param1W, param2W}; static OLECHAR *names2[] = {func2W, param1W, param2W}; static OLECHAR *propname[] = {prop1W, param1W}; @@ -1561,7 +1632,10 @@ static void test_CreateTypeLib(SYSKIND sys) { ICreateTypeInfo2 *createti2; ITypeLib *tl, *stdole; ITypeInfo *interface1, *interface2, *dual, *unknown, *dispatch, *ti; + ITypeInfo *tinfos[2]; ITypeInfo2 *ti2; + ITypeComp *tcomp; + MEMBERID memids[2]; FUNCDESC funcdesc, *pfuncdesc; ELEMDESC elemdesc[5], *edesc; PARAMDESCEX paramdescex; @@ -1573,9 +1647,12 @@ static void test_CreateTypeLib(SYSKIND sys) { DWORD helpcontext, ptr_size, alignment; int impltypeflags; unsigned int cnames; + USHORT found; VARIANT cust_data; HRESULT hres; TYPEKIND kind; + DESCKIND desckind; + BINDPTR bindptr; switch(sys){ case SYS_WIN32: @@ -1594,7 +1671,7 @@ static void test_CreateTypeLib(SYSKIND sys) { trace("CreateTypeLib tests\n"); - hres = LoadTypeLib(stdoleW, &stdole); + hres = LoadTypeLib(wszStdOle2, &stdole); ok(hres == S_OK, "got %08x\n", hres); hres = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IUnknown, &unknown); @@ -2666,10 +2743,49 @@ static void test_CreateTypeLib(SYSKIND sys) { ok(libattr->syskind == sys, "syskind = %d\n", libattr->syskind); ok(libattr->wMajorVerNum == 0, "wMajorVer = %d\n", libattr->wMajorVerNum); ok(libattr->wMinorVerNum == 0, "wMinorVerNum = %d\n", libattr->wMinorVerNum); - todo_wine - ok(libattr->wLibFlags == LIBFLAG_FHASDISKIMAGE, "wLibFlags = %d\n", libattr->wLibFlags); + ok(libattr->wLibFlags == LIBFLAG_FHASDISKIMAGE, "wLibFlags = %d\n", libattr->wLibFlags); ITypeLib_ReleaseTLibAttr(tl, libattr); + found = 2; + memset(tinfos, 0, sizeof(tinfos)); + memids[0] = 0xdeadbeef; + memids[1] = 0xdeadbeef; + hres = ITypeLib_FindName(tl, param1W, 0, tinfos, memids, &found); + ok(hres == S_OK, "got: %08x\n", hres); + ok(found == 0, "got wrong count: %u\n", found); + ok(tinfos[0] == NULL, "got invalid typeinfo[0]\n"); + ok(tinfos[1] == NULL, "got invalid typeinfo[1]\n"); + ok(memids[0] == 0xdeadbeef, "got invalid memid[0]\n"); + ok(memids[1] == 0xdeadbeef, "got invalid memid[1]\n"); + + found = 2; + memset(tinfos, 0, sizeof(tinfos)); + memids[0] = 0xdeadbeef; + memids[1] = 0xdeadbeef; + hres = ITypeLib_FindName(tl, func1W, 0, tinfos, memids, &found); + ok(hres == S_OK, "got: %08x\n", hres); + ok(found == 1, "got wrong count: %u\n", found); + ok(tinfos[0] != NULL, "got invalid typeinfo[0]\n"); + ok(tinfos[1] == NULL, "got invalid typeinfo[1]\n"); + ok(memids[0] == 0, "got invalid memid[0]\n"); + ok(memids[1] == 0xdeadbeef, "got invalid memid[1]\n"); + if(tinfos[0]) + ITypeInfo_Release(tinfos[0]); + + found = 2; + memset(tinfos, 0, sizeof(tinfos)); + memids[0] = 0xdeadbeef; + memids[1] = 0xdeadbeef; + hres = ITypeLib_FindName(tl, interface1W, 0, tinfos, memids, &found); + ok(hres == S_OK, "got: %08x\n", hres); + ok(found == 1, "got wrong count: %u\n", found); + ok(tinfos[0] != NULL, "got invalid typeinfo[0]\n"); + ok(tinfos[1] == NULL, "got invalid typeinfo[1]\n"); + ok(memids[0] == MEMBERID_NIL, "got invalid memid[0]: %x\n", memids[0]); + ok(memids[1] == 0xdeadbeef, "got invalid memid[1]\n"); + if(tinfos[0]) + ITypeInfo_Release(tinfos[0]); + hres = ITypeLib_GetDocumentation(tl, -1, &name, &docstring, &helpcontext, &helpfile); ok(hres == S_OK, "got %08x\n", hres); ok(memcmp(typelibW, name, sizeof(typelibW)) == 0, "got wrong typelib name: %s\n", @@ -3450,6 +3566,34 @@ static void test_CreateTypeLib(SYSKIND sys) { ok(typeattr->wMinorVerNum == 0, "wMinorVerNum = %d\n", typeattr->wMinorVerNum); ITypeInfo_ReleaseTypeAttr(ti, typeattr); + hres = ITypeInfo_GetTypeComp(ti, &tcomp); + ok(hres == S_OK, "got %08x\n", hres); + + hres = ITypeComp_Bind(tcomp, invokeW, 0, INVOKE_FUNC, &interface1, &desckind, &bindptr); + ok(hres == S_OK, "got %08x\n", hres); + ok(desckind == DESCKIND_FUNCDESC, "got wrong desckind: 0x%x\n", desckind); + ok(bindptr.lpfuncdesc->memid == 0x60010003, "got %x\n", bindptr.lpfuncdesc->memid); + ok(bindptr.lpfuncdesc->lprgscode == NULL, "got %p\n", bindptr.lpfuncdesc->lprgscode); + ok(bindptr.lpfuncdesc->lprgelemdescParam != NULL, "got %p\n", bindptr.lpfuncdesc->lprgelemdescParam); + ok(bindptr.lpfuncdesc->funckind == FUNC_DISPATCH, "got 0x%x\n", bindptr.lpfuncdesc->funckind); + ok(bindptr.lpfuncdesc->invkind == INVOKE_FUNC, "got 0x%x\n", bindptr.lpfuncdesc->invkind); + ok(bindptr.lpfuncdesc->callconv == CC_STDCALL, "got 0x%x\n", bindptr.lpfuncdesc->callconv); + ok(bindptr.lpfuncdesc->cParams == 8, "got %d\n", bindptr.lpfuncdesc->cParams); + ok(bindptr.lpfuncdesc->cParamsOpt == 0, "got %d\n", bindptr.lpfuncdesc->cParamsOpt); +#ifdef _WIN64 + if(sys == SYS_WIN32) + todo_wine ok(bindptr.lpfuncdesc->oVft == 6 * sizeof(void*), "got %x\n", bindptr.lpfuncdesc->oVft); + else +#endif + ok(bindptr.lpfuncdesc->oVft == 6 * sizeof(void*), "got %x\n", bindptr.lpfuncdesc->oVft); + ok(bindptr.lpfuncdesc->cScodes == 0, "got %d\n", bindptr.lpfuncdesc->cScodes); + ok(bindptr.lpfuncdesc->elemdescFunc.tdesc.vt == VT_VOID, "got %d\n", bindptr.lpfuncdesc->elemdescFunc.tdesc.vt); + ok(bindptr.lpfuncdesc->wFuncFlags == FUNCFLAG_FRESTRICTED, "got 0x%x\n", bindptr.lpfuncdesc->wFuncFlags); + + ITypeInfo_ReleaseFuncDesc(interface1, bindptr.lpfuncdesc); + ITypeInfo_Release(interface1); + ITypeComp_Release(tcomp); + hres = ITypeInfo_GetRefTypeOfImplType(ti, -1, &hreftype); ok(hres == S_OK, "got %08x\n", hres); ok(hreftype == -2, "got wrong hreftype: %x\n", hreftype); @@ -3675,9 +3819,10 @@ typedef struct _function_info LPCSTR names[15]; } function_info; -typedef struct _interface_info +typedef struct _type_info { LPCSTR name; + LPCSTR uuid; TYPEKIND type; WORD wTypeFlags; USHORT cbAlignment; @@ -3685,17 +3830,17 @@ typedef struct _interface_info USHORT cbSizeVft; USHORT cFuncs; function_info funcs[20]; -} interface_info; +} type_info; -static const interface_info info[] = { -/* interfaces count: 2 */ +static const type_info info[] = { { "IDualIface", - /*kind*/ TKIND_DISPATCH, /*flags*/ 0x1040, /*align*/ 4, /*size*/ 4, + "{b14b6bb5-904e-4ff9-b247-bd361f7aaedd}", + /*kind*/ TKIND_DISPATCH, /*flags*/ TYPEFLAG_FDISPATCHABLE|TYPEFLAG_FDUAL, /*align*/ 4, /*size*/ sizeof(void*), /*#vtbl*/ 7, /*#func*/ 8, { { - 0x60000000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60000000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 2, /*#opt*/ 0, /*vtbl*/ 0, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ @@ -3711,7 +3856,7 @@ static const interface_info info[] = { }, }, { - 0x60000001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60000001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 1, /*#scodes*/ 0, /*flags*/ 0x1, {19, 0}, /* ret */ { /* params */ @@ -3723,7 +3868,7 @@ static const interface_info info[] = { }, }, { - 0x60000002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60000002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 2, /*#scodes*/ 0, /*flags*/ 0x1, {19, 0}, /* ret */ { /* params */ @@ -3735,7 +3880,7 @@ static const interface_info info[] = { }, }, { - 0x60010000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60010000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 1, /*#opt*/ 0, /*vtbl*/ 3, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ @@ -3749,7 +3894,7 @@ static const interface_info info[] = { }, }, { - 0x60010001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60010001, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 3, /*#opt*/ 0, /*vtbl*/ 4, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ @@ -3767,7 +3912,7 @@ static const interface_info info[] = { }, }, { - 0x60010002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60010002, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 5, /*#opt*/ 0, /*vtbl*/ 5, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ @@ -3789,7 +3934,7 @@ static const interface_info info[] = { }, }, { - 0x60010003, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60010003, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 8, /*#opt*/ 0, /*vtbl*/ 6, /*#scodes*/ 0, /*flags*/ 0x1, {24, 0}, /* ret */ { /* params */ @@ -3817,7 +3962,7 @@ static const interface_info info[] = { }, }, { - 0x60020000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60020000, /*func*/ FUNC_DISPATCH, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 7, /*#scodes*/ 0, /*flags*/ 0x0, {24, 0}, /* ret */ { /* params */ @@ -3832,11 +3977,12 @@ static const interface_info info[] = { }, { "ISimpleIface", - /*kind*/ TKIND_INTERFACE, /*flags*/ 0x1000, /*align*/ 4, /*size*/ 4, + "{ec5dfcd6-eeb0-4cd6-b51e-8030e1dac009}", + /*kind*/ TKIND_INTERFACE, /*flags*/ TYPEFLAG_FDISPATCHABLE, /*align*/ 4, /*size*/ sizeof(void*), /*#vtbl*/ 8, /*#func*/ 1, { { - 0x60020000, /*func*/ FUNC_PUREVIRTUAL, /*inv*/ INVOKE_FUNC, /*call*/ 0x4, + 0x60020000, /*func*/ FUNC_PUREVIRTUAL, /*inv*/ INVOKE_FUNC, /*call*/ CC_STDCALL, /*#param*/ 0, /*#opt*/ 0, /*vtbl*/ 7, /*#scodes*/ 0, /*flags*/ 0x0, {25, 0}, /* ret */ { /* params */ @@ -3849,6 +3995,11 @@ static const interface_info info[] = { }, } }, +{ + "test_struct", + "{4029f190-ca4a-4611-aeb9-673983cb96dd}", + /* kind */ TKIND_RECORD, /*flags*/ 0, /*align*/ 4, /*size*/ sizeof(struct test_struct) +} }; #define check_type(elem, info) { \ @@ -3860,36 +4011,55 @@ static void test_dump_typelib(const char *name) { WCHAR wszName[MAX_PATH]; ITypeLib *typelib; - int ifcount = sizeof(info)/sizeof(info[0]); + int ticount = sizeof(info)/sizeof(info[0]); int iface, func; MultiByteToWideChar(CP_ACP, 0, name, -1, wszName, MAX_PATH); ole_check(LoadTypeLibEx(wszName, REGKIND_NONE, &typelib)); - expect_eq(ITypeLib_GetTypeInfoCount(typelib), ifcount, UINT, "%d"); - for (iface = 0; iface < ifcount; iface++) + expect_eq(ITypeLib_GetTypeInfoCount(typelib), ticount, UINT, "%d"); + for (iface = 0; iface < ticount; iface++) { - const interface_info *if_info = &info[iface]; + const type_info *ti = &info[iface]; ITypeInfo *typeinfo; TYPEATTR *typeattr; BSTR bstrIfName; - trace("Interface %s\n", if_info->name); + trace("Interface %s\n", ti->name); ole_check(ITypeLib_GetTypeInfo(typelib, iface, &typeinfo)); ole_check(ITypeLib_GetDocumentation(typelib, iface, &bstrIfName, NULL, NULL, NULL)); - expect_wstr_acpval(bstrIfName, if_info->name); + expect_wstr_acpval(bstrIfName, ti->name); SysFreeString(bstrIfName); ole_check(ITypeInfo_GetTypeAttr(typeinfo, &typeattr)); - expect_int(typeattr->typekind, if_info->type); - expect_hex(typeattr->wTypeFlags, if_info->wTypeFlags); - expect_int(typeattr->cbAlignment, if_info->cbAlignment); - expect_int(typeattr->cbSizeInstance, if_info->cbSizeInstance); - expect_int(typeattr->cbSizeVft, if_info->cbSizeVft * sizeof(void*)); - expect_int(typeattr->cFuncs, if_info->cFuncs); + expect_int(typeattr->typekind, ti->type); + expect_hex(typeattr->wTypeFlags, ti->wTypeFlags); + expect_int(typeattr->cbAlignment, ti->cbAlignment); + expect_int(typeattr->cbSizeInstance, ti->cbSizeInstance); + expect_int(typeattr->cbSizeVft, ti->cbSizeVft * sizeof(void*)); + expect_int(typeattr->cFuncs, ti->cFuncs); + + /* compare type uuid */ + if (ti->uuid && *ti->uuid) + { + WCHAR guidW[39]; + ITypeInfo *typeinfo2; + HRESULT hr; + GUID guid; + + MultiByteToWideChar(CP_ACP, 0, ti->uuid, -1, guidW, sizeof(guidW)/sizeof(guidW[0])); + IIDFromString(guidW, &guid); + expect_guid(&guid, &typeattr->guid); + + /* check that it's possible to search using this uuid */ + typeinfo2 = NULL; + hr = ITypeLib_GetTypeInfoOfGuid(typelib, &guid, &typeinfo2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ITypeInfo_Release(typeinfo2); + } for (func = 0; func < typeattr->cFuncs; func++) { - function_info *fn_info = (function_info *)&if_info->funcs[func]; + function_info *fn_info = (function_info *)&ti->funcs[func]; FUNCDESC *desc; BSTR namesTab[256]; UINT cNames; @@ -3941,7 +4111,9 @@ static void test_create_typelib_lcid(LCID lcid) HRESULT hr; ICreateTypeLib2 *tl; HANDLE file; - DWORD msft_header[7]; + DWORD msft_header[8]; + ITypeLib *typelib; + TLIBATTR *attr; DWORD read; GetTempFileNameA( ".", "tlb", 0, filename ); @@ -3950,6 +4122,14 @@ static void test_create_typelib_lcid(LCID lcid) hr = CreateTypeLib2(SYS_WIN32, name, &tl); ok(hr == S_OK, "got %08x\n", hr); + hr = ICreateTypeLib2_QueryInterface(tl, &IID_ITypeLib, (void**)&typelib); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ITypeLib_GetLibAttr(typelib, &attr); + ok(hr == S_OK, "got %08x\n", hr); + ok(attr->wLibFlags == 0, "flags 0x%x\n", attr->wLibFlags); + ITypeLib_ReleaseTLibAttr(typelib, attr); + hr = ICreateTypeLib2_SetLcid(tl, lcid); ok(hr == S_OK, "got %08x\n", hr); @@ -3959,6 +4139,12 @@ static void test_create_typelib_lcid(LCID lcid) hr = ICreateTypeLib2_SaveAllChanges(tl); ok(hr == S_OK, "got %08x\n", hr); + hr = ITypeLib_GetLibAttr(typelib, &attr); + ok(hr == S_OK, "got %08x\n", hr); + ok(attr->wLibFlags == 0, "flags 0x%x\n", attr->wLibFlags); + ITypeLib_ReleaseTLibAttr(typelib, attr); + + ITypeLib_Release(typelib); ICreateTypeLib2_Release(tl); file = CreateFileA( filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 ); @@ -3974,6 +4160,17 @@ static void test_create_typelib_lcid(LCID lcid) ok(msft_header[3] == (lcid ? lcid : 0x409), "got %08x (lcid %08x)\n", msft_header[3], lcid); ok(msft_header[4] == lcid, "got %08x (lcid %08x)\n", msft_header[4], lcid); ok(msft_header[6] == 0x00040003, "got %08x\n", msft_header[6]); + ok(msft_header[7] == 0, "got %08x\n", msft_header[7]); + + /* check flags after loading */ + hr = LoadTypeLib(name, &typelib); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ITypeLib_GetLibAttr(typelib, &attr); + ok(hr == S_OK, "got %08x\n", hr); + ok(attr->wLibFlags == LIBFLAG_FHASDISKIMAGE, "flags 0x%x\n", attr->wLibFlags); + ITypeLib_ReleaseTLibAttr(typelib, attr); + ITypeLib_Release(typelib); DeleteFileA(filename); } @@ -4059,6 +4256,7 @@ static void test_register_typelib(BOOL system_registration) { ITypeInfo *typeinfo; TYPEATTR *attr; + REGSAM opposite = (sizeof(void*) == 8 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY); hr = ITypeLib_GetTypeInfo(typelib, i, &typeinfo); ok(hr == S_OK, "got %08x\n", hr); @@ -4108,6 +4306,11 @@ static void test_register_typelib(BOOL system_registration) ok(ret == expect_ret, "%d: got %d\n", i, ret); if(ret == ERROR_SUCCESS) RegCloseKey(hkey); + /* 32-bit typelibs should be registered into both registry bit modes */ + ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, key_name, 0, KEY_READ | opposite, &hkey); + ok(ret == expect_ret, "%d: got %d\n", i, ret); + if(ret == ERROR_SUCCESS) RegCloseKey(hkey); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); ITypeInfo_Release(typeinfo); } @@ -4199,8 +4402,8 @@ static void test_SetVarHelpContext(void) ok(pdesc->memid == 0x40000000, "got wrong memid: %x\n", pdesc->memid); ok(pdesc->elemdescVar.tdesc.vt == VT_INT, "got wrong vardesc type: %u\n", pdesc->elemdescVar.tdesc.vt); ok(pdesc->varkind == VAR_CONST, "got wrong varkind: %u\n", pdesc->varkind); - ok(V_VT(U(pdesc)->lpvarValue) == VT_INT, "got wrong value type: %u\n", V_VT(U(pdesc)->lpvarValue)); - ok(V_INT(U(pdesc)->lpvarValue) == 1, "got wrong value: 0x%x\n", V_INT(U(pdesc)->lpvarValue)); + ok(V_VT(U(*pdesc).lpvarValue) == VT_INT, "got wrong value type: %u\n", V_VT(U(*pdesc).lpvarValue)); + ok(V_INT(U(*pdesc).lpvarValue) == 1, "got wrong value: 0x%x\n", V_INT(U(*pdesc).lpvarValue)); hr = ITypeInfo_GetDocumentation(ti, pdesc->memid, NULL, NULL, &ctx, NULL); ok(hr == S_OK, "got %08x\n", hr); @@ -4216,15 +4419,22 @@ static void test_SetVarHelpContext(void) static void test_SetFuncAndParamNames(void) { static OLECHAR nameW[] = {'n','a','m','e',0}; + static OLECHAR name2W[] = {'n','a','m','e','2',0}; static OLECHAR prop[] = {'p','r','o','p',0}; static OLECHAR *propW[] = {prop}; + static OLECHAR func[] = {'f','u','n','c',0}; + static OLECHAR *funcW[] = {func, NULL}; CHAR filenameA[MAX_PATH]; WCHAR filenameW[MAX_PATH]; ICreateTypeLib2 *ctl; ICreateTypeInfo *cti; + ITypeLib *tl; + ITypeInfo *infos[3]; + MEMBERID memids[3]; FUNCDESC funcdesc; ELEMDESC edesc; HRESULT hr; + USHORT found; GetTempFileNameA(".", "tlb", 0, filenameA); MultiByteToWideChar(CP_ACP, 0, filenameA, -1, filenameW, MAX_PATH); @@ -4284,24 +4494,80 @@ static void test_SetFuncAndParamNames(void) hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 3, propW, 1); ok(hr == TYPE_E_AMBIGUOUSNAME, "got 0x%08x\n", hr); + /* regular function */ + funcdesc.invkind = INVOKE_FUNC; + funcdesc.cParams = 1; + hr = ICreateTypeInfo_AddFuncDesc(cti, 4, &funcdesc); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 4, funcW, 2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ICreateTypeInfo_Release(cti); + + hr = ICreateTypeLib2_CreateTypeInfo(ctl, name2W, TKIND_INTERFACE, &cti); + ok(hr == S_OK, "got %08x\n", hr); + + funcdesc.funckind = FUNC_PUREVIRTUAL; + funcdesc.invkind = INVOKE_FUNC; + funcdesc.cParams = 0; + funcdesc.lprgelemdescParam = NULL; + hr = ICreateTypeInfo_AddFuncDesc(cti, 0, &funcdesc); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = ICreateTypeInfo_SetFuncAndParamNames(cti, 0, funcW, 1); + ok(hr == S_OK, "got 0x%08x\n", hr); + + ICreateTypeInfo_Release(cti); + + hr = ICreateTypeLib2_QueryInterface(ctl, &IID_ITypeLib, (void**)&tl); + ok(hr == S_OK, "got %08x\n", hr); + + found = 1; + memset(infos, 0, sizeof(infos)); + memids[0] = 0xdeadbeef; + memids[1] = 0xdeadbeef; + memids[2] = 0xdeadbeef; + hr = ITypeLib_FindName(tl, func, 0, infos, memids, &found); + ok(hr == S_OK, "got %08x\n", hr); + ok(found == 1, "got wrong count: %u\n", found); + ok(infos[0] && !infos[1] && !infos[2], "got wrong typeinfo\n"); + ok(memids[0] == 0, "got wrong memid[0]\n"); + ok(memids[1] == 0xdeadbeef && memids[2] == 0xdeadbeef, "got wrong memids\n"); + + found = 3; + memset(infos, 0, sizeof(infos)); + memids[0] = 0xdeadbeef; + memids[1] = 0xdeadbeef; + memids[2] = 0xdeadbeef; + hr = ITypeLib_FindName(tl, func, 0, infos, memids, &found); + ok(hr == S_OK, "got %08x\n", hr); + ok(found == 2, "got wrong count: %u\n", found); + ok(infos[0] && infos[1] && infos[0] != infos[1], "got same typeinfo\n"); + ok(memids[0] == 0, "got wrong memid[0]\n"); + ok(memids[1] == 0, "got wrong memid[1]\n"); + + ITypeLib_Release(tl); ICreateTypeLib2_Release(ctl); DeleteFileA(filenameA); } -static void test_SetVarDocString(void) +static void test_SetDocString(void) { static OLECHAR nameW[] = {'n','a','m','e',0}; + static OLECHAR name2W[] = {'n','a','m','e','2',0}; static OLECHAR doc1W[] = {'d','o','c','1',0}; static OLECHAR doc2W[] = {'d','o','c','2',0}; + static OLECHAR var_nameW[] = {'v','a','r','n','a','m','e',0}; CHAR filenameA[MAX_PATH]; WCHAR filenameW[MAX_PATH]; ICreateTypeLib2 *ctl; ICreateTypeInfo *cti; ITypeLib *tl; ITypeInfo *ti; - BSTR docstr; + BSTR namestr, docstr; VARDESC desc, *pdesc; + FUNCDESC funcdesc, *pfuncdesc; HRESULT hr; VARIANT v; @@ -4331,6 +4597,15 @@ static void test_SetVarDocString(void) hr = ICreateTypeInfo_AddVarDesc(cti, 0, &desc); ok(hr == S_OK, "got %08x\n", hr); + hr = ICreateTypeInfo_SetVarName(cti, 0, NULL); + ok(hr == E_INVALIDARG, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetVarName(cti, 1, var_nameW); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetVarName(cti, 0, var_nameW); + ok(hr == S_OK, "got %08x\n", hr); + hr = ICreateTypeInfo_SetVarDocString(cti, 0, NULL); ok(hr == E_INVALIDARG, "got %08x\n", hr); @@ -4347,6 +4622,29 @@ static void test_SetVarDocString(void) ICreateTypeInfo_Release(cti); + hr = ICreateTypeLib2_CreateTypeInfo(ctl, name2W, TKIND_INTERFACE, &cti); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetFuncDocString(cti, 0, doc1W); + ok(hr == TYPE_E_ELEMENTNOTFOUND, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetFuncDocString(cti, 0, NULL); + ok(hr == E_INVALIDARG, "got %08x\n", hr); + + memset(&funcdesc, 0, sizeof(funcdesc)); + funcdesc.memid = MEMBERID_NIL; + funcdesc.funckind = FUNC_PUREVIRTUAL; + funcdesc.invkind = INVOKE_FUNC; + funcdesc.callconv = CC_STDCALL; + + hr = ICreateTypeInfo_AddFuncDesc(cti, 0, &funcdesc); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetFuncDocString(cti, 0, doc1W); + ok(hr == S_OK, "got %08x\n", hr); + + ICreateTypeInfo_Release(cti); + hr = ICreateTypeLib2_SaveAllChanges(ctl); ok(hr == S_OK, "got: %08x\n", hr); @@ -4363,17 +4661,40 @@ static void test_SetVarDocString(void) ok(pdesc->memid == 0x40000000, "got wrong memid: %x\n", pdesc->memid); ok(pdesc->elemdescVar.tdesc.vt == VT_INT, "got wrong vardesc type: %u\n", pdesc->elemdescVar.tdesc.vt); ok(pdesc->varkind == VAR_CONST, "got wrong varkind: %u\n", pdesc->varkind); - ok(V_VT(U(pdesc)->lpvarValue) == VT_INT, "got wrong value type: %u\n", V_VT(U(pdesc)->lpvarValue)); - ok(V_INT(U(pdesc)->lpvarValue) == 1, "got wrong value: 0x%x\n", V_INT(U(pdesc)->lpvarValue)); + ok(V_VT(U(*pdesc).lpvarValue) == VT_INT, "got wrong value type: %u\n", V_VT(U(*pdesc).lpvarValue)); + ok(V_INT(U(*pdesc).lpvarValue) == 1, "got wrong value: 0x%x\n", V_INT(U(*pdesc).lpvarValue)); - hr = ITypeInfo_GetDocumentation(ti, pdesc->memid, NULL, &docstr, NULL, NULL); + hr = ITypeInfo_GetDocumentation(ti, pdesc->memid, &namestr, &docstr, NULL, NULL); ok(hr == S_OK, "got %08x\n", hr); + ok(memcmp(namestr, var_nameW, sizeof(var_nameW)) == 0, "got wrong name: %s\n", wine_dbgstr_w(namestr)); ok(memcmp(docstr, doc2W, sizeof(doc2W)) == 0, "got wrong docstring: %s\n", wine_dbgstr_w(docstr)); + SysFreeString(namestr); SysFreeString(docstr); ITypeInfo_ReleaseVarDesc(ti, pdesc); ITypeInfo_Release(ti); + + hr = ITypeLib_GetTypeInfo(tl, 1, &ti); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ITypeInfo_GetFuncDesc(ti, 0, &pfuncdesc); + ok(hr == S_OK, "got %08x\n", hr); + ok(pfuncdesc->memid == 0x60000000, "got wrong memid: %x\n", pfuncdesc->memid); + ok(pfuncdesc->funckind == FUNC_PUREVIRTUAL, "got wrong funckind: %x\n", pfuncdesc->funckind); + ok(pfuncdesc->invkind == INVOKE_FUNC, "got wrong invkind: %x\n", pfuncdesc->invkind); + ok(pfuncdesc->callconv == CC_STDCALL, "got wrong callconv: %x\n", pfuncdesc->callconv); + + hr = ITypeInfo_GetDocumentation(ti, pfuncdesc->memid, &namestr, &docstr, NULL, NULL); + ok(hr == S_OK, "got %08x\n", hr); + ok(namestr == NULL, "got wrong name: %s\n", wine_dbgstr_w(namestr)); + ok(memcmp(docstr, doc1W, sizeof(doc1W)) == 0, "got wrong docstring: %s\n", wine_dbgstr_w(docstr)); + + SysFreeString(docstr); + + ITypeInfo_ReleaseFuncDesc(ti, pfuncdesc); + ITypeInfo_Release(ti); + ITypeLib_Release(tl); DeleteFileA(filenameA); @@ -4418,8 +4739,7 @@ static void test_FindName(void) 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(memid == MEMBERID_NIL, "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); @@ -4431,7 +4751,7 @@ todo_wine 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(memid == MEMBERID_NIL, "got %d\n", memid); ok(!lstrcmpW(buffW, wszGUID), "got %s\n", wine_dbgstr_w(buffW)); ok(c == 1, "got %d\n", c); } @@ -4444,7 +4764,7 @@ todo_wine { 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(memid == MEMBERID_NIL, "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); @@ -4545,7 +4865,7 @@ static const char manifest_dep[] = "" "" " " "" "" @@ -4608,19 +4928,24 @@ static void test_LoadRegTypeLib(void) path = NULL; hr = QueryPathOfRegTypeLib(&LIBID_TestTypelib, 2, 0, LOCALE_NEUTRAL, &path); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); SysFreeString(path); path = NULL; hr = QueryPathOfRegTypeLib(&LIBID_TestTypelib, 2, 0, lcid_en, &path); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); SysFreeString(path); path = NULL; hr = QueryPathOfRegTypeLib(&LIBID_TestTypelib, 2, 0, lcid_ru, &path); -todo_wine + ok(hr == S_OK, "got 0x%08x\n", hr); + SysFreeString(path); + + hr = QueryPathOfRegTypeLib(&LIBID_TestTypelib, 2, 8, LOCALE_NEUTRAL, &path); + ok(hr == TYPE_E_LIBNOTREGISTERED || broken(hr == S_OK) /* winxp */, "got 0x%08x\n", hr); + + path = NULL; + hr = QueryPathOfRegTypeLib(&LIBID_TestTypelib, 2, 7, LOCALE_NEUTRAL, &path); ok(hr == S_OK, "got 0x%08x\n", hr); SysFreeString(path); @@ -4639,22 +4964,18 @@ todo_wine /* manifest version is 2.7, actual is 2.5 */ hr = LoadRegTypeLib(&LIBID_TestTypelib, 2, 0, LOCALE_NEUTRAL, &tl); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); if (hr == S_OK) ITypeLib_Release(tl); hr = LoadRegTypeLib(&LIBID_TestTypelib, 2, 1, LOCALE_NEUTRAL, &tl); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); if (hr == S_OK) ITypeLib_Release(tl); hr = LoadRegTypeLib(&LIBID_TestTypelib, 2, 0, lcid_en, &tl); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); if (hr == S_OK) ITypeLib_Release(tl); hr = LoadRegTypeLib(&LIBID_TestTypelib, 2, 0, lcid_ru, &tl); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); if (hr == S_OK) ITypeLib_Release(tl); @@ -4662,11 +4983,8 @@ todo_wine ok(hr == TYPE_E_LIBNOTREGISTERED, "got 0x%08x\n", hr); hr = LoadRegTypeLib(&LIBID_TestTypelib, 2, 5, LOCALE_NEUTRAL, &tl); -todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); -if (hr == S_OK) -{ hr = ITypeLib_GetLibAttr(tl, &attr); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -4677,7 +4995,6 @@ if (hr == S_OK) ITypeLib_ReleaseTLibAttr(tl, attr); ITypeLib_Release(tl); -} hr = LoadRegTypeLib(&LIBID_TestTypelib, 1, 7, LOCALE_NEUTRAL, &tl); ok(hr == TYPE_E_LIBNOTREGISTERED, "got 0x%08x\n", hr); @@ -4931,6 +5248,179 @@ static void test_SetTypeDescAlias(SYSKIND kind) DeleteFileA(filenameA); } +static void test_GetLibAttr(void) +{ + ULONG ref1, ref2; + TLIBATTR *attr; + ITypeLib *tl; + HRESULT hr; + + hr = LoadTypeLib(wszStdOle2, &tl); + ok(hr == S_OK, "got 0x%08x\n", hr); + + ref1 = ITypeLib_AddRef(tl); + ITypeLib_Release(tl); + + hr = ITypeLib_GetLibAttr(tl, &attr); + ok(hr == S_OK, "got 0x%08x\n", hr); + + ref2 = ITypeLib_AddRef(tl); + ITypeLib_Release(tl); + ok(ref2 == ref1, "got %d, %d\n", ref2, ref1); + + ITypeLib_ReleaseTLibAttr(tl, attr); + ITypeLib_Release(tl); +} + +static HRESULT WINAPI uk_QueryInterface(IUnknown *obj, REFIID iid, void **out) +{ + return E_NOINTERFACE; +} + +static ULONG WINAPI uk_AddRef(IUnknown *obj) +{ + return 2; +} + +static ULONG WINAPI uk_Release(IUnknown *obj) +{ + return 1; +} + +IUnknownVtbl vt = { + uk_QueryInterface, + uk_AddRef, + uk_Release, +}; + +IUnknown uk = {&vt}; + +static void test_stub(void) +{ + HRESULT hr; + CLSID clsid; + IPSFactoryBuffer *factory; + IRpcStubBuffer *base_stub; + ITypeLib *stdole; + ICreateTypeLib2 *ctl; + ICreateTypeInfo *cti; + ITypeLib *tl; + ITypeInfo *unk, *ti; + HREFTYPE href; + char filenameA[MAX_PATH]; + WCHAR filenameW[MAX_PATH]; + HKEY hkey; + LONG lr; + + static const GUID libguid = {0x3b9ff02e,0x9675,0x4861,{0xb7,0x81,0xce,0xae,0xa4,0x78,0x2a,0xcc}}; + static const GUID interfaceguid = {0x3b9ff02f,0x9675,0x4861,{0xb7,0x81,0xce,0xae,0xa4,0x78,0x2a,0xcc}}; + static const GUID coclassguid = {0x3b9ff030,0x9675,0x4861,{0xb7,0x81,0xce,0xae,0xa4,0x78,0x2a,0xcc}}; + static OLECHAR interfaceW[] = {'i','n','t','e','r','f','a','c','e',0}; + static OLECHAR classW[] = {'c','l','a','s','s',0}; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = LoadTypeLib(wszStdOle2, &stdole); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ITypeLib_GetTypeInfoOfGuid(stdole, &IID_IUnknown, &unk); + ok(hr == S_OK, "got %08x\n", 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_SetGuid(ctl, &libguid); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeLib2_SetLcid(ctl, LOCALE_NEUTRAL); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeLib2_CreateTypeInfo(ctl, interfaceW, TKIND_INTERFACE, &cti); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetGuid(cti, &interfaceguid); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetTypeFlags(cti, TYPEFLAG_FOLEAUTOMATION); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_AddRefTypeInfo(cti, unk, &href); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_AddImplType(cti, 0, href); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_QueryInterface(cti, &IID_ITypeInfo, (void**)&ti); + ok(hr == S_OK, "got %08x\n", hr); + + ICreateTypeInfo_Release(cti); + ITypeInfo_Release(unk); + ITypeLib_Release(stdole); + + hr = ICreateTypeLib2_CreateTypeInfo(ctl, classW, TKIND_COCLASS, &cti); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_SetGuid(cti, &coclassguid); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_AddRefTypeInfo(cti, ti, &href); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeInfo_AddImplType(cti, 0, href); + ok(hr == S_OK, "got %08x\n", hr); + + ITypeInfo_Release(ti); + ICreateTypeInfo_Release(cti); + + hr = ICreateTypeLib2_SaveAllChanges(ctl); + ok(hr == S_OK, "got %08x\n", hr); + + hr = ICreateTypeLib2_QueryInterface(ctl, &IID_ITypeLib, (void**)&tl); + ok(hr == S_OK, "got %08x\n", hr); + + hr = RegisterTypeLib(tl, filenameW, NULL); + if (hr == TYPE_E_REGISTRYACCESS) + { + win_skip("Insufficient privileges to register typelib in the registry\n"); + ITypeLib_Release(tl); + DeleteFileW(filenameW); + CoUninitialize(); + return; + } + ok(hr == S_OK, "got %08x\n", hr); + + ITypeLib_Release(tl); + ok(0 == ICreateTypeLib2_Release(ctl), "Typelib still has references\n"); + + /* SYS_WIN32 typelibs should be registered only as 32-bit */ + lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "TypeLib\\{3b9ff02e-9675-4861-b781-ceaea4782acc}\\0.0\\0\\win64", 0, KEY_READ, &hkey); + ok(lr == ERROR_FILE_NOT_FOUND, "got wrong return code: %u\n", lr); + + lr = RegOpenKeyExA(HKEY_CLASSES_ROOT, "TypeLib\\{3b9ff02e-9675-4861-b781-ceaea4782acc}\\0.0\\0\\win32", 0, KEY_READ, &hkey); + ok(lr == ERROR_SUCCESS, "got wrong return code: %u\n", lr); + RegCloseKey(hkey); + + hr = CoGetPSClsid(&interfaceguid, &clsid); + ok(hr == S_OK, "got: %x\n", hr); + + hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, + &IID_IPSFactoryBuffer, (void **)&factory); + ok(hr == S_OK, "got: %x\n", hr); + + hr = IPSFactoryBuffer_CreateStub(factory, &interfaceguid, &uk, &base_stub); + ok(hr == S_OK, "got: %x\n", hr); + + IPSFactoryBuffer_Release(factory); + + UnRegisterTypeLib(&libguid, 0, 0, 0, SYS_WIN32); + DeleteFileW(filenameW); + + CoUninitialize(); +} + START_TEST(typelib) { const char *filename; @@ -4953,13 +5443,13 @@ START_TEST(typelib) test_inheritance(); test_SetVarHelpContext(); test_SetFuncAndParamNames(); - test_SetVarDocString(); + test_SetDocString(); test_FindName(); if ((filename = create_test_typelib(2))) { test_dump_typelib( filename ); - DeleteFile( filename ); + DeleteFileA( filename ); } test_register_typelib(TRUE); @@ -4968,4 +5458,6 @@ START_TEST(typelib) test_LoadTypeLib(); test_TypeInfo2_GetContainingTypeLib(); test_LoadRegTypeLib(); + test_GetLibAttr(); + test_stub(); } diff --git a/rostests/winetests/oleaut32/vartest.c b/rostests/winetests/oleaut32/vartest.c index b78e8716fd7..0327af396fd 100644 --- a/rostests/winetests/oleaut32/vartest.c +++ b/rostests/winetests/oleaut32/vartest.c @@ -28,6 +28,7 @@ #include #include +#define COBJMACROS #define CONST_VTABLE //#include "windef.h" @@ -100,6 +101,198 @@ static BOOL has_i8; #define R8_MAX DBL_MAX #define R8_MIN DBL_MIN +typedef struct IRecordInfoImpl +{ + IRecordInfo IRecordInfo_iface; + LONG ref; + unsigned int recordclear; + unsigned int getsize; + unsigned int recordcopy; + struct __tagBRECORD *rec; +} IRecordInfoImpl; + +static inline IRecordInfoImpl *impl_from_IRecordInfo(IRecordInfo *iface) +{ + return CONTAINING_RECORD(iface, IRecordInfoImpl, IRecordInfo_iface); +} + +static HRESULT WINAPI RecordInfo_QueryInterface(IRecordInfo *iface, REFIID riid, void **obj) +{ + *obj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IRecordInfo)) + { + *obj = iface; + IRecordInfo_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI RecordInfo_AddRef(IRecordInfo *iface) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI RecordInfo_Release(IRecordInfo *iface) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) + HeapFree(GetProcessHeap(), 0, This); + + return ref; +} + +static HRESULT WINAPI RecordInfo_RecordInit(IRecordInfo *iface, PVOID pvNew) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_RecordClear(IRecordInfo *iface, void *data) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + This->recordclear++; + This->rec->pvRecord = NULL; + return S_OK; +} + +static HRESULT WINAPI RecordInfo_RecordCopy(IRecordInfo *iface, void *src, void *dest) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + This->recordcopy++; + ok(src == (void*)0xdeadbeef, "wrong src pointer %p\n", src); + return S_OK; +} + +static HRESULT WINAPI RecordInfo_GetGuid(IRecordInfo *iface, GUID *pguid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetName(IRecordInfo *iface, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetSize(IRecordInfo *iface, ULONG* size) +{ + IRecordInfoImpl* This = impl_from_IRecordInfo(iface); + This->getsize++; + *size = 0; + return S_OK; +} + +static HRESULT WINAPI RecordInfo_GetTypeInfo(IRecordInfo *iface, ITypeInfo **ppTypeInfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetField(IRecordInfo *iface, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetFieldNoCopy(IRecordInfo *iface, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField, PVOID *ppvDataCArray) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_PutField(IRecordInfo *iface, ULONG wFlags, PVOID pvData, + LPCOLESTR szFieldName, VARIANT *pvarField) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_PutFieldNoCopy(IRecordInfo *iface, ULONG wFlags, + PVOID pvData, LPCOLESTR szFieldName, VARIANT *pvarField) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_GetFieldNames(IRecordInfo *iface, ULONG *pcNames, + BSTR *rgBstrNames) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static BOOL WINAPI RecordInfo_IsMatchingType(IRecordInfo *iface, IRecordInfo *info2) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static PVOID WINAPI RecordInfo_RecordCreate(IRecordInfo *iface) +{ + ok(0, "unexpected call\n"); + return NULL; +} + +static HRESULT WINAPI RecordInfo_RecordCreateCopy(IRecordInfo *iface, PVOID pvSource, + PVOID *ppvDest) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecordInfo_RecordDestroy(IRecordInfo *iface, PVOID pvRecord) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IRecordInfoVtbl RecordInfoVtbl = +{ + RecordInfo_QueryInterface, + RecordInfo_AddRef, + RecordInfo_Release, + RecordInfo_RecordInit, + RecordInfo_RecordClear, + RecordInfo_RecordCopy, + RecordInfo_GetGuid, + RecordInfo_GetName, + RecordInfo_GetSize, + RecordInfo_GetTypeInfo, + RecordInfo_GetField, + RecordInfo_GetFieldNoCopy, + RecordInfo_PutField, + RecordInfo_PutFieldNoCopy, + RecordInfo_GetFieldNames, + RecordInfo_IsMatchingType, + RecordInfo_RecordCreate, + RecordInfo_RecordCreateCopy, + RecordInfo_RecordDestroy +}; + +static IRecordInfoImpl *get_test_recordinfo(void) +{ + IRecordInfoImpl *rec; + + rec = HeapAlloc(GetProcessHeap(), 0, sizeof(IRecordInfoImpl)); + rec->IRecordInfo_iface.lpVtbl = &RecordInfoVtbl; + rec->ref = 1; + rec->recordclear = 0; + rec->getsize = 0; + rec->recordcopy = 0; + + return rec; +} + static void init(void) { BSTR bstr; @@ -120,7 +313,7 @@ static void init(void) if (bstr) memcpy(&sz12_false[2], bstr, SysStringByteLen(bstr) + sizeof(WCHAR)); SysFreeString(bstr); - hOleaut32 = GetModuleHandle("oleaut32.dll"); + hOleaut32 = GetModuleHandleA("oleaut32.dll"); has_i8 = GetProcAddress(hOleaut32, "VarI8FromI1") != NULL; if (!has_i8) skip("No support for I8 and UI8 data types\n"); @@ -294,7 +487,7 @@ static BOOL is_expected_variant( const VARIANT *result, const VARIANT *expected return !memcmp( &V_DECIMAL(result), &V_DECIMAL(expected), sizeof(DECIMAL) ); default: ok(0, "unhandled variant type %s\n",vtstr(V_VT(expected))); - return 0; + return FALSE; } } @@ -353,14 +546,11 @@ static void _test_bstr_var(unsigned line, const VARIANT *v, const char *str) static void test_VariantInit(void) { - VARIANTARG v1, v2; + VARIANT v; - /* Test that VariantInit() only sets the type */ - memset(&v1, -1, sizeof(v1)); - v2 = v1; - V_VT(&v2) = VT_EMPTY; - VariantInit(&v1); - ok(!memcmp(&v1, &v2, sizeof(v1)), "VariantInit() set extra fields\n"); + memset(&v, -1, sizeof(v)); + VariantInit(&v); + ok(V_VT(&v) == VT_EMPTY, "VariantInit() returned vt %d\n", V_VT(&v)); } /* All possible combinations of extra V_VT() flags */ @@ -385,9 +575,9 @@ static const VARTYPE ExtraFlags[16] = }; /* Determine if a vt is valid for VariantClear() */ -static int IsValidVariantClearVT(VARTYPE vt, VARTYPE extraFlags) +static BOOL IsValidVariantClearVT(VARTYPE vt, VARTYPE extraFlags) { - int ret = 0; + BOOL ret = FALSE; /* Only the following flags/types are valid */ if ((vt <= VT_LPWSTR || vt == VT_RECORD || vt == VT_CLSID) && @@ -396,10 +586,10 @@ static int IsValidVariantClearVT(VARTYPE vt, VARTYPE extraFlags) (!(extraFlags & (VT_BYREF|VT_ARRAY)) || vt > VT_NULL) && (extraFlags == 0 || extraFlags == VT_BYREF || extraFlags == VT_ARRAY || extraFlags == (VT_ARRAY|VT_BYREF))) - ret = 1; /* ok */ + ret = TRUE; /* ok */ if (!has_i8 && (vt == VT_I8 || vt == VT_UI8)) - ret = 0; /* Old versions of oleaut32 */ + ret = FALSE; /* Old versions of oleaut32 */ return ret; } @@ -445,6 +635,8 @@ static test_VariantClearImpl test_myVariantClearImpl = {{&test_VariantClear_vtbl static void test_VariantClear(void) { + struct __tagBRECORD *rec; + IRecordInfoImpl *recinfo; HRESULT hres; VARIANTARG v; VARIANT v2; @@ -563,10 +755,28 @@ static void test_VariantClear(void) ok(V_DISPATCHREF(&v) == (IDispatch**)&punk, "dispatch ref %p\n", V_DISPATCHREF(&v)); /* Check that nothing got called */ ok(test_myVariantClearImpl.events == 0, "Unexpected call. events %08x\n", test_myVariantClearImpl.events); + + /* RECORD */ + recinfo = get_test_recordinfo(); + V_VT(&v) = VT_RECORD; + rec = &V_UNION(&v, brecVal); + rec->pRecInfo = &recinfo->IRecordInfo_iface; + rec->pvRecord = (void*)0xdeadbeef; + recinfo->recordclear = 0; + recinfo->ref = 2; + recinfo->rec = rec; + hres = VariantClear(&v); + ok(hres == S_OK, "ret %08x\n", hres); + ok(rec->pvRecord == NULL, "got %p\n", rec->pvRecord); + ok(recinfo->recordclear == 1, "got %d\n", recinfo->recordclear); + ok(recinfo->ref == 1, "got %d\n", recinfo->ref); + IRecordInfo_Release(&recinfo->IRecordInfo_iface); } static void test_VariantCopy(void) { + struct __tagBRECORD *rec; + IRecordInfoImpl *recinfo; VARIANTARG vSrc, vDst; VARTYPE vt; size_t i; @@ -682,18 +892,45 @@ static void test_VariantCopy(void) } VariantClear(&vDst); } + + /* copy RECORD */ + recinfo = get_test_recordinfo(); + + memset(&vDst, 0, sizeof(vDst)); + V_VT(&vDst) = VT_EMPTY; + + V_VT(&vSrc) = VT_RECORD; + rec = &V_UNION(&vSrc, brecVal); + rec->pRecInfo = &recinfo->IRecordInfo_iface; + rec->pvRecord = (void*)0xdeadbeef; + + recinfo->recordclear = 0; + recinfo->recordcopy = 0; + recinfo->getsize = 0; + recinfo->rec = rec; + hres = VariantCopy(&vDst, &vSrc); + ok(hres == S_OK, "ret %08x\n", hres); + + rec = &V_UNION(&vDst, brecVal); + ok(rec->pvRecord != (void*)0xdeadbeef && rec->pvRecord != NULL, "got %p\n", rec->pvRecord); + ok(rec->pRecInfo == &recinfo->IRecordInfo_iface, "got %p\n", rec->pRecInfo); + ok(recinfo->getsize == 1, "got %d\n", recinfo->recordclear); + ok(recinfo->recordcopy == 1, "got %d\n", recinfo->recordclear); + + VariantClear(&vDst); + VariantClear(&vSrc); } /* Determine if a vt is valid for VariantCopyInd() */ -static int IsValidVariantCopyIndVT(VARTYPE vt, VARTYPE extraFlags) +static BOOL IsValidVariantCopyIndVT(VARTYPE vt, VARTYPE extraFlags) { - int ret = 0; + BOOL ret = FALSE; if ((extraFlags & VT_ARRAY) || (vt > VT_NULL && vt != (VARTYPE)15 && vt < VT_VOID && !(extraFlags & (VT_VECTOR|VT_RESERVED)))) { - ret = 1; /* ok */ + ret = TRUE; /* ok */ } return ret; } @@ -1731,6 +1968,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(32,1,1980,0,0,0,0,FALSE,0.0); /* Fails on invalid day */ + ST2DT(1,1,-1,0,0,0,0,FALSE,0.0); /* Fails on invalid year */ + ST2DT(1,1,10000,0,0,0,0,FALSE,0.0); /* Fails on invalid year */ + ST2DT(1,1,9999,0,0,0,0,TRUE,2958101.0); /* 9999 is last valid 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 */ @@ -2879,7 +3120,7 @@ static void test_VarFix(void) for (vt = 0; vt <= VT_BSTR_BLOB; vt++) { - HRESULT bFail = TRUE; + BOOL bFail = TRUE; SKIPTESTS(vt); @@ -2994,7 +3235,7 @@ static void test_VarInt(void) for (vt = 0; vt <= VT_BSTR_BLOB; vt++) { - HRESULT bFail = TRUE; + BOOL bFail = TRUE; SKIPTESTS(vt); @@ -3115,7 +3356,7 @@ static void test_VarNeg(void) for (vt = 0; vt <= VT_BSTR_BLOB; vt++) { - HRESULT bFail = TRUE; + BOOL bFail = TRUE; SKIPTESTS(vt); @@ -5370,7 +5611,7 @@ static void test_VarCat(void) static const WCHAR sz12_date[] = {'1','2','9','/','3','0','/','1','9','8','0','\0'}; static const WCHAR sz12_date_broken[] = {'1','2','9','/','3','0','/','8','0','\0'}; static const WCHAR sz_empty[] = {'\0'}; - TCHAR orig_date_format[128]; + CHAR orig_date_format[128]; VARTYPE leftvt, rightvt, resultvt; HRESULT hres; HRESULT expected_error_num; @@ -5379,8 +5620,8 @@ static void test_VarCat(void) /* Set date format for testing */ lcid = LOCALE_USER_DEFAULT; - GetLocaleInfo(lcid,LOCALE_SSHORTDATE,orig_date_format,128); - SetLocaleInfo(lcid,LOCALE_SSHORTDATE,"M/d/yyyy"); + GetLocaleInfoA(lcid,LOCALE_SSHORTDATE,orig_date_format,128); + SetLocaleInfoA(lcid,LOCALE_SSHORTDATE,"M/d/yyyy"); VariantInit(&left); VariantInit(&right); @@ -5701,7 +5942,7 @@ static void test_VarCat(void) "VarCat: EMPTY concat with EMPTY did not return empty VT_BSTR\n"); /* Restore original date format settings */ - SetLocaleInfo(lcid,LOCALE_SSHORTDATE,orig_date_format); + SetLocaleInfoA(lcid,LOCALE_SSHORTDATE,orig_date_format); VariantClear(&left); VariantClear(&right); @@ -5763,11 +6004,11 @@ static void test_VarAnd(void) VARTYPE i; HRESULT hres; + CHECKPTR(VarAnd); + true_str = SysAllocString(szTrue); false_str = SysAllocString(szFalse); - CHECKPTR(VarAnd); - /* Test all possible flag/vt combinations & the resulting vt type */ for (i = 0; i < sizeof(ExtraFlags)/sizeof(ExtraFlags[0]); i++) { @@ -7242,11 +7483,11 @@ static void test_VarDiv(void) HRESULT hres; double r; + CHECKPTR(VarDiv); + num1_str = SysAllocString(str1); num2_str = SysAllocString(str2); - CHECKPTR(VarDiv); - /* Test all possible flag/vt combinations & the resulting vt type */ for (i = 0; i < sizeof(ExtraFlags)/sizeof(ExtraFlags[0]); i++) { diff --git a/rostests/winetests/oleaut32/vartype.c b/rostests/winetests/oleaut32/vartype.c index dda443dc010..8998d2d948a 100644 --- a/rostests/winetests/oleaut32/vartype.c +++ b/rostests/winetests/oleaut32/vartype.c @@ -23,12 +23,18 @@ #define COM_NO_WINDOWS_H #define CONST_VTABLE +#define COBJMACROS #include #include #include #include #include +#include + +#include + +DEFINE_GUID(UUID_test_struct, 0x4029f190, 0xca4a, 0x4611, 0xae,0xb9,0x67,0x39,0x83,0xcb,0x96,0xdd); /* Some Visual C++ versions choke on __uint64 to float conversions. * To fix this you need either VC++ 6.0 plus the processor pack @@ -251,6 +257,32 @@ static BOOL has_locales; BADVAR(VT_CLSID); \ BADVAR(VT_BSTR_BLOB) +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(dispatch_invoke); + /* Early versions of oleaut32 are missing many functions */ static HRESULT (WINAPI *pVarI1FromUI1)(BYTE,signed char*); static HRESULT (WINAPI *pVarI1FromI2)(SHORT,signed char*); @@ -461,6 +493,7 @@ static HRESULT (WINAPI *pVarDecDiv)(const DECIMAL*,const DECIMAL*,DECIMAL*); static HRESULT (WINAPI *pVarDecCmp)(const DECIMAL*,const DECIMAL*); static HRESULT (WINAPI *pVarDecCmpR8)(const DECIMAL*,double); static HRESULT (WINAPI *pVarDecNeg)(const DECIMAL*,DECIMAL*); +static HRESULT (WINAPI *pVarDecRound)(const DECIMAL*,int,DECIMAL*); static HRESULT (WINAPI *pVarBoolFromUI1)(BYTE,VARIANT_BOOL*); static HRESULT (WINAPI *pVarBoolFromI2)(SHORT,VARIANT_BOOL*); @@ -502,73 +535,93 @@ typedef struct BOOL bFailInvoke; } DummyDispatch; -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) +static ULONG WINAPI DummyDispatch_AddRef(IDispatch *iface) { DummyDispatch *This = impl_from_IDispatch(iface); - - trace("AddRef(%p)\n", iface); return InterlockedIncrement(&This->ref); } -static ULONG WINAPI DummyDispatch_Release(LPDISPATCH iface) +static ULONG WINAPI DummyDispatch_Release(IDispatch *iface) { DummyDispatch *This = impl_from_IDispatch(iface); - - trace("Release(%p)\n", iface); return InterlockedDecrement(&This->ref); } -static HRESULT WINAPI DummyDispatch_QueryInterface(LPDISPATCH iface, +static HRESULT WINAPI DummyDispatch_QueryInterface(IDispatch *iface, REFIID riid, void** ppvObject) { - trace("QueryInterface(%p)\n", iface); - if (ppvObject) + *ppvObject = NULL; + + if (IsEqualIID(riid, &IID_IDispatch) || + IsEqualIID(riid, &IID_IUnknown)) { - *ppvObject = NULL; - if (IsEqualIID(riid, &IID_IDispatch)) - { - trace("Asked for IID_IDispatch\n"); *ppvObject = iface; - } - else if (IsEqualIID(riid, &IID_IUnknown)) - { - trace("Asked for IID_IUnknown\n"); - *ppvObject = iface; - } - if (*ppvObject) - { - DummyDispatch_AddRef(*ppvObject); - return S_OK; - } + IDispatch_AddRef(iface); } - return E_NOINTERFACE; + + return *ppvObject ? S_OK : E_NOINTERFACE; } -static HRESULT WINAPI DummyDispatch_Invoke(LPDISPATCH iface, - DISPID dispIdMember, REFIID riid, - LCID lcid, WORD wFlags, - DISPPARAMS *pDispParams, - VARIANT *pVarResult, - EXCEPINFO *pExcepInfo, - UINT *puArgErr) +static HRESULT WINAPI DummyDispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) { - trace("Invoke(%p)\n", iface); - ok(wFlags == DISPATCH_PROPERTYGET, "Flags wrong\n"); - ok(pDispParams->cArgs == 0, "Property get has args\n"); + ok(0, "Unexpected call\n"); + return E_NOTIMPL; +} - if (dispatch.bFailInvoke) +static HRESULT WINAPI DummyDispatch_GetTypeInfo(IDispatch *iface, UINT tinfo, LCID lcid, ITypeInfo **ti) +{ + ok(0, "Unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, + UINT cnames, LCID lcid, DISPID *dispid) +{ + ok(0, "Unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DummyDispatch_Invoke(IDispatch *iface, + DISPID dispid, REFIID riid, + LCID lcid, WORD wFlags, + DISPPARAMS *params, + VARIANT *res, + EXCEPINFO *ei, + UINT *arg_err) +{ + DummyDispatch *This = impl_from_IDispatch(iface); + + CHECK_EXPECT(dispatch_invoke); + + ok(dispid == DISPID_VALUE, "got dispid %d\n", dispid); + ok(IsEqualIID(riid, &IID_NULL), "go riid %s\n", wine_dbgstr_guid(riid)); + ok(wFlags == DISPATCH_PROPERTYGET, "Flags wrong\n"); + + ok(params->rgvarg == NULL, "got %p\n", params->rgvarg); + ok(params->rgdispidNamedArgs == NULL, "got %p\n", params->rgdispidNamedArgs); + ok(params->cArgs == 0, "got %d\n", params->cArgs); + ok(params->cNamedArgs == 0, "got %d\n", params->cNamedArgs); + + ok(res != NULL, "got %p\n", res); + ok(V_VT(res) == VT_EMPTY, "got %d\n", V_VT(res)); + ok(ei == NULL, "got %p\n", ei); + ok(arg_err == NULL, "got %p\n", arg_err); + + if (This->bFailInvoke) return E_OUTOFMEMORY; - memset(pVarResult, 0, sizeof(*pVarResult)); - V_VT(pVarResult) = dispatch.vt; + V_VT(res) = This->vt; + if (This->vt == VT_UI1) + V_UI1(res) = 1; + else + memset(res, 0, sizeof(*res)); + return S_OK; } @@ -577,13 +630,19 @@ static const IDispatchVtbl DummyDispatch_VTable = DummyDispatch_QueryInterface, DummyDispatch_AddRef, DummyDispatch_Release, - NULL, - NULL, - NULL, + DummyDispatch_GetTypeInfoCount, + DummyDispatch_GetTypeInfo, + DummyDispatch_GetIDsOfNames, DummyDispatch_Invoke }; -static DummyDispatch dispatch = { { &DummyDispatch_VTable }, 1, 0, 0 }; +static void init_test_dispatch(LONG ref, VARTYPE vt, DummyDispatch *dispatch) +{ + dispatch->IDispatch_iface.lpVtbl = &DummyDispatch_VTable; + dispatch->ref = ref; + dispatch->vt = vt; + dispatch->bFailInvoke = FALSE; +} /* * VT_I1/VT_UI1 @@ -685,11 +744,15 @@ static void test_VarI1FromR4(void) CHECKPTR(VarI1FromR4); CONVERT(VarI1FromR4, -129.0f); EXPECT_OVERFLOW; + CONVERT(VarI1FromR4, -128.51f); EXPECT_OVERFLOW; + CONVERT(VarI1FromR4, -128.5f); EXPECT(-128); CONVERT(VarI1FromR4, -128.0f); EXPECT(-128); CONVERT(VarI1FromR4, -1.0f); EXPECT(-1); CONVERT(VarI1FromR4, 0.0f); EXPECT(0); CONVERT(VarI1FromR4, 1.0f); EXPECT(1); CONVERT(VarI1FromR4, 127.0f); EXPECT(127); + CONVERT(VarI1FromR4, 127.49f); EXPECT(127); + CONVERT(VarI1FromR4, 127.5f); EXPECT_OVERFLOW; CONVERT(VarI1FromR4, 128.0f); EXPECT_OVERFLOW; CONVERT(VarI1FromR4, -1.5f); EXPECT(-2); @@ -708,11 +771,15 @@ static void test_VarI1FromR8(void) CHECKPTR(VarI1FromR8); CONVERT(VarI1FromR8, -129.0); EXPECT_OVERFLOW; + CONVERT(VarI1FromR8, -128.51); EXPECT_OVERFLOW; + CONVERT(VarI1FromR8, -128.5); EXPECT(-128); CONVERT(VarI1FromR8, -128.0); EXPECT(-128); CONVERT(VarI1FromR8, -1.0); EXPECT(-1); CONVERT(VarI1FromR8, 0.0); EXPECT(0); CONVERT(VarI1FromR8, 1.0); EXPECT(1); CONVERT(VarI1FromR8, 127.0); EXPECT(127); + CONVERT(VarI1FromR8, 127.49); EXPECT(127); + CONVERT(VarI1FromR8, 127.5); EXPECT_OVERFLOW; CONVERT(VarI1FromR8, 128.0); EXPECT_OVERFLOW; CONVERT(VarI1FromR8, -1.5); EXPECT(-2); @@ -929,9 +996,13 @@ static void test_VarUI1FromR4(void) CHECKPTR(VarUI1FromR4); CONVERT(VarUI1FromR4, -1.0f); EXPECT_OVERFLOW; + CONVERT(VarUI1FromR4, -0.51f); EXPECT_OVERFLOW; + CONVERT(VarUI1FromR4, -0.5f); EXPECT(0); CONVERT(VarUI1FromR4, 0.0f); EXPECT(0); CONVERT(VarUI1FromR4, 1.0f); EXPECT(1); CONVERT(VarUI1FromR4, 255.0f); EXPECT(255); + CONVERT(VarUI1FromR4, 255.49f); EXPECT(255); + CONVERT(VarUI1FromR4, 255.5f); EXPECT_OVERFLOW; CONVERT(VarUI1FromR4, 256.0f); EXPECT_OVERFLOW; /* Rounding */ @@ -951,9 +1022,13 @@ static void test_VarUI1FromR8(void) CHECKPTR(VarUI1FromR8); CONVERT(VarUI1FromR8, -1.0); EXPECT_OVERFLOW; + CONVERT(VarUI1FromR8, -0.51); EXPECT_OVERFLOW; + CONVERT(VarUI1FromR8, -0.5); EXPECT(0); CONVERT(VarUI1FromR8, 0.0); EXPECT(0); CONVERT(VarUI1FromR8, 1.0); EXPECT(1); CONVERT(VarUI1FromR8, 255.0); EXPECT(255); + CONVERT(VarUI1FromR8, 255.49); EXPECT(255); + CONVERT(VarUI1FromR8, 255.5); EXPECT_OVERFLOW; CONVERT(VarUI1FromR8, 256.0); EXPECT_OVERFLOW; /* Rounding */ @@ -1057,6 +1132,7 @@ static void test_VarUI1FromStr(void) static void test_VarUI1FromDisp(void) { + DummyDispatch dispatch; CONVVARS(LCID); VARIANTARG vSrc, vDst; @@ -1079,24 +1155,41 @@ static void test_VarUI1FromDisp(void) VariantInit(&vSrc); VariantInit(&vDst); + init_test_dispatch(1, VT_UI1, &dispatch); V_VT(&vSrc) = VT_DISPATCH; V_DISPATCH(&vSrc) = &dispatch.IDispatch_iface; - dispatch.vt = VT_UI1; - dispatch.bFailInvoke = FALSE; + SET_EXPECT(dispatch_invoke); + out = 10; hres = pVarUI1FromDisp(&dispatch.IDispatch_iface, in, &out); - trace("0x%08x\n", hres); + ok(broken(hres == DISP_E_BADVARTYPE) || hres == S_OK, "got 0x%08x\n", hres); + ok(broken(out == 10) || out == 1, "got %d\n", out); + CHECK_CALLED(dispatch_invoke); + SET_EXPECT(dispatch_invoke); + V_VT(&vDst) = VT_EMPTY; + V_UI1(&vDst) = 0; hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1); - trace("0x%08x\n", hres); + ok(hres == S_OK, "got 0x%08x\n", hres); + ok(V_VT(&vDst) == VT_UI1, "got %d\n", V_VT(&vDst)); + ok(V_UI1(&vDst) == 1, "got %d\n", V_UI1(&vDst)); + CHECK_CALLED(dispatch_invoke); dispatch.bFailInvoke = TRUE; + SET_EXPECT(dispatch_invoke); + out = 10; hres = pVarUI1FromDisp(&dispatch.IDispatch_iface, in, &out); - trace("0x%08x\n", hres); + ok(hres == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hres); + ok(out == 10, "got %d\n", out); + CHECK_CALLED(dispatch_invoke); + SET_EXPECT(dispatch_invoke); + V_VT(&vDst) = VT_EMPTY; hres = VariantChangeTypeEx(&vDst, &vSrc, in, 0, VT_UI1); - trace("0x%08x\n", hres); + ok(hres == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hres); + ok(V_VT(&vDst) == VT_EMPTY, "got %d\n", V_VT(&vDst)); + CHECK_CALLED(dispatch_invoke); } static void test_VarUI1Copy(void) @@ -1209,11 +1302,15 @@ static void test_VarI2FromR4(void) CHECKPTR(VarI2FromR4); CONVERT(VarI2FromR4, -32769.0f); EXPECT_OVERFLOW; + CONVERT(VarI2FromR4, -32768.51f); EXPECT_OVERFLOW; + CONVERT(VarI2FromR4, -32768.5f); EXPECT(-32768); CONVERT(VarI2FromR4, -32768.0f); EXPECT(-32768); CONVERT(VarI2FromR4, -1.0f); EXPECT(-1); CONVERT(VarI2FromR4, 0.0f); EXPECT(0); CONVERT(VarI2FromR4, 1.0f); EXPECT(1); CONVERT(VarI2FromR4, 32767.0f); EXPECT(32767); + CONVERT(VarI2FromR4, 32767.49f); EXPECT(32767); + CONVERT(VarI2FromR4, 32767.5f); EXPECT_OVERFLOW; CONVERT(VarI2FromR4, 32768.0f); EXPECT_OVERFLOW; /* Rounding */ @@ -1233,11 +1330,15 @@ static void test_VarI2FromR8(void) CHECKPTR(VarI2FromR8); CONVERT(VarI2FromR8, -32769.0); EXPECT_OVERFLOW; + CONVERT(VarI2FromR8, -32768.51); EXPECT_OVERFLOW; + CONVERT(VarI2FromR8, -32768.5); EXPECT(-32768); CONVERT(VarI2FromR8, -32768.0); EXPECT(-32768); CONVERT(VarI2FromR8, -1.0); EXPECT(-1); CONVERT(VarI2FromR8, 0.0); EXPECT(0); CONVERT(VarI2FromR8, 1.0); EXPECT(1); CONVERT(VarI2FromR8, 32767.0); EXPECT(32767); + CONVERT(VarI2FromR8, 32767.49); EXPECT(32767); + CONVERT(VarI2FromR8, 32767.5); EXPECT_OVERFLOW; CONVERT(VarI2FromR8, 32768.0); EXPECT_OVERFLOW; /* Rounding */ @@ -1457,9 +1558,13 @@ static void test_VarUI2FromR4(void) CHECKPTR(VarUI2FromR4); CONVERT(VarUI2FromR4, -1.0f); EXPECT_OVERFLOW; + CONVERT(VarUI2FromR4, -0.51f); EXPECT_OVERFLOW; + CONVERT(VarUI2FromR4, -0.5f); EXPECT(0); CONVERT(VarUI2FromR4, 0.0f); EXPECT(0); CONVERT(VarUI2FromR4, 1.0f); EXPECT(1); CONVERT(VarUI2FromR4, 65535.0f); EXPECT(65535); + CONVERT(VarUI2FromR4, 65535.49f); EXPECT(65535); + CONVERT(VarUI2FromR4, 65535.5f); EXPECT_OVERFLOW; CONVERT(VarUI2FromR4, 65536.0f); EXPECT_OVERFLOW; /* Rounding */ @@ -1479,9 +1584,13 @@ static void test_VarUI2FromR8(void) CHECKPTR(VarUI2FromR8); CONVERT(VarUI2FromR8, -1.0); EXPECT_OVERFLOW; + CONVERT(VarUI2FromR8, -0.51); EXPECT_OVERFLOW; + CONVERT(VarUI2FromR8, -0.5); EXPECT(0); CONVERT(VarUI2FromR8, 0.0); EXPECT(0); CONVERT(VarUI2FromR8, 1.0); EXPECT(1); CONVERT(VarUI2FromR8, 65535.0); EXPECT(65535); + CONVERT(VarUI2FromR8, 65535.49); EXPECT(65535); + CONVERT(VarUI2FromR8, 65535.5); EXPECT_OVERFLOW; CONVERT(VarUI2FromR8, 65536.0); EXPECT_OVERFLOW; /* Rounding */ @@ -1720,11 +1829,15 @@ static void test_VarI4FromR8(void) CHECKPTR(VarI4FromR8); CONVERT(VarI4FromR8, -2147483649.0); EXPECT_OVERFLOW; + CONVERT(VarI4FromR8, -2147483648.51); EXPECT_OVERFLOW; + CONVERT(VarI4FromR8, -2147483648.5); EXPECT(-2147483647 - 1); CONVERT(VarI4FromR8, -2147483648.0); EXPECT(-2147483647 - 1); CONVERT(VarI4FromR8, -1.0); EXPECT(-1); CONVERT(VarI4FromR8, 0.0); EXPECT(0); CONVERT(VarI4FromR8, 1.0); EXPECT(1); CONVERT(VarI4FromR8, 2147483647.0); EXPECT(2147483647); + CONVERT(VarI4FromR8, 2147483647.49); EXPECT(2147483647); + CONVERT(VarI4FromR8, 2147483647.5); EXPECT_OVERFLOW; CONVERT(VarI4FromR8, 2147483648.0); EXPECT_OVERFLOW; CONVERT(VarI4FromR8, -1.5); EXPECT(-2); @@ -1945,6 +2058,8 @@ static void test_VarUI4FromR4(void) CHECKPTR(VarUI4FromR4); /* We can't test max values as they are not exactly representable in a float */ CONVERT(VarUI4FromR4, -1.0f); EXPECT_OVERFLOW; + CONVERT(VarUI4FromR4, -0.51f); EXPECT_OVERFLOW; + CONVERT(VarUI4FromR4, -0.5f); EXPECT(0); CONVERT(VarUI4FromR4, 0.0f); EXPECT(0); CONVERT(VarUI4FromR4, 1.0f); EXPECT(1); @@ -1965,9 +2080,13 @@ static void test_VarUI4FromR8(void) CHECKPTR(VarUI4FromR8); CONVERT(VarUI4FromR8, -1.0); EXPECT_OVERFLOW; + CONVERT(VarUI4FromR4, -0.51f); EXPECT_OVERFLOW; + CONVERT(VarUI4FromR4, -0.5f); EXPECT(0); CONVERT(VarUI4FromR8, 0.0); EXPECT(0); CONVERT(VarUI4FromR8, 1.0); EXPECT(1); CONVERT(VarUI4FromR8, 4294967295.0); EXPECT(4294967295ul); + CONVERT(VarUI4FromR8, 4294967295.49); EXPECT(4294967295ul); + CONVERT(VarUI4FromR8, 4294967295.5); EXPECT_OVERFLOW; CONVERT(VarUI4FromR8, 4294967296.0); EXPECT_OVERFLOW; CONVERT(VarUI4FromR8, -1.5); EXPECT_OVERFLOW; @@ -4551,6 +4670,39 @@ static void test_VarDecCmpR8(void) SETDEC(l,0,DECIMAL_NEG,-1,-1); r = DECIMAL_NEG; MATH3(VarDecCmpR8); EXPECT_LT; } +#define CLEAR(x) memset(&(x), 0xBB, sizeof(x)) + +static void test_VarDecRound(void) +{ + HRESULT hres; + DECIMAL l, out; + + CHECKPTR(VarDecRound); + + CLEAR(out); SETDEC(l, 0, 0, 0, 1); hres = pVarDecRound(&l, 3, &out); EXPECTDEC(0, 0, 0, 1); + + CLEAR(out); SETDEC(l, 0, 0, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, 0, 0, 1); + CLEAR(out); SETDEC(l, 1, 0, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, 0, 0, 0); + CLEAR(out); SETDEC(l, 1, 0, 0, 1); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 1); + CLEAR(out); SETDEC(l, 2, 0, 0, 11); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 1); + CLEAR(out); SETDEC(l, 2, 0, 0, 15); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 2); + CLEAR(out); SETDEC(l, 6, 0, 0, 550001); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 6); + + CLEAR(out); SETDEC(l, 0, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 1, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 0, &out); EXPECTDEC(0, DECIMAL_NEG, 0, 0); + CLEAR(out); SETDEC(l, 1, DECIMAL_NEG, 0, 1); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 2, DECIMAL_NEG, 0, 11); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 1); + CLEAR(out); SETDEC(l, 2, DECIMAL_NEG, 0, 15); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 2); + CLEAR(out); SETDEC(l, 6, DECIMAL_NEG, 0, 550001); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, DECIMAL_NEG, 0, 6); + + CLEAR(out); SETDEC64(l, 0, 0, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, 0, 0xffffffff, 0xffffffff, 0xffffffff); + CLEAR(out); SETDEC64(l, 28, 0, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, 0, 0, 0, 8); + CLEAR(out); SETDEC64(l, 0, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); + CLEAR(out); SETDEC64(l, 28, DECIMAL_NEG, 0xffffffff, 0xffffffff, 0xffffffff); hres = pVarDecRound(&l, 0, &out); EXPECTDEC64(0, DECIMAL_NEG, 0, 0, 8); + + CLEAR(out); SETDEC(l, 2, 0, 0, 0); hres = pVarDecRound(&l, 1, &out); EXPECTDEC(1, 0, 0, 0); +} + /* * VT_BOOL */ @@ -5588,8 +5740,11 @@ static void test_IUnknownClear(void) { HRESULT hres; VARIANTARG v; - DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IUnknown* pu = (IUnknown*)&u.IDispatch_iface; + DummyDispatch u; + IUnknown* pu; + + init_test_dispatch(1, VT_UI1, &u); + pu = (IUnknown*)&u.IDispatch_iface; /* Test that IUnknown_Release is called on by-value */ V_VT(&v) = VT_UNKNOWN; @@ -5613,8 +5768,11 @@ static void test_IUnknownCopy(void) { HRESULT hres; VARIANTARG vSrc, vDst; - DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IUnknown* pu = (IUnknown*)&u.IDispatch_iface; + DummyDispatch u; + IUnknown* pu; + + init_test_dispatch(1, VT_UI1, &u); + pu = (IUnknown*)&u.IDispatch_iface; /* AddRef is called on by-value copy */ VariantInit(&vDst); @@ -5661,8 +5819,11 @@ static void test_IUnknownChangeTypeEx(void) VARIANTARG vSrc, vDst; LCID lcid; VARTYPE vt; - DummyDispatch u = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IUnknown* pu = (IUnknown*)&u.IDispatch_iface; + DummyDispatch u; + IUnknown* pu; + + init_test_dispatch(1, VT_UI1, &u); + pu = (IUnknown*)&u.IDispatch_iface; lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); @@ -5726,8 +5887,11 @@ static void test_IDispatchClear(void) { HRESULT hres; VARIANTARG v; - DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IDispatch* pd = &d.IDispatch_iface; + DummyDispatch d; + IDispatch* pd; + + init_test_dispatch(1, VT_UI1, &d); + pd = &d.IDispatch_iface; /* As per IUnknown */ @@ -5751,8 +5915,11 @@ static void test_IDispatchCopy(void) { HRESULT hres; VARIANTARG vSrc, vDst; - DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IDispatch* pd = &d.IDispatch_iface; + DummyDispatch d; + IDispatch* pd; + + init_test_dispatch(1, VT_UI1, &d); + pd = &d.IDispatch_iface; /* As per IUnknown */ @@ -5796,8 +5963,11 @@ static void test_IDispatchChangeTypeEx(void) HRESULT hres; VARIANTARG vSrc, vDst; LCID lcid; - DummyDispatch d = { { &DummyDispatch_VTable }, 1, VT_UI1, FALSE }; - IDispatch* pd = &d.IDispatch_iface; + DummyDispatch d; + IDispatch* pd; + + init_test_dispatch(1, VT_UI1, &d); + pd = &d.IDispatch_iface; lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); @@ -5872,89 +6042,147 @@ static void test_ErrorChangeTypeEx(void) /* VT_EMPTY */ static void test_EmptyChangeTypeEx(void) { - HRESULT hres; - VARIANTARG vSrc, vDst; VARTYPE vt; LCID lcid; lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - for (vt = 0; vt <= VT_BSTR_BLOB; vt++) + for (vt = VT_EMPTY; vt <= VT_BSTR_BLOB; vt++) { - HRESULT hExpected = DISP_E_BADVARTYPE; + HRESULT hExpected, hres; + VARIANTARG vSrc, vDst; - VariantInit(&vSrc); - memset(&vDst, 0, sizeof(vDst)); - V_VT(&vDst) = VT_EMPTY; + /* skip for undefined types */ + if ((vt == 15) || (vt > VT_VERSIONED_STREAM && vt < VT_BSTR_BLOB)) + continue; - if (vt == VT_I8 || vt == VT_UI8) + switch (vt) { + case VT_I8: + case VT_UI8: if (has_i8) hExpected = S_OK; - } - else if (vt == VT_RECORD) - { + else + hExpected = DISP_E_BADVARTYPE; + break; + case VT_RECORD: + case VT_VARIANT: + case VT_DISPATCH: + case VT_UNKNOWN: + case VT_ERROR: hExpected = DISP_E_TYPEMISMATCH; - } - else if (vt == VT_VARIANT || vt == VT_DISPATCH || - vt == VT_UNKNOWN || vt == VT_ERROR) - { - hExpected = DISP_E_TYPEMISMATCH; - } - else if (vt <= VT_UINT && vt != (VARTYPE)15) + break; + case VT_EMPTY: + case VT_NULL: + case VT_I2: + case VT_I4: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_BSTR: + case VT_BOOL: + case VT_DECIMAL: + case VT_I1: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_INT: + case VT_UINT: hExpected = S_OK; + break; + default: + hExpected = DISP_E_BADVARTYPE; + } + + VariantInit(&vSrc); + V_VT(&vSrc) = VT_EMPTY; + memset(&vDst, 0, sizeof(vDst)); + V_VT(&vDst) = VT_NULL; hres = VariantChangeTypeEx(&vDst, &vSrc, lcid, 0, vt); - - ok(hres == hExpected && (hres != S_OK || V_VT(&vDst) == vt), - "change empty: vt %d expected 0x%08x, got 0x%08x, vt %d\n", - vt, hExpected, hres, V_VT(&vDst)); - if(hres == S_OK) VariantClear(&vDst); + ok(hres == hExpected, "change empty: vt %d expected 0x%08x, got 0x%08x, vt %d\n", + vt, hExpected, hres, V_VT(&vDst)); + if (hres == S_OK) + { + ok(V_VT(&vDst) == vt, "change empty: vt %d, got %d\n", vt, V_VT(&vDst)); + VariantClear(&vDst); + } } } /* VT_NULL */ static void test_NullChangeTypeEx(void) { - HRESULT hres; - VARIANTARG vSrc, vDst; VARTYPE vt; LCID lcid; lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - for (vt = 0; vt <= VT_BSTR_BLOB; vt++) + for (vt = VT_EMPTY; vt <= VT_BSTR_BLOB; vt++) { - HRESULT hExpected = DISP_E_BADVARTYPE; + VARIANTARG vSrc, vDst; + HRESULT hExpected, hres; + + /* skip for undefined types */ + if ((vt == 15) || (vt > VT_VERSIONED_STREAM && vt < VT_BSTR_BLOB)) + continue; + + switch (vt) + { + case VT_I8: + case VT_UI8: + if (has_i8) + hExpected = DISP_E_TYPEMISMATCH; + else + hExpected = DISP_E_BADVARTYPE; + break; + case VT_NULL: + hExpected = S_OK; + break; + case VT_EMPTY: + case VT_I2: + case VT_I4: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_BSTR: + case VT_DISPATCH: + case VT_ERROR: + case VT_BOOL: + case VT_VARIANT: + case VT_UNKNOWN: + case VT_DECIMAL: + case VT_I1: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_INT: + case VT_UINT: + case VT_RECORD: + hExpected = DISP_E_TYPEMISMATCH; + break; + default: + hExpected = DISP_E_BADVARTYPE; + } VariantInit(&vSrc); V_VT(&vSrc) = VT_NULL; memset(&vDst, 0, sizeof(vDst)); V_VT(&vDst) = VT_EMPTY; - if (vt == VT_I8 || vt == VT_UI8) - { - if (has_i8) - hExpected = DISP_E_TYPEMISMATCH; - } - else if (vt == VT_RECORD) - { - hExpected = DISP_E_TYPEMISMATCH; - } - else if (vt == VT_NULL) - { - hExpected = S_OK; - } - else if (vt == VT_VARIANT || vt == VT_DISPATCH || - vt == VT_UNKNOWN || vt == VT_ERROR || - (vt <= VT_UINT && vt != (VARTYPE)15)) - hExpected = DISP_E_TYPEMISMATCH; - hres = VariantChangeTypeEx(&vDst, &vSrc, lcid, 0, vt); - - ok(hres == hExpected && (hres != S_OK || V_VT(&vDst) == vt), - "change null: vt %d expected 0x%08x, got 0x%08x, vt %d\n", + ok(hres == hExpected, "change null: vt %d expected 0x%08x, got 0x%08x, vt %d\n", vt, hExpected, hres, V_VT(&vDst)); + + /* should work only for VT_NULL -> VT_NULL case */ + if (hres == S_OK) + ok(V_VT(&vDst) == VT_NULL, "change null: VT_NULL expected 0x%08x, got 0x%08x, vt %d\n", + hExpected, hres, V_VT(&vDst)); + else + ok(V_VT(&vDst) == VT_EMPTY, "change null: vt %d expected 0x%08x, got 0x%08x, vt %d\n", + vt, hExpected, hres, V_VT(&vDst)); } } @@ -6090,6 +6318,129 @@ static void test_bstr_cache(void) SysFreeString(str2); } +static void write_typelib(int res_no, const char *filename) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA( filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "file creation failed\n" ); + if (file == INVALID_HANDLE_VALUE) return; + res = FindResourceA( GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(res_no), "TYPELIB" ); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +static const char *create_test_typelib(int res_no) +{ + static char filename[MAX_PATH]; + + GetTempFileNameA( ".", "tlb", 0, filename ); + write_typelib(res_no, filename); + return filename; +} + +static void test_recinfo(void) +{ + static const WCHAR testW[] = {'t','e','s','t',0}; + static WCHAR teststructW[] = {'t','e','s','t','_','s','t','r','u','c','t',0}; + struct test_struct teststruct, testcopy; + WCHAR filenameW[MAX_PATH]; + const char *filename; + IRecordInfo *recinfo; + ITypeInfo *typeinfo; + DummyDispatch dispatch; + ITypeLib *typelib; + TYPEATTR *attr; + MEMBERID memid; + UINT16 found; + HRESULT hr; + ULONG size; + + filename = create_test_typelib(2); + MultiByteToWideChar(CP_ACP, 0, filename, -1, filenameW, MAX_PATH); + hr = LoadTypeLibEx(filenameW, REGKIND_NONE, &typelib); + ok(hr == S_OK, "got 0x%08x\n", hr); + + typeinfo = NULL; + found = 1; + hr = ITypeLib_FindName(typelib, teststructW, 0, &typeinfo, &memid, &found); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(typeinfo != NULL, "got %p\n", typeinfo); + hr = ITypeInfo_GetTypeAttr(typeinfo, &attr); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(IsEqualGUID(&attr->guid, &UUID_test_struct), "got %s\n", wine_dbgstr_guid(&attr->guid)); + ok(attr->typekind == TKIND_RECORD, "got %d\n", attr->typekind); + + hr = GetRecordInfoFromTypeInfo(typeinfo, &recinfo); + ok(hr == S_OK, "got 0x%08x\n", hr); + + size = 0; + hr = IRecordInfo_GetSize(recinfo, &size); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(size == sizeof(struct test_struct), "got size %d\n", size); + ok(attr->cbSizeInstance == sizeof(struct test_struct), "got instance size %d\n", attr->cbSizeInstance); + ITypeInfo_ReleaseTypeAttr(typeinfo, attr); + + /* RecordInit() */ + teststruct.hr = E_FAIL; + teststruct.b = 0x1; + teststruct.disp = (void*)0xdeadbeef; + teststruct.bstr = (void*)0xdeadbeef; + + hr = IRecordInfo_RecordInit(recinfo, &teststruct); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(teststruct.hr == 0, "got 0x%08x\n", teststruct.hr); + ok(teststruct.b == 0, "got 0x%08x\n", teststruct.b); + ok(teststruct.disp == NULL, "got %p\n", teststruct.disp); + ok(teststruct.bstr == NULL, "got %p\n", teststruct.bstr); + + init_test_dispatch(10, VT_UI1, &dispatch); + + /* RecordCopy(), interface field reference increased */ + teststruct.hr = S_FALSE; + teststruct.b = VARIANT_TRUE; + teststruct.disp = &dispatch.IDispatch_iface; + teststruct.bstr = SysAllocString(testW); + memset(&testcopy, 0, sizeof(testcopy)); + hr = IRecordInfo_RecordCopy(recinfo, &teststruct, &testcopy); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(testcopy.hr == S_FALSE, "got 0x%08x\n", testcopy.hr); + ok(testcopy.b == VARIANT_TRUE, "got %d\n", testcopy.b); + ok(testcopy.disp == teststruct.disp, "got %p\n", testcopy.disp); + ok(dispatch.ref == 11, "got %d\n", dispatch.ref); + ok(testcopy.bstr != teststruct.bstr, "got %p\n", testcopy.bstr); + ok(!lstrcmpW(testcopy.bstr, teststruct.bstr), "got %s, %s\n", wine_dbgstr_w(testcopy.bstr), wine_dbgstr_w(teststruct.bstr)); + + /* RecordClear() */ + hr = IRecordInfo_RecordClear(recinfo, &teststruct); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(teststruct.bstr == NULL, "got %p\n", teststruct.bstr); + hr = IRecordInfo_RecordClear(recinfo, &testcopy); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(testcopy.bstr == NULL, "got %p\n", testcopy.bstr); + + /* now destination contains inteface pointer */ + memset(&testcopy, 0, sizeof(testcopy)); + testcopy.disp = &dispatch.IDispatch_iface; + dispatch.ref = 10; + + hr = IRecordInfo_RecordCopy(recinfo, &teststruct, &testcopy); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(dispatch.ref == 9, "got %d\n", dispatch.ref); + + IRecordInfo_Release(recinfo); + + ITypeInfo_Release(typeinfo); + ITypeLib_Release(typelib); + DeleteFileA(filename); +} + START_TEST(vartype) { hOleaut32 = GetModuleHandleA("oleaut32.dll"); @@ -6340,6 +6691,7 @@ START_TEST(vartype) test_VarDecCmpR8(); test_VarDecMul(); test_VarDecDiv(); + test_VarDecRound(); test_VarBoolFromI1(); test_VarBoolFromUI1(); @@ -6390,4 +6742,6 @@ START_TEST(vartype) test_NullByRef(); test_ChangeType_keep_dst(); + + test_recinfo(); }