|
|
#include "precomp.hxx"
#pragma hdrstop
#include <shguidp.h> // CLSID_MyDocuments, CLSID_ShellFSFolder
#include <shellp.h> // SHCoCreateInstance
#include <shlguidp.h> // IID_IResolveShellLink
#include "util.h"
#include "dll.h"
#include "resource.h"
#include "prop.h"
HRESULT _GetUIObjectForMyDocs(REFIID riid, void **ppv) { LPITEMIDLIST pidl; HRESULT hr = SHGetFolderLocation(NULL, CSIDL_PERSONAL | CSIDL_FLAG_NO_ALIAS, NULL, 0, &pidl); if (SUCCEEDED(hr)) { hr = SHGetUIObjectFromFullPIDL(pidl, NULL, riid, ppv); ILFree(pidl); } return hr; }
// send to "My Documents" handler
class CMyDocsSendTo : public IDropTarget, IPersistFile { public: CMyDocsSendTo(); HRESULT _InitTarget();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)();
// IDropTarget
STDMETHODIMP DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect); STDMETHODIMP DragLeave(); STDMETHODIMP Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
// IPersist
STDMETHOD(GetClassID)(CLSID *pClassID);
// IPersistFile
STDMETHOD(IsDirty)(void); STDMETHOD(Load)(LPCOLESTR pszFileName, DWORD dwMode); STDMETHOD(Save)(LPCOLESTR pszFileName, BOOL fRemember); STDMETHOD(SaveCompleted)(LPCOLESTR pszFileName); STDMETHOD(GetCurFile)(LPOLESTR *ppszFileName);
private: ~CMyDocsSendTo();
LONG _cRef; IDropTarget *_pdtgt; };
CMyDocsSendTo::CMyDocsSendTo() : _cRef(1) { DllAddRef(); }
CMyDocsSendTo::~CMyDocsSendTo() { if (_pdtgt) _pdtgt->Release(); DllRelease(); }
STDMETHODIMP CMyDocsSendTo::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMyDocsSendTo, IDropTarget), QITABENT(CMyDocsSendTo, IPersistFile), QITABENTMULTI(CMyDocsSendTo, IPersist, IPersistFile), { 0 }, }; return QISearch(this, qit, riid, ppv); }
STDMETHODIMP_(ULONG) CMyDocsSendTo::AddRef() { return InterlockedIncrement(&_cRef); }
STDMETHODIMP_(ULONG) CMyDocsSendTo::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
HRESULT CMyDocsSendTo::_InitTarget() { if (_pdtgt) return S_OK; return _GetUIObjectForMyDocs(IID_PPV_ARG(IDropTarget, &_pdtgt)); }
STDMETHODIMP CMyDocsSendTo::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
HRESULT hr = _InitTarget(); if (SUCCEEDED(hr)) hr = _pdtgt->DragEnter(pDataObject, grfKeyState, pt, pdwEffect); return hr; }
STDMETHODIMP CMyDocsSendTo::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
HRESULT hr = _InitTarget(); if (SUCCEEDED(hr)) hr = _pdtgt->DragOver(grfKeyState, pt, pdwEffect); return hr; }
STDMETHODIMP CMyDocsSendTo::DragLeave() { HRESULT hr = _InitTarget(); if (SUCCEEDED(hr)) hr = _pdtgt->DragLeave(); return hr; }
STDMETHODIMP CMyDocsSendTo::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
HRESULT hr = _InitTarget(); if (SUCCEEDED(hr)) hr = _pdtgt->Drop(pDataObject, grfKeyState, pt, pdwEffect); return hr; }
STDMETHODIMP CMyDocsSendTo::GetClassID(CLSID *pClassID) { *pClassID = CLSID_MyDocsDropTarget; return S_OK; }
STDMETHODIMP CMyDocsSendTo::IsDirty(void) { return S_OK; // no
}
STDMETHODIMP CMyDocsSendTo::Load(LPCOLESTR pszFileName, DWORD dwMode) { if (_pdtgt) return S_OK; UpdateSendToFile(); // refresh the send to target (in case the desktop icon was renamed)
return S_OK; }
STDMETHODIMP CMyDocsSendTo::Save(LPCOLESTR pszFileName, BOOL fRemember) { return S_OK; }
STDMETHODIMP CMyDocsSendTo::SaveCompleted(LPCOLESTR pszFileName) { return S_OK; }
STDMETHODIMP CMyDocsSendTo::GetCurFile(LPOLESTR *ppszFileName) { *ppszFileName = NULL; return E_NOTIMPL; }
HRESULT CMyDocsSendTo_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { CMyDocsSendTo* pdt = new CMyDocsSendTo(); if (pdt) { *ppunk = SAFECAST(pdt, IDropTarget *); return S_OK; } *ppunk = NULL; return E_OUTOFMEMORY; }
// properyt page and context menu shell extension
class CMyDocsProp : public IShellPropSheetExt, public IShellExtInit { public: CMyDocsProp();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(); STDMETHOD_(ULONG, Release)();
// IShellExtInit
STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, IDataObject *lpdobj, HKEY hkeyProgID);
// IShellPropSheetExt
STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam); STDMETHOD(ReplacePage)(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam);
private: ~CMyDocsProp(); void _AddExtraPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
LONG _cRef; };
CMyDocsProp::CMyDocsProp() : _cRef(1) { DllAddRef(); }
CMyDocsProp::~CMyDocsProp() { DllRelease(); }
STDMETHODIMP CMyDocsProp::QueryInterface( REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CMyDocsProp, IShellPropSheetExt), QITABENT(CMyDocsProp, IShellExtInit), { 0 }, }; return QISearch(this, qit, riid, ppv); }
STDMETHODIMP_ (ULONG) CMyDocsProp::AddRef() { return InterlockedIncrement(&_cRef); }
STDMETHODIMP_ (ULONG) CMyDocsProp::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
STDMETHODIMP CMyDocsProp::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkey) { return S_OK; }
// {f81e9010-6ea4-11ce-a7ff-00aa003ca9f6}
const CLSID CLSID_CShare = {0xf81e9010, 0x6ea4, 0x11ce, 0xa7, 0xff, 0x00, 0xaa, 0x00, 0x3c, 0xa9, 0xf6 };
// {1F2E5C40-9550-11CE-99D2-00AA006E086C}
const CLSID CLSID_RShellExt = {0x1F2E5C40, 0x9550, 0x11CE, 0x99, 0xD2, 0x00, 0xAA, 0x00, 0x6E, 0x08, 0x6C };
const CLSID *c_rgFilePages[] = { &CLSID_ShellFileDefExt, &CLSID_CShare, &CLSID_RShellExt, };
const CLSID *c_rgDrivePages[] = { &CLSID_ShellDrvDefExt, &CLSID_CShare, &CLSID_RShellExt, };
// add optional pages to Explore/Options.
void CMyDocsProp::_AddExtraPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { IDataObject *pdtobj;
if (SUCCEEDED(_GetUIObjectForMyDocs(IID_PPV_ARG(IDataObject, &pdtobj)))) { TCHAR szPath[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPath); BOOL fDriveRoot = PathIsRoot(szPath) && !PathIsUNC(szPath); const CLSID** pCLSIDs = fDriveRoot ? c_rgDrivePages : c_rgFilePages; int nCLSIDs = (int)(fDriveRoot ? ARRAYSIZE(c_rgDrivePages) : ARRAYSIZE(c_rgFilePages)); for (int i = 0; i < nCLSIDs; i++) { IUnknown *punk;
// We need to CoCreate for IUnknown instead of IShellPropSheetExt because the
// class factory for the Win9x sharing property sheet (msshrui.dll) is buggy
// and return E_NOINTERFACE ISPSE...
HRESULT hr = SHCoCreateInstance(NULL, pCLSIDs[i], NULL, IID_PPV_ARG(IUnknown, &punk)); if (SUCCEEDED(hr)) { IShellPropSheetExt *pspse; hr = punk->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse)); punk->Release(); if (SUCCEEDED(hr)) { IShellExtInit *psei; if (SUCCEEDED(pspse->QueryInterface(IID_PPV_ARG(IShellExtInit, &psei)))) { hr = psei->Initialize(NULL, pdtobj, NULL); psei->Release(); }
if (SUCCEEDED(hr)) pspse->AddPages(pfnAddPage, lParam); pspse->Release(); } } } } }
STDMETHODIMP CMyDocsProp::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { HRESULT hr = S_OK;
PROPSHEETPAGE psp = {0};
psp.dwSize = sizeof(psp); psp.dwFlags = PSP_DEFAULT; psp.hInstance = g_hInstance; psp.pszTemplate = MAKEINTRESOURCE(DLG_TARGET); psp.pfnDlgProc = TargetDlgProc;
HPROPSHEETPAGE hPage = CreatePropertySheetPage( &psp ); if (hPage) { pfnAddPage( hPage, lParam ); _AddExtraPages(pfnAddPage, lParam); } return hr; }
STDMETHODIMP CMyDocsProp::ReplacePage( UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) { return E_NOTIMPL; }
HRESULT CMyDocsProp_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { CMyDocsProp* pmp = new CMyDocsProp(); if (pmp) { *ppunk = SAFECAST(pmp, IShellExtInit *); return S_OK; } *ppunk = NULL; return E_OUTOFMEMORY; }
|