windows-nt/Source/XPSP1/NT/shell/shell32/folderviewhost.cpp
2020-09-26 16:20:57 +08:00

409 lines
13 KiB
C++

#include "shellprv.h"
#include "cowsite.h"
#pragma hdrstop
// this is the comdlg frame that we will use to host the file picker object, it mostly is
// a stub that will forward accordingly
//
// the lifetime of this is handled by the DefView object we are attached to, which when
// the parent (CFolderViewHost) is destroyed will be taken down.
class CViewHostBrowser : public IShellBrowser, ICommDlgBrowser2, IServiceProvider
{
public:
CViewHostBrowser(HWND hwndParent, IShellView *psvWeak, IUnknown *punkSiteWeak);
~CViewHostBrowser();
// IServiceProvider
STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
// *** IUnknown methods ***
STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj);
STDMETHOD_(ULONG,AddRef)(THIS);
STDMETHOD_(ULONG,Release)(THIS);
// *** IOleWindow methods ***
STDMETHOD(GetWindow)(HWND *lphwnd)
{ *lphwnd = _hwndParent; return S_OK; }
STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
{ return S_OK; }
// *** IShellBrowser methods *** (same as IOleInPlaceFrame)
STDMETHOD(InsertMenusSB)(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{ return E_NOTIMPL; }
STDMETHOD(SetMenuSB)(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
{ return S_OK; }
STDMETHOD(RemoveMenusSB)(HMENU hmenuShared)
{ return E_NOTIMPL; }
STDMETHOD(SetStatusTextSB)(LPCOLESTR lpszStatusText)
{ return S_OK; }
STDMETHOD(EnableModelessSB)(BOOL fEnable)
{ return S_OK; }
STDMETHOD(TranslateAcceleratorSB)(LPMSG lpmsg, WORD wID)
{ return S_FALSE; }
// *** IShellBrowser methods ***
STDMETHOD(BrowseObject)(LPCITEMIDLIST pidl, UINT wFlags)
{ return E_FAIL; }
STDMETHOD(GetViewStateStream)(DWORD grfMode, LPSTREAM *pStrm)
{ return E_FAIL; }
STDMETHOD(GetControlWindow)(UINT id, HWND *lphwnd)
{ return E_NOTIMPL; }
STDMETHOD(SendControlMsg)(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
STDMETHOD(QueryActiveShellView)(IShellView **ppshv);
STDMETHOD(OnViewWindowActive)(IShellView *pshv)
{ return S_OK; }
STDMETHOD(SetToolbarItems)(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
{ return S_OK; }
// *** ICommDlgBrowser methods ***
STDMETHOD(OnDefaultCommand)(IShellView *ppshv)
{ return S_OK; }
STDMETHOD(OnStateChange)(IShellView *ppshv, ULONG uChange);
STDMETHOD(IncludeObject)(IShellView *ppshv, LPCITEMIDLIST lpItem);
// *** ICommDlgBrowser2 methods ***
STDMETHOD(Notify)(IShellView *ppshv, DWORD dwNotifyType)
{ return S_FALSE; }
STDMETHOD(GetDefaultMenuText)(IShellView *ppshv, WCHAR *pszText, INT cchMax)
{ return S_FALSE; }
STDMETHOD(GetViewFlags)(DWORD *pdwFlags)
{ *pdwFlags = 0; return S_OK; }
private:
long _cRef;
HWND _hwndParent;
IShellView *_psvWeak;
IUnknown *_punkSiteWeak; // not addref'd.
friend class CFolderViewHost;
};
CViewHostBrowser::CViewHostBrowser(HWND hwndParent, IShellView *psvWeak, IUnknown *punkSiteWeak) :
_cRef(1), _hwndParent(hwndParent), _psvWeak(psvWeak), _punkSiteWeak(punkSiteWeak)
{
// _psvWeak->AddRef(); // we hold a weak refernece to our parent, therefore don't AddRef()
// _punkSiteWeak->AddRef(); // we hold a weak reference to our parent, therefore don't AddRef()!
}
CViewHostBrowser::~CViewHostBrowser()
{
// _psvWeak->Release(); // this is scoped on the lifetime of our parent
// _punkSiteWeak->Release(); // we hold a weak reference to our parent, therefore don't Release()!
}
HRESULT CViewHostBrowser::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CViewHostBrowser, IShellBrowser), // IID_IShellBrowser
QITABENT(CViewHostBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser2
QITABENTMULTI(CViewHostBrowser, ICommDlgBrowser, ICommDlgBrowser2), // IID_ICommDlgBrowser
QITABENT(CViewHostBrowser, IServiceProvider), // IID_IServiceProvider
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
ULONG CViewHostBrowser::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CViewHostBrowser::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
// IShellBrowser
HRESULT CViewHostBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
{
if (pret)
*pret = 0L;
return S_OK;
}
HRESULT CViewHostBrowser::QueryActiveShellView(IShellView **ppshv)
{
HRESULT hr = E_NOINTERFACE;
if (_psvWeak)
{
hr = _psvWeak->QueryInterface(IID_PPV_ARG(IShellView, ppshv));
}
return hr;
}
// ICommDlgBrowser - these are forwarded to our site object
HRESULT CViewHostBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
{
HRESULT hr = S_OK;
ICommDlgBrowser *pcdb;
if (SUCCEEDED(IUnknown_QueryService(_punkSiteWeak, SID_SCommDlgBrowser, IID_PPV_ARG(ICommDlgBrowser, &pcdb))))
{
hr = pcdb->OnStateChange(ppshv, uChange);
pcdb->Release();
}
return hr;
}
HRESULT CViewHostBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST lpItem)
{
HRESULT hr = S_OK;
ICommDlgBrowser *pcdb;
if (SUCCEEDED(IUnknown_QueryService(_punkSiteWeak, SID_SCommDlgBrowser, IID_PPV_ARG(ICommDlgBrowser, &pcdb))))
{
hr = pcdb->IncludeObject(ppshv, lpItem);
pcdb->Release();
}
return hr;
}
// IServiceProvider
HRESULT CViewHostBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
{
HRESULT hr = E_FAIL;
*ppvObj = NULL;
if (IsEqualGUID(guidService, SID_SCommDlgBrowser))
{
hr = this->QueryInterface(riid, ppvObj);
}
return hr;
}
// this is the file picker object it creates an IShellView (which for us should result in
// a defview implement). from this we can then give the window to the caller and they
// can place on their dialog as needed.
class CFolderViewHost : public IFolderViewHost, IServiceProvider, IOleWindow, IFolderView, CObjectWithSite
{
public:
CFolderViewHost();
~CFolderViewHost();
// *** IFolderViewHost ***
STDMETHODIMP Initialize(HWND hwndParent, IDataObject *pdo, RECT *prc);
// *** IUnknown methods ***
STDMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj);
STDMETHOD_(ULONG,AddRef)(THIS);
STDMETHOD_(ULONG,Release)(THIS);
// *** IOleWindow methods ***
STDMETHOD(GetWindow)(HWND *lphwnd)
{ *lphwnd = _hwndView; return S_OK; }
STDMETHOD(ContextSensitiveHelp)(BOOL fEnterMode)
{ return S_OK; }
// IServiceProvider
STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv)
{ return IUnknown_QueryService(_punkSite, guidService, riid, ppv); }
// IFolderView
STDMETHODIMP GetCurrentViewMode(UINT *pViewMode)
{ return _pfv->GetCurrentViewMode(pViewMode); }
STDMETHODIMP SetCurrentViewMode(UINT ViewMode)
{ return _pfv->SetCurrentViewMode(ViewMode); }
STDMETHODIMP GetFolder(REFIID ridd, void **ppv)
{ return _pfv->GetFolder(ridd, ppv); }
STDMETHODIMP Item(int iItemIndex, LPITEMIDLIST *ppidl)
{ return _pfv->Item(iItemIndex, ppidl); }
STDMETHODIMP ItemCount(UINT uFlags, int *pcItems)
{ return _pfv->ItemCount(uFlags, pcItems); }
STDMETHODIMP Items(UINT uFlags, REFIID riid, void **ppv)
{ return _pfv->Items(uFlags, riid, ppv); }
STDMETHODIMP GetSelectionMarkedItem(int *piItem)
{ return _pfv->GetSelectionMarkedItem(piItem); }
STDMETHODIMP GetFocusedItem(int *piItem)
{ return _pfv->GetFocusedItem(piItem); }
STDMETHODIMP GetItemPosition(LPCITEMIDLIST pidl, POINT* ppt)
{ return _pfv->GetItemPosition(pidl, ppt); }
STDMETHODIMP GetSpacing(POINT* ppt)
{ return _pfv->GetSpacing(ppt); }
STDMETHODIMP GetDefaultSpacing(POINT* ppt)
{ return _pfv->GetDefaultSpacing(ppt); }
STDMETHODIMP GetAutoArrange()
{ return _pfv->GetAutoArrange(); }
STDMETHODIMP SelectItem(int iItem, DWORD dwFlags)
{ return _pfv->SelectItem(iItem, dwFlags); }
STDMETHODIMP SelectAndPositionItems(UINT cidl, LPCITEMIDLIST* apidl, POINT* apt, DWORD dwFlags)
{ return _pfv->SelectAndPositionItems(cidl, apidl, apt, dwFlags); }
private:
long _cRef;
IFolderView *_pfv; // IFolderView
HWND _hwndView;
};
CFolderViewHost::CFolderViewHost() :
_cRef(1)
{
}
CFolderViewHost::~CFolderViewHost()
{
if (_pfv)
_pfv->Release();
}
HRESULT CFolderViewHost::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENT(CFolderViewHost, IFolderViewHost), // IID_IFolderViewHost
QITABENT(CFolderViewHost, IOleWindow), // IID_IOleWindow
QITABENT(CFolderViewHost, IFolderView), // IID_IFolderView
QITABENT(CFolderViewHost, IServiceProvider), // IID_IServiceProvider
QITABENT(CFolderViewHost, IObjectWithSite), // IID_IObjectWithSite
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
ULONG CFolderViewHost::AddRef()
{
return InterlockedIncrement(&_cRef);
}
ULONG CFolderViewHost::Release()
{
if (InterlockedDecrement(&_cRef))
return _cRef;
delete this;
return 0;
}
// the initialize method handles the creation of the view object from the.
HRESULT CFolderViewHost::Initialize(HWND hwndParent, IDataObject *pdo, RECT *prc)
{
// first we perform a namespace walk, this will retrieve our selection from the view
// using this we can then create the view object.
INamespaceWalk *pnsw;
HRESULT hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw));
if (SUCCEEDED(hr))
{
LPITEMIDLIST *aItems = NULL;
UINT cItems = 0;
hr = pnsw->Walk(pdo, NSWF_NONE_IMPLIES_ALL, 0, NULL);
if (SUCCEEDED(hr))
{
IShellFolder *psf = NULL;
hr = pnsw->GetIDArrayResult(&cItems, &aItems);
if (S_OK == hr)
{
hr = SHBindToIDListParent(aItems[0], IID_PPV_ARG(IShellFolder, &psf), NULL);
}
else if (S_FALSE == hr)
{
hr = E_FAIL; // fail unless we perform the bind.
STGMEDIUM medium;
LPIDA pida = DataObj_GetHIDA(pdo, &medium);
if (pida)
{
if (pida->cidl == 1)
{
LPITEMIDLIST pidl = IDA_ILClone(pida, 0);
if (pidl)
{
hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf));
ILFree(pidl);
}
}
HIDA_ReleaseStgMedium(pida, &medium);
}
}
else
{
hr = E_FAIL;
}
if (SUCCEEDED(hr))
{
IShellView *psv;
hr = psf->CreateViewObject(hwndParent, IID_PPV_ARG(IShellView, &psv));
if (SUCCEEDED(hr))
{
CViewHostBrowser *pvhb = new CViewHostBrowser(hwndParent, psv, SAFECAST(this, IServiceProvider*));
if (pvhb)
{
hr = psv->QueryInterface(IID_PPV_ARG(IFolderView, &_pfv));
if (SUCCEEDED(hr))
{
FOLDERSETTINGS fs = {0};
fs.ViewMode = FVM_THUMBNAIL;
fs.fFlags = FWF_AUTOARRANGE|FWF_NOWEBVIEW|FWF_HIDEFILENAMES|FWF_CHECKSELECT;
IFolderView *pfv;
if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IFolderView, &pfv))))
{
pfv->GetCurrentViewMode(&fs.ViewMode);
pfv->Release();
}
hr = psv->CreateViewWindow(NULL, &fs, pvhb, prc, &_hwndView);
if (SUCCEEDED(hr))
{
hr = psv->UIActivate(SVUIA_INPLACEACTIVATE);
}
}
pvhb->Release();
}
else
{
hr = E_OUTOFMEMORY;
}
psv->Release();
}
for (int i = 0; SUCCEEDED(hr) && (i != cItems); i++)
{
LPCITEMIDLIST pidlChild = ILFindLastID(aItems[i]);
hr = _pfv->SelectAndPositionItems(1, &pidlChild, NULL, SVSI_CHECK);
}
psf->Release();
}
FreeIDListArray(aItems, cItems);
}
pnsw->Release();
}
return hr;
}
STDAPI CFolderViewHost_CreateInstance(IUnknown *punkOut, REFIID riid, void **ppv)
{
CFolderViewHost *pfp = new CFolderViewHost();
if (!pfp)
return E_OUTOFMEMORY;
HRESULT hr = pfp->QueryInterface(riid, ppv);
pfp->Release();
return hr;
}