409 lines
13 KiB
C++
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;
|
|
}
|