From e639d7c1e7e0215e865a82535457a8de602b8785 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Mon, 19 Aug 2024 00:34:05 +0200 Subject: [PATCH] [SHELL32] Handle SHCreateShellFolderViewEx callback function (#7240) The caller supplied callback function is wrapped in a IShellFolderViewCB so we can use (the newer) SHCreateShellFolderView. --- dll/win32/shell32/CDefView.cpp | 25 +----- dll/win32/shell32/CDefViewUtil.cpp | 140 +++++++++++++++++++++++++++++ dll/win32/shell32/CMakeLists.txt | 1 + sdk/include/psdk/shlobj.h | 1 + 4 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 dll/win32/shell32/CDefViewUtil.cpp diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 3ada8ae10b7..7617f85e5d7 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -1733,7 +1733,7 @@ LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl LPITEMIDLIST pidlTarget = NULL; LONG fEvents = 0; HRESULT hr = _DoFolderViewCB(SFVM_GETNOTIFY, (WPARAM)&pidlTarget, (LPARAM)&fEvents); - if (FAILED(hr) || (!pidlTarget && !fEvents)) + if (FAILED(hr) || (!pidlTarget && !fEvents)) // FIXME: MSDN says both zero means no notifications { pidlTarget = m_pidlParent; fEvents = SHCNE_ALLEVENTS; @@ -3464,7 +3464,7 @@ HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut) FOLDERVIEWMODE CDefView::GetDefaultViewMode() { FOLDERVIEWMODE mode = ((m_FolderSettings.fFlags & FWF_DESKTOP) || !IsOS(OS_SERVERADMINUI)) ? FVM_ICON : FVM_DETAILS; - FOLDERVIEWMODE temp; + FOLDERVIEWMODE temp = mode; if (SUCCEEDED(_DoFolderViewCB(SFVM_DEFVIEWMODE, 0, (LPARAM)&temp)) && temp >= FVM_FIRST && temp <= FVM_LAST) mode = temp; return mode; @@ -3753,6 +3753,7 @@ HRESULT STDMETHODCALLTYPE CDefView::CreateViewWindow3(IShellBrowser *psb, IShell /* Get our parent window */ m_pShellBrowser->GetWindow(&m_hWndParent); + _DoFolderViewCB(SFVM_HWNDMAIN, 0, (LPARAM)m_hWndParent); /* Try to get the ICommDlgBrowserInterface, adds a reference !!! */ m_pCommDlgBrowser = NULL; @@ -4656,26 +4657,6 @@ HRESULT CDefView_CreateInstance(IShellFolder *pFolder, REFIID riid, LPVOID * ppv return ShellObjectCreatorInit(pFolder, riid, ppvOut); } -HRESULT WINAPI SHCreateShellFolderViewEx( - LPCSFV psvcbi, // [in] shelltemplate struct - IShellView **ppsv) // [out] IShellView pointer -{ - CComPtr psv; - HRESULT hRes; - - TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n", - psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback, - psvcbi->fvm, psvcbi->psvOuter); - - *ppsv = NULL; - hRes = CDefView_CreateInstance(psvcbi->pshf, IID_PPV_ARG(IShellView, &psv)); - if (FAILED_UNEXPECTEDLY(hRes)) - return hRes; - - *ppsv = psv.Detach(); - return hRes; -} - HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, IShellView **ppsv) { diff --git a/dll/win32/shell32/CDefViewUtil.cpp b/dll/win32/shell32/CDefViewUtil.cpp new file mode 100644 index 00000000000..3996b0d3891 --- /dev/null +++ b/dll/win32/shell32/CDefViewUtil.cpp @@ -0,0 +1,140 @@ +/* + * PROJECT: shell32 + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: DefView utility functions + * COPYRIGHT: Copyright 2024 Whindmar Saksit + */ + +#include "precomp.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +class CObjectWithSiteBase : + public IObjectWithSite +{ +public: + IUnknown* m_pUnkSite; + + CObjectWithSiteBase() : m_pUnkSite(NULL) {} + virtual ~CObjectWithSiteBase() { SetSite(NULL); } + + // IObjectWithSite + STDMETHODIMP SetSite(IUnknown *pUnkSite) override + { + IUnknown_Set(&m_pUnkSite, pUnkSite); + return S_OK; + } + STDMETHODIMP GetSite(REFIID riid, void **ppvSite) override + { + *ppvSite = NULL; + return m_pUnkSite ? m_pUnkSite->QueryInterface(riid, ppvSite) : E_FAIL; + } +}; + +// This class adapts the legacy function callback to work as an IShellFolderViewCB +class CShellFolderViewCBWrapper : + public CComObjectRootEx, + public IShellFolderViewCB, + public CObjectWithSiteBase +{ +protected: + HWND m_hWndMain; + PIDLIST_ABSOLUTE m_Pidl; + CComPtr m_psf; + CComPtr m_psvOuter; + LPFNVIEWCALLBACK m_Callback; + FOLDERVIEWMODE m_FVM; + LONG m_Events; + +public: + CShellFolderViewCBWrapper() : m_hWndMain(NULL), m_Pidl(NULL) {} + + virtual ~CShellFolderViewCBWrapper() + { + ILFree(m_Pidl); + } + + HRESULT WINAPI Initialize(LPCSFV psvcbi) + { + m_psf = psvcbi->pshf; + m_psvOuter = psvcbi->psvOuter; + m_Pidl = psvcbi->pidl ? ILClone(psvcbi->pidl) : NULL; + m_Callback = psvcbi->pfnCallback; + m_FVM = psvcbi->fvm; + m_Events = psvcbi->lEvents; + return S_OK; + } + + // IShellFolderViewCB + STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) override + { + switch (uMsg) + { + case SFVM_HWNDMAIN: + m_hWndMain = (HWND)lParam; + break; + + case SFVM_DEFVIEWMODE: + if (m_FVM) + *(FOLDERVIEWMODE*)lParam = m_FVM; + break; + } + + HRESULT hr = m_Callback(m_psvOuter, m_psf, m_hWndMain, uMsg, wParam, lParam); + if (SUCCEEDED(hr)) + return hr; + + switch (uMsg) + { + case SFVM_GETNOTIFY: + *(LPITEMIDLIST*)wParam = m_Pidl; + *(LONG*)lParam = m_Events; + return S_OK; + } + return hr; + } + + // IObjectWithSite + STDMETHODIMP SetSite(IUnknown *pUnkSite) override + { + // learn.microsoft.com/en-us/windows/win32/shell/sfvm-setisfv + HRESULT hr = CObjectWithSiteBase::SetSite(pUnkSite); + MessageSFVCB(SFVM_SETISFV, 0, (LPARAM)pUnkSite); + return hr; + } + + DECLARE_NO_REGISTRY() + DECLARE_NOT_AGGREGATABLE(CShellFolderViewCBWrapper) + BEGIN_COM_MAP(CShellFolderViewCBWrapper) + COM_INTERFACE_ENTRY_IID(IID_IShellFolderViewCB, IShellFolderViewCB) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + END_COM_MAP() +}; + +/************************************************************************* + * SHCreateShellFolderViewEx [SHELL32.174] (Win95+) + */ +EXTERN_C HRESULT WINAPI +SHCreateShellFolderViewEx(_In_ LPCSFV pcsfv, _Out_ IShellView **ppsv) +{ + if (!ppsv) + return E_INVALIDARG; + *ppsv = NULL; + + TRACE("sf=%p pidl=%p cb=%p mode=0x%08x outer=%p\n", + pcsfv->pshf, pcsfv->pidl, pcsfv->pfnCallback, + pcsfv->fvm, pcsfv->psvOuter); + + CComPtr psfvcb; + SFV_CREATE create = { sizeof(create), pcsfv->pshf, pcsfv->psvOuter }; + + if (pcsfv->pfnCallback) + { + HRESULT hr = ShellObjectCreatorInit(pcsfv, + IID_PPV_ARG(IShellFolderViewCB, &psfvcb)); + if (FAILED(hr)) + return hr; + create.psfvcb = psfvcb; + } + return SHCreateShellFolderView(&create, ppsv); +} diff --git a/dll/win32/shell32/CMakeLists.txt b/dll/win32/shell32/CMakeLists.txt index 1b76acb0560..7226ba4105d 100644 --- a/dll/win32/shell32/CMakeLists.txt +++ b/dll/win32/shell32/CMakeLists.txt @@ -65,6 +65,7 @@ list(APPEND SOURCE shlfolder.cpp CFileSysBindData.cpp CDefView.cpp + CDefViewUtil.cpp CDefViewDual.cpp CDefViewBckgrndMenu.cpp stubs.cpp diff --git a/sdk/include/psdk/shlobj.h b/sdk/include/psdk/shlobj.h index 608e78618f0..10e73f0ddcd 100644 --- a/sdk/include/psdk/shlobj.h +++ b/sdk/include/psdk/shlobj.h @@ -1331,6 +1331,7 @@ SHCreateShellFolderViewEx( #define SFVM_GETEXTVIEWS 40 /* undocumented */ #define SFVM_THISIDLIST 41 #define SFVM_UPDATINGOBJECT 43 /* undocumented */ +#define SFVM_HWNDMAIN 46 /* undocumented */ #define SFVM_ADDPROPERTYPAGES 47 #define SFVM_BACKGROUNDENUMDONE 48 #define SFVM_GETNOTIFY 49