2014-02-25 18:23:02 +00:00
|
|
|
/*
|
|
|
|
* Shell Menu Site
|
|
|
|
*
|
|
|
|
* Copyright 2014 David Quintana
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <atlwin.h>
|
|
|
|
#include <shlwapi_undoc.h>
|
|
|
|
|
|
|
|
#include "CMergedFolder.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(CMergedFolder);
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
struct LocalPidlInfo
|
|
|
|
{
|
2014-06-29 13:54:08 +00:00
|
|
|
BOOL shared;
|
|
|
|
IShellFolder * parent;
|
2014-06-28 15:38:25 +00:00
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
};
|
|
|
|
|
2014-02-25 18:23:02 +00:00
|
|
|
class CEnumMergedFolder :
|
|
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
|
|
public IEnumIDList
|
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
|
2014-02-25 18:23:02 +00:00
|
|
|
private:
|
2014-06-28 15:38:25 +00:00
|
|
|
CComPtr<IShellFolder> m_UserLocalFolder;
|
|
|
|
CComPtr<IShellFolder> m_AllUSersFolder;
|
|
|
|
|
|
|
|
HWND m_HwndOwner;
|
|
|
|
SHCONTF m_Flags;
|
|
|
|
|
|
|
|
HDSA m_hDsa;
|
|
|
|
UINT m_hDsaIndex;
|
|
|
|
UINT m_hDsaCount;
|
2014-02-25 18:23:02 +00:00
|
|
|
|
|
|
|
public:
|
2014-06-28 15:38:25 +00:00
|
|
|
CEnumMergedFolder();
|
|
|
|
virtual ~CEnumMergedFolder();
|
2014-02-25 18:23:02 +00:00
|
|
|
|
|
|
|
DECLARE_NOT_AGGREGATABLE(CEnumMergedFolder)
|
|
|
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
|
|
|
|
|
|
|
BEGIN_COM_MAP(CEnumMergedFolder)
|
|
|
|
COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
|
|
|
|
END_COM_MAP()
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
int DsaDeleteCallback(LocalPidlInfo * info);
|
|
|
|
|
|
|
|
static int CALLBACK s_DsaDeleteCallback(void *pItem, void *pData);
|
|
|
|
|
|
|
|
HRESULT SetSources(IShellFolder * userLocal, IShellFolder * allUSers);
|
|
|
|
HRESULT Begin(HWND hwndOwner, SHCONTF flags);
|
2014-07-09 23:05:37 +00:00
|
|
|
HRESULT FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo);
|
2014-02-25 18:23:02 +00:00
|
|
|
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Next(
|
|
|
|
ULONG celt,
|
|
|
|
LPITEMIDLIST *rgelt,
|
2014-06-28 15:38:25 +00:00
|
|
|
ULONG *pceltFetched);
|
|
|
|
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Reset();
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum);
|
|
|
|
};
|
|
|
|
|
|
|
|
CEnumMergedFolder::CEnumMergedFolder() :
|
|
|
|
m_UserLocalFolder(NULL),
|
|
|
|
m_AllUSersFolder(NULL),
|
|
|
|
m_HwndOwner(NULL),
|
|
|
|
m_Flags(0),
|
2014-07-09 23:05:37 +00:00
|
|
|
m_hDsa(NULL),
|
|
|
|
m_hDsaIndex(0),
|
|
|
|
m_hDsaCount(0)
|
2014-06-28 15:38:25 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CEnumMergedFolder::~CEnumMergedFolder()
|
|
|
|
{
|
|
|
|
DSA_DestroyCallback(m_hDsa, s_DsaDeleteCallback, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CEnumMergedFolder::DsaDeleteCallback(LocalPidlInfo * info)
|
|
|
|
{
|
|
|
|
ILFree(info->pidl);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CALLBACK CEnumMergedFolder::s_DsaDeleteCallback(void *pItem, void *pData)
|
|
|
|
{
|
|
|
|
CEnumMergedFolder * mf = (CEnumMergedFolder*) pData;
|
|
|
|
LocalPidlInfo * item = (LocalPidlInfo*) pItem;
|
|
|
|
return mf->DsaDeleteCallback(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CEnumMergedFolder::SetSources(IShellFolder * userLocal, IShellFolder * allUSers)
|
|
|
|
{
|
|
|
|
m_UserLocalFolder = userLocal;
|
|
|
|
m_AllUSersFolder = allUSers;
|
2014-07-10 17:17:36 +00:00
|
|
|
|
2014-07-10 19:16:21 +00:00
|
|
|
TRACE("SetSources %p %p\n", userLocal, allUSers);
|
2014-06-28 15:38:25 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
2014-07-09 23:05:37 +00:00
|
|
|
|
|
|
|
if (m_hDsa && m_HwndOwner == hwndOwner && m_Flags == flags)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
return Reset();
|
|
|
|
}
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
TRACE("Search conditions changed, recreating list...\n");
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-07-10 17:17:36 +00:00
|
|
|
CComPtr<IEnumIDList> userLocal;
|
|
|
|
CComPtr<IEnumIDList> allUSers;
|
|
|
|
hr = m_UserLocalFolder->EnumObjects(hwndOwner, flags, &userLocal);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
2014-07-10 17:17:36 +00:00
|
|
|
hr = m_AllUSersFolder->EnumObjects(hwndOwner, flags, &allUSers);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
userLocal = NULL;
|
2014-06-28 15:38:25 +00:00
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
if (!m_hDsa)
|
|
|
|
{
|
|
|
|
m_hDsa = DSA_Create(sizeof(LocalPidlInfo), 10);
|
|
|
|
}
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
DSA_EnumCallback(m_hDsa, s_DsaDeleteCallback, this);
|
|
|
|
DSA_DeleteAllItems(m_hDsa);
|
|
|
|
m_hDsaCount = 0;
|
|
|
|
|
|
|
|
HRESULT hr1 = S_OK;
|
|
|
|
HRESULT hr2 = S_OK;
|
|
|
|
LPITEMIDLIST pidl1 = NULL;
|
|
|
|
LPITEMIDLIST pidl2 = NULL;
|
|
|
|
int order = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (order <= 0)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
if (hr1 == S_OK)
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
hr1 = userLocal->Next(1, &pidl1, NULL);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr1))
|
|
|
|
return hr1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pidl1 = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (order >= 0)
|
|
|
|
{
|
|
|
|
if (hr2 == S_OK)
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
hr2 = allUSers->Next(1, &pidl2, NULL);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr2))
|
|
|
|
return hr2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pidl2 = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hr1 == S_OK && hr2 == S_OK)
|
|
|
|
{
|
|
|
|
LPWSTR name1;
|
|
|
|
LPWSTR name2;
|
|
|
|
STRRET str1 = { STRRET_WSTR };
|
|
|
|
STRRET str2 = { STRRET_WSTR };
|
|
|
|
hr = m_UserLocalFolder->GetDisplayNameOf(pidl1, SHGDN_FORPARSING | SHGDN_INFOLDER, &str1);
|
|
|
|
if (FAILED(hr))
|
2014-02-25 18:23:02 +00:00
|
|
|
return hr;
|
2014-06-28 15:38:25 +00:00
|
|
|
hr = m_AllUSersFolder->GetDisplayNameOf(pidl2, SHGDN_FORPARSING | SHGDN_INFOLDER, &str2);
|
|
|
|
if (FAILED(hr))
|
2014-02-25 18:23:02 +00:00
|
|
|
return hr;
|
2014-06-28 15:38:25 +00:00
|
|
|
StrRetToStrW(&str1, pidl1, &name1);
|
|
|
|
StrRetToStrW(&str2, pidl2, &name2);
|
|
|
|
order = StrCmpW(name1, name2);
|
2014-07-10 17:17:36 +00:00
|
|
|
|
|
|
|
TRACE("Both sources are S_OK, comparison between %S and %S returns %d\n", name1, name2, order);
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
CoTaskMemFree(name1);
|
|
|
|
CoTaskMemFree(name2);
|
|
|
|
}
|
|
|
|
else if (hr1 == S_OK)
|
|
|
|
{
|
|
|
|
order = -1;
|
2014-07-10 17:17:36 +00:00
|
|
|
|
|
|
|
TRACE("Both sources are S_OK, forcing %d\n", order);
|
2014-06-28 15:38:25 +00:00
|
|
|
}
|
|
|
|
else if (hr2 == S_OK)
|
|
|
|
{
|
|
|
|
order = 1;
|
2014-07-10 17:17:36 +00:00
|
|
|
|
|
|
|
TRACE("Both sources are S_OK, forcing %d\n", order);
|
2014-06-28 15:38:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
TRACE("None of the sources\n");
|
2014-06-28 15:38:25 +00:00
|
|
|
break;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
LocalPidlInfo info = { FALSE };
|
2014-06-28 15:38:25 +00:00
|
|
|
if (order < 0)
|
|
|
|
{
|
2014-06-29 13:54:08 +00:00
|
|
|
info.parent = m_UserLocalFolder;
|
2014-06-28 15:38:25 +00:00
|
|
|
info.pidl = ILClone(pidl1);
|
|
|
|
ILFree(pidl1);
|
|
|
|
}
|
|
|
|
else if (order > 0)
|
|
|
|
{
|
2014-06-29 13:54:08 +00:00
|
|
|
info.parent = m_AllUSersFolder;
|
2014-06-28 15:38:25 +00:00
|
|
|
info.pidl = ILClone(pidl2);
|
|
|
|
ILFree(pidl2);
|
|
|
|
}
|
|
|
|
else // if (order == 0)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-06-29 13:54:08 +00:00
|
|
|
info.shared = TRUE;
|
|
|
|
info.parent = m_UserLocalFolder;
|
2014-06-28 15:38:25 +00:00
|
|
|
info.pidl = ILClone(pidl1);
|
|
|
|
ILFree(pidl1);
|
|
|
|
ILFree(pidl2);
|
|
|
|
}
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
TRACE("Inserting item %d with parent %p and pidl { cb=%d }\n", m_hDsaCount, info.parent, info.pidl->mkid.cb);
|
2014-06-28 15:38:25 +00:00
|
|
|
int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info);
|
|
|
|
TRACE("New index: %d\n", idx);
|
2014-02-26 11:13:23 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
m_hDsaCount++;
|
2014-02-26 11:13:23 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
} while (hr1 == S_OK || hr2 == S_OK);
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
m_HwndOwner = hwndOwner;
|
|
|
|
m_Flags = flags;
|
|
|
|
|
|
|
|
return Reset();
|
|
|
|
}
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
HRESULT CEnumMergedFolder::FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo)
|
2014-06-28 15:38:25 +00:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
if (!m_hDsa)
|
|
|
|
{
|
|
|
|
Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);
|
|
|
|
}
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDsaCount);
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
for (int i = 0; i < (int)m_hDsaCount; i++)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo * tinfo = (LocalPidlInfo *)DSA_GetItemPtr(m_hDsa, i);
|
|
|
|
if (!tinfo)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
LocalPidlInfo info = *tinfo;
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
TRACE("Comparing with item at %d with parent %p and pidl { cb=%d }\n", i, info.parent, info.pidl->mkid.cb);
|
2014-06-28 15:38:25 +00:00
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
hr = info.parent->CompareIDs(0, info.pidl, pcidl);
|
2014-06-28 18:05:01 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
if (hr == S_OK)
|
|
|
|
{
|
|
|
|
*pinfo = info;
|
|
|
|
return S_OK;
|
2014-06-28 15:38:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-28 18:05:01 +00:00
|
|
|
TRACE("Comparison returned %d\n", (int) (short) (hr & 0xFFFF));
|
2014-06-28 15:38:25 +00:00
|
|
|
}
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
TRACE("Pidl not found\n");
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Next(
|
|
|
|
ULONG celt,
|
|
|
|
LPITEMIDLIST *rgelt,
|
|
|
|
ULONG *pceltFetched)
|
|
|
|
{
|
|
|
|
if (pceltFetched) *pceltFetched = 0;
|
|
|
|
|
|
|
|
if (m_hDsaIndex == m_hDsaCount)
|
|
|
|
return S_FALSE;
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)celt;)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo * tinfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, m_hDsaIndex);
|
|
|
|
if (!tinfo)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
LocalPidlInfo info = *tinfo;
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
TRACE("Returning next item at %d with parent %p and pidl { cb=%d }\n", m_hDsaIndex, info.parent, info.pidl->mkid.cb);
|
2014-06-28 15:38:25 +00:00
|
|
|
|
|
|
|
// FIXME: ILClone shouldn't be needed here! This should be causing leaks
|
|
|
|
if (rgelt) rgelt[i] = ILClone(info.pidl);
|
|
|
|
i++;
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
m_hDsaIndex++;
|
2014-06-28 15:38:25 +00:00
|
|
|
if (m_hDsaIndex == m_hDsaCount)
|
|
|
|
{
|
|
|
|
if (pceltFetched) *pceltFetched = i;
|
|
|
|
return (i == (int)celt) ? S_OK : S_FALSE;
|
|
|
|
}
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
2014-06-28 15:38:25 +00:00
|
|
|
|
|
|
|
if (pceltFetched) *pceltFetched = celt;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Skip(ULONG celt)
|
|
|
|
{
|
|
|
|
return Next(celt, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Reset()
|
|
|
|
{
|
|
|
|
m_hDsaIndex = 0;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Clone(
|
|
|
|
IEnumIDList **ppenum)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CMergedFolder
|
2014-02-25 18:23:02 +00:00
|
|
|
|
|
|
|
extern "C"
|
2014-07-10 17:17:36 +00:00
|
|
|
HRESULT WINAPI CMergedFolder_Constructor(REFIID riid, LPVOID *ppv)
|
2014-02-25 18:23:02 +00:00
|
|
|
{
|
2014-10-20 21:09:55 +00:00
|
|
|
return ShellObjectCreator<CMergedFolder>(riid, ppv);
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
CMergedFolder::CMergedFolder() :
|
|
|
|
m_UserLocal(NULL),
|
|
|
|
m_AllUSers(NULL),
|
|
|
|
m_EnumSource(NULL),
|
2014-07-10 17:17:36 +00:00
|
|
|
m_UserLocalPidl(NULL),
|
|
|
|
m_AllUsersPidl(NULL),
|
2014-07-02 14:48:21 +00:00
|
|
|
m_shellPidl(NULL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CMergedFolder::~CMergedFolder()
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
if (m_UserLocalPidl) ILFree(m_UserLocalPidl);
|
|
|
|
if (m_AllUsersPidl) ILFree(m_AllUsersPidl);
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
// IAugmentedShellFolder2
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::AddNameSpace(LPGUID lpGuid, IShellFolder * psf, LPCITEMIDLIST pcidl, ULONG dwUnknown)
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
if (lpGuid)
|
|
|
|
{
|
|
|
|
TRACE("FIXME: No idea how to handle the GUID\n");
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2014-07-10 19:16:21 +00:00
|
|
|
TRACE("AddNameSpace %p %p\n", m_UserLocal.p, m_AllUSers.p);
|
2014-07-10 17:17:36 +00:00
|
|
|
|
|
|
|
// FIXME: Use a DSA to store the list of merged namespaces, together with their related info (psf, pidl, ...)
|
|
|
|
// For now, assume only 2 will ever be used, and ignore all the other data.
|
|
|
|
if (!m_UserLocal)
|
|
|
|
{
|
|
|
|
m_UserLocal = psf;
|
|
|
|
m_UserLocalPidl = ILClone(pcidl);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_AllUSers)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
m_AllUSers = psf;
|
|
|
|
m_AllUsersPidl = ILClone(pcidl);
|
|
|
|
|
|
|
|
m_EnumSource = new CComObject<CEnumMergedFolder>();
|
|
|
|
return m_EnumSource->SetSources(m_UserLocal, m_AllUSers);
|
2014-07-09 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID lpGuid)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid, IShellFolder ** ppsf)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown, IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2014-02-25 18:23:02 +00:00
|
|
|
// IShellFolder
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::ParseDisplayName(
|
|
|
|
HWND hwndOwner,
|
|
|
|
LPBC pbcReserved,
|
|
|
|
LPOLESTR lpszDisplayName,
|
|
|
|
ULONG *pchEaten,
|
|
|
|
LPITEMIDLIST *ppidl,
|
|
|
|
ULONG *pdwAttributes)
|
|
|
|
{
|
2014-07-09 23:05:37 +00:00
|
|
|
HRESULT hr;
|
|
|
|
LocalPidlInfo info;
|
2014-07-10 17:17:36 +00:00
|
|
|
LPITEMIDLIST pidl;
|
2014-07-09 23:05:37 +00:00
|
|
|
|
|
|
|
if (!ppidl) return E_FAIL;
|
|
|
|
|
|
|
|
if (pchEaten) *pchEaten = 0;
|
|
|
|
if (pdwAttributes) *pdwAttributes = 0;
|
|
|
|
|
2014-07-10 17:17:36 +00:00
|
|
|
TRACE("ParseDisplayName name=%S\n", lpszDisplayName);
|
|
|
|
|
|
|
|
hr = m_UserLocal->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten, &pidl, pdwAttributes);
|
2014-07-09 23:05:37 +00:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
TRACE("ParseDisplayName result local\n");
|
|
|
|
hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
|
2014-07-09 23:05:37 +00:00
|
|
|
if (SUCCEEDED(hr))
|
2014-07-10 17:17:36 +00:00
|
|
|
{
|
|
|
|
ILFree(pidl);
|
|
|
|
*ppidl = ILClone(info.pidl);
|
2014-07-09 23:05:37 +00:00
|
|
|
return hr;
|
2014-07-10 17:17:36 +00:00
|
|
|
}
|
2014-07-09 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 17:17:36 +00:00
|
|
|
hr = m_AllUSers->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName, pchEaten, &pidl, pdwAttributes);
|
2014-07-09 23:05:37 +00:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
2014-07-10 17:17:36 +00:00
|
|
|
TRACE("ParseDisplayName result common\n");
|
|
|
|
hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
|
2014-07-09 23:05:37 +00:00
|
|
|
if (SUCCEEDED(hr))
|
2014-07-10 17:17:36 +00:00
|
|
|
{
|
|
|
|
ILFree(pidl);
|
|
|
|
*ppidl = ILClone(info.pidl);
|
2014-07-09 23:05:37 +00:00
|
|
|
return hr;
|
2014-07-10 17:17:36 +00:00
|
|
|
}
|
2014-07-09 23:05:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ppidl) *ppidl = NULL;
|
|
|
|
if (pchEaten) *pchEaten = 0;
|
|
|
|
if (pdwAttributes) *pdwAttributes = 0;
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::EnumObjects(
|
|
|
|
HWND hwndOwner,
|
|
|
|
SHCONTF grfFlags,
|
|
|
|
IEnumIDList **ppenumIDList)
|
|
|
|
{
|
2014-07-09 00:42:05 +00:00
|
|
|
TRACE("EnumObjects\n");
|
2014-06-28 15:38:25 +00:00
|
|
|
HRESULT hr = m_EnumSource->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenumIDList));
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
return m_EnumSource->Begin(hwndOwner, grfFlags);
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::BindToObject(
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
LPBC pbcReserved,
|
|
|
|
REFIID riid,
|
|
|
|
void **ppvOut)
|
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo info;
|
2014-02-25 18:23:02 +00:00
|
|
|
HRESULT hr;
|
2014-07-10 17:17:36 +00:00
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
2014-02-25 18:23:02 +00:00
|
|
|
return hr;
|
2014-06-29 13:54:08 +00:00
|
|
|
|
2014-07-10 17:17:36 +00:00
|
|
|
TRACE("BindToObject shared = %d\n", info.shared);
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
if (!info.shared)
|
2014-07-02 14:48:21 +00:00
|
|
|
return info.parent->BindToObject(info.pidl, pbcReserved, riid, ppvOut);
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
if (riid != IID_IShellFolder)
|
|
|
|
return E_FAIL;
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
CComPtr<IShellFolder> fld1;
|
|
|
|
CComPtr<IShellFolder> fld2;
|
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
hr = m_UserLocal->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder, &fld1));
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
hr = m_AllUSers->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder, &fld2));
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
2014-07-10 17:17:36 +00:00
|
|
|
CComPtr<IAugmentedShellFolder> pasf;
|
|
|
|
hr = CMergedFolder_Constructor(IID_PPV_ARG(IAugmentedShellFolder, &pasf));
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = pasf->QueryInterface(riid, ppvOut);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = pasf->AddNameSpace(NULL, fld1, info.pidl, 0xFF00);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = pasf->AddNameSpace(NULL, fld2, info.pidl, 0x0000);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
return hr;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::BindToStorage(
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
LPBC pbcReserved,
|
|
|
|
REFIID riid,
|
|
|
|
void **ppvObj)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::CompareIDs(
|
|
|
|
LPARAM lParam,
|
|
|
|
LPCITEMIDLIST pidl1,
|
|
|
|
LPCITEMIDLIST pidl2)
|
|
|
|
{
|
2014-07-09 00:42:05 +00:00
|
|
|
TRACE("CompareIDs\n");
|
2014-06-28 15:38:25 +00:00
|
|
|
return m_UserLocal->CompareIDs(lParam, pidl1, pidl2);
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::CreateViewObject(
|
|
|
|
HWND hwndOwner,
|
|
|
|
REFIID riid,
|
|
|
|
void **ppvOut)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetAttributesOf(
|
|
|
|
UINT cidl,
|
|
|
|
LPCITEMIDLIST *apidl,
|
|
|
|
SFGAOF *rgfInOut)
|
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo info;
|
2014-02-25 18:23:02 +00:00
|
|
|
HRESULT hr;
|
|
|
|
|
2014-07-09 00:42:05 +00:00
|
|
|
TRACE("GetAttributesOf\n");
|
2014-07-02 14:48:21 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
for (int i = 0; i < (int)cidl; i++)
|
|
|
|
{
|
|
|
|
LPCITEMIDLIST pidl = apidl[i];
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
pidl = info.pidl;
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
SFGAOF * pinOut1 = rgfInOut ? rgfInOut + i : NULL;
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
hr = info.parent->GetAttributesOf(1, &pidl, pinOut1);
|
2014-06-28 15:38:25 +00:00
|
|
|
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetUIObjectOf(
|
|
|
|
HWND hwndOwner,
|
|
|
|
UINT cidl,
|
|
|
|
LPCITEMIDLIST *apidl,
|
|
|
|
REFIID riid,
|
|
|
|
UINT *prgfInOut,
|
|
|
|
void **ppvOut)
|
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo info;
|
2014-02-25 18:23:02 +00:00
|
|
|
HRESULT hr;
|
|
|
|
|
2014-07-09 00:42:05 +00:00
|
|
|
TRACE("GetUIObjectOf\n");
|
2014-07-02 14:48:21 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
for (int i = 0; i < (int)cidl; i++)
|
|
|
|
{
|
|
|
|
LPCITEMIDLIST pidl = apidl[i];
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
TRACE("Processing GetUIObjectOf item %d of %u...\n", i, cidl);
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
pidl = info.pidl;
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
TRACE("FindPidlInList succeeded with parent %p and pidl { db=%d }\n", info.parent, info.pidl->mkid.cb);
|
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
UINT * pinOut1 = prgfInOut ? prgfInOut+i : NULL;
|
|
|
|
void** ppvOut1 = ppvOut ? ppvOut + i : NULL;
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
hr = info.parent->GetUIObjectOf(hwndOwner, 1, &pidl, riid, pinOut1, ppvOut1);
|
2014-06-28 15:38:25 +00:00
|
|
|
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDisplayNameOf(
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
SHGDNF uFlags,
|
|
|
|
STRRET *lpName)
|
|
|
|
{
|
2014-06-28 15:38:25 +00:00
|
|
|
LocalPidlInfo info;
|
2014-02-25 18:23:02 +00:00
|
|
|
HRESULT hr;
|
|
|
|
|
2014-07-09 00:42:05 +00:00
|
|
|
TRACE("GetDisplayNameOf\n");
|
2014-07-02 14:48:21 +00:00
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
2014-02-25 18:23:02 +00:00
|
|
|
return hr;
|
|
|
|
|
2014-07-02 14:48:21 +00:00
|
|
|
hr = info.parent->GetDisplayNameOf(info.pidl, uFlags, lpName);
|
2014-02-25 18:23:02 +00:00
|
|
|
|
2014-06-28 15:38:25 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
return S_OK;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::SetNameOf(
|
|
|
|
HWND hwnd,
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
LPCOLESTR lpszName,
|
|
|
|
SHGDNF uFlags,
|
|
|
|
LPITEMIDLIST *ppidlOut)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2014-06-29 13:54:08 +00:00
|
|
|
// IPersist
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetClassID(CLSID *lpClassId)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IPersistFolder
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::Initialize(LPCITEMIDLIST pidl)
|
|
|
|
{
|
|
|
|
m_shellPidl = ILClone(pidl);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IPersistFolder2
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetCurFolder(LPITEMIDLIST * pidl)
|
|
|
|
{
|
|
|
|
if (pidl)
|
|
|
|
*pidl = m_shellPidl;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2014-02-25 18:23:02 +00:00
|
|
|
// IShellFolder2
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultSearchGUID(
|
|
|
|
GUID *lpguid)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::EnumSearches(
|
|
|
|
IEnumExtraSearch **ppenum)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumn(
|
|
|
|
DWORD dwReserved,
|
|
|
|
ULONG *pSort,
|
|
|
|
ULONG *pDisplay)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDefaultColumnState(
|
|
|
|
UINT iColumn,
|
|
|
|
SHCOLSTATEF *pcsFlags)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsEx(
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
const SHCOLUMNID *pscid,
|
|
|
|
VARIANT *pv)
|
|
|
|
{
|
2014-07-09 00:42:05 +00:00
|
|
|
LocalPidlInfo info;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("GetDetailsEx\n");
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
|
2014-07-09 00:42:05 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
CComPtr<IShellFolder2> parent2;
|
|
|
|
hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2));
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = parent2->GetDetailsEx(info.pidl, pscid, pv);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
return S_OK;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::GetDetailsOf(
|
|
|
|
LPCITEMIDLIST pidl,
|
|
|
|
UINT iColumn,
|
|
|
|
SHELLDETAILS *psd)
|
|
|
|
{
|
2014-07-09 00:42:05 +00:00
|
|
|
LocalPidlInfo info;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
TRACE("GetDetailsOf\n");
|
|
|
|
|
2014-07-09 23:05:37 +00:00
|
|
|
hr = m_EnumSource->FindPidlInList(NULL, pidl, &info);
|
2014-07-09 00:42:05 +00:00
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
CComPtr<IShellFolder2> parent2;
|
|
|
|
hr = info.parent->QueryInterface(IID_PPV_ARG(IShellFolder2, &parent2));
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
hr = parent2->GetDetailsOf(info.pidl, iColumn, psd);
|
|
|
|
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
return S_OK;
|
2014-02-25 18:23:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CMergedFolder::MapColumnToSCID(
|
|
|
|
UINT iColumn,
|
|
|
|
SHCOLUMNID *pscid)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|