diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c index 1162e8b720f..3599e723011 100644 --- a/dll/win32/shlwapi/ordinal.c +++ b/dll/win32/shlwapi/ordinal.c @@ -5350,6 +5350,36 @@ DoDefault: return hr; } +BOOL +VariantArrayToBuffer( + _In_ const VARIANT *pvarIn, + _Out_writes_(cbSize) LPVOID pvDest, + _In_ SIZE_T cbSize) +{ + LPVOID pvData; + LONG LowerBound, UpperBound; + LPSAFEARRAY pArray; + + /* Only supports byte array */ + if (!pvarIn || V_VT(pvarIn) != (VT_UI1 | VT_ARRAY)) + return FALSE; + + /* Boundary check and access */ + pArray = V_ARRAY(pvarIn); + if (SafeArrayGetDim(pArray) == 1 && + SUCCEEDED(SafeArrayGetLBound(pArray, 1, &LowerBound)) && + SUCCEEDED(SafeArrayGetUBound(pArray, 1, &UpperBound)) && + ((LONG)cbSize <= UpperBound - LowerBound + 1) && + SUCCEEDED(SafeArrayAccessData(pArray, &pvData))) + { + CopyMemory(pvDest, pvData, cbSize); + SafeArrayUnaccessData(pArray); + return TRUE; /* Success */ + } + + return FALSE; /* Failure */ +} + /************************************************************************** * SHPropertyBag_ReadType (SHLWAPI.493) */ @@ -5670,6 +5700,74 @@ HRESULT WINAPI SHPropertyBag_ReadRECTL(IPropertyBag *ppb, LPCWSTR pszPropName, R return SHPropertyBag_ReadLONG(ppb, szBuff, &prcl->bottom); } +/************************************************************************** + * SHPropertyBag_ReadGUID (SHLWAPI.505) + */ +HRESULT WINAPI SHPropertyBag_ReadGUID(IPropertyBag *ppb, LPCWSTR pszPropName, GUID *pguid) +{ + HRESULT hr; + BOOL bRet; + VARIANT vari; + + TRACE("%p %s %p\n", ppb, debugstr_w(pszPropName), pguid); + + if (!ppb || !pszPropName || !pguid) + { + ERR("%p %s %p\n", ppb, debugstr_w(pszPropName), pguid); + return E_INVALIDARG; + } + + hr = SHPropertyBag_ReadType(ppb, pszPropName, &vari, VT_EMPTY); + if (FAILED(hr)) + { + ERR("%p %s %p\n", ppb, debugstr_w(pszPropName), pguid); + return hr; + } + + if (V_VT(&vari) == (VT_UI1 | VT_ARRAY)) /* Byte Array */ + bRet = VariantArrayToBuffer(&vari, pguid, sizeof(*pguid)); + else if (V_VT(&vari) == VT_BSTR) + bRet = GUIDFromStringW(V_BSTR(&vari), pguid); + else +#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) + bRet = FALSE; +#else + bRet = TRUE; /* This is by design in WinXP/Win2k3. */ +#endif + + if (!bRet) + ERR("%p %s %p\n", ppb, debugstr_w(pszPropName), pguid); + + VariantClear(&vari); + return (bRet ? S_OK : E_FAIL); +} + +/************************************************************************** + * SHPropertyBag_ReadStream (SHLWAPI.531) + */ +HRESULT WINAPI SHPropertyBag_ReadStream(IPropertyBag *ppb, LPCWSTR pszPropName, IStream **ppStream) +{ + HRESULT hr; + VARIANT vari; + + TRACE("%p %s %p\n", ppb, debugstr_w(pszPropName), ppStream); + + if (!ppb || !pszPropName || !ppStream) + { + ERR("%p %s %p\n", ppb, debugstr_w(pszPropName), ppStream); + return E_INVALIDARG; + } + + hr = SHPropertyBag_ReadType(ppb, pszPropName, &vari, VT_UNKNOWN); + if (FAILED(hr)) + return hr; + + hr = IUnknown_QueryInterface(V_UNKNOWN(&vari), &IID_IStream, (void **)ppStream); + IUnknown_Release(V_UNKNOWN(&vari)); + + return hr; +} + /************************************************************************** * SHPropertyBag_Delete (SHLWAPI.535) */ diff --git a/dll/win32/shlwapi/shlwapi.spec b/dll/win32/shlwapi/shlwapi.spec index 001d7b9ab17..8dc01d454dc 100644 --- a/dll/win32/shlwapi/shlwapi.spec +++ b/dll/win32/shlwapi/shlwapi.spec @@ -502,7 +502,7 @@ 502 stdcall AssocQueryKeyA(long long str str ptr) 503 stdcall AssocQueryKeyW(long long wstr wstr ptr) 504 stdcall AssocQueryStringA(long long str str ptr ptr) -505 stub -noname SHPropertyBag_ReadGUID +505 stdcall -noname SHPropertyBag_ReadGUID(ptr wstr ptr) 506 stdcall -noname SHPropertyBag_WriteGUID(ptr wstr ptr) 507 stdcall -noname SHPropertyBag_ReadDWORD(ptr wstr ptr) 508 stdcall -noname SHPropertyBag_WriteDWORD(ptr wstr long) @@ -528,7 +528,7 @@ 528 stdcall -noname SHPropertyBag_WriteSHORT(ptr wstr long) 529 stdcall -noname SHPropertyBag_ReadInt(ptr wstr ptr) SHPropertyBag_ReadLONG 530 stdcall -noname SHPropertyBag_WriteInt(ptr wstr long) SHPropertyBag_WriteLONG -531 stub -noname SHPropertyBag_ReadStream +531 stdcall -noname SHPropertyBag_ReadStream(ptr wstr ptr) 532 stdcall -noname SHPropertyBag_WriteStream(ptr wstr ptr) 533 stub -noname SHGetPerScreenResName 534 stdcall -noname SHPropertyBag_ReadBOOL(ptr wstr ptr) diff --git a/modules/rostests/apitests/shlwapi/CMakeLists.txt b/modules/rostests/apitests/shlwapi/CMakeLists.txt index ef141efc92f..d5c4d32562e 100644 --- a/modules/rostests/apitests/shlwapi/CMakeLists.txt +++ b/modules/rostests/apitests/shlwapi/CMakeLists.txt @@ -24,7 +24,7 @@ add_rc_deps(testdata.rc ${CMAKE_CURRENT_BINARY_DIR}/shlwapi_resource_dll/shlwapi add_executable(shlwapi_apitest ${SOURCE}) set_module_type(shlwapi_apitest win32cui) -target_link_libraries(shlwapi_apitest ${PSEH_LIB}) -add_importlibs(shlwapi_apitest shlwapi oleaut32 user32 advapi32 msvcrt kernel32) +target_link_libraries(shlwapi_apitest ${PSEH_LIB} uuid) +add_importlibs(shlwapi_apitest shlwapi oleaut32 ole32 user32 advapi32 msvcrt kernel32) add_dependencies(shlwapi_apitest shlwapi_resource_dll) add_rostests_file(TARGET shlwapi_apitest) diff --git a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp index bdf3e6f02e1..1aca2d256c0 100644 --- a/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp +++ b/modules/rostests/apitests/shlwapi/SHPropertyBag.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -29,6 +30,30 @@ static void ResetTest(VARTYPE vt, s_pszPropNames[3] = pszName3; } +static SAFEARRAY* CreateByteArray(LPCVOID pvSrc, DWORD cbSize) +{ + SAFEARRAYBOUND Bound; + Bound.lLbound = 0; + Bound.cElements = cbSize; + + SAFEARRAY* pArray = SafeArrayCreate(VT_UI1, 1, &Bound); + if (!pArray) + return NULL; + + void HUGEP *pvData; + HRESULT hr = SafeArrayAccessData(pArray, &pvData); + if (FAILED(hr)) + { + SafeArrayDestroy(pArray); + return NULL; + } + + CopyMemory(pvData, pvSrc, cbSize); + SafeArrayUnaccessData(pArray); + + return pArray; +} + class CDummyPropertyBag : public IPropertyBag { public: @@ -39,17 +64,17 @@ public: // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override { - ok_int(0, 1); + ok(FALSE, "Unexpected call\n"); return S_OK; } STDMETHODIMP_(ULONG) AddRef() override { - ok_int(0, 1); + ok(FALSE, "Unexpected call\n"); return S_OK; } STDMETHODIMP_(ULONG) Release() override { - ok_int(0, 1); + ok(FALSE, "Unexpected call\n"); return S_OK; } @@ -64,13 +89,38 @@ public: { ok_wstr(pszPropName, s_pszPropNames[i]); s_pszPropNames[i] = NULL; + if (lstrcmpiW(pszPropName, L"RECTL2.top") == 0) return E_FAIL; + if (lstrcmpiW(pszPropName, L"GUID1") == 0) + { + V_VT(pvari) = (VT_UI1 | VT_ARRAY); + V_ARRAY(pvari) = CreateByteArray(&IID_IShellLink, sizeof(IID)); + return S_OK; + } + + if (lstrcmpiW(pszPropName, L"GUID2") == 0) + { + WCHAR szText[50]; + StringFromGUID2(IID_IUnknown, szText, _countof(szText)); + + V_VT(pvari) = VT_BSTR; + V_BSTR(pvari) = SysAllocString(szText); + return S_OK; + } + + if (lstrcmpiW(pszPropName, L"GUID3") == 0) + { + V_VT(pvari) = VT_EMPTY; + V_UI4(pvari) = 0xDEADFACE; + return S_OK; + } + goto Skip1; } } - ok_int(0, 1); + ok(FALSE, "Unexpected call\n"); Skip1: return S_OK; } @@ -95,7 +145,7 @@ Skip1: goto Skip2; } } - ok_int(0, 1); + ok(FALSE, "Unexpected call\n"); Skip2: return S_OK; } @@ -113,6 +163,7 @@ static void SHPropertyBag_ReadTest(void) POINTL ptl = { 0xEEEE, 0xDDDD }; POINTS pts = { 0x2222, 0x3333 }; RECTL rcl = { 123, 456, 789, 101112 }; + GUID guid = { 0 }; ResetTest(VT_BOOL, L"BOOL1"); hr = SHPropertyBag_ReadBOOL(&dummy, s_pszPropNames[0], &bValue); @@ -168,6 +219,33 @@ static void SHPropertyBag_ReadTest(void) ok_long(hr, E_FAIL); ok_int(s_cRead, 2); ok_int(s_cWrite, 0); + + ResetTest(VT_EMPTY, L"GUID1"); + hr = SHPropertyBag_ReadGUID(&dummy, L"GUID1", &guid); + ok_long(hr, S_OK); + ok_int(s_cRead, 1); + ok_int(s_cWrite, 0); + ok_int(IsEqualGUID(guid, IID_IShellLink), TRUE); + + ResetTest(VT_EMPTY, L"GUID2"); + hr = SHPropertyBag_ReadGUID(&dummy, L"GUID2", &guid); + ok_long(hr, S_OK); + ok_int(s_cRead, 1); + ok_int(s_cWrite, 0); + ok_int(IsEqualGUID(guid, IID_IUnknown), TRUE); + + ResetTest(VT_EMPTY, L"GUID3"); + guid = IID_IExtractIcon; + hr = SHPropertyBag_ReadGUID(&dummy, L"GUID3", &guid); + + if (IsWindowsVistaOrGreater()) + ok_long(hr, E_INVALIDARG); + else + ok_long(hr, S_OK); + + ok_int(s_cRead, 1); + ok_int(s_cWrite, 0); + ok_int(IsEqualGUID(guid, IID_IExtractIcon), TRUE); } static void SHPropertyBag_WriteTest(void) diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 564a105f5e9..a2cec2e047c 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -103,12 +103,13 @@ HRESULT WINAPI SHPropertyBag_ReadStr(IPropertyBag *ppb, LPCWSTR pszPropName, LPW HRESULT WINAPI SHPropertyBag_ReadPOINTL(IPropertyBag *ppb, LPCWSTR pszPropName, POINTL *pptl); HRESULT WINAPI SHPropertyBag_ReadPOINTS(IPropertyBag *ppb, LPCWSTR pszPropName, POINTS *ppts); HRESULT WINAPI SHPropertyBag_ReadRECTL(IPropertyBag *ppb, LPCWSTR pszPropName, RECTL *prcl); +HRESULT WINAPI SHPropertyBag_ReadGUID(IPropertyBag *ppb, LPCWSTR pszPropName, GUID *pguid); +HRESULT WINAPI SHPropertyBag_ReadStream(IPropertyBag *ppb, LPCWSTR pszPropName, IStream **ppStream); HRESULT WINAPI SHGetPerScreenResName(OUT LPWSTR lpResName, IN INT cchResName, IN DWORD dwReserved); -HRESULT WINAPI SHPropertyBag_ReadStream(IPropertyBag*,LPCWSTR,IStream**); HRESULT WINAPI SHPropertyBag_Delete(IPropertyBag *ppb, LPCWSTR pszPropName); HRESULT WINAPI SHPropertyBag_WriteBOOL(IPropertyBag *ppb, LPCWSTR pszPropName, BOOL bValue); HRESULT WINAPI SHPropertyBag_WriteSHORT(IPropertyBag *ppb, LPCWSTR pszPropName, SHORT sValue);