From a2d8e464c805122243f474801d2c96f2d40eca8d Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Tue, 22 Aug 2023 12:01:20 +0900 Subject: [PATCH] [SHLWAPI][SDK][SHELL32_APITEST][SHLWAPI_WINETEST] Property Bag on Desktop Upgrade (#5590) - Add CDesktopUpgradePropertyBag class. - Implement SHGetDesktopUpgradePropertyBag function. CORE-9283 --- dll/win32/shlwapi/ordinal.c | 2 + dll/win32/shlwapi/propbag.cpp | 195 +++++++++++++++++- .../rostests/apitests/shell32/ShellState.cpp | 3 +- modules/rostests/winetests/shlwapi/ordinal.c | 5 + sdk/include/reactos/shlwapi_undoc.h | 19 ++ 5 files changed, 221 insertions(+), 3 deletions(-) diff --git a/dll/win32/shlwapi/ordinal.c b/dll/win32/shlwapi/ordinal.c index 6f8855fd10a..985b79a9f40 100644 --- a/dll/win32/shlwapi/ordinal.c +++ b/dll/win32/shlwapi/ordinal.c @@ -4505,6 +4505,7 @@ BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid) */ HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create) { +#ifndef __REACTOS__ enum _shellkey_flags { SHKEY_Root_HKCU = 0x1, SHKEY_Root_HKLM = 0x2, @@ -4520,6 +4521,7 @@ HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create) SHKEY_Subkey_MUICache = 0x5000, SHKEY_Subkey_FileExts = 0x6000 }; +#endif static const WCHAR explorerW[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', diff --git a/dll/win32/shlwapi/propbag.cpp b/dll/win32/shlwapi/propbag.cpp index ce65aa6c6a0..fbd5b87a49b 100644 --- a/dll/win32/shlwapi/propbag.cpp +++ b/dll/win32/shlwapi/propbag.cpp @@ -719,7 +719,7 @@ SHGetIniStringUTF7W( return SHGetIniStringW(lpAppName, lpKeyName + 1, lpReturnedString, nSize, lpFileName); return GetPrivateProfileStringW(lpAppName, lpKeyName, L"", lpReturnedString, nSize, lpFileName); -} +} /************************************************************************** * SHSetIniStringUTF7W (SHLWAPI.474) @@ -995,3 +995,196 @@ SHCreatePropertyBagOnProfileSection( return pIniPB->QueryInterface(riid, ppvObj); } + +class CDesktopUpgradePropertyBag : public CBasePropertyBag +{ +protected: + BOOL _AlreadyUpgraded(HKEY hKey); + VOID _MarkAsUpgraded(HKEY hkey); + HRESULT _ReadFlags(VARIANT *pvari); + HRESULT _ReadItemPositions(VARIANT *pvari); + IStream* _GetOldDesktopViewStream(); + IStream* _NewStreamFromOld(IStream *pOldStream); + +public: + CDesktopUpgradePropertyBag() : CBasePropertyBag(0) { } + + STDMETHODIMP Read( + _In_z_ LPCWSTR pszPropName, + _Inout_ VARIANT *pvari, + _Inout_opt_ IErrorLog *pErrorLog) override; + + STDMETHODIMP Write(_In_z_ LPCWSTR pszPropName, _In_ VARIANT *pvari) override + { + return E_NOTIMPL; + } +}; + +VOID CDesktopUpgradePropertyBag::_MarkAsUpgraded(HKEY hkey) +{ + DWORD dwValue = TRUE; + SHSetValueW(hkey, NULL, L"Upgrade", REG_DWORD, &dwValue, sizeof(dwValue)); +} + +BOOL CDesktopUpgradePropertyBag::_AlreadyUpgraded(HKEY hKey) +{ + // Check the existence of the value written in _MarkAsUpgraded. + DWORD dwValue, cbData = sizeof(dwValue); + return SHGetValueW(hKey, NULL, L"Upgrade", NULL, &dwValue, &cbData) == ERROR_SUCCESS; +} + +typedef DWORDLONG DESKVIEW_FLAGS; // 64-bit data + +HRESULT CDesktopUpgradePropertyBag::_ReadFlags(VARIANT *pvari) +{ + DESKVIEW_FLAGS Flags; + DWORD cbValue = sizeof(Flags); + if (SHGetValueW(HKEY_CURRENT_USER, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DeskView", + L"Settings", + NULL, + &Flags, + &cbValue) != ERROR_SUCCESS || cbValue < sizeof(Flags)) + { + return E_FAIL; + } + + V_UINT(pvari) = ((UINT)(Flags >> 32)) | 0x220; // FIXME: Magic number + V_VT(pvari) = VT_UINT; + return S_OK; +} + +typedef struct tagOLD_STREAM_HEADER +{ + WORD wMagic; + WORD awUnknown[6]; + WORD wSize; +} OLD_STREAM_HEADER, *POLD_STREAM_HEADER; + +IStream* CDesktopUpgradePropertyBag::_NewStreamFromOld(IStream *pOldStream) +{ + OLD_STREAM_HEADER Header; + HRESULT hr = pOldStream->Read(&Header, sizeof(Header), NULL); + if (FAILED(hr) || Header.wMagic != 28) + return NULL; + + // Move stream pointer + LARGE_INTEGER li; + li.QuadPart = Header.wSize - sizeof(Header); + hr = pOldStream->Seek(li, STREAM_SEEK_CUR, NULL); + if (FAILED(hr)) + return NULL; + + // Get the size + ULARGE_INTEGER uli; + hr = IStream_Size(pOldStream, &uli); + if (FAILED(hr)) + return NULL; + + // Create new stream and attach + CComPtr pNewStream; + pNewStream.Attach(SHCreateMemStream(NULL, 0)); + if (!pNewStream) + return NULL; + + // Subtract Header.wSize from the size + uli.QuadPart -= Header.wSize; + + // Copy to pNewStream + hr = pOldStream->CopyTo(pNewStream, uli, NULL, NULL); + if (FAILED(hr)) + return NULL; + + li.QuadPart = 0; + pNewStream->Seek(li, STREAM_SEEK_SET, NULL); + + return pNewStream.Detach(); +} + +IStream* CDesktopUpgradePropertyBag::_GetOldDesktopViewStream() +{ + HKEY hKey = SHGetShellKey(SHKEY_Root_HKCU, L"Streams\\Desktop", FALSE); + if (!hKey) + return NULL; + + CComPtr pOldStream; + if (!_AlreadyUpgraded(hKey)) + { + pOldStream.Attach(SHOpenRegStream2W(hKey, NULL, L"ViewView2", 0)); + if (pOldStream) + { + ULARGE_INTEGER uli; + HRESULT hr = IStream_Size(pOldStream, &uli); + if (SUCCEEDED(hr) && !uli.QuadPart) + pOldStream.Release(); + } + + if (!pOldStream) + pOldStream.Attach(SHOpenRegStream2W(hKey, NULL, L"ViewView", 0)); + + _MarkAsUpgraded(hKey); + } + + ::RegCloseKey(hKey); + return pOldStream.Detach(); +} + +HRESULT CDesktopUpgradePropertyBag::_ReadItemPositions(VARIANT *pvari) +{ + CComPtr pOldStream; + pOldStream.Attach(_GetOldDesktopViewStream()); + if (!pOldStream) + return E_FAIL; + + HRESULT hr = E_FAIL; + IStream *pNewStream = _NewStreamFromOld(pOldStream); + if (pNewStream) + { + V_UNKNOWN(pvari) = pNewStream; + V_VT(pvari) = VT_UNKNOWN; + hr = S_OK; + } + + return hr; +} + +STDMETHODIMP +CDesktopUpgradePropertyBag::Read( + _In_z_ LPCWSTR pszPropName, + _Inout_ VARIANT *pvari, + _Inout_opt_ IErrorLog *pErrorLog) +{ + UNREFERENCED_PARAMETER(pErrorLog); + + VARTYPE vt = V_VT(pvari); + + HRESULT hr = E_FAIL; + if (StrCmpW(L"FFlags", pszPropName) == 0) + hr = _ReadFlags(pvari); + else if (StrCmpNW(L"ItemPos", pszPropName, 7) == 0) + hr = _ReadItemPositions(pvari); + + if (FAILED(hr)) + { + ::VariantInit(pvari); + return hr; + } + + return ::VariantChangeType(pvari, pvari, 0, vt); +} + +/************************************************************************** + * SHGetDesktopUpgradePropertyBag (Not exported; used in CViewStatePropertyBag) + * + * Creates or gets a property bag object for desktop upgrade + * + * @param riid Specifies either IID_IUnknown, IID_IPropertyBag or IID_IPropertyBag2. + * @param ppvObj Receives an IPropertyBag pointer. + * @return An HRESULT value. S_OK on success, non-zero on failure. + */ +HRESULT SHGetDesktopUpgradePropertyBag(REFIID riid, void **ppvObj) +{ + *ppvObj = NULL; + CComPtr pPropBag(new CDesktopUpgradePropertyBag()); + return pPropBag->QueryInterface(riid, ppvObj); +} diff --git a/modules/rostests/apitests/shell32/ShellState.cpp b/modules/rostests/apitests/shell32/ShellState.cpp index 7c50806d2fd..97ae49c719a 100644 --- a/modules/rostests/apitests/shell32/ShellState.cpp +++ b/modules/rostests/apitests/shell32/ShellState.cpp @@ -12,6 +12,7 @@ #include #include #include +#include /* [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer] */ /* The contents of RegValue ShellState. */ @@ -72,8 +73,6 @@ static int read_key(REGSHELLSTATE *prss) return 0; } -extern "C" HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create); - static int read_advanced_key(SHELLSTATE* pss) { HKEY hKey; diff --git a/modules/rostests/winetests/shlwapi/ordinal.c b/modules/rostests/winetests/shlwapi/ordinal.c index cd9231351e6..f4ea269f2ce 100644 --- a/modules/rostests/winetests/shlwapi/ordinal.c +++ b/modules/rostests/winetests/shlwapi/ordinal.c @@ -33,6 +33,9 @@ #include "docobj.h" #include "shobjidl.h" #include "shlobj.h" +#ifdef __REACTOS__ + #include +#endif /* Function ptrs for ordinal calls */ static HMODULE hShlwapi; @@ -2796,6 +2799,7 @@ static void test_SHSetIniString(void) DeleteFileW(TestIniW); } +#ifndef __REACTOS__ enum _shellkey_flags { SHKEY_Root_HKCU = 0x1, SHKEY_Root_HKLM = 0x2, @@ -2811,6 +2815,7 @@ enum _shellkey_flags { SHKEY_Subkey_MUICache = 0x5000, SHKEY_Subkey_FileExts = 0x6000 }; +#endif static void test_SHGetShellKey(void) { diff --git a/sdk/include/reactos/shlwapi_undoc.h b/sdk/include/reactos/shlwapi_undoc.h index 270bc344291..37363db934b 100644 --- a/sdk/include/reactos/shlwapi_undoc.h +++ b/sdk/include/reactos/shlwapi_undoc.h @@ -217,6 +217,25 @@ SHSetIniStringUTF7W( _In_opt_z_ LPCWSTR lpString, _In_z_ LPCWSTR lpFileName); +enum _shellkey_flags +{ + SHKEY_Root_HKCU = 0x1, + SHKEY_Root_HKLM = 0x2, + SHKEY_Key_Explorer = 0x00, + SHKEY_Key_Shell = 0x10, + SHKEY_Key_ShellNoRoam = 0x20, + SHKEY_Key_Classes = 0x30, + SHKEY_Subkey_Default = 0x0000, + SHKEY_Subkey_ResourceName = 0x1000, + SHKEY_Subkey_Handlers = 0x2000, + SHKEY_Subkey_Associations = 0x3000, + SHKEY_Subkey_Volatile = 0x4000, + SHKEY_Subkey_MUICache = 0x5000, + SHKEY_Subkey_FileExts = 0x6000 +}; + +HKEY WINAPI SHGetShellKey(DWORD flags, LPCWSTR sub_key, BOOL create); + int WINAPIV ShellMessageBoxWrapW(