3384 lines
110 KiB
C++
3384 lines
110 KiB
C++
|
//-------------------------------------------------------------------------//
|
||
|
//
|
||
|
// AugMisf.cpp - Augmented Merge IShellFolder class implementation.
|
||
|
//
|
||
|
//-------------------------------------------------------------------------//
|
||
|
#include "priv.h"
|
||
|
#include "augmisf.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
#include "mluisupp.h"
|
||
|
|
||
|
#define TF_AUGM 0x10000000
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// BUGBUG: Shell allocator bullchit, inserted here because SHRealloc
|
||
|
// isn't imported into browseui, this module's hosting executable.
|
||
|
// If we get SHRealloc, the following block can be removed:
|
||
|
#define _EXPL_SHELL_ALLOCATOR_
|
||
|
|
||
|
#ifdef _EXPL_SHELL_ALLOCATOR_
|
||
|
|
||
|
#define SHRealloc( pv, cb ) shrealloc( pv, cb )
|
||
|
|
||
|
void* shrealloc( void* pv, size_t cb )
|
||
|
{
|
||
|
IMalloc* pMalloc ;
|
||
|
void* pvRet = NULL ;
|
||
|
if( SUCCEEDED( SHGetMalloc( &pMalloc ) ) ) {
|
||
|
pvRet = pMalloc->Realloc( pv, cb ) ;
|
||
|
ATOMICRELEASE( pMalloc ) ;
|
||
|
}
|
||
|
return pvRet ;
|
||
|
}
|
||
|
|
||
|
#endif _EXPL_SHELL_ALLOCATOR_
|
||
|
|
||
|
BOOL AffectAllUsers(HWND hwnd);
|
||
|
|
||
|
// id - verb mappings for IContextMenu impl
|
||
|
const struct
|
||
|
{
|
||
|
UINT id;
|
||
|
LPCSTR pszVerb;
|
||
|
} c_sIDVerbMap[] =
|
||
|
{
|
||
|
{SMIDM_DELETE, "delete"},
|
||
|
{SMIDM_RENAME, "rename"},
|
||
|
{SMIDM_PROPERTIES, "properties"},
|
||
|
//{SMIDM_OPEN, "open"},
|
||
|
//{SMIDM_EXPLORE, "explore"},
|
||
|
};
|
||
|
|
||
|
// augmisf context menu
|
||
|
|
||
|
class CAugMergeISFContextMenu : public IContextMenu2
|
||
|
{
|
||
|
public:
|
||
|
// *** IUnknown methods ***
|
||
|
STDMETHOD (QueryInterface)(REFIID, void**);
|
||
|
STDMETHOD_(ULONG, AddRef)();
|
||
|
STDMETHOD_(ULONG, Release)();
|
||
|
|
||
|
// *** IContextMenu methods ***
|
||
|
STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
|
||
|
STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
|
||
|
STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax);
|
||
|
|
||
|
// *** IContextMenu2 methods ***
|
||
|
STDMETHOD(HandleMenuMsg)(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
protected:
|
||
|
CAugMergeISFContextMenu(IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
|
||
|
IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
|
||
|
HWND hwnd, UINT * prgfInOut);
|
||
|
~CAugMergeISFContextMenu();
|
||
|
|
||
|
friend class CAugmentedMergeISF;
|
||
|
friend CAugMergeISFContextMenu* CreateMergeISFContextMenu(
|
||
|
IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
|
||
|
IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
|
||
|
HWND hwnd, UINT * prgfInOut);
|
||
|
protected:
|
||
|
LPITEMIDLIST _pidlItem;
|
||
|
IShellFolder * _psfCommon;
|
||
|
IShellFolder * _psfUser;
|
||
|
IContextMenu * _pcmCommon;
|
||
|
IContextMenu * _pcmUser;
|
||
|
LPITEMIDLIST _pidlCommon;
|
||
|
LPITEMIDLIST _pidlUser;
|
||
|
UINT _idFirst;
|
||
|
LONG _cRef;
|
||
|
HWND _hwnd;
|
||
|
};
|
||
|
|
||
|
CAugMergeISFContextMenu* CreateMergeISFContextMenu(
|
||
|
IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
|
||
|
IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
|
||
|
HWND hwnd, UINT * prgfInOut)
|
||
|
{
|
||
|
CAugMergeISFContextMenu* pcm = new CAugMergeISFContextMenu(psfCommon, pidlCommon,
|
||
|
psfUser, pidlUser,
|
||
|
pidl, hwnd, prgfInOut);
|
||
|
if (pcm)
|
||
|
{
|
||
|
if (!pcm->_pidlItem)
|
||
|
{
|
||
|
delete pcm;
|
||
|
pcm = NULL;
|
||
|
}
|
||
|
}
|
||
|
return pcm;
|
||
|
}
|
||
|
|
||
|
|
||
|
CAugMergeISFContextMenu::CAugMergeISFContextMenu(IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
|
||
|
IShellFolder *psfUser, LPCITEMIDLIST pidlUser,
|
||
|
LPITEMIDLIST pidl, HWND hwnd, UINT * prgfInOut)
|
||
|
{
|
||
|
_cRef = 1;
|
||
|
HRESULT hres;
|
||
|
|
||
|
_hwnd = hwnd;
|
||
|
_psfCommon = psfCommon;
|
||
|
if (_psfCommon)
|
||
|
{
|
||
|
_psfCommon->AddRef();
|
||
|
hres = _psfCommon->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, (void **)&_pcmCommon);
|
||
|
|
||
|
ASSERT(SUCCEEDED(hres) || !_pcmCommon);
|
||
|
_pidlCommon = ILClone(pidlCommon);
|
||
|
}
|
||
|
_psfUser = psfUser;
|
||
|
if (_psfUser)
|
||
|
{
|
||
|
_psfUser->AddRef();
|
||
|
hres = _psfUser->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, (void **)&_pcmUser);
|
||
|
|
||
|
ASSERT(SUCCEEDED(hres) || !_pcmUser);
|
||
|
_pidlUser = ILClone(pidlUser);
|
||
|
}
|
||
|
_pidlItem = ILClone(pidl);
|
||
|
ASSERT(_psfCommon || _psfUser);
|
||
|
}
|
||
|
|
||
|
CAugMergeISFContextMenu::~CAugMergeISFContextMenu()
|
||
|
{
|
||
|
ATOMICRELEASE(_psfCommon);
|
||
|
ATOMICRELEASE(_pcmCommon);
|
||
|
ATOMICRELEASE(_psfUser);
|
||
|
ATOMICRELEASE(_pcmUser);
|
||
|
ILFree(_pidlCommon);
|
||
|
ILFree(_pidlUser);
|
||
|
ILFree(_pidlItem);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CAugMergeISFContextMenu::QueryInterface(REFIID riid, LPVOID *ppvOut)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENTMULTI(CAugMergeISFContextMenu, IContextMenu, IContextMenu2),
|
||
|
QITABENT(CAugMergeISFContextMenu, IContextMenu2),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppvOut);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CAugMergeISFContextMenu::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CAugMergeISFContextMenu::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugMergeISFContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
|
||
|
{
|
||
|
HRESULT hres = E_INVALIDARG;
|
||
|
|
||
|
if (hmenu)
|
||
|
{
|
||
|
HMENU hmContext = LoadMenuPopup(MENU_SM_CONTEXTMENU);
|
||
|
if (hmContext)
|
||
|
{
|
||
|
if (!_psfCommon || !_psfUser)
|
||
|
{
|
||
|
DeleteMenu(hmContext, SMIDM_OPENCOMMON, MF_BYCOMMAND);
|
||
|
DeleteMenu(hmContext, SMIDM_EXPLORECOMMON, MF_BYCOMMAND);
|
||
|
}
|
||
|
|
||
|
_idFirst = idCmdFirst;
|
||
|
Shell_MergeMenus(hmenu, hmContext, -1, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
|
||
|
DestroyMenu(hmContext);
|
||
|
|
||
|
// Make it look "Shell Like"
|
||
|
SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
|
||
|
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
else
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugMergeISFContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
|
||
|
{
|
||
|
UINT id = -1;
|
||
|
HRESULT hres = E_FAIL;
|
||
|
CMINVOKECOMMANDINFO ici = *pici;
|
||
|
|
||
|
if (pici->cbSize < SIZEOF(CMINVOKECOMMANDINFO))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (HIWORD(pici->lpVerb))
|
||
|
{
|
||
|
for (int i=0; i < ARRAYSIZE(c_sIDVerbMap); i++)
|
||
|
{
|
||
|
if (lstrcmpiA(pici->lpVerb, c_sIDVerbMap[i].pszVerb) == 0)
|
||
|
{
|
||
|
id = c_sIDVerbMap[i].id;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
id = (UINT) PtrToUlong( pici->lpVerb ); // Win64: should be ok since MAKEINTRESOURCE assumed
|
||
|
|
||
|
switch (id)
|
||
|
{
|
||
|
case -1:
|
||
|
hres = E_INVALIDARG;
|
||
|
break;
|
||
|
|
||
|
case SMIDM_OPEN:
|
||
|
case SMIDM_EXPLORE:
|
||
|
case SMIDM_OPENCOMMON:
|
||
|
case SMIDM_EXPLORECOMMON:
|
||
|
{
|
||
|
IShellFolder * psf;
|
||
|
LPITEMIDLIST pidl;
|
||
|
|
||
|
if (id == SMIDM_OPEN || id == SMIDM_EXPLORE)
|
||
|
{
|
||
|
if (_psfUser)
|
||
|
{
|
||
|
psf = _psfUser;
|
||
|
pidl = _pidlUser;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
psf = _psfCommon;
|
||
|
pidl = _pidlCommon;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
psf = _psfCommon;
|
||
|
pidl = _pidlCommon;
|
||
|
}
|
||
|
|
||
|
if (psf && pidl)
|
||
|
{
|
||
|
SHELLEXECUTEINFO shei = {0};
|
||
|
|
||
|
shei.lpIDList = ILCombine(pidl, _pidlItem);
|
||
|
if (shei.lpIDList)
|
||
|
{
|
||
|
shei.cbSize = sizeof(shei);
|
||
|
shei.fMask = SEE_MASK_IDLIST;
|
||
|
shei.nShow = SW_SHOWNORMAL;
|
||
|
if (id == SMIDM_EXPLORE || id == SMIDM_EXPLORECOMMON)
|
||
|
shei.lpVerb = TEXT("explore");
|
||
|
else
|
||
|
shei.lpVerb = TEXT("open");
|
||
|
hres = ShellExecuteEx(&shei) ? S_OK : E_FAIL;
|
||
|
ILFree((LPITEMIDLIST)shei.lpIDList);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SMIDM_PROPERTIES:
|
||
|
{
|
||
|
IContextMenu * pcm = _pcmUser ? _pcmUser : _pcmCommon;
|
||
|
|
||
|
if (pcm)
|
||
|
{
|
||
|
ici.lpVerb = "properties";
|
||
|
hres = pcm->InvokeCommand(&ici);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case SMIDM_DELETE:
|
||
|
ici.lpVerb = "delete";
|
||
|
hres = S_OK;
|
||
|
|
||
|
if (_pcmUser)
|
||
|
{
|
||
|
hres = _pcmUser->InvokeCommand(&ici);
|
||
|
}
|
||
|
else if (_pcmCommon)
|
||
|
{
|
||
|
ici.fMask |= CMIC_MASK_FLAG_NO_UI;
|
||
|
if (AffectAllUsers(_hwnd))
|
||
|
hres = _pcmCommon->InvokeCommand(&ici);
|
||
|
else
|
||
|
hres = E_FAIL;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case SMIDM_RENAME:
|
||
|
ASSERT(0);
|
||
|
hres = E_NOTIMPL; // sftbar picks this off
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugMergeISFContextMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
|
||
|
{
|
||
|
HRESULT hres = E_NOTIMPL;
|
||
|
|
||
|
// if hiword in not null then a string is passed to us. we don't handle that case (yet?)
|
||
|
if (!HIWORD(idCmd) && (uType == GCS_VERBA || uType == GCS_VERBW))
|
||
|
{
|
||
|
hres = E_INVALIDARG;
|
||
|
|
||
|
for (int i = 0; hres != S_OK && i < ARRAYSIZE(c_sIDVerbMap); i++)
|
||
|
{
|
||
|
if (c_sIDVerbMap[i].id == idCmd)
|
||
|
{
|
||
|
if (uType == GCS_VERBA)
|
||
|
lstrcpynA(pszName, c_sIDVerbMap[i].pszVerb, cchMax);
|
||
|
else
|
||
|
SHAnsiToUnicode(c_sIDVerbMap[i].pszVerb, (LPWSTR)pszName, cchMax);
|
||
|
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
// we need IContextMenu2 although HandleMenuMsg is not impl because of the way sftbar
|
||
|
// works -- it caches only IContextMenu2 so if we don't have ICM2 sftbar will think
|
||
|
// that it does not have context menu so it will eat the messages intended for the hmenu
|
||
|
// that way, with context menu up, if user presses esc it will kill start menu sub menu
|
||
|
// not the context menu.
|
||
|
HRESULT CAugMergeISFContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Augmented Merge Shell Folder's pidl wrapper package consists of a versioned
|
||
|
// header followed by n 'source namespace' pidl wrappers.
|
||
|
// Each individual pidl wrapper consists of a header containing a
|
||
|
// collection lookup index followed by the source pidl itself. The
|
||
|
// source pidl's mkid.cb member is used to seek the next pidl wrap in
|
||
|
// the package.
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
//--- Augmented Merge Shell Folder's pidl wrapper header
|
||
|
typedef struct tagAUGM_IDWRAP {
|
||
|
USHORT cb ; // pidl wrap length
|
||
|
USHORT Reserved ; // reserved.
|
||
|
ULONG tag ; // AugMergeISF pidl signature
|
||
|
ULONG version ; // AugMergeISF pidl version
|
||
|
ULONG cSrcs ; // Number of source namespace objects backing this composite pidl
|
||
|
} AUGM_IDWRAP;
|
||
|
|
||
|
typedef UNALIGNED AUGM_IDWRAP *PAUGM_IDWRAP;
|
||
|
|
||
|
//--- Source pidl header. One or more of these records will be concatenated
|
||
|
// within the wrap following the wrap header.
|
||
|
typedef struct tagAUGM_IDSRC {
|
||
|
UINT nID ; // source namespace index
|
||
|
BYTE pidl[0] ; // source pidl
|
||
|
} AUGM_IDSRC;
|
||
|
|
||
|
typedef UNALIGNED AUGM_IDSRC *PAUGM_IDSRC;
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Constants
|
||
|
//-------------------------------------------------------------------------//
|
||
|
#define AUGM_WRAPTAG MAKELONG( MAKEWORD('A','u'), MAKEWORD('g','M') )
|
||
|
#define AUGM_WRAPVERSION_1_0 MAKELONG( 1, 0 )
|
||
|
#define AUGM_WRAPCURRENTVERSION AUGM_WRAPVERSION_1_0
|
||
|
#define INVALID_NAMESPACE_INDEX ((UINT)-1)
|
||
|
#define CB_IDLIST_TERMINATOR sizeof(USHORT)
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Augmented Merge shell folder pidl wrap utilities
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Resolves the wrap header from the indicated pidl.
|
||
|
#define AugMergeISF_GetWrap( p ) ((PAUGM_IDWRAP)(p))
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Determines whether the indicated pidl is an Augmented Merge
|
||
|
// shell folder pidl wrapper.
|
||
|
HRESULT AugMergeISF_IsWrap(
|
||
|
IN LPCITEMIDLIST pidlTest,
|
||
|
IN ULONG nVersion = AUGM_WRAPCURRENTVERSION )
|
||
|
{
|
||
|
ASSERT(IS_VALID_PIDL( pidlTest ));
|
||
|
|
||
|
if (pidlTest)
|
||
|
{
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlTest ) ;
|
||
|
|
||
|
return (pWrap->cb >= sizeof(AUGM_IDWRAP) &&
|
||
|
pWrap->tag == AUGM_WRAPTAG &&
|
||
|
pWrap->version == nVersion) ?
|
||
|
S_OK : E_UNEXPECTED ; //BUGBUG: better error code for version mismatch?
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Retrieves the number of source namespace pidls in the wrap.
|
||
|
// If the pidl was not wrapped, the return value is -1.
|
||
|
ULONG AugMergeISF_GetSourceCount( IN LPCITEMIDLIST pidl )
|
||
|
{
|
||
|
ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidl)));
|
||
|
return AugMergeISF_GetWrap(pidl)->cSrcs;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Creates an IDLIST wrapper object based on the indicated source pidl.
|
||
|
HRESULT AugMergeISF_CreateWrap(
|
||
|
IN LPCITEMIDLIST pidlSrc,
|
||
|
IN UINT nSrcID,
|
||
|
OUT LPITEMIDLIST* ppidlWrap )
|
||
|
{
|
||
|
ASSERT( ppidlWrap ) ;
|
||
|
ASSERT( IS_VALID_PIDL( pidlSrc ) && INVALID_NAMESPACE_INDEX != nSrcID ) ;
|
||
|
|
||
|
*ppidlWrap = NULL ;
|
||
|
|
||
|
// Allocate a header and terminator
|
||
|
LPBYTE pBuf = NULL ;
|
||
|
WORD cbAlloc = sizeof(AUGM_IDWRAP) +
|
||
|
sizeof(AUGM_IDSRC) + pidlSrc->mkid.cb +
|
||
|
// we need two terminators, one for pidlSrc and one for the wrap
|
||
|
// the one for pidlSrc is necessary for the ILClone to work
|
||
|
// because it gets confused with the nSrcID that follows the pidl
|
||
|
CB_IDLIST_TERMINATOR +
|
||
|
CB_IDLIST_TERMINATOR ;
|
||
|
|
||
|
if( NULL == (pBuf = (LPBYTE)IEILCreate( cbAlloc )) )
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
// Initialize wrap header members
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pBuf ) ;
|
||
|
pWrap->cb = cbAlloc - CB_IDLIST_TERMINATOR ;
|
||
|
pWrap->tag = AUGM_WRAPTAG ;
|
||
|
pWrap->version = AUGM_WRAPCURRENTVERSION ;
|
||
|
|
||
|
if( pidlSrc )
|
||
|
{
|
||
|
PAUGM_IDSRC pSrc = (PAUGM_IDSRC)(pBuf + sizeof(AUGM_IDWRAP)) ;
|
||
|
pSrc->nID = nSrcID ;
|
||
|
memcpy( pSrc->pidl, pidlSrc, pidlSrc->mkid.cb ) ;
|
||
|
pWrap->cSrcs = 1 ;
|
||
|
}
|
||
|
|
||
|
*ppidlWrap = (LPITEMIDLIST)pWrap ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
BOOL WrappedPidlContainsSrcID(LPCITEMIDLIST pidlWrap, UINT uSrcID)
|
||
|
{
|
||
|
ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)));
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
|
||
|
|
||
|
if( pWrap->cSrcs > 0 )
|
||
|
{
|
||
|
LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
|
||
|
PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
|
||
|
// offset to next pidl header, needs terminator so that ILClone below can work
|
||
|
UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
|
||
|
|
||
|
if (pSrc->nID != uSrcID && pWrap->cSrcs > 1)
|
||
|
{
|
||
|
pSrc = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
|
||
|
}
|
||
|
|
||
|
if (pSrc->nID == uSrcID)
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT AugMergeISF_WrapRemovePidl(
|
||
|
IN LPITEMIDLIST pidlWrap,
|
||
|
IN UINT nSrcID,
|
||
|
OUT LPITEMIDLIST* ppidlRet )
|
||
|
{
|
||
|
ASSERT( IS_VALID_WRITE_PTR( ppidlRet, LPITEMIDLIST )) ;
|
||
|
|
||
|
*ppidlRet = NULL ;
|
||
|
|
||
|
HRESULT hr = AugMergeISF_IsWrap(pidlWrap);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
|
||
|
|
||
|
ASSERT(pWrap->cSrcs > 1);
|
||
|
|
||
|
LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
|
||
|
PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
|
||
|
// offset to next pidl header, needs terminator so that ILClone below can work
|
||
|
UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
|
||
|
|
||
|
// We want to look for the Other SrcID. So we loop while the source id we're removing is
|
||
|
// equal. When it's not equal, we've got the ID.
|
||
|
if (pSrc->nID == nSrcID)
|
||
|
{
|
||
|
pSrc = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
|
||
|
}
|
||
|
|
||
|
if (pSrc->nID != nSrcID)
|
||
|
{
|
||
|
hr = AugMergeISF_CreateWrap((LPITEMIDLIST)pSrc->pidl, pSrc->nID, ppidlRet);
|
||
|
ILFree(pidlWrap);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Adds a source pidl to the indicated pidl wrap.
|
||
|
HRESULT AugMergeISF_WrapAddPidl(
|
||
|
IN LPCITEMIDLIST pidlSrc,
|
||
|
IN UINT nSrcID,
|
||
|
IN OUT LPITEMIDLIST* ppidlWrap )
|
||
|
{
|
||
|
ASSERT (ppidlWrap && IS_VALID_PIDL( *ppidlWrap ));
|
||
|
ASSERT (IS_VALID_PIDL( pidlSrc ));
|
||
|
ASSERT (INVALID_NAMESPACE_INDEX != nSrcID );
|
||
|
|
||
|
HRESULT hr ;
|
||
|
if (FAILED((hr = AugMergeISF_IsWrap(*ppidlWrap))))
|
||
|
return hr ;
|
||
|
|
||
|
// AHHHHHHHHHHH Rewrite this.
|
||
|
if (WrappedPidlContainsSrcID(*ppidlWrap, nSrcID))
|
||
|
{
|
||
|
if (AugMergeISF_GetSourceCount(*ppidlWrap) > 1)
|
||
|
{
|
||
|
hr = AugMergeISF_WrapRemovePidl((LPITEMIDLIST)*ppidlWrap, nSrcID, ppidlWrap);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ILFree(*ppidlWrap);
|
||
|
return AugMergeISF_CreateWrap(pidlSrc, nSrcID, ppidlWrap);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Retrieve wrap header
|
||
|
PAUGM_IDWRAP pWrap = (PAUGM_IDWRAP)*ppidlWrap ;
|
||
|
|
||
|
// Reallocate a block large enough to contain our new record.
|
||
|
WORD offTerm0 = pWrap->cb, // offset to end of existing wrap
|
||
|
offTerm1 = offTerm0 + sizeof(AUGM_IDSRC) + pidlSrc->mkid.cb, // offset to end of next record
|
||
|
cbRealloc= offTerm1 + 2*CB_IDLIST_TERMINATOR ; // total bytes to reallocate
|
||
|
|
||
|
LPBYTE pRealloc ;
|
||
|
if( NULL == (pRealloc = (LPBYTE)SHRealloc( pWrap, cbRealloc )) )
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
// Adjust our pointers if memory moved
|
||
|
pWrap = (PAUGM_IDWRAP)pRealloc ;
|
||
|
|
||
|
// Initialize new record in the wrap
|
||
|
UNALIGNED AUGM_IDSRC* pSrc = (PAUGM_IDSRC)(pRealloc + offTerm0 ) ;
|
||
|
pSrc->nID = nSrcID ;
|
||
|
memcpy( pSrc->pidl, pidlSrc, pidlSrc->mkid.cb ) ;
|
||
|
|
||
|
// Terminate new record
|
||
|
ZeroMemory( pRealloc + offTerm1, 2*CB_IDLIST_TERMINATOR ) ;
|
||
|
|
||
|
// Update our header
|
||
|
pWrap->cb = cbRealloc - CB_IDLIST_TERMINATOR ;
|
||
|
pWrap->cSrcs++ ;
|
||
|
|
||
|
*ppidlWrap = (LPITEMIDLIST)pWrap ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Private pidl enumeration block (GetFirst/GetNext)
|
||
|
typedef struct tagAUGM_IDWRAP_ENUM
|
||
|
{
|
||
|
ULONG cbStruct ; // structure size
|
||
|
PAUGM_IDWRAP pWrap ; // wrap header.
|
||
|
PAUGM_IDSRC pSrcNext ; // pointer to next src header
|
||
|
} AUGM_IDWRAP_ENUM, *PAUGM_IDWRAP_ENUM ;
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Begins enumeration of source pidls in the indicated pidl wrap.
|
||
|
HANDLE AugMergeISF_EnumFirstSrcPidl(
|
||
|
IN LPCITEMIDLIST pidlWrap,
|
||
|
OUT UINT* pnSrcID,
|
||
|
OUT LPITEMIDLIST* ppidlRet )
|
||
|
{
|
||
|
ASSERT( IS_VALID_WRITE_PTR( ppidlRet, LPITEMIDLIST ) && IS_VALID_WRITE_PTR( pnSrcID, UINT ) ) ;
|
||
|
|
||
|
PAUGM_IDWRAP_ENUM pEnum = NULL ;
|
||
|
*ppidlRet = NULL ;
|
||
|
*pnSrcID = (UINT)-1 ;
|
||
|
|
||
|
HRESULT hr = AugMergeISF_IsWrap(pidlWrap);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
|
||
|
|
||
|
if( pWrap->cSrcs > 0 )
|
||
|
{
|
||
|
LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
|
||
|
PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
|
||
|
// offset to next pidl header, needs terminator so that ILClone below can work
|
||
|
UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
|
||
|
|
||
|
if( NULL != (pEnum = new AUGM_IDWRAP_ENUM) )
|
||
|
{
|
||
|
pEnum->cbStruct = sizeof(*pEnum) ;
|
||
|
pEnum->pWrap = pWrap ;
|
||
|
pEnum->pSrcNext = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
|
||
|
*pnSrcID = pSrc->nID ;
|
||
|
*ppidlRet = ILClone( (LPITEMIDLIST)pSrc->pidl ) ;
|
||
|
if ( NULL == *ppidlRet )
|
||
|
{
|
||
|
delete pEnum;
|
||
|
pEnum = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return pEnum ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Continues source pidl enumeration
|
||
|
BOOL AugMergeISF_EnumNextSrcPidl(
|
||
|
IN HANDLE hEnum,
|
||
|
OUT UINT* pnSrcID,
|
||
|
OUT LPITEMIDLIST* ppidlRet )
|
||
|
{
|
||
|
PAUGM_IDWRAP_ENUM pEnum = (PAUGM_IDWRAP_ENUM)hEnum ;
|
||
|
HRESULT hr = E_UNEXPECTED ;
|
||
|
|
||
|
ASSERT( IS_VALID_WRITE_PTR( pEnum, AUGM_IDWRAP_ENUM ) ) ;
|
||
|
ASSERT( sizeof(*pEnum) == pEnum->cbStruct ) ;
|
||
|
ASSERT( sizeof(*pEnum) == pEnum->cbStruct );
|
||
|
|
||
|
*ppidlRet = NULL ;
|
||
|
*pnSrcID = (UINT)-1 ;
|
||
|
|
||
|
if (SUCCEEDED((hr = AugMergeISF_IsWrap((LPCITEMIDLIST)pEnum->pWrap))))
|
||
|
{
|
||
|
if ((LPBYTE)(pEnum->pWrap) + pEnum->pWrap->cb <= (LPBYTE)pEnum->pSrcNext)
|
||
|
hr = S_FALSE ;
|
||
|
else
|
||
|
{
|
||
|
UNALIGNED AUGM_IDSRC* pualSrcNext = pEnum->pSrcNext;
|
||
|
|
||
|
*pnSrcID = pualSrcNext->nID;
|
||
|
*ppidlRet = ILClone((LPITEMIDLIST)pualSrcNext->pidl);
|
||
|
|
||
|
pEnum->pSrcNext = (PAUGM_IDSRC)(
|
||
|
((LPBYTE)pualSrcNext) +
|
||
|
sizeof(AUGM_IDSRC) +
|
||
|
((LPITEMIDLIST)pualSrcNext->pidl)->mkid.cb +
|
||
|
CB_IDLIST_TERMINATOR);
|
||
|
|
||
|
hr = S_OK ;
|
||
|
return TRUE ;
|
||
|
}
|
||
|
}
|
||
|
return FALSE ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Terminates source pidl enumeration
|
||
|
void AugMergeISF_EndEnumSrcPidls(
|
||
|
IN OUT HANDLE& hEnum )
|
||
|
{
|
||
|
PAUGM_IDWRAP_ENUM pEnum = (PAUGM_IDWRAP_ENUM)hEnum ;
|
||
|
|
||
|
ASSERT( IS_VALID_WRITE_PTR( pEnum, AUGM_IDWRAP_ENUM ) &&
|
||
|
sizeof(*pEnum) == pEnum->cbStruct );
|
||
|
delete pEnum ;
|
||
|
hEnum = NULL ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Allocates and returns a copy of the specified source pidl
|
||
|
// from the wrapped pidl.
|
||
|
HRESULT AugMergeISF_GetSrcPidl(
|
||
|
IN LPCITEMIDLIST pidlWrap,
|
||
|
IN UINT nSrcID,
|
||
|
OUT LPITEMIDLIST* ppidlRet )
|
||
|
{
|
||
|
ASSERT( ppidlRet ) ;
|
||
|
*ppidlRet = NULL ;
|
||
|
|
||
|
HANDLE hEnum ;
|
||
|
BOOL bEnum ;
|
||
|
UINT nSrcIDEnum ;
|
||
|
LPITEMIDLIST pidlEnum ;
|
||
|
|
||
|
for( hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcIDEnum, &pidlEnum ), bEnum = TRUE ;
|
||
|
hEnum && bEnum ;
|
||
|
bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcIDEnum, &pidlEnum ) )
|
||
|
{
|
||
|
if( nSrcIDEnum == nSrcID )
|
||
|
{
|
||
|
*ppidlRet = pidlEnum ;
|
||
|
AugMergeISF_EndEnumSrcPidls(hEnum);
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
ILFree( pidlEnum ) ;
|
||
|
}
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum ) ;
|
||
|
|
||
|
return E_FAIL ;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
BOOL IsValidWrappedPidl(LPCITEMIDLIST pidlWrap)
|
||
|
{
|
||
|
BOOL fValid = FALSE;
|
||
|
|
||
|
if (pidlWrap == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FAILED(AugMergeISF_IsWrap(pidlWrap)))
|
||
|
return FALSE;
|
||
|
|
||
|
|
||
|
HANDLE hEnum ;
|
||
|
UINT nSrcIDEnum ;
|
||
|
LPITEMIDLIST pidlEnum ;
|
||
|
|
||
|
hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcIDEnum, &pidlEnum );
|
||
|
do
|
||
|
{
|
||
|
fValid = IS_VALID_PIDL(pidlEnum);
|
||
|
ILFree(pidlEnum);
|
||
|
}
|
||
|
while( fValid && AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcIDEnum, &pidlEnum ));
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum ) ;
|
||
|
|
||
|
return fValid;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
int AugmEnumCompare(void *pv1, void *pv2, LPARAM lParam)
|
||
|
{
|
||
|
CAugISFEnumItem* paugmEnum1 = (CAugISFEnumItem*)pv1;
|
||
|
CAugISFEnumItem* paugmEnum2 = (CAugISFEnumItem*)pv2;
|
||
|
int iRet = -1;
|
||
|
|
||
|
if (paugmEnum1 && paugmEnum2)
|
||
|
{
|
||
|
// Are these two items of different types?
|
||
|
if (BOOLIFY(paugmEnum1->_rgfAttrib & SFGAO_FOLDER) ^ BOOLIFY(paugmEnum2->_rgfAttrib & SFGAO_FOLDER))
|
||
|
{
|
||
|
// Yes. Then Folders sort before items.
|
||
|
iRet = BOOLIFY(paugmEnum1->_rgfAttrib & SFGAO_FOLDER) ? 1 : -1;
|
||
|
}
|
||
|
else // They are of the same type. Then compare by name
|
||
|
{
|
||
|
iRet = lstrcmpi(paugmEnum1->_pszDisplayName, paugmEnum2->_pszDisplayName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return iRet;
|
||
|
}
|
||
|
|
||
|
LPVOID AugmEnumMerge(UINT uMsg, void * pv1, void * pv2, LPARAM lParam)
|
||
|
{
|
||
|
void * pvRet = pv1;
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case DPAMM_MERGE:
|
||
|
{
|
||
|
HANDLE hEnum;
|
||
|
UINT nSrcID;
|
||
|
LPITEMIDLIST pidl;
|
||
|
CAugISFEnumItem* paugmeDest = (CAugISFEnumItem*)pv1;
|
||
|
CAugISFEnumItem* paugmeSrc = (CAugISFEnumItem*)pv2;
|
||
|
|
||
|
ASSERT(paugmeDest && paugmeSrc);
|
||
|
|
||
|
hEnum = AugMergeISF_EnumFirstSrcPidl(paugmeSrc->_pidlWrap, &nSrcID, &pidl);
|
||
|
if (hEnum)
|
||
|
{
|
||
|
// add pidl from src to dest
|
||
|
AugMergeISF_WrapAddPidl(pidl, nSrcID, &paugmeDest->_pidlWrap);
|
||
|
// no longer need hEnum
|
||
|
AugMergeISF_EndEnumSrcPidls(hEnum);
|
||
|
// this was copied to paugmeDest->_pidlWrap
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case DPAMM_INSERT:
|
||
|
{
|
||
|
CAugISFEnumItem* paugmNew = new CAugISFEnumItem;
|
||
|
CAugISFEnumItem* paugmSrc = (CAugISFEnumItem*)pv1;
|
||
|
|
||
|
if (paugmNew)
|
||
|
{
|
||
|
paugmNew->_pidlWrap = ILClone(paugmSrc->_pidlWrap);
|
||
|
if (paugmNew->_pidlWrap)
|
||
|
{
|
||
|
paugmNew->SetDisplayName(paugmSrc->_pszDisplayName);
|
||
|
paugmNew->_rgfAttrib = paugmSrc->_rgfAttrib;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete paugmNew;
|
||
|
paugmNew = NULL;
|
||
|
}
|
||
|
}
|
||
|
pvRet = paugmNew;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
return pvRet;
|
||
|
}
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
LPTSTR pszDisplayName;
|
||
|
BOOL fFolder;
|
||
|
} AUGMISFSEARCHFORPIDL;
|
||
|
|
||
|
int CALLBACK AugMISFSearchForOnePidlByDisplayName(LPVOID p1, LPVOID p2, LPARAM lParam)
|
||
|
{
|
||
|
AUGMISFSEARCHFORPIDL* pSearchFor = (AUGMISFSEARCHFORPIDL*)p1;
|
||
|
CAugISFEnumItem* paugmEnum = (CAugISFEnumItem*)p2;
|
||
|
|
||
|
// Are they of different types?
|
||
|
if (BOOLIFY(paugmEnum->_rgfAttrib & SFGAO_FOLDER) ^ pSearchFor->fFolder)
|
||
|
{
|
||
|
// Yes.
|
||
|
return pSearchFor->fFolder ? 1 : -1;
|
||
|
}
|
||
|
else // They are of the same type. Then compare by name
|
||
|
{
|
||
|
return StrCmpI(pSearchFor->pszDisplayName, paugmEnum->_pszDisplayName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// DPA utilities
|
||
|
#define DPA_GETPTRCOUNT( hdpa ) ((NULL != (hdpa)) ? DPA_GetPtrCount((hdpa)) : 0)
|
||
|
#define DPA_GETPTR( hdpa, i, type ) ((NULL != (hdpa)) ? (type*)DPA_GetPtr((hdpa), i) : (type*)NULL)
|
||
|
#define DPA_DESTROY( hdpa, pfn ) { if( NULL != hdpa ) \
|
||
|
{ DPA_DestroyCallback( hdpa, pfn, NULL ) ; \
|
||
|
hdpa = NULL ; }}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Forwards...
|
||
|
class CEnum ;
|
||
|
class CChildObject ;
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Augmented Merge Shell Folder source namespace descriptor.
|
||
|
//
|
||
|
// Objects of class CNamespace are created by CAugmentedMergeISF in
|
||
|
// the AddNameSpace() method impl, and are maintained in the collection
|
||
|
// CAugmentedMergeISF::_hdpaNamespaces.
|
||
|
//
|
||
|
class CNamespace
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
{
|
||
|
public:
|
||
|
CNamespace( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib ) ;
|
||
|
~CNamespace() ;
|
||
|
|
||
|
IShellFolder* ShellFolder() { return _psf ; }
|
||
|
REFGUID Guid() { return _guid ; }
|
||
|
ULONG Attrib() const { return _dwAttrib ; }
|
||
|
LPITEMIDLIST GetPidl() const { return _pidl; }
|
||
|
|
||
|
void Assign( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib ) ;
|
||
|
void Unassign() ;
|
||
|
|
||
|
HRESULT RegisterNotify( HWND, UINT, ULONG ) ;
|
||
|
HRESULT UnregisterNotify() ;
|
||
|
|
||
|
BOOL SetOwner( IUnknown *punk ) ;
|
||
|
|
||
|
protected:
|
||
|
IShellFolder* _psf ; // IShellFolder interface pointer
|
||
|
GUID _guid ; // optional GUID for specialized UI handling
|
||
|
LPITEMIDLIST _pidl ; // optional pidl
|
||
|
ULONG _dwAttrib ; // optional flags
|
||
|
UINT _uChangeReg ; // Shell change notify registration ID.
|
||
|
} ;
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
inline CNamespace::CNamespace( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib )
|
||
|
: _psf(NULL),
|
||
|
_pidl(NULL),
|
||
|
_guid(GUID_NULL),
|
||
|
_dwAttrib(0),
|
||
|
_uChangeReg(0)
|
||
|
{
|
||
|
Assign( pguidUIObject, psf, pidl, dwAttrib ) ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
inline CNamespace::~CNamespace() {
|
||
|
UnregisterNotify() ;
|
||
|
Unassign() ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Assigns data members.
|
||
|
void CNamespace::Assign( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib )
|
||
|
{
|
||
|
Unassign() ;
|
||
|
if( NULL != (_psf = psf) )
|
||
|
_psf->AddRef() ;
|
||
|
|
||
|
_pidl = ILClone( pidl ) ;
|
||
|
_guid = pguidUIObject ? *pguidUIObject : GUID_NULL ;
|
||
|
_dwAttrib = dwAttrib ;
|
||
|
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Unassigns data members.
|
||
|
void CNamespace::Unassign()
|
||
|
{
|
||
|
ATOMICRELEASE( _psf ) ;
|
||
|
ILFree( _pidl ) ;
|
||
|
_pidl = NULL ;
|
||
|
_guid = GUID_NULL ;
|
||
|
_dwAttrib = 0L ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Register change notification for the namespace
|
||
|
HRESULT CNamespace::RegisterNotify( HWND hwnd, UINT uMsg, ULONG lEvents )
|
||
|
{
|
||
|
if( 0 == _uChangeReg )
|
||
|
_uChangeReg = ::RegisterNotify(hwnd,
|
||
|
uMsg,
|
||
|
_pidl,
|
||
|
lEvents,
|
||
|
SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt,
|
||
|
TRUE);
|
||
|
|
||
|
return 0 != _uChangeReg ? S_OK : E_FAIL ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
// Unregister change notification for the namespace
|
||
|
HRESULT CNamespace::UnregisterNotify()
|
||
|
{
|
||
|
if( 0 != _uChangeReg )
|
||
|
{
|
||
|
UINT uID = _uChangeReg;
|
||
|
|
||
|
_uChangeReg = 0;
|
||
|
::SHChangeNotifyDeregister(uID);
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
inline BOOL CNamespace::SetOwner(IUnknown *punkOwner)
|
||
|
{
|
||
|
if (_psf)
|
||
|
{
|
||
|
IUnknown_SetOwner(_psf, punkOwner);
|
||
|
return TRUE ;
|
||
|
}
|
||
|
|
||
|
return FALSE ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
CAugmentedMergeISF::CAugmentedMergeISF() : _cRef(1)
|
||
|
{
|
||
|
ASSERT(_hdpaNamespaces == NULL);
|
||
|
ASSERT(_punkOwner == NULL);
|
||
|
ASSERT(_pdt == NULL);
|
||
|
DllAddRef() ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
CAugmentedMergeISF::~CAugmentedMergeISF()
|
||
|
{
|
||
|
SetOwner(NULL);
|
||
|
FreeNamespaces();
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// CAugmentedMergeISF global CreateInstance method for da class factory
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDAPI CAugmentedISF2_CreateInstance( IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi )
|
||
|
{
|
||
|
// aggregation checking is handled in class factory
|
||
|
CAugmentedMergeISF* pObj;
|
||
|
|
||
|
if( NULL == (pObj = new CAugmentedMergeISF) )
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
*ppunk = SAFECAST( pObj, IAugmentedShellFolder2 * ) ;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// CAugmentedMergeISF - IUnknown methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::QueryInterface(REFIID riid, void **ppvObj)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENTMULTI( CAugmentedMergeISF, IShellFolder, IAugmentedShellFolder ),
|
||
|
QITABENT( CAugmentedMergeISF, IAugmentedShellFolder ),
|
||
|
QITABENT( CAugmentedMergeISF, IAugmentedShellFolder2 ),
|
||
|
QITABENT( CAugmentedMergeISF, IShellFolder2 ),
|
||
|
QITABENT( CAugmentedMergeISF, IShellService ),
|
||
|
QITABENT( CAugmentedMergeISF, ITranslateShellChangeNotify ),
|
||
|
QITABENT( CAugmentedMergeISF, IDropTarget ),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch( this, qit, riid, ppvObj ) ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP_(ULONG) CAugmentedMergeISF::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP_(ULONG) CAugmentedMergeISF::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// CAugmentedMergeISF - IShellFolder methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
if (_hdpaNamespaces)
|
||
|
{
|
||
|
// BUGBUG (lamadio): This does not work if you have 2 enumerators. But,
|
||
|
// when asking for a new enumerator, we should flush the cache.
|
||
|
FreeObjects();
|
||
|
|
||
|
*ppenumIDList = new CEnum(this, grfFlags);
|
||
|
|
||
|
if (NULL == *ppenumIDList)
|
||
|
return E_OUTOFMEMORY ;
|
||
|
hr = S_OK ;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::BindToObject( LPCITEMIDLIST pidlWrap, LPBC pbc, REFIID riid, LPVOID *ppvOut )
|
||
|
{
|
||
|
ASSERT(IS_VALID_PIDL( pidlWrap ) && NULL != ppvOut);
|
||
|
|
||
|
*ppvOut = NULL ;
|
||
|
|
||
|
if (SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)))
|
||
|
{
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
|
||
|
ASSERT(IsValidWrappedPidl(pidlWrap));
|
||
|
ASSERT( pWrap ) ;
|
||
|
ASSERT( pWrap->cSrcs > 0 ) ; // should never, never happen
|
||
|
|
||
|
HANDLE hEnum ;
|
||
|
BOOL bEnum ;
|
||
|
UINT nIDSrc = -1 ;
|
||
|
DEBUG_CODE(int iNumBound = 0);
|
||
|
LPITEMIDLIST pidlSrc ;
|
||
|
HRESULT hr = E_UNEXPECTED ;
|
||
|
CNamespace* pSrc = NULL ;
|
||
|
|
||
|
CAugmentedMergeISF* pISF ;
|
||
|
if (NULL == (pISF = new CAugmentedMergeISF))
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
for (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nIDSrc, &pidlSrc ), bEnum = TRUE ;
|
||
|
hEnum && bEnum ;
|
||
|
bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nIDSrc, &pidlSrc))
|
||
|
{
|
||
|
if (SUCCEEDED((hr = QueryNameSpace(nIDSrc, (PVOID*)&pSrc))) && pSrc)
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
|
||
|
hr = S_FALSE;
|
||
|
if (SUCCEEDED(pSrc->ShellFolder()->BindToObject(pidlSrc, NULL, IID_IShellFolder, (void **)&psf)))
|
||
|
{
|
||
|
LPCITEMIDLIST pidlParent = pSrc->GetPidl();
|
||
|
LPITEMIDLIST pidlFull = ILCombine(pidlParent, pidlSrc);
|
||
|
|
||
|
hr = pISF->AddNameSpace(NULL, psf, pidlFull, pSrc->Attrib());
|
||
|
#ifdef DEBUG
|
||
|
if (SUCCEEDED(hr))
|
||
|
iNumBound++;
|
||
|
#endif
|
||
|
ILFree(pidlFull);
|
||
|
psf->Release();
|
||
|
}
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
}
|
||
|
ILFree(pidlSrc);
|
||
|
}
|
||
|
|
||
|
// If this hits, then something is terribly wrong. Either we were unable to bind to the
|
||
|
// ShellFolders, or the add failed. This could be caused by a bad wrapped pidl.
|
||
|
ASSERT(iNumBound > 0);
|
||
|
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum ) ;
|
||
|
hr = pISF->QueryInterface(riid, ppvOut);
|
||
|
pISF->Release();
|
||
|
return hr ;
|
||
|
}
|
||
|
return E_UNEXPECTED ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::BindToStorage( LPCITEMIDLIST, LPBC, REFIID, void ** )
|
||
|
{
|
||
|
return E_NOTIMPL ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::CompareIDs(
|
||
|
LPARAM lParam,
|
||
|
LPCITEMIDLIST pidl1,
|
||
|
LPCITEMIDLIST pidl2)
|
||
|
{
|
||
|
IShellFolder *psf1 = NULL, *psf2 = NULL;
|
||
|
LPITEMIDLIST pidlItem1 = NULL, pidlItem2 = NULL;
|
||
|
int iRet = 0 ;
|
||
|
HRESULT hr1, hr2, hr ;
|
||
|
|
||
|
hr1 = GetDefNamespace( pidl1, ASFF_DEFNAMESPACE_DISPLAYNAME, &psf1, &pidlItem1 ) ;
|
||
|
hr2 = GetDefNamespace( pidl2, ASFF_DEFNAMESPACE_DISPLAYNAME, &psf2, &pidlItem2 ) ;
|
||
|
|
||
|
if( SUCCEEDED( hr1 ) && SUCCEEDED( hr2 ) )
|
||
|
{
|
||
|
ULONG dwAttrib1 = SFGAO_FOLDER, dwAttrib2 = SFGAO_FOLDER;
|
||
|
// Same namespace? Just forward the request.
|
||
|
if( psf1 == psf2 )
|
||
|
{
|
||
|
hr = psf1->CompareIDs( lParam, pidlItem1, pidlItem2 ) ;
|
||
|
ILFree( pidlItem1 ) ;
|
||
|
ILFree( pidlItem2 ) ;
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
hr1 = psf1->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem1, &dwAttrib1 ) ;
|
||
|
hr2 = psf2->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem2, &dwAttrib2 ) ;
|
||
|
|
||
|
if( SUCCEEDED( hr1 ) && SUCCEEDED( hr2 ) )
|
||
|
{
|
||
|
// Comparison heuristics:
|
||
|
// (1) folders take precedence over nonfolders, (2) alphanum comparison
|
||
|
if( 0 != (dwAttrib1 & SFGAO_FOLDER) &&
|
||
|
0 == (dwAttrib2 & SFGAO_FOLDER) )
|
||
|
iRet = -1 ;
|
||
|
else if( 0 == (dwAttrib1 & SFGAO_FOLDER) &&
|
||
|
0 != (dwAttrib2 & SFGAO_FOLDER) )
|
||
|
iRet = 1 ;
|
||
|
else
|
||
|
{
|
||
|
STRRET strName1, strName2;
|
||
|
HRESULT hres1 = E_FAIL;
|
||
|
HRESULT hres2 = E_FAIL;
|
||
|
TCHAR szName1[MAX_PATH], szName2[MAX_PATH];
|
||
|
hr1 = psf1->GetDisplayNameOf(pidlItem1, SHGDN_FORPARSING | SHGDN_INFOLDER, &strName1);
|
||
|
hr2 = psf2->GetDisplayNameOf(pidlItem2, SHGDN_FORPARSING | SHGDN_INFOLDER, &strName2);
|
||
|
|
||
|
if (SUCCEEDED(hr1) && SUCCEEDED(hr2))
|
||
|
{
|
||
|
// must call StrRetToBuf because it frees StrRet strings if allocated
|
||
|
hres1 = StrRetToBuf(&strName1, pidlItem1, szName1, ARRAYSIZE(szName1));
|
||
|
hres2 = StrRetToBuf(&strName2, pidlItem2, szName2, ARRAYSIZE(szName2));
|
||
|
}
|
||
|
// if the names match we return -1 because they are different pidls with
|
||
|
// the same name
|
||
|
|
||
|
if (SUCCEEDED(hr1) && SUCCEEDED(hr2) && SUCCEEDED(hres1) && SUCCEEDED(hres2))
|
||
|
{
|
||
|
iRet = lstrcmp(szName1, szName2); // Comparisons are by name with items of the same type.
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hr = FAILED( hr1 ) ? hr1 :
|
||
|
FAILED( hr2 ) ? hr2 :
|
||
|
S_OK ;
|
||
|
|
||
|
if( pidlItem1 )
|
||
|
ILFree( pidlItem1 ) ;
|
||
|
if( pidlItem2 )
|
||
|
ILFree( pidlItem2 ) ;
|
||
|
|
||
|
return MAKE_HRESULT( HRESULT_SEVERITY( hr ), HRESULT_FACILITY( hr ), iRet ) ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::CreateViewObject(
|
||
|
HWND hwndOwner,
|
||
|
REFIID riid,
|
||
|
LPVOID * ppvOut )
|
||
|
{
|
||
|
HRESULT hr ;
|
||
|
CNamespace *pSrc, *pSrc0 ;
|
||
|
|
||
|
pSrc = pSrc0 = NULL ;
|
||
|
|
||
|
// TODO: Handle IDropTarget here, delegate for all others.
|
||
|
if (IsEqualIID(riid, IID_IDropTarget))
|
||
|
{
|
||
|
hr = QueryInterface(riid, ppvOut);
|
||
|
if (SUCCEEDED(hr))
|
||
|
_hwnd = hwndOwner;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// Search for default namespace for CreateViewObj()
|
||
|
if( FAILED( (hr = GetDefNamespace( ASFF_DEFNAMESPACE_VIEWOBJ, (PVOID*)&pSrc, NULL, (PVOID*)&pSrc0 )) ) )
|
||
|
return hr ;
|
||
|
|
||
|
if( NULL == pSrc )
|
||
|
pSrc = pSrc0 ;
|
||
|
|
||
|
if( NULL != pSrc )
|
||
|
{
|
||
|
ASSERT( pSrc->ShellFolder() ) ;
|
||
|
hr = pSrc->ShellFolder()->CreateViewObject( hwndOwner, riid, ppvOut ) ;
|
||
|
}
|
||
|
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetAttributesOf(
|
||
|
UINT cidl,
|
||
|
LPCITEMIDLIST * apidl,
|
||
|
ULONG * rgfInOut )
|
||
|
{
|
||
|
IShellFolder* pISF ;
|
||
|
LPITEMIDLIST pidlItem ;
|
||
|
HRESULT hr ;
|
||
|
|
||
|
if( cidl > 1 ) // support 1 only.
|
||
|
return E_NOTIMPL ;
|
||
|
|
||
|
if( !apidl )
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
// Forward to default namespace for item attributes
|
||
|
if( FAILED( (hr = GetDefNamespace(
|
||
|
apidl[0], ASFF_DEFNAMESPACE_ATTRIB, &pISF, &pidlItem )) ) )
|
||
|
return hr ;
|
||
|
|
||
|
hr = pISF->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem, rgfInOut ) ;
|
||
|
|
||
|
ILFree( pidlItem ) ;
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetUIObjectOf(
|
||
|
HWND hwndOwner,
|
||
|
UINT cidl,
|
||
|
LPCITEMIDLIST * apidl,
|
||
|
REFIID riid,
|
||
|
UINT * prgfInOut,
|
||
|
LPVOID * ppvOut )
|
||
|
{
|
||
|
IShellFolder* pISF ;
|
||
|
LPITEMIDLIST pidlItem ;
|
||
|
HRESULT hr ;
|
||
|
|
||
|
if (cidl > 1) // support 1 only.
|
||
|
return E_NOTIMPL ;
|
||
|
|
||
|
if (!apidl)
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
if (IsEqualGUID(riid, IID_IContextMenu))
|
||
|
{
|
||
|
hr = _GetContextMenu(hwndOwner, cidl, apidl, prgfInOut, ppvOut);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Forward to default namespace for UI object
|
||
|
if (FAILED((hr = GetDefNamespace(apidl[0], ASFF_DEFNAMESPACE_UIOBJ, &pISF, &pidlItem))))
|
||
|
return hr ;
|
||
|
|
||
|
hr = pISF->GetUIObjectOf(hwndOwner, 1, (LPCITEMIDLIST*)&pidlItem, riid, prgfInOut, ppvOut);
|
||
|
ILFree(pidlItem);
|
||
|
}
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetDisplayNameOf(
|
||
|
LPCITEMIDLIST pidl,
|
||
|
DWORD grfFlags,
|
||
|
LPSTRRET pstrName )
|
||
|
{
|
||
|
IShellFolder* pISF ;
|
||
|
LPITEMIDLIST pidlItem ;
|
||
|
HRESULT hr ;
|
||
|
|
||
|
// Forward to default namespace for display name
|
||
|
if (FAILED((hr = GetDefNamespace(
|
||
|
pidl, ASFF_DEFNAMESPACE_DISPLAYNAME, &pISF, &pidlItem))))
|
||
|
return hr ;
|
||
|
|
||
|
if (SUCCEEDED((hr = pISF->GetDisplayNameOf(pidlItem, grfFlags, pstrName))))
|
||
|
{
|
||
|
// STRRET_OFFSET has no meaning in context of the pidl wrapper.
|
||
|
// We can either calculate the offset into the wrapper, or allocate
|
||
|
// a wide char for the name. For expedience, we'll allocate the name.
|
||
|
|
||
|
if (pstrName->uType == STRRET_OFFSET)
|
||
|
{
|
||
|
UINT cch = lstrlenA( STRRET_OFFPTR( pidlItem, pstrName ) ) ;
|
||
|
LPWSTR pwszName = (LPWSTR)SHAlloc( (cch + 1) * sizeof(WCHAR));
|
||
|
|
||
|
if (NULL != pwszName)
|
||
|
{
|
||
|
SHAnsiToUnicode( STRRET_OFFPTR( pidlItem, pstrName ), pwszName, cch+1 );
|
||
|
pwszName[cch] = (WCHAR)0 ;
|
||
|
}
|
||
|
pstrName->pOleStr = pwszName ;
|
||
|
pstrName->uType = STRRET_WSTR ;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
// If the trace flags are set, and this is not comming from an internal query,
|
||
|
// Then append the location where this name came from
|
||
|
if (g_qwTraceFlags & TF_AUGM && _fInternalGDNO == FALSE)
|
||
|
{
|
||
|
if (pstrName->uType == STRRET_WSTR)
|
||
|
{
|
||
|
LPWSTR wszOldName = pstrName->pOleStr;
|
||
|
UINT cch = lstrlenW(wszOldName);
|
||
|
|
||
|
pstrName->pOleStr = (LPWSTR)SHAlloc( (cch + 50) * sizeof(WCHAR));
|
||
|
|
||
|
if (pstrName->pOleStr)
|
||
|
{
|
||
|
StrCpyW(pstrName->pOleStr, wszOldName);
|
||
|
|
||
|
if (AugMergeISF_GetSourceCount(pidl) > 1)
|
||
|
StrCatW(pstrName->pOleStr, L" (Merged)");
|
||
|
else if (WrappedPidlContainsSrcID(pidl, 0))
|
||
|
StrCatW(pstrName->pOleStr, L" (1)");
|
||
|
else
|
||
|
StrCatW(pstrName->pOleStr, L" (2)");
|
||
|
|
||
|
SHFree(wszOldName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pstrName->pOleStr = wszOldName;
|
||
|
}
|
||
|
}
|
||
|
else if (pstrName->uType == STRRET_CSTR)
|
||
|
{
|
||
|
if (AugMergeISF_GetSourceCount(pidl) > 1)
|
||
|
StrCatA(pstrName->cStr, " (Merged)");
|
||
|
else if (WrappedPidlContainsSrcID(pidl, 0))
|
||
|
StrCatA(pstrName->cStr, " (1)");
|
||
|
else
|
||
|
StrCatA(pstrName->cStr, " (2)");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
ILFree( pidlItem ) ;
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::ParseDisplayName(
|
||
|
HWND hwndOwner,
|
||
|
LPBC pbcReserved,
|
||
|
LPOLESTR pwszName,
|
||
|
ULONG * pchEaten,
|
||
|
LPITEMIDLIST * ppidl,
|
||
|
ULONG * pdwAttrib )
|
||
|
{
|
||
|
int iIndex;
|
||
|
LPITEMIDLIST pidl;
|
||
|
|
||
|
*ppidl = NULL;
|
||
|
// This ParseDisplayName should iterate through all our delegates until one works.
|
||
|
for (iIndex = NamespaceCount() - 1; iIndex >=0 ; iIndex--)
|
||
|
{
|
||
|
CNamespace* pSrc = Namespace(iIndex) ;
|
||
|
if (pSrc)
|
||
|
{
|
||
|
if (SUCCEEDED(pSrc->ShellFolder()->ParseDisplayName(hwndOwner, pbcReserved, pwszName, pchEaten,
|
||
|
&pidl, pdwAttrib)))
|
||
|
{
|
||
|
ASSERT(pidl); // Make sure a valid pidl comes out.
|
||
|
if (*ppidl == NULL)
|
||
|
AugMergeISF_CreateWrap(pidl, iIndex, ppidl);
|
||
|
else
|
||
|
AugMergeISF_WrapAddPidl(pidl, iIndex, ppidl);
|
||
|
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return *ppidl? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::SetNameOf(
|
||
|
HWND hwndOwner,
|
||
|
LPCITEMIDLIST pidl,
|
||
|
LPCOLESTR pwszName,
|
||
|
DWORD uFlags,
|
||
|
LPITEMIDLIST *ppidlOut )
|
||
|
{
|
||
|
CNamespace* pnsCommon;
|
||
|
CNamespace* pnsUser;
|
||
|
LPITEMIDLIST pidlItem;
|
||
|
HRESULT hres;
|
||
|
UINT uiUser;
|
||
|
UINT uiCommon;
|
||
|
|
||
|
hres = _GetNamespaces(pidl, &pnsCommon, &uiCommon, &pnsUser, &uiUser, &pidlItem, NULL);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
LPITEMIDLIST pidlNew = NULL;
|
||
|
UINT uiNamespace = INVALID_NAMESPACE_INDEX;
|
||
|
|
||
|
if (pnsUser)
|
||
|
{
|
||
|
hres = pnsUser->ShellFolder()->SetNameOf(hwndOwner, pidlItem, pwszName, uFlags, &pidlNew);
|
||
|
uiNamespace = uiUser;
|
||
|
}
|
||
|
else if (pnsCommon)
|
||
|
{
|
||
|
hres = E_FAIL;
|
||
|
|
||
|
if (AffectAllUsers(hwndOwner))
|
||
|
{
|
||
|
hres = pnsCommon->ShellFolder()->SetNameOf(hwndOwner, pidlItem, pwszName, uFlags, &pidlNew);
|
||
|
uiNamespace = uiCommon;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ppidlOut)
|
||
|
{
|
||
|
*ppidlOut = NULL;
|
||
|
// wrap the pidl
|
||
|
if (SUCCEEDED(hres) && pidlNew)
|
||
|
AugMergeISF_CreateWrap(pidlNew, uiNamespace, ppidlOut);
|
||
|
}
|
||
|
|
||
|
ILFree(pidlNew);
|
||
|
ILFree(pidlItem);
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// IAugmentedShellFolder methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Adds a source namespace to the Augmented Merge shell folder object.
|
||
|
STDMETHODIMP CAugmentedMergeISF::AddNameSpace(
|
||
|
const GUID * pguidObject,
|
||
|
IShellFolder * psf,
|
||
|
LPCITEMIDLIST pidl,
|
||
|
DWORD dwFlags )
|
||
|
{
|
||
|
ASSERT (IS_VALID_CODE_PTR(psf, IShellFolder*));
|
||
|
ASSERT (IS_VALID_PIDL(pidl));
|
||
|
|
||
|
// Check for duplicate via full display name
|
||
|
|
||
|
for( int i=0, max = NamespaceCount() ; i < max; i++ )
|
||
|
{
|
||
|
CNamespace* pSrc = Namespace( i ) ;
|
||
|
if (pSrc)
|
||
|
{
|
||
|
if (ILIsEqual(pSrc->GetPidl(), pidl))
|
||
|
{
|
||
|
// Found! Reassign attributes
|
||
|
pSrc->Assign( pguidObject, psf, pidl, dwFlags ) ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// No match; safe to append it to collection, creating DPA if necessary.
|
||
|
if( NULL == _hdpaNamespaces &&
|
||
|
NULL == (_hdpaNamespaces= DPA_Create( 2 )) )
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
CNamespace *pSrc = new CNamespace( pguidObject, psf, pidl, dwFlags );
|
||
|
if( NULL == pSrc )
|
||
|
return E_OUTOFMEMORY ;
|
||
|
|
||
|
return DPA_AppendPtr( _hdpaNamespaces, pSrc ) >= 0 ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Retrieves the primary namespace iid for the wrapped pidl.
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetNameSpaceID(
|
||
|
LPCITEMIDLIST pidl,
|
||
|
GUID * pguidOut )
|
||
|
{
|
||
|
HRESULT hr ;
|
||
|
if (FAILED((hr = AugMergeISF_IsWrap( pidl ))))
|
||
|
return hr ;
|
||
|
|
||
|
// BUGBUG: need to enumerate wrapped source pidls
|
||
|
return E_NOTIMPL ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Retrieves a pointer to a source namespace descriptor associated with
|
||
|
// the specified lookup index.
|
||
|
STDMETHODIMP CAugmentedMergeISF::QueryNameSpace( ULONG nID, PVOID* ppSrc )
|
||
|
{
|
||
|
if (!ppSrc)
|
||
|
return E_INVALIDARG;
|
||
|
*ppSrc = NULL;
|
||
|
|
||
|
LONG cSrcs;
|
||
|
|
||
|
if ((cSrcs = NamespaceCount()) <=0)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if(nID >= (ULONG)cSrcs)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (NULL == (*ppSrc = Namespace(nID)))
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Retrieves data for the namespace identified by dwID.
|
||
|
STDMETHODIMP CAugmentedMergeISF::QueryNameSpace(
|
||
|
ULONG nID,
|
||
|
GUID * pguidOut,
|
||
|
IShellFolder ** ppsf )
|
||
|
{
|
||
|
CNamespace* pSrc = NULL ;
|
||
|
HRESULT hr = QueryNameSpace( nID, (PVOID*)&pSrc ) ;
|
||
|
|
||
|
if( pguidOut )
|
||
|
*pguidOut = NULL != pSrc ? pSrc->Guid() : GUID_NULL ;
|
||
|
|
||
|
if( ppsf )
|
||
|
{
|
||
|
if( (*ppsf = (NULL != pSrc) ? pSrc->ShellFolder() : NULL) != NULL )
|
||
|
(*ppsf)->AddRef() ;
|
||
|
}
|
||
|
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::EnumNameSpace(
|
||
|
DWORD uNameSpace,
|
||
|
DWORD * pdwID )
|
||
|
{
|
||
|
return E_NOTIMPL ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// IAugmentedShellFolder2 methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//GetNameSpaceCount and GetIDListWrapCount are not used anywhere
|
||
|
#if 0
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetNameSpaceCount( OUT LONG* pcNamespaces )
|
||
|
{
|
||
|
if( !pcNamespaces )
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
*pcNamespaces = (LONG)NamespaceCount() ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetIDListWrapCount(
|
||
|
LPCITEMIDLIST pidlWrap,
|
||
|
OUT LONG * pcPidls)
|
||
|
{
|
||
|
if( NULL == pidlWrap || NULL == pcPidls )
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
*pcPidls = 0 ;
|
||
|
|
||
|
HRESULT hr ;
|
||
|
if (SUCCEEDED((hr = AugMergeISF_IsWrap(pidlWrap))))
|
||
|
{
|
||
|
PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap(pidlWrap);
|
||
|
*pcPidls = pWrap->cSrcs;
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
#endif // #if 0
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::UnWrapIDList(
|
||
|
LPCITEMIDLIST pidlWrap,
|
||
|
LONG cPidls,
|
||
|
IShellFolder** apsf,
|
||
|
LPITEMIDLIST* apidlFolder,
|
||
|
LPITEMIDLIST* apidlItems,
|
||
|
LONG* pcFetched )
|
||
|
{
|
||
|
HRESULT hr ;
|
||
|
HANDLE hEnum ;
|
||
|
BOOL bEnum = TRUE ;
|
||
|
UINT nSrcID ;
|
||
|
LPITEMIDLIST pidlItem ;
|
||
|
LONG cFetched = 0;
|
||
|
|
||
|
if (NULL == pidlWrap || cPidls <= 0)
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
if (FAILED((hr = AugMergeISF_IsWrap(pidlWrap))))
|
||
|
return hr ;
|
||
|
|
||
|
// Enumerate pidls in wrap
|
||
|
for (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcID, &pidlItem);
|
||
|
cFetched < cPidls && hEnum && bEnum ;
|
||
|
bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcID, &pidlItem))
|
||
|
{
|
||
|
// Retrieve namespace data
|
||
|
CNamespace* pSrc ;
|
||
|
if (SUCCEEDED((hr = QueryNameSpace(nSrcID, (PVOID*)&pSrc))))
|
||
|
{
|
||
|
if (apsf)
|
||
|
{
|
||
|
apsf[cFetched] = pSrc->ShellFolder() ;
|
||
|
if (apsf[cFetched])
|
||
|
apsf[cFetched]->AddRef();
|
||
|
}
|
||
|
if (apidlFolder)
|
||
|
apidlFolder[cFetched] = ILClone(pSrc->GetPidl());
|
||
|
if (apidlItems)
|
||
|
{
|
||
|
apidlItems[cFetched] = pidlItem;
|
||
|
pidlItem = NULL; // paranoia -- just making sure we, somehow, don't free this guy at the end of the for loop
|
||
|
}
|
||
|
cFetched++ ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ILFree( pidlItem ) ;
|
||
|
}
|
||
|
}
|
||
|
ILFree(pidlItem); // AugMergeISF_EnumNextSrcPidl is called (if there are 2 wrapped pidls and we ask for only one)
|
||
|
// right before we exit the for loop so we have to free pidl if allocated.
|
||
|
if (hEnum)
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum );
|
||
|
|
||
|
if( pcFetched )
|
||
|
*pcFetched = cFetched ;
|
||
|
|
||
|
return cFetched == cPidls ? S_OK : S_FALSE ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::SetOwner( IUnknown* punkOwner )
|
||
|
{
|
||
|
HRESULT hr = S_OK ;
|
||
|
|
||
|
int cSrcs = NamespaceCount() ;
|
||
|
|
||
|
if( cSrcs > 0 )
|
||
|
DPA_EnumCallback( _hdpaNamespaces, SetOwnerProc, NULL ) ;
|
||
|
|
||
|
ATOMICRELEASE( _punkOwner ) ;
|
||
|
|
||
|
if( punkOwner )
|
||
|
{
|
||
|
hr = punkOwner->QueryInterface(IID_IUnknown, (LPVOID *)&_punkOwner ) ;
|
||
|
|
||
|
if( cSrcs )
|
||
|
DPA_EnumCallback( _hdpaNamespaces, SetOwnerProc, (void *)_punkOwner);
|
||
|
}
|
||
|
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
int CAugmentedMergeISF::SetOwnerProc( LPVOID pv, LPVOID pvParam )
|
||
|
{
|
||
|
CNamespace* pSrc = (CNamespace*) pv ;
|
||
|
ASSERT( pSrc ) ;
|
||
|
|
||
|
return pSrc->SetOwner( (IUnknown*)pvParam ) ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// ITranslateShellChangeNotify methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
LPITEMIDLIST ILCombineBase(LPCITEMIDLIST pidlContainingBase, LPCITEMIDLIST pidlRel)
|
||
|
{
|
||
|
// This routine differs from ILCombine in that it takes the First pidl's base, and
|
||
|
// cats on the last id of the second pidl. We need this so Wrapped pidls
|
||
|
// end up with the same base, and we get a valid full pidl.
|
||
|
LPITEMIDLIST pidlRet = NULL;
|
||
|
LPITEMIDLIST pidlBase = ILClone(pidlContainingBase);
|
||
|
if (pidlBase)
|
||
|
{
|
||
|
ILRemoveLastID(pidlBase);
|
||
|
|
||
|
pidlRet = ILCombine(pidlBase, pidlRel);
|
||
|
|
||
|
ILFree(pidlBase);
|
||
|
}
|
||
|
|
||
|
return pidlRet;
|
||
|
}
|
||
|
|
||
|
BOOL IsFolderEvent(LONG lEvent)
|
||
|
{
|
||
|
return lEvent == SHCNE_MKDIR || lEvent == SHCNE_RMDIR || lEvent == SHCNE_RENAMEFOLDER;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void CAugmentedMergeISF::DumpObjects()
|
||
|
{
|
||
|
if (g_dwDumpFlags & TF_AUGM)
|
||
|
{
|
||
|
ASSERT(_hdpaObjects);
|
||
|
int iObjectCount = DPA_GetPtrCount(_hdpaObjects);
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::DumpObjects: Number of items: %d", iObjectCount);
|
||
|
|
||
|
CNamespace* pns = (CNamespace *)DPA_FastGetPtr(_hdpaNamespaces, 0);
|
||
|
if (pns)
|
||
|
DebugDumpPidl(TF_AUGM, TEXT("CAugMISF::DumpObjects Namespace 1"), pns->GetPidl());
|
||
|
|
||
|
pns = (CNamespace *)DPA_FastGetPtr(_hdpaNamespaces, 1);
|
||
|
if (pns)
|
||
|
DebugDumpPidl(TF_AUGM, TEXT("CAugMISF::DumpObjects Namespace 2"), pns->GetPidl());
|
||
|
|
||
|
for (int i = 0; i < iObjectCount; i++)
|
||
|
{
|
||
|
CAugISFEnumItem* pEnumItem = (CAugISFEnumItem*)DPA_FastGetPtr(_hdpaObjects, i);
|
||
|
TraceMsg(TF_ALWAYS, "CAugMISF::DumpObjects: %s, Folder: %s Merged: %s",
|
||
|
pEnumItem->_pszDisplayName,
|
||
|
BOOLIFY(pEnumItem->_rgfAttrib & SFGAO_FOLDER) ? TEXT("Yes") : TEXT("No"),
|
||
|
(AugMergeISF_GetSourceCount(pEnumItem->_pidlWrap) > 1)? TEXT("Yes") : TEXT("No"));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
BOOL GetRealPidlFromSimple(LPCITEMIDLIST pidlSimple, LPITEMIDLIST* ppidlReal)
|
||
|
{
|
||
|
// Similar to SHGetRealIDL in Function, but SHGetRealIDL does SHGDN_FORPARSING | INFOLDER.
|
||
|
// I need the parsing name. I can't rev SHGetRealIDL very easily, so here's this one!
|
||
|
TCHAR szFullName[MAX_PATH];
|
||
|
if (SUCCEEDED(SHGetNameAndFlags(pidlSimple, SHGDN_FORPARSING, szFullName, SIZECHARS(szFullName), NULL)))
|
||
|
{
|
||
|
*ppidlReal = ILCreateFromPath(szFullName);
|
||
|
}
|
||
|
|
||
|
if (*ppidlReal == NULL) // Unable to create? Then use the simple pidl. This is because it does not exist any more
|
||
|
{ // For say, a Delete Notify
|
||
|
*ppidlReal = ILClone(pidlSimple);
|
||
|
}
|
||
|
|
||
|
return *ppidlReal != NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::TranslateIDs(
|
||
|
LONG *plEvent,
|
||
|
LPCITEMIDLIST pidl1,
|
||
|
LPCITEMIDLIST pidl2,
|
||
|
LPITEMIDLIST * ppidlOut1,
|
||
|
LPITEMIDLIST * ppidlOut2,
|
||
|
LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
|
||
|
LPITEMIDLIST *ppidlOut2Event2)
|
||
|
{
|
||
|
HRESULT hres = E_FAIL;
|
||
|
|
||
|
switch (*plEvent)
|
||
|
{
|
||
|
case SHCNE_EXTENDED_EVENT:
|
||
|
case SHCNE_ASSOCCHANGED:
|
||
|
case SHCNE_UPDATEIMAGE:
|
||
|
return S_OK;
|
||
|
|
||
|
case SHCNE_UPDATEDIR:
|
||
|
FreeObjects();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
ASSERT(ppidlOut1);
|
||
|
ASSERT(ppidlOut2);
|
||
|
LONG lEvent = *plEvent;
|
||
|
|
||
|
*plEvent2 = (LONG)-1;
|
||
|
*ppidlOut1Event2 = NULL;
|
||
|
*ppidlOut2Event2 = NULL;
|
||
|
|
||
|
|
||
|
*ppidlOut1 = (LPITEMIDLIST)pidl1;
|
||
|
*ppidlOut2 = (LPITEMIDLIST)pidl2;
|
||
|
|
||
|
if (!plEvent)
|
||
|
return E_FAIL;
|
||
|
|
||
|
// If they are already wrapped, don't wrap twice.
|
||
|
if ((pidl1 && SUCCEEDED(AugMergeISF_IsWrap(ILFindLastID(pidl1)))) ||
|
||
|
(pidl2 && SUCCEEDED(AugMergeISF_IsWrap(ILFindLastID(pidl2)))))
|
||
|
{
|
||
|
// We don't want to wrap twice.
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (!_hdpaNamespaces)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if (!_hdpaObjects)
|
||
|
return E_FAIL;
|
||
|
|
||
|
CAugISFEnumItem* pEnumItem;
|
||
|
|
||
|
int iIndex;
|
||
|
int iShellFolder1 = -1;
|
||
|
int iShellFolder2 = -1;
|
||
|
IShellFolder* psf1 = NULL;
|
||
|
IShellFolder* psf2 = NULL;
|
||
|
LPITEMIDLIST pidlReal1 = NULL;
|
||
|
LPITEMIDLIST pidlReal2 = NULL;
|
||
|
LPITEMIDLIST pidlRealRel1 = NULL;
|
||
|
LPITEMIDLIST pidlRealRel2 = NULL;
|
||
|
BOOL fFolder = IsFolderEvent(*plEvent);
|
||
|
|
||
|
// Get the information about these Simple pidls: Are they our Children? If so, what namespace?
|
||
|
BOOL fChild1 = IsChildIDInternal(pidl1, TRUE, &iShellFolder1);
|
||
|
BOOL fChild2 = IsChildIDInternal(pidl2, TRUE, &iShellFolder2);
|
||
|
|
||
|
// Is either a child?
|
||
|
if (!(fChild1 || fChild2))
|
||
|
return hres;
|
||
|
|
||
|
// Ok, pidl1 is a child, can we get the Real pidl from the simple one?
|
||
|
if (pidl1 && !GetRealPidlFromSimple(pidl1, &pidlReal1))
|
||
|
goto Cleanup;
|
||
|
|
||
|
// Ok, pidl2 is a child, can we get the Real pidl from the simple one?
|
||
|
if (pidl2 && !GetRealPidlFromSimple(pidl2, &pidlReal2))
|
||
|
goto Cleanup;
|
||
|
|
||
|
// These are for code clarity later on. We deal with Relative pidls from here until the very end,
|
||
|
// when we combine the base of the in pidls with the outgoing wrapped pidls.
|
||
|
if (pidlReal1)
|
||
|
pidlRealRel1 = ILFindLastID(pidlReal1);
|
||
|
|
||
|
if (pidlReal2)
|
||
|
pidlRealRel2 = ILFindLastID(pidlReal2);
|
||
|
|
||
|
// Is Pidl1 in our namespaces?
|
||
|
if (iShellFolder1 != -1)
|
||
|
{
|
||
|
// Yes, lets get the non-refcounted shell folder that know's about this pidl.
|
||
|
CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, iShellFolder1);
|
||
|
psf1 = pns->ShellFolder(); // Non ref counted.
|
||
|
}
|
||
|
|
||
|
// Is Pidl2 in our namespaces?
|
||
|
if (iShellFolder2 != -1)
|
||
|
{
|
||
|
// Yes, lets get the non-refcounted shell folder that know's about this pidl.
|
||
|
CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, iShellFolder2);
|
||
|
psf2 = pns->ShellFolder(); // Non ref counted.
|
||
|
}
|
||
|
|
||
|
hres = S_OK;
|
||
|
|
||
|
DEBUG_CODE(_fInternalGDNO = TRUE);
|
||
|
|
||
|
switch(*plEvent)
|
||
|
{
|
||
|
case 0: // Just look up the pidls and return.
|
||
|
{
|
||
|
DWORD rgfAttrib = SFGAO_FOLDER;
|
||
|
if (iShellFolder1 != -1)
|
||
|
{
|
||
|
psf1->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlRealRel1, &rgfAttrib);
|
||
|
if (S_OK == _SearchForPidl(psf1, pidlRealRel1, BOOLIFY(rgfAttrib & SFGAO_FOLDER), &iIndex, &pEnumItem))
|
||
|
{
|
||
|
*ppidlOut1 = ILCombineBase(pidlReal1, pEnumItem->_pidlWrap);
|
||
|
if (!*ppidlOut1)
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rgfAttrib = SFGAO_FOLDER;
|
||
|
if (iShellFolder2 != -1 && SUCCEEDED(hres))
|
||
|
{
|
||
|
psf2->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlRealRel2, &rgfAttrib);
|
||
|
if (S_OK == _SearchForPidl(psf2, pidlRealRel2, BOOLIFY(rgfAttrib & SFGAO_FOLDER), &iIndex, &pEnumItem))
|
||
|
{
|
||
|
*ppidlOut2 = ILCombineBase(pidlReal2, pEnumItem->_pidlWrap);
|
||
|
if (!*ppidlOut2)
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case SHCNE_CREATE:
|
||
|
case SHCNE_MKDIR:
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
|
||
|
TEXT("SHCNE_MKDIR") : TEXT("SHCNE_CREATE"));
|
||
|
// Is there a thing of this name already?
|
||
|
if (S_OK == _SearchForPidl(psf1, pidlRealRel1, fFolder, &iIndex, &pEnumItem))
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s needs to be merged. Converting to Rename", pEnumItem->_pszDisplayName);
|
||
|
// Yes; Then we need to merge this new pidl into the wrapped pidl, and change this
|
||
|
// to a rename, passing the Old wrapped pidl as the first arg, and the new wrapped pidl
|
||
|
// as the second arg. I have to be careful about the freeing:
|
||
|
// Free *ppidlOut1
|
||
|
// Clone pEnumItem->_pidlWrap -> *ppidlOut1.
|
||
|
// Add pidl1 to pEnumItem->_pidlWrap.
|
||
|
// Clone new pEnumItem->_pidlWrap -> *ppidlOut2. ASSERT(*ppidlOut2 == NULL)
|
||
|
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
if (*ppidlOut1)
|
||
|
{
|
||
|
AugMergeISF_WrapAddPidl(pidlRealRel1, iShellFolder1, &pEnumItem->_pidlWrap);
|
||
|
*ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
|
||
|
if (!*ppidlOut2)
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
|
||
|
|
||
|
*plEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidlWrap;
|
||
|
CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
|
||
|
if (paugmEnum)
|
||
|
{
|
||
|
if (SUCCEEDED(AugMergeISF_CreateWrap(pidlRealRel1, (UINT)iShellFolder1, &pidlWrap)) &&
|
||
|
paugmEnum->InitWithWrappedToOwn(SAFECAST(this, IAugmentedShellFolder2*),
|
||
|
iShellFolder1, pidlWrap))
|
||
|
{
|
||
|
AUGMISFSEARCHFORPIDL AugMSearch;
|
||
|
AugMSearch.pszDisplayName = paugmEnum->_pszDisplayName;
|
||
|
AugMSearch.fFolder = fFolder;
|
||
|
|
||
|
int iInsertIndex = DPA_Search(_hdpaObjects, (LPVOID)&AugMSearch, 0,
|
||
|
AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED | DPAS_INSERTAFTER);
|
||
|
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Creating new unmerged %s at %d",
|
||
|
paugmEnum->_pszDisplayName, iInsertIndex);
|
||
|
|
||
|
if (iInsertIndex < 0)
|
||
|
iInsertIndex = DA_LAST;
|
||
|
|
||
|
if (DPA_InsertPtr(_hdpaObjects, iInsertIndex, paugmEnum) == -1)
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Was unable to add %s for some reason. Bailing",
|
||
|
paugmEnum->_pszDisplayName);
|
||
|
DestroyObjectsProc(paugmEnum, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, paugmEnum->_pidlWrap);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
DestroyObjectsProc(paugmEnum, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHCNE_DELETE:
|
||
|
case SHCNE_RMDIR:
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
|
||
|
TEXT("SHCNE_RMDIR") : TEXT("SHCNE_DELETE"));
|
||
|
int iDeleteIndex;
|
||
|
// Is there a folder of this name already?
|
||
|
if (S_OK == _SearchForPidl(psf1, pidlRealRel1,
|
||
|
fFolder, &iDeleteIndex, &pEnumItem))
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Found %s checking merge state.", pEnumItem->_pszDisplayName);
|
||
|
// Yes; Then we need to unmerge this pidl from the wrapped pidl, and change this
|
||
|
// to a rename, passing the Old wrapped pidl as the first arg, and the new wrapped pidl
|
||
|
// as the second arg. I have to be careful about the freeing:
|
||
|
// Free *ppidlOut1
|
||
|
// Clone pEnumItem->_pidlWrap -> *ppidlOut1.
|
||
|
// Remove pidl1 from pEnumItem->_pidlWrap
|
||
|
// Convert to rename, pass new wrapped as second arg.
|
||
|
|
||
|
if (AugMergeISF_GetSourceCount( pEnumItem->_pidlWrap ) > 1 )
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is Merged. Removing pidl, convert to rename", pEnumItem->_pszDisplayName);
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
if (*ppidlOut1)
|
||
|
{
|
||
|
EVAL(SUCCEEDED(AugMergeISF_WrapRemovePidl(pEnumItem->_pidlWrap,
|
||
|
iShellFolder1, &pEnumItem->_pidlWrap)));
|
||
|
|
||
|
*ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
|
||
|
if (!*ppidlOut2)
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
|
||
|
|
||
|
*plEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is not Merged. deleteing", pEnumItem->_pszDisplayName);
|
||
|
pEnumItem = (CAugISFEnumItem*)DPA_DeletePtr(_hdpaObjects, iDeleteIndex);
|
||
|
|
||
|
if (EVAL(pEnumItem))
|
||
|
{
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
DestroyObjectsProc(pEnumItem, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to get %d from DPA", iDeleteIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SHCNE_RENAMEITEM:
|
||
|
case SHCNE_RENAMEFOLDER:
|
||
|
{
|
||
|
// BUGBUG (lamadio): When renaming an item in the menu, this code will split it into
|
||
|
// a Delete and a Create. We need to detect this situation and convert it to 1 rename. This
|
||
|
// will solve the problem of the lost order during a rename....
|
||
|
BOOL fEvent1Set = FALSE;
|
||
|
BOOL fFirstPidlInNamespace = FALSE;
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
|
||
|
TEXT("SHCNE_RENAMEFOLDER") : TEXT("SHCNE_RENAMEITEM"));
|
||
|
|
||
|
// Is this item being renamed FROM the Folder?
|
||
|
if (iShellFolder1 != -1 && // Is this pidl a child of the Folder?
|
||
|
S_OK == _SearchForPidl(psf1, pidlRealRel1,
|
||
|
fFolder, &iIndex, &pEnumItem)) // Is it found?
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Old pidl %s is in the Folder", pEnumItem->_pszDisplayName);
|
||
|
// Yes.
|
||
|
// Then we need to see if the item that it's being renamed from was Merged
|
||
|
|
||
|
// Need this for reentrancy
|
||
|
if (WrappedPidlContainsSrcID(pEnumItem->_pidlWrap, iShellFolder1))
|
||
|
{
|
||
|
// Was it merged?
|
||
|
if (AugMergeISF_GetSourceCount(pEnumItem->_pidlWrap) > 1) // Case 3)
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is Merged. Removing pidl. Convert to rename for event 1",
|
||
|
pEnumItem->_pszDisplayName);
|
||
|
// Yes;
|
||
|
// Then we need to unmerge that item.
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
if (*ppidlOut1)
|
||
|
{
|
||
|
// UnWrap
|
||
|
AugMergeISF_WrapRemovePidl(pEnumItem->_pidlWrap, iShellFolder1, &pEnumItem->_pidlWrap);
|
||
|
|
||
|
*ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
|
||
|
if (!*ppidlOut2)
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
|
||
|
|
||
|
// This We need to "Rename" the old wrapped pidl, to this new one
|
||
|
// that does not contain the old item.
|
||
|
fEvent1Set = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is not merged. Nuking item Convert to Delete for event 1.",
|
||
|
pEnumItem->_pszDisplayName);
|
||
|
// No, This was not a wrapped pidl. Then, convert to a delete:
|
||
|
pEnumItem = (CAugISFEnumItem*)DPA_DeletePtr(_hdpaObjects, iIndex);
|
||
|
|
||
|
if (EVAL(pEnumItem))
|
||
|
{
|
||
|
// If we're renaming from this folder, into this folder, Then the first event stays a rename.
|
||
|
if (iShellFolder2 == -1)
|
||
|
{
|
||
|
fEvent1Set = TRUE;
|
||
|
*plEvent = fFolder? SHCNE_RMDIR : SHCNE_DELETE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fFirstPidlInNamespace = TRUE;
|
||
|
}
|
||
|
*ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
|
||
|
DestroyObjectsProc(pEnumItem, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to find Item at %d", iIndex);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Skipping this because we already processed it."
|
||
|
"Dragging To Desktop?");
|
||
|
hres = E_FAIL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Is this item is being rename INTO the Start Menu?
|
||
|
if (iShellFolder2 != -1)
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: New pidl is in the Folder");
|
||
|
LPITEMIDLIST* ppidlNewWrapped1 = ppidlOut1;
|
||
|
LPITEMIDLIST* ppidlNewWrapped2 = ppidlOut2;
|
||
|
LONG* plNewEvent = plEvent;
|
||
|
|
||
|
if (fEvent1Set)
|
||
|
{
|
||
|
plNewEvent = plEvent2;
|
||
|
ppidlNewWrapped1 = ppidlOut1Event2;
|
||
|
ppidlNewWrapped2 = ppidlOut2Event2;
|
||
|
}
|
||
|
|
||
|
if (S_OK == _SearchForPidl(psf2, pidlRealRel2,
|
||
|
fFolder, &iIndex, &pEnumItem))
|
||
|
{
|
||
|
|
||
|
// If we're renaming from this folder, into this folder, Check to see if the destination has a
|
||
|
// conflict. If there is a confict (This case), then convert first event to a remove,
|
||
|
// and the second event to the rename.
|
||
|
if (fFirstPidlInNamespace)
|
||
|
{
|
||
|
fEvent1Set = TRUE;
|
||
|
*plEvent = fFolder? SHCNE_RMDIR : SHCNE_DELETE;
|
||
|
plNewEvent = plEvent2;
|
||
|
ppidlNewWrapped1 = ppidlOut1Event2;
|
||
|
ppidlNewWrapped2 = ppidlOut2Event2;
|
||
|
}
|
||
|
|
||
|
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is in Folder", pEnumItem->_pszDisplayName);
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Adding pidl to %s. Convert to Rename for event %s",
|
||
|
pEnumItem->_pszDisplayName, fEvent1Set? TEXT("2") : TEXT("1"));
|
||
|
|
||
|
// Then the destination needs to be merged.
|
||
|
*ppidlNewWrapped1 = ILCombineBase(pidl2, pEnumItem->_pidlWrap);
|
||
|
if (*ppidlNewWrapped1)
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Successfully created out pidl1");
|
||
|
AugMergeISF_WrapAddPidl(pidlRealRel2, iShellFolder2, &pEnumItem->_pidlWrap);
|
||
|
|
||
|
*ppidlNewWrapped2 = ILCombineBase(pidl2, pEnumItem->_pidlWrap);
|
||
|
|
||
|
*plNewEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidlWrap;
|
||
|
CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
|
||
|
|
||
|
if (paugmEnum)
|
||
|
{
|
||
|
if (SUCCEEDED(AugMergeISF_CreateWrap(pidlRealRel2, (UINT)iShellFolder2, &pidlWrap)) &&
|
||
|
paugmEnum->InitWithWrappedToOwn(SAFECAST(this, IAugmentedShellFolder2*),
|
||
|
iShellFolder2, pidlWrap))
|
||
|
{
|
||
|
AUGMISFSEARCHFORPIDL AugMSearch;
|
||
|
AugMSearch.pszDisplayName = paugmEnum->_pszDisplayName;
|
||
|
AugMSearch.fFolder = BOOLIFY(paugmEnum->_rgfAttrib & SFGAO_FOLDER);
|
||
|
|
||
|
int iInsertIndex = DPA_Search(_hdpaObjects, &AugMSearch, 0,
|
||
|
AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED | DPAS_INSERTAFTER);
|
||
|
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is a new item. Converting to Create",
|
||
|
paugmEnum->_pszDisplayName);
|
||
|
|
||
|
if (iInsertIndex < 0)
|
||
|
iInsertIndex = DA_LAST;
|
||
|
|
||
|
if (DPA_InsertPtr(_hdpaObjects, iInsertIndex, paugmEnum) == -1)
|
||
|
{
|
||
|
TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Was unable to add %s for some reason. Bailing",
|
||
|
paugmEnum->_pszDisplayName);
|
||
|
DestroyObjectsProc(paugmEnum, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Creating new item %s at %d for event %s",
|
||
|
paugmEnum->_pszDisplayName, iInsertIndex, fEvent1Set? TEXT("2") : TEXT("1"));
|
||
|
|
||
|
// If we're renaming from this folder, into this folder, Then the first event stays
|
||
|
// a rename.
|
||
|
if (!fFirstPidlInNamespace)
|
||
|
{
|
||
|
*plNewEvent = fFolder ? SHCNE_MKDIR : SHCNE_CREATE;
|
||
|
*ppidlNewWrapped1 = ILCombineBase(pidl2, pidlWrap);
|
||
|
*ppidlNewWrapped2 = NULL;
|
||
|
}
|
||
|
else
|
||
|
*ppidlOut2 = ILCombineBase(pidl2, pidlWrap);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
DestroyObjectsProc(paugmEnum, NULL);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
ILFree(pidlReal1);
|
||
|
ILFree(pidlReal2);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
DumpObjects();
|
||
|
_fInternalGDNO = FALSE;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
BOOL CAugmentedMergeISF::IsChildIDInternal(LPCITEMIDLIST pidlKid, BOOL fImmediate, int* piShellFolder)
|
||
|
{
|
||
|
// This is basically the same Method as the interface method, but returns the shell folder
|
||
|
// that it came from.
|
||
|
BOOL fChild = FALSE;
|
||
|
|
||
|
//At this point we should have a translated pidl
|
||
|
if (pidlKid)
|
||
|
{
|
||
|
if (SUCCEEDED(AugMergeISF_IsWrap(pidlKid)))
|
||
|
{
|
||
|
LPCITEMIDLIST pidlRelKid = ILFindLastID(pidlKid);
|
||
|
if (pidlRelKid)
|
||
|
{
|
||
|
UINT uiId;
|
||
|
LPITEMIDLIST pidl;
|
||
|
HANDLE hEnum = AugMergeISF_EnumFirstSrcPidl(pidlRelKid, &uiId, &pidl);
|
||
|
|
||
|
if (hEnum)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
ILFree(pidl);
|
||
|
|
||
|
for (int i = 0; fChild == FALSE && i < DPA_GetPtrCount(_hdpaNamespaces); i++)
|
||
|
{
|
||
|
CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, i);
|
||
|
// reuse pidl
|
||
|
if (pns && (pidl = pns->GetPidl()) != NULL)
|
||
|
{
|
||
|
if (ILIsParent(pidl, pidlKid, fImmediate) &&
|
||
|
!ILIsEqual(pidl, pidlKid))
|
||
|
{
|
||
|
fChild = TRUE;
|
||
|
if (piShellFolder)
|
||
|
*piShellFolder = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (fChild == FALSE && AugMergeISF_EnumNextSrcPidl(hEnum, &uiId, &pidl));
|
||
|
|
||
|
AugMergeISF_EndEnumSrcPidls(hEnum);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int cSrcs = NamespaceCount();
|
||
|
|
||
|
for(int i = 0; fChild == FALSE && i < cSrcs ; i++)
|
||
|
{
|
||
|
CNamespace* pSrc = Namespace(i);
|
||
|
if (pSrc && ILIsParent(pSrc->GetPidl(), pidlKid, fImmediate) &&
|
||
|
!ILIsEqual(pSrc->GetPidl(), pidlKid))
|
||
|
{
|
||
|
fChild = TRUE;
|
||
|
if (piShellFolder)
|
||
|
*piShellFolder = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fChild;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::IsChildID( LPCITEMIDLIST pidlKid, BOOL fImmediate)
|
||
|
{
|
||
|
return IsChildIDInternal(pidlKid, fImmediate, NULL) ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::IsEqualID( LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2 )
|
||
|
{
|
||
|
// This used to return E_NOTIMPL. I'm kinda overloading the interface to mean:
|
||
|
// is this equal tp any of your namespaces.
|
||
|
HRESULT hres = S_FALSE;
|
||
|
int cSrcs = NamespaceCount();
|
||
|
|
||
|
for(int i = 0; hres == S_FALSE && i < cSrcs ; i++)
|
||
|
{
|
||
|
CNamespace* pSrc = Namespace(i);
|
||
|
if (pidl1)
|
||
|
{
|
||
|
if (pSrc && ILIsEqual(pSrc->GetPidl(), pidl1))
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
else if (pidl2) // If you pass a pidl2 it means: Is pidl2 a parent of one of my namespaces?
|
||
|
{
|
||
|
if (pSrc && ILIsParent(pidl2, pSrc->GetPidl(), FALSE))
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::Register(
|
||
|
HWND hwnd,
|
||
|
UINT uMsg,
|
||
|
long lEvents )
|
||
|
{
|
||
|
int i, cSrcs ;
|
||
|
|
||
|
if( 0 >= (cSrcs = NamespaceCount()) )
|
||
|
return E_FAIL ;
|
||
|
|
||
|
for( i = 0; i < cSrcs ; i++ )
|
||
|
{
|
||
|
CNamespace* pSrc ;
|
||
|
if( NULL != (pSrc = Namespace( i )) )
|
||
|
pSrc->RegisterNotify( hwnd, uMsg, lEvents ) ;
|
||
|
}
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::Unregister ()
|
||
|
{
|
||
|
int i, cSrcs = NamespaceCount() ;
|
||
|
|
||
|
if( cSrcs <= 0 )
|
||
|
return E_FAIL ;
|
||
|
|
||
|
for( i = 0; i < cSrcs ; i++ )
|
||
|
{
|
||
|
CNamespace* pSrc ;
|
||
|
if( NULL != (pSrc = Namespace( i )) )
|
||
|
pSrc->UnregisterNotify() ;
|
||
|
}
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
// *** IDropTarget methods ***
|
||
|
#define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
|
||
|
#define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||
|
{
|
||
|
ASSERT(!_fCommon);
|
||
|
ASSERT(_pdt == NULL);
|
||
|
if (pDataObj)
|
||
|
{
|
||
|
InitClipboardFormats();
|
||
|
|
||
|
FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
||
|
STGMEDIUM medium;
|
||
|
|
||
|
medium.pUnkForRelease = NULL;
|
||
|
medium.hGlobal = NULL;
|
||
|
|
||
|
if (SUCCEEDED(pDataObj->GetData(&fmte, &medium)))
|
||
|
{
|
||
|
LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
|
||
|
|
||
|
if (pida)
|
||
|
{
|
||
|
LPCITEMIDLIST pidlItem = HIDA_GetPIDLFolder(pida);
|
||
|
|
||
|
_fCommon = BOOLIFY(_IsCommonPidl(pidlItem));
|
||
|
GlobalUnlock(medium.hGlobal);
|
||
|
}
|
||
|
ReleaseStgMedium(&medium);
|
||
|
}
|
||
|
|
||
|
CNamespace *pSrc = NULL;
|
||
|
ULONG gdnsAttribs = 0;
|
||
|
|
||
|
if (!_fCommon)
|
||
|
gdnsAttribs = ASFF_DEFNAMESPACE_ALL;
|
||
|
|
||
|
if (SUCCEEDED(GetDefNamespace(gdnsAttribs, (PVOID*)&pSrc, NULL, NULL)))
|
||
|
{
|
||
|
if (SUCCEEDED(pSrc->ShellFolder()->CreateViewObject(_hwnd, IID_IDropTarget, (void **)&_pdt)))
|
||
|
{
|
||
|
_pdt->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_grfDragEnterKeyState = grfKeyState;
|
||
|
_dwDragEnterEffect = *pdwEffect;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||
|
{
|
||
|
HRESULT hres = S_OK;
|
||
|
|
||
|
if (_pdt)
|
||
|
hres = _pdt->DragOver(grfKeyState, pt, pdwEffect);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::DragLeave(void)
|
||
|
{
|
||
|
HRESULT hres = S_OK;
|
||
|
|
||
|
_fCommon = 0;
|
||
|
if (_pdt)
|
||
|
{
|
||
|
hres = _pdt->DragLeave();
|
||
|
ATOMICRELEASE(_pdt);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||
|
{
|
||
|
HRESULT hres = S_OK;
|
||
|
BOOL bNoUI = !_fCommon;
|
||
|
BOOL bConfirmed = !_fCommon;
|
||
|
|
||
|
if (!_pdt && pDataObj)
|
||
|
{
|
||
|
LPITEMIDLIST pidlParent = NULL,
|
||
|
pidlOther = NULL;
|
||
|
|
||
|
int csidl = _fCommon ? CSIDL_COMMON_STARTMENU : CSIDL_STARTMENU,
|
||
|
csidlOther = _fCommon ? CSIDL_STARTMENU : CSIDL_COMMON_STARTMENU;
|
||
|
|
||
|
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl, &pidlParent)) &&
|
||
|
SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidlOther, &pidlOther)))
|
||
|
{
|
||
|
FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
||
|
STGMEDIUM medium;
|
||
|
|
||
|
medium.pUnkForRelease = NULL;
|
||
|
medium.hGlobal = NULL;
|
||
|
|
||
|
if (SUCCEEDED(pDataObj->GetData(&fmte, &medium)))
|
||
|
{
|
||
|
LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
|
||
|
|
||
|
if (pida)
|
||
|
{
|
||
|
IShellFolder *psfParent = NULL,
|
||
|
*psfOther = NULL;
|
||
|
|
||
|
if (SUCCEEDED(IEBindToObject(pidlParent, &psfParent)) &&
|
||
|
SUCCEEDED(IEBindToObject(pidlOther, &psfOther)))
|
||
|
{
|
||
|
LPCITEMIDLIST pidlItem, pidl;
|
||
|
LPITEMIDLIST pidlRel;
|
||
|
|
||
|
pidlItem = HIDA_GetPIDLItem(pida, 0);
|
||
|
|
||
|
// we came here because we don't have pdt which means that
|
||
|
// there is only one folder in our namespace and that's not
|
||
|
// the one we have to drop IDataObj on.
|
||
|
|
||
|
CNamespace* pCNamespace = Namespace(0);
|
||
|
|
||
|
if (pCNamespace)
|
||
|
{
|
||
|
pidl = pCNamespace->GetPidl(); // don't need to free pidl.
|
||
|
|
||
|
if (pidl)
|
||
|
{
|
||
|
pidlRel = ILClone(ILFindChild(pidlOther, pidl));
|
||
|
|
||
|
if (pidlRel)
|
||
|
{
|
||
|
STRRET strret;
|
||
|
TCHAR szDir[MAX_PATH];
|
||
|
|
||
|
strret.uType = STRRET_CSTR;
|
||
|
if (SUCCEEDED(psfParent->GetDisplayNameOf(pidlRel, SHGDN_FORPARSING, &strret)) &&
|
||
|
SUCCEEDED(StrRetToBuf(&strret, pidlRel, szDir, ARRAYSIZE(szDir))))
|
||
|
{
|
||
|
if (_fCommon)
|
||
|
{
|
||
|
bConfirmed = AffectAllUsers(_hwnd);
|
||
|
bNoUI = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bConfirmed)
|
||
|
{
|
||
|
BOOL bCreated = FALSE;
|
||
|
|
||
|
switch (SHCreateDirectory(_hwnd, szDir))
|
||
|
{
|
||
|
case ERROR_FILENAME_EXCED_RANGE:
|
||
|
case ERROR_FILE_EXISTS:
|
||
|
case ERROR_ALREADY_EXISTS:
|
||
|
case 0: // It was created successfully.
|
||
|
bCreated = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bCreated)
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
|
||
|
if (SUCCEEDED(psfParent->BindToObject(pidlRel, NULL, IID_IShellFolder, (void **)&psf)))
|
||
|
{
|
||
|
psf->CreateViewObject(_hwnd, IID_IDropTarget, (void **)&_pdt);
|
||
|
// we're going to call drop on it, call dragenter first
|
||
|
if (_pdt)
|
||
|
_pdt->DragEnter(pDataObj, _grfDragEnterKeyState, pt, &_dwDragEnterEffect);
|
||
|
psf->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ILFree(pidlRel);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (psfParent)
|
||
|
psfParent->Release();
|
||
|
if (psfOther)
|
||
|
psfOther->Release();
|
||
|
|
||
|
GlobalUnlock(medium.hGlobal);
|
||
|
}
|
||
|
ReleaseStgMedium(&medium);
|
||
|
}
|
||
|
}
|
||
|
ILFree(pidlParent);
|
||
|
ILFree(pidlOther);
|
||
|
}
|
||
|
|
||
|
if (_pdt)
|
||
|
{
|
||
|
hres = E_FAIL;
|
||
|
|
||
|
if ((bNoUI || (bConfirmed = AffectAllUsers(_hwnd))) && bConfirmed)
|
||
|
hres = _pdt->Drop(pDataObj, grfKeyState, pt, pdwEffect);
|
||
|
else
|
||
|
hres = _pdt->DragLeave();
|
||
|
|
||
|
ATOMICRELEASE(_pdt);
|
||
|
}
|
||
|
_fCommon = 0;
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------------------//
|
||
|
LPITEMIDLIST CAugmentedMergeISF::GetNativePidl(LPCITEMIDLIST pidlWrap, LPARAM nSrcID /*int nID*/)
|
||
|
{
|
||
|
LPITEMIDLIST pidlRet = NULL;
|
||
|
|
||
|
if (SUCCEEDED(AugMergeISF_GetSrcPidl(pidlWrap, (UINT)nSrcID, &pidlRet)))
|
||
|
return pidlRet ;
|
||
|
|
||
|
// not wrapped by me.
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL AffectAllUsers(HWND hwnd)
|
||
|
{
|
||
|
TCHAR szMessage[255];
|
||
|
TCHAR szTitle[20];
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
if (MLLoadShellLangString(IDS_ALLUSER_WARNING, szMessage, ARRAYSIZE(szMessage)) > 0 &&
|
||
|
MLLoadShellLangString(IDS_ALLUSER_WARNING_TITLE, szTitle, ARRAYSIZE(szTitle)) > 0)
|
||
|
{
|
||
|
bRet = IDYES == MessageBox(hwnd, szMessage, szTitle, MB_YESNO | MB_ICONINFORMATION);
|
||
|
}
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL CAugmentedMergeISF::_IsCommonPidl(LPCITEMIDLIST pidlItem)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
LPITEMIDLIST pidlCommon;
|
||
|
|
||
|
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommon)))
|
||
|
{
|
||
|
bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
|
||
|
ILFree(pidlCommon);
|
||
|
}
|
||
|
if (!bRet &&
|
||
|
SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlCommon)))
|
||
|
{
|
||
|
bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
|
||
|
ILFree(pidlCommon);
|
||
|
}
|
||
|
if (!bRet &&
|
||
|
SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidlCommon)))
|
||
|
{
|
||
|
bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
|
||
|
ILFree(pidlCommon);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::_SearchForPidl(IShellFolder* psf, LPCITEMIDLIST pidl, BOOL fFolder, int* piIndex, CAugISFEnumItem** ppEnumItem)
|
||
|
{
|
||
|
STRRET str;
|
||
|
TCHAR szDisplayName[MAX_PATH];
|
||
|
int iIndex = -1;
|
||
|
|
||
|
*ppEnumItem = NULL;
|
||
|
|
||
|
if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str)) &&
|
||
|
SUCCEEDED(StrRetToBuf(&str, pidl, szDisplayName, ARRAYSIZE(szDisplayName))))
|
||
|
{
|
||
|
AUGMISFSEARCHFORPIDL SearchFor;
|
||
|
SearchFor.pszDisplayName = szDisplayName;
|
||
|
SearchFor.fFolder = fFolder;
|
||
|
|
||
|
iIndex = DPA_Search(_hdpaObjects, (LPVOID)&SearchFor, 0,
|
||
|
AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED);
|
||
|
|
||
|
if (iIndex >= 0)
|
||
|
{
|
||
|
*ppEnumItem = DPA_GETPTR( _hdpaObjects, iIndex, CAugISFEnumItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (piIndex)
|
||
|
*piIndex = iIndex;
|
||
|
|
||
|
if (*ppEnumItem)
|
||
|
return S_OK;
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// given a wrapped pidl
|
||
|
// f-n returns common and user namespaces (if they are in wrapped pidl) -- note that they are not addrefed
|
||
|
// unwrapped pidl, and if the unwrapped pidl is folder or not
|
||
|
HRESULT CAugmentedMergeISF::_GetNamespaces(LPCITEMIDLIST pidlWrap,
|
||
|
CNamespace** ppnsCommon,
|
||
|
UINT* pnCommonID,
|
||
|
CNamespace** ppnsUser,
|
||
|
UINT* pnUserID,
|
||
|
LPITEMIDLIST* ppidl,
|
||
|
BOOL *pbIsFolder)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
UINT nSrcID;
|
||
|
CNamespace * pns;
|
||
|
int cWrapped;
|
||
|
HANDLE hEnum;
|
||
|
|
||
|
ASSERT(ppnsCommon && ppnsUser && ppidl);
|
||
|
|
||
|
*ppnsCommon = NULL;
|
||
|
*ppnsUser = NULL;
|
||
|
*ppidl = NULL;
|
||
|
|
||
|
ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)));
|
||
|
|
||
|
cWrapped = AugMergeISF_GetSourceCount(pidlWrap);
|
||
|
|
||
|
if (NULL == _hdpaNamespaces || 0 >= cWrapped ||
|
||
|
NULL == (hEnum = AugMergeISF_EnumFirstSrcPidl(pidlWrap, &nSrcID, ppidl)))
|
||
|
return E_FAIL;
|
||
|
|
||
|
hres = QueryNameSpace(nSrcID, (void **)&pns);
|
||
|
if (EVAL(SUCCEEDED(hres)))
|
||
|
{
|
||
|
IShellFolder * psf;
|
||
|
ULONG rgf = SFGAO_FOLDER;
|
||
|
|
||
|
psf = pns->ShellFolder(); // no addref
|
||
|
ASSERT(psf);
|
||
|
if (SUCCEEDED(psf->GetAttributesOf(1, (LPCITEMIDLIST*)ppidl, &rgf)))
|
||
|
{
|
||
|
if (pbIsFolder)
|
||
|
*pbIsFolder = rgf & SFGAO_FOLDER;
|
||
|
|
||
|
LPITEMIDLIST pidlItem;
|
||
|
UINT nCommonID;
|
||
|
CNamespace* pnsCommonTemp;
|
||
|
|
||
|
// get common namespace (attribs = 0)
|
||
|
hres = GetDefNamespace(0, (void **)&pnsCommonTemp, &nCommonID, NULL);
|
||
|
ASSERT(NamespaceCount() == 2 && SUCCEEDED(hres) || NamespaceCount() == 1);
|
||
|
if (FAILED(hres))
|
||
|
nCommonID = 1;
|
||
|
|
||
|
if (nCommonID == nSrcID)
|
||
|
{
|
||
|
*ppnsCommon = pns;
|
||
|
if (pnCommonID)
|
||
|
*pnCommonID = nCommonID;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppnsUser = pns;
|
||
|
if (pnUserID)
|
||
|
*pnUserID = nSrcID;
|
||
|
}
|
||
|
|
||
|
if (AugMergeISF_EnumNextSrcPidl(hEnum, &nSrcID, &pidlItem))
|
||
|
{
|
||
|
ASSERT(ILIsEqual(*ppidl, pidlItem));
|
||
|
ILFree(pidlItem);
|
||
|
if (SUCCEEDED(QueryNameSpace(nSrcID, (void **)&pns)))
|
||
|
{
|
||
|
ASSERT(pns);
|
||
|
if (nCommonID == nSrcID)
|
||
|
{
|
||
|
*ppnsCommon = pns;
|
||
|
if (pnCommonID)
|
||
|
*pnCommonID = nCommonID;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppnsUser = pns;
|
||
|
if (pnUserID)
|
||
|
*pnUserID = nSrcID;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hres = S_OK;
|
||
|
}
|
||
|
}
|
||
|
AugMergeISF_EndEnumSrcPidls(hEnum);
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CAugmentedMergeISF::_GetContextMenu(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
|
||
|
UINT * prgfInOut, void ** ppvOut)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
LPITEMIDLIST pidl;
|
||
|
BOOL bIsFolder;
|
||
|
CNamespace * pnsCommon;
|
||
|
CNamespace * pnsUser;
|
||
|
|
||
|
ASSERT(cidl == 1);
|
||
|
|
||
|
// psfCommon and psfUser are not addrefed
|
||
|
hres = _GetNamespaces(apidl[0], &pnsCommon, NULL, &pnsUser, NULL, &pidl, &bIsFolder);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
ASSERT(pnsCommon || pnsUser);
|
||
|
if (bIsFolder)
|
||
|
{
|
||
|
// folder? need our context menu
|
||
|
IShellFolder * psfCommon = NULL;
|
||
|
IShellFolder * psfUser = NULL;
|
||
|
LPCITEMIDLIST pidlCommon = NULL;
|
||
|
LPCITEMIDLIST pidlUser = NULL;
|
||
|
|
||
|
if (pnsCommon)
|
||
|
{
|
||
|
psfCommon = pnsCommon->ShellFolder();
|
||
|
pidlCommon = pnsCommon->GetPidl();
|
||
|
}
|
||
|
if (pnsUser)
|
||
|
{
|
||
|
psfUser = pnsUser->ShellFolder();
|
||
|
pidlUser = pnsUser->GetPidl();
|
||
|
}
|
||
|
CAugMergeISFContextMenu * pcm = CreateMergeISFContextMenu(psfCommon, pidlCommon,
|
||
|
psfUser, pidlUser,
|
||
|
pidl, hwnd, prgfInOut);
|
||
|
|
||
|
if (pcm)
|
||
|
{
|
||
|
hres = pcm->QueryInterface(IID_IContextMenu, ppvOut);
|
||
|
pcm->Release();
|
||
|
}
|
||
|
else
|
||
|
hres = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{ // it's not a folder
|
||
|
// delegate to the isf
|
||
|
IShellFolder * psf = pnsUser ? pnsUser->ShellFolder() : pnsCommon->ShellFolder();
|
||
|
|
||
|
hres = psf->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, ppvOut);
|
||
|
}
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetDefNamespace(
|
||
|
LPCITEMIDLIST pidlWrap,
|
||
|
ULONG dwAttrib,
|
||
|
OUT IShellFolder** ppsf,
|
||
|
OUT LPITEMIDLIST* ppidlItem )
|
||
|
{
|
||
|
HRESULT hr ;
|
||
|
LPITEMIDLIST pidl ;
|
||
|
CNamespace* pSrc ;
|
||
|
ULONG dwDefAttrib = dwAttrib & ASFF_DEFNAMESPACE_ALL ;
|
||
|
int cWrapped ;
|
||
|
UINT nSrcID ;
|
||
|
HANDLE hEnum ;
|
||
|
|
||
|
ASSERT( ppsf ) ;
|
||
|
|
||
|
*ppsf = NULL ;
|
||
|
if (ppidlItem)
|
||
|
*ppidlItem = NULL ;
|
||
|
|
||
|
if (FAILED((hr = AugMergeISF_IsWrap( pidlWrap ))))
|
||
|
return hr ;
|
||
|
cWrapped = AugMergeISF_GetSourceCount( pidlWrap ) ;
|
||
|
|
||
|
// No namespaces?
|
||
|
if (NULL == _hdpaNamespaces || 0 >= cWrapped ||
|
||
|
NULL == (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcID, &pidl)))
|
||
|
return E_FAIL ;
|
||
|
|
||
|
// Only one namespace in wrap? Give up the shell folder and item ID.
|
||
|
if (1 == cWrapped || 0==dwDefAttrib)
|
||
|
{
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum ) ; // no need to go further
|
||
|
|
||
|
// Retrieve the namespace object identified by nSrcID.
|
||
|
if( SUCCEEDED( (hr = QueryNameSpace( nSrcID, (PVOID*)&pSrc )) ) )
|
||
|
{
|
||
|
*ppsf = pSrc->ShellFolder() ;
|
||
|
if( ppidlItem )
|
||
|
*ppidlItem = pidl ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
ILFree( pidl ) ;
|
||
|
return hr ;
|
||
|
}
|
||
|
|
||
|
// More than one namespace in wrap?
|
||
|
if( cWrapped > 1 )
|
||
|
{
|
||
|
LPITEMIDLIST pidl0 = NULL ;
|
||
|
CNamespace* pSrc0 = NULL ; // get this below.
|
||
|
|
||
|
for (BOOL bEnum = TRUE ; bEnum ;
|
||
|
bEnum = AugMergeISF_EnumNextSrcPidl(hEnum, &nSrcID, &pidl))
|
||
|
{
|
||
|
if (SUCCEEDED((hr = QueryNameSpace(nSrcID, (PVOID*)&pSrc))))
|
||
|
{
|
||
|
if (dwDefAttrib & pSrc->Attrib())
|
||
|
{
|
||
|
// Matched attributes; we're done.
|
||
|
AugMergeISF_EndEnumSrcPidls(hEnum);
|
||
|
*ppsf = pSrc->ShellFolder() ;
|
||
|
if (ppidlItem)
|
||
|
*ppidlItem = pidl;
|
||
|
if(pidl0)
|
||
|
ILFree(pidl0);
|
||
|
return S_OK ;
|
||
|
}
|
||
|
|
||
|
// Stash first namespace object and item pidl.
|
||
|
// We'll default to these if
|
||
|
if( NULL == pSrc0 )
|
||
|
{
|
||
|
pSrc0 = pSrc ;
|
||
|
pidl0 = ILClone( pidl ) ;
|
||
|
}
|
||
|
}
|
||
|
ILFree( pidl ) ;
|
||
|
}
|
||
|
AugMergeISF_EndEnumSrcPidls( hEnum ) ;
|
||
|
|
||
|
// Default to first namespace
|
||
|
if( pSrc0 && pidl0 )
|
||
|
{
|
||
|
*ppsf = pSrc0->ShellFolder() ;
|
||
|
if( ppidlItem )
|
||
|
*ppidlItem = pidl0 ;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return E_UNEXPECTED ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// Retrieves the default namespaces for the indicated attibutes.
|
||
|
// The dwAttrib arg must be initialized prior to function entry,
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetDefNamespace(
|
||
|
ULONG dwAttrib,
|
||
|
OUT PVOID* ppSrc, UINT *pnSrcID, PVOID* ppSrc0 )
|
||
|
{
|
||
|
CNamespace* pSrc ;
|
||
|
ULONG dwDefAttrib = dwAttrib & ASFF_DEFNAMESPACE_ALL ;
|
||
|
|
||
|
// this is an internal helper so we better make sure we pass the correct params!
|
||
|
//if (NULL == ppSrc)
|
||
|
// return E_INVALIDARG ;
|
||
|
*ppSrc = NULL ;
|
||
|
if( ppSrc0 )
|
||
|
*ppSrc0 = NULL ;
|
||
|
|
||
|
for( int i = 0, cSrcs = NamespaceCount(); i < cSrcs ; i++ )
|
||
|
{
|
||
|
if( NULL != (pSrc = Namespace( i )) )
|
||
|
{
|
||
|
if( 0 == i && ppSrc0 )
|
||
|
*ppSrc0 = pSrc ;
|
||
|
|
||
|
if( dwDefAttrib & pSrc->Attrib() ||
|
||
|
dwDefAttrib == 0 && !(pSrc->Attrib() & ASFF_DEFNAMESPACE_ALL))
|
||
|
{
|
||
|
*ppSrc = pSrc;
|
||
|
if (NULL != pnSrcID)
|
||
|
*pnSrcID = i;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return E_FAIL ;
|
||
|
}
|
||
|
|
||
|
// BUGBUG(lamadio): Move this to a better location, This is a nice generic function
|
||
|
#ifdef DEBUG
|
||
|
BOOL DPA_VerifySorted(HDPA hdpa, PFNDPACOMPARE pfn, LPARAM lParam)
|
||
|
{
|
||
|
if (!EVAL(hdpa))
|
||
|
return FALSE;
|
||
|
|
||
|
for (int i = 0; i < DPA_GetPtrCount(hdpa) - 1; i++)
|
||
|
{
|
||
|
if (pfn(DPA_FastGetPtr(hdpa, i), DPA_FastGetPtr(hdpa, i + 1), lParam) > 0)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
#else
|
||
|
#define DPA_VerifySorted(hdpa, pfn, lParam)
|
||
|
#endif
|
||
|
|
||
|
int CAugmentedMergeISF::AcquireObjects()
|
||
|
{
|
||
|
HDPA hdpa2 = NULL;
|
||
|
|
||
|
DEBUG_CODE(_fInternalGDNO = TRUE);
|
||
|
|
||
|
for (int i = 0; i < DPA_GETPTRCOUNT(_hdpaNamespaces); i++)
|
||
|
{
|
||
|
CNamespace * pns = DPA_GETPTR(_hdpaNamespaces, i, CNamespace);
|
||
|
IShellFolder * psf;
|
||
|
IEnumIDList * peid;
|
||
|
HDPA * phdpa;
|
||
|
|
||
|
ASSERT(pns);
|
||
|
psf = pns->ShellFolder(); // no addref here!
|
||
|
|
||
|
if (i == 0)
|
||
|
{
|
||
|
phdpa = &_hdpaObjects;
|
||
|
_hdpaObjects = DPA_Create(4); // We should always create the DPA
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ASSERT(i == 1); // no support for more than 2 isf's
|
||
|
phdpa = &hdpa2;
|
||
|
}
|
||
|
|
||
|
HRESULT hres = psf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &peid);
|
||
|
if (SUCCEEDED(hres))
|
||
|
{
|
||
|
if (!*phdpa)
|
||
|
*phdpa = DPA_Create(4);
|
||
|
|
||
|
if (*phdpa)
|
||
|
{
|
||
|
LPITEMIDLIST pidl;
|
||
|
ULONG cEnum;
|
||
|
|
||
|
while (SUCCEEDED(peid->Next(1, &pidl, &cEnum)) && 1 == cEnum)
|
||
|
{
|
||
|
CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
|
||
|
|
||
|
if (paugmEnum)
|
||
|
{
|
||
|
|
||
|
if (paugmEnum->Init(SAFECAST(this, IAugmentedShellFolder2*), i, pidl))
|
||
|
{
|
||
|
if (DPA_AppendPtr(*phdpa, paugmEnum) == -1)
|
||
|
DestroyObjectsProc(paugmEnum, NULL);
|
||
|
}
|
||
|
else
|
||
|
delete paugmEnum;
|
||
|
}
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
peid->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_WARNING, "CAugMISF::AcquireObjects: Failed to get enumerator 0x%x", hres);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// now that we have both hdpa's (or one) let's merge them.
|
||
|
if (DPA_GETPTRCOUNT(_hdpaNamespaces) == 2 && hdpa2)
|
||
|
{
|
||
|
DPA_Merge(_hdpaObjects, hdpa2, DPAM_UNION, AugmEnumCompare, AugmEnumMerge, (LPARAM)0);
|
||
|
DPA_DESTROY(hdpa2, DestroyObjectsProc);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPA_Sort(_hdpaObjects, AugmEnumCompare, 0);
|
||
|
}
|
||
|
|
||
|
ASSERT(DPA_VerifySorted(_hdpaObjects, AugmEnumCompare, 0));
|
||
|
|
||
|
DEBUG_CODE(_fInternalGDNO = FALSE);
|
||
|
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
TraceMsg(TF_AUGM, "CAugMISF::AcquireObjects");
|
||
|
DumpObjects();
|
||
|
#endif
|
||
|
|
||
|
_count = DPA_GETPTRCOUNT(_hdpaObjects);
|
||
|
|
||
|
return _count;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
void CAugmentedMergeISF::FreeObjects()
|
||
|
{
|
||
|
DPA_DESTROY( _hdpaObjects, DestroyObjectsProc ) ;
|
||
|
_hdpaObjects = NULL;
|
||
|
_count = 0 ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
int CAugmentedMergeISF::DestroyObjectsProc( LPVOID pv, LPVOID pvData )
|
||
|
{
|
||
|
CAugISFEnumItem* paugmEnum = (CAugISFEnumItem*)pv;
|
||
|
|
||
|
if (EVAL(NULL != paugmEnum))
|
||
|
{
|
||
|
delete paugmEnum;
|
||
|
}
|
||
|
return TRUE ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
void CAugmentedMergeISF::FreeNamespaces()
|
||
|
{
|
||
|
DPA_DESTROY( _hdpaNamespaces, DestroyNamespacesProc ) ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
int CAugmentedMergeISF::DestroyNamespacesProc( LPVOID pv, LPVOID pvData )
|
||
|
{
|
||
|
CNamespace* p ;
|
||
|
if( NULL != (p = (CNamespace*)pv) )
|
||
|
delete p ;
|
||
|
return TRUE ;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CAugmentedMergeISF::GetPidl(int* piPos, DWORD grfEnumFlags, LPITEMIDLIST* ppidl)
|
||
|
{
|
||
|
*ppidl = NULL;
|
||
|
|
||
|
if (_hdpaObjects == NULL)
|
||
|
AcquireObjects();
|
||
|
|
||
|
if (_hdpaObjects == NULL)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
BOOL fWantFolders = 0 != (grfEnumFlags & SHCONTF_FOLDERS),
|
||
|
fWantNonFolders = 0 != (grfEnumFlags & SHCONTF_NONFOLDERS),
|
||
|
fWantHidden = 0 != (grfEnumFlags & SHCONTF_INCLUDEHIDDEN) ;
|
||
|
|
||
|
while (*piPos < _count)
|
||
|
{
|
||
|
CAugISFEnumItem* paugmEnum = DPA_GETPTR( _hdpaObjects, *piPos, CAugISFEnumItem);
|
||
|
if ( NULL != paugmEnum )
|
||
|
{
|
||
|
BOOL fFolder = 0 != (paugmEnum->_rgfAttrib & SFGAO_FOLDER),
|
||
|
fHidden = 0 != (paugmEnum->_rgfAttrib & SFGAO_HIDDEN);
|
||
|
|
||
|
if ((!fHidden || fWantHidden) &&
|
||
|
((fFolder && fWantFolders) || (!fFolder && fWantNonFolders)))
|
||
|
{
|
||
|
// Copy out the pidl ;
|
||
|
*ppidl = ILClone(paugmEnum->_pidlWrap);
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
(*piPos)++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*ppidl)
|
||
|
return S_OK;
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
CEnum::CEnum(IAugmentedMergedShellFolderInternal* psmsfi, DWORD grfEnumFlags, int iPos) :
|
||
|
_cRef(1),
|
||
|
_iPos(iPos),
|
||
|
_psmsfi(psmsfi),
|
||
|
_grfEnumFlags(grfEnumFlags)
|
||
|
|
||
|
{
|
||
|
_psmsfi->AddRef();
|
||
|
}
|
||
|
|
||
|
CEnum::~CEnum()
|
||
|
{
|
||
|
ATOMICRELEASE(_psmsfi);
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// class CEnum - IUnknown methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CEnum::QueryInterface( REFIID riid, LPVOID * ppvObj )
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CEnum, IEnumIDList),
|
||
|
{ 0 }
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppvObj);
|
||
|
}
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP_(ULONG) CEnum::AddRef ()
|
||
|
{
|
||
|
return InterlockedIncrement((LONG*)&_cRef);
|
||
|
}
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP_(ULONG) CEnum::Release ()
|
||
|
{
|
||
|
if (InterlockedDecrement((LONG*)&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this ;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// class CEnum - IEnumIDList methods
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CEnum::Next(
|
||
|
ULONG celt,
|
||
|
LPITEMIDLIST *rgelt,
|
||
|
ULONG *pceltFetched )
|
||
|
{
|
||
|
int iStart = _iPos;
|
||
|
int cFetched = 0;
|
||
|
HRESULT hres = S_OK;
|
||
|
|
||
|
if( !(celt > 0 && rgelt) || (NULL == pceltFetched && celt > 1 ) )
|
||
|
return E_INVALIDARG ;
|
||
|
|
||
|
*rgelt = 0;
|
||
|
|
||
|
while(hres == S_OK && (_iPos - iStart) < (int)celt)
|
||
|
{
|
||
|
LPITEMIDLIST pidl;
|
||
|
hres = _psmsfi->GetPidl(&_iPos, _grfEnumFlags, &pidl);
|
||
|
if (hres == S_OK)
|
||
|
{
|
||
|
rgelt[cFetched] = pidl;
|
||
|
cFetched++ ;
|
||
|
}
|
||
|
_iPos++;
|
||
|
}
|
||
|
|
||
|
if( pceltFetched )
|
||
|
*pceltFetched = cFetched ;
|
||
|
|
||
|
return celt == (ULONG)cFetched ? S_OK : S_FALSE ;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CEnum::Skip(ULONG celt)
|
||
|
{
|
||
|
_iPos += celt;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
//-------------------------------------------------------------------------//
|
||
|
STDMETHODIMP CEnum::Reset()
|
||
|
{
|
||
|
_iPos = 0;
|
||
|
return S_OK ;
|
||
|
}
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// REVIEW: Can probably be E_NOTIMPL
|
||
|
STDMETHODIMP CEnum::Clone( IEnumIDList **ppenum )
|
||
|
{
|
||
|
if( NULL == (*ppenum = new CEnum( _psmsfi, _grfEnumFlags, _iPos )) )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL CAugISFEnumItem::Init(IShellFolder* psf, int iShellFolder, LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
// This is ok, the memory just gets written to twice.
|
||
|
if (SUCCEEDED(AugMergeISF_CreateWrap(pidl, iShellFolder, &_pidlWrap)))
|
||
|
{
|
||
|
// Takes ownership of passed in pidl.
|
||
|
return InitWithWrappedToOwn(psf, iShellFolder, _pidlWrap);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CAugISFEnumItem::InitWithWrappedToOwn(IShellFolder* psf, int iShellFolder, LPITEMIDLIST pidl)
|
||
|
{
|
||
|
BOOL fRet = FALSE;
|
||
|
STRRET str;
|
||
|
TCHAR szDisplayName[MAX_PATH];
|
||
|
|
||
|
_pidlWrap = pidl;
|
||
|
|
||
|
_rgfAttrib = SFGAO_FOLDER | SFGAO_HIDDEN;
|
||
|
|
||
|
psf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &_rgfAttrib);
|
||
|
|
||
|
if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str)) &&
|
||
|
SUCCEEDED(StrRetToBuf(&str, pidl, szDisplayName, ARRAYSIZE(szDisplayName))))
|
||
|
{
|
||
|
SetDisplayName(szDisplayName);
|
||
|
fRet = TRUE;
|
||
|
}
|
||
|
return fRet;
|
||
|
}
|