1243 lines
38 KiB
C++
1243 lines
38 KiB
C++
|
#include "shellprv.h"
|
||
|
#include "util.h"
|
||
|
#include "ids.h"
|
||
|
#include "infotip.h"
|
||
|
#include "fstreex.h"
|
||
|
#include "lm.h"
|
||
|
#include "shgina.h"
|
||
|
#include "prop.h"
|
||
|
#include "datautil.h"
|
||
|
#include "filefldr.h"
|
||
|
#include "buytasks.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
// this define causes the shared folder code to work on domains (for debug)
|
||
|
//#define SHOW_SHARED_FOLDERS
|
||
|
|
||
|
// filter out the current user accounts
|
||
|
#define FILTER_CURRENT_USER 0
|
||
|
|
||
|
// where do we store the doc folder paths
|
||
|
#define REGSTR_PATH_DOCFOLDERPATH TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DocFolderPaths")
|
||
|
|
||
|
// state API for showing the shared documents folder
|
||
|
|
||
|
STDAPI_(BOOL) SHShowSharedFolders()
|
||
|
{
|
||
|
#ifndef SHOW_SHARED_FOLDERS
|
||
|
// restriction overrides all logic for the shared documents
|
||
|
|
||
|
if (SHRestricted(REST_NOSHAREDDOCUMENTS))
|
||
|
return FALSE;
|
||
|
|
||
|
// if we haven't computed the "show shared folders flag" then do so
|
||
|
|
||
|
static int iShow = -1;
|
||
|
if (iShow == -1)
|
||
|
iShow = IsOS(OS_DOMAINMEMBER) ? 0:1; // only works if we are not a domain user
|
||
|
|
||
|
return (iShow >= 1);
|
||
|
#else
|
||
|
return true;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// implementation of a delegate shell folder for merging in shared documents
|
||
|
|
||
|
STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
|
||
|
|
||
|
HRESULT CSharedDocsEnum_CreateInstance(HDPA hItems, DWORD grfFlags, IEnumIDList **ppenum);
|
||
|
|
||
|
#pragma pack(1)
|
||
|
typedef struct
|
||
|
{
|
||
|
// these memebers overlap DELEGATEITEMID struct
|
||
|
// for our IDelegateFolder support
|
||
|
WORD cbSize;
|
||
|
WORD wOuter;
|
||
|
WORD cbInner;
|
||
|
|
||
|
// our stuff
|
||
|
DWORD dwType; // our type of folder
|
||
|
TCHAR wszID[1]; // unique ID for the user
|
||
|
} SHAREDITEM;
|
||
|
#pragma pack()
|
||
|
|
||
|
typedef UNALIGNED SHAREDITEM * LPSHAREDITEM;
|
||
|
typedef const UNALIGNED SHAREDITEM * LPCSHAREDITEM;
|
||
|
|
||
|
#define SHAREDID_COMMON 0x0
|
||
|
#define SHAREDID_USER 0x2
|
||
|
|
||
|
|
||
|
class CSharedDocuments : public IDelegateFolder, IPersistFolder2, IShellFolder2, IShellIconOverlay
|
||
|
{
|
||
|
public:
|
||
|
CSharedDocuments();
|
||
|
~CSharedDocuments();
|
||
|
|
||
|
// IUnknown
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
|
||
|
STDMETHOD_(ULONG, AddRef)();
|
||
|
STDMETHOD_(ULONG, Release)();
|
||
|
|
||
|
// IDelegateFolder
|
||
|
STDMETHODIMP SetItemAlloc(IMalloc *pmalloc);
|
||
|
|
||
|
// IPersist
|
||
|
STDMETHODIMP GetClassID(CLSID* pclsid)
|
||
|
{ *pclsid = CLSID_SharedDocuments; return S_OK; }
|
||
|
|
||
|
// IPersistFolder
|
||
|
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
|
||
|
|
||
|
// IPersistFolder2
|
||
|
STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
|
||
|
|
||
|
// IShellFolder
|
||
|
STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
|
||
|
STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
|
||
|
STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
|
||
|
STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
|
||
|
{ return BindToObject(pidl, pbc, riid, ppv); }
|
||
|
STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
|
||
|
STDMETHODIMP CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
|
||
|
STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,REFIID riid, UINT* prgfInOut, void **ppv);
|
||
|
STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
|
||
|
STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST* ppidlOut)
|
||
|
{ return E_NOTIMPL; }
|
||
|
|
||
|
// IShellFolder2
|
||
|
STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
|
||
|
STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP MapColumnToSCID(UINT iCol, SHCOLUMNID *pscid)
|
||
|
{ return E_NOTIMPL; }
|
||
|
|
||
|
// IShellIconOverlay
|
||
|
STDMETHODIMP GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
|
||
|
{ return _GetOverlayIndex(pidl, pIndex, FALSE); }
|
||
|
STDMETHODIMP GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIconIndex)
|
||
|
{ return _GetOverlayIndex(pidl, pIconIndex, TRUE); }
|
||
|
|
||
|
private:
|
||
|
LONG _cRef;
|
||
|
IMalloc *_pmalloc;
|
||
|
LPITEMIDLIST _pidl;
|
||
|
|
||
|
CRITICAL_SECTION _cs; // critical section for managing lifetime of the cache
|
||
|
|
||
|
TCHAR _szCurrentUser[UNLEN+1]; // user name (cached for current user)
|
||
|
|
||
|
BOOL _fCachedAllUser:1; // cached the all user account
|
||
|
TCHAR _szCachedUser[UNLEN+1]; // if (FALSE) then this contains the user ID.
|
||
|
|
||
|
IUnknown *_punkCached; // IUnknown object (from FS folder) that we cache
|
||
|
LPITEMIDLIST _pidlCached; // IDLIST of the cached folder
|
||
|
|
||
|
void _ClearCachedObjects();
|
||
|
BOOL _IsCached(LPCITEMIDLIST pidl);
|
||
|
HRESULT _CreateFolder(LPBC pbc, LPCITEMIDLIST pidl, REFIID riid, void **ppv, BOOL fRegisterAlias);
|
||
|
HRESULT _GetTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl);
|
||
|
HRESULT _GetTargetIDList(BOOL fForceReCache, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl);
|
||
|
HRESULT _AddIDList(HDPA hdpa, DWORD dwType, LPCTSTR pszUser);
|
||
|
HRESULT _AllocIDList(DWORD dwType, LPCTSTR pszUser, LPITEMIDLIST *ppidl);
|
||
|
HRESULT _GetSharedFolders(HDPA *phItems);
|
||
|
HRESULT _GetAttributesOf(LPCITEMIDLIST pidl, DWORD rgfIn, DWORD *prgfOut);
|
||
|
LPCTSTR _GetUserFromIDList(LPCITEMIDLIST pidl, LPTSTR pszBuffer, INT cchBuffer);
|
||
|
HRESULT _GetPathForUser(LPCTSTR pcszUser, LPTSTR pszBuffer, int cchBuffer);
|
||
|
HRESULT _GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex, BOOL fIcon);
|
||
|
|
||
|
static HRESULT s_FolderMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
friend class CSharedDocsEnum;
|
||
|
};
|
||
|
|
||
|
|
||
|
// constructors
|
||
|
|
||
|
CSharedDocuments::CSharedDocuments() :
|
||
|
_cRef(1)
|
||
|
{
|
||
|
InitializeCriticalSection(&_cs);
|
||
|
}
|
||
|
|
||
|
CSharedDocuments::~CSharedDocuments()
|
||
|
{
|
||
|
ATOMICRELEASE(_pmalloc);
|
||
|
ATOMICRELEASE(_punkCached);
|
||
|
|
||
|
ILFree(_pidlCached);
|
||
|
ILFree(_pidl);
|
||
|
|
||
|
DeleteCriticalSection(&_cs);
|
||
|
}
|
||
|
|
||
|
STDAPI CSharedDocFolder_CreateInstance(IUnknown *punkOut, REFIID riid, void **ppv)
|
||
|
{
|
||
|
CSharedDocuments *psdf = new CSharedDocuments;
|
||
|
if (!psdf)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
HRESULT hr = psdf->QueryInterface(riid, ppv);
|
||
|
psdf->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// IUnknown handling
|
||
|
|
||
|
STDMETHODIMP CSharedDocuments::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] =
|
||
|
{
|
||
|
QITABENT(CSharedDocuments, IDelegateFolder), // IID_IDelegateFolder
|
||
|
QITABENTMULTI(CSharedDocuments, IShellFolder, IShellFolder2), // IID_IShellFOlder
|
||
|
QITABENT(CSharedDocuments, IShellFolder2), // IID_IShellFolder2
|
||
|
QITABENTMULTI(CSharedDocuments, IPersistFolder, IPersistFolder2), // IID_IPersistFolder
|
||
|
QITABENTMULTI(CSharedDocuments, IPersist, IPersistFolder2), // IID_IPersist
|
||
|
QITABENT(CSharedDocuments, IPersistFolder2), // IID_IPersistFolder2
|
||
|
QITABENT(CSharedDocuments, IShellIconOverlay), // IID_IShellIconOverlay
|
||
|
QITABENTMULTI2(CSharedDocuments, IID_IPersistFreeThreadedObject, IPersist), // IID_IPersistFreeThreadedObject
|
||
|
{ 0 },
|
||
|
};
|
||
|
|
||
|
if (riid == CLSID_SharedDocuments)
|
||
|
{
|
||
|
*ppv = this; // no ref
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedDocuments::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedDocuments::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// IDelegateFolder
|
||
|
HRESULT CSharedDocuments::SetItemAlloc(IMalloc *pmalloc)
|
||
|
{
|
||
|
IUnknown_Set((IUnknown**)&_pmalloc, pmalloc);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSharedDocuments::Initialize(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
ILFree(_pidl);
|
||
|
return SHILClone(pidl, &_pidl);
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::GetCurFolder(LPITEMIDLIST* ppidl)
|
||
|
{
|
||
|
return SHILClone(_pidl, ppidl);
|
||
|
}
|
||
|
|
||
|
|
||
|
// single level cache for the objects
|
||
|
|
||
|
void CSharedDocuments::_ClearCachedObjects()
|
||
|
{
|
||
|
ATOMICRELEASE(_punkCached); // clear out the cached items (old)
|
||
|
ILFree(_pidlCached);
|
||
|
_pidlCached = NULL;
|
||
|
}
|
||
|
|
||
|
BOOL CSharedDocuments::_IsCached(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
|
||
|
TCHAR szUser[UNLEN+1];
|
||
|
if (_GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)))
|
||
|
{
|
||
|
// did we cache the users account information?
|
||
|
|
||
|
if (!_szCachedUser[0] || (StrCmpI(_szCachedUser, szUser) != 0))
|
||
|
{
|
||
|
_fCachedAllUser = FALSE;
|
||
|
StrCpyN(_szCachedUser, szUser, ARRAYSIZE(_szCachedUser));
|
||
|
_ClearCachedObjects();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fResult = TRUE; // were set!
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// the all user case is keyed on a flag rather than the
|
||
|
// account name we are supposed to be using.
|
||
|
|
||
|
if (!_fCachedAllUser)
|
||
|
{
|
||
|
_fCachedAllUser = TRUE;
|
||
|
_szCachedUser[0] = TEXT('\0');
|
||
|
_ClearCachedObjects();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fResult = TRUE; // were set
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
// IShellFolder methods
|
||
|
|
||
|
HRESULT CSharedDocuments::_CreateFolder(LPBC pbc, LPCITEMIDLIST pidl, REFIID riid, void **ppv, BOOL fRegisterAlias)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
EnterCriticalSection(&_cs);
|
||
|
|
||
|
// get the target folder (were already in a critical section)
|
||
|
// and then bind down to the shell folder if we have not already
|
||
|
// cached one for ourselves.
|
||
|
|
||
|
if (!_IsCached(pidl) || !_punkCached)
|
||
|
{
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
hr = _GetTargetIDList(TRUE, pidl, &pidlTarget); // clears _punkCached in here (so no leak)
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LPITEMIDLIST pidlInit;
|
||
|
hr = SHILCombine(_pidl, pidl, &pidlInit);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = SHCoCreateInstance(NULL, &CLSID_ShellFSFolder, NULL, IID_PPV_ARG(IUnknown, &_punkCached));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IPersistFolder3 *ppf;
|
||
|
hr = _punkCached->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
PERSIST_FOLDER_TARGET_INFO pfti = {0};
|
||
|
pfti.pidlTargetFolder = (LPITEMIDLIST)pidlTarget;
|
||
|
pfti.dwAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
||
|
pfti.csidl = -1;
|
||
|
hr = ppf->InitializeEx(NULL, pidlInit, &pfti);
|
||
|
ppf->Release();
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr) && fRegisterAlias)
|
||
|
SHChangeNotifyRegisterAlias(pidlTarget, pidlInit);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
_punkCached->Release();
|
||
|
_punkCached = NULL;
|
||
|
}
|
||
|
}
|
||
|
ILFree(pidlInit);
|
||
|
}
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = _punkCached->QueryInterface(riid, ppv);
|
||
|
|
||
|
LeaveCriticalSection(&_cs);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSharedDocuments::_GetTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
|
||
|
{
|
||
|
EnterCriticalSection(&_cs);
|
||
|
HRESULT hr = _GetTargetIDList(FALSE, pidl, ppidl);
|
||
|
LeaveCriticalSection(&_cs);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::_GetTargetIDList(BOOL fForceReCache, LPCITEMIDLIST pidl, LPITEMIDLIST *ppidl)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
if (fForceReCache || !_IsCached(pidl) || !_pidlCached)
|
||
|
{
|
||
|
_ClearCachedObjects(); // we don't have it cached now
|
||
|
|
||
|
LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
|
||
|
if (psid->dwType == SHAREDID_COMMON)
|
||
|
{
|
||
|
hr = SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DOCUMENTS|CSIDL_FLAG_NO_ALIAS, &_pidlCached);
|
||
|
}
|
||
|
else if (psid->dwType == SHAREDID_USER)
|
||
|
{
|
||
|
TCHAR szPath[MAX_PATH], szUser[UNLEN+1];
|
||
|
hr = _GetPathForUser(_GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)), szPath, ARRAYSIZE(szPath));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ILCreateFromPathEx(szPath, NULL, ILCFP_FLAG_NO_MAP_ALIAS, &_pidlCached, NULL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_INVALIDARG; // invalid IDLIST passed
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = SHILClone(_pidlCached, ppidl);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::_AddIDList(HDPA hdpa, DWORD dwType, LPCTSTR pszUser)
|
||
|
{
|
||
|
LPITEMIDLIST pidl;
|
||
|
HRESULT hr = _AllocIDList(dwType, pszUser, &pidl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
DWORD grfFlags = SFGAO_FOLDER;
|
||
|
hr = _GetAttributesOf(pidl, SFGAO_FOLDER, &grfFlags);
|
||
|
if (SUCCEEDED(hr) && grfFlags & SFGAO_FOLDER)
|
||
|
{
|
||
|
if (-1 == DPA_AppendPtr(hdpa, pidl))
|
||
|
{
|
||
|
ILFree(pidl);
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSharedDocuments::_AllocIDList(DWORD dwType, LPCTSTR pszUser, LPITEMIDLIST *ppidl)
|
||
|
{
|
||
|
DWORD cb = sizeof(SHAREDITEM);
|
||
|
int cchUser = pszUser ? lstrlen(pszUser) + 1 : 0;
|
||
|
|
||
|
// ID list contains strings if its a user
|
||
|
|
||
|
if (dwType == SHAREDID_USER)
|
||
|
cb += sizeof(TCHAR) * cchUser;
|
||
|
|
||
|
SHAREDITEM *psid = (SHAREDITEM*)_pmalloc->Alloc(cb);
|
||
|
if (!psid)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
psid->dwType = dwType; // type is universal
|
||
|
|
||
|
if (dwType == SHAREDID_USER)
|
||
|
StrCpyW(psid->wszID, pszUser);
|
||
|
|
||
|
*ppidl = (LPITEMIDLIST)psid;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
LPCTSTR CSharedDocuments::_GetUserFromIDList(LPCITEMIDLIST pidl, LPTSTR pszUser, int cchUser)
|
||
|
{
|
||
|
LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
|
||
|
|
||
|
if (psid->dwType == SHAREDID_COMMON)
|
||
|
{
|
||
|
pszUser[0] = 0; // initialize
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ualstrcpynW(pszUser, psid->wszID, cchUser);
|
||
|
return pszUser;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::_GetPathForUser(LPCTSTR pszUser, LPTSTR pszBuffer, int cchBuffer)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
BOOL fResult = FALSE;
|
||
|
|
||
|
if (!pszUser)
|
||
|
{
|
||
|
// get the common documents path (which covers all users), this user is always defined
|
||
|
// so lets return TRUE if they just want to check to see if its defined, otherwise
|
||
|
// just pass out the result from fetching the path.
|
||
|
|
||
|
fResult = !pszBuffer || (SHGetSpecialFolderPath(NULL, pszBuffer, CSIDL_COMMON_DOCUMENTS, FALSE));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// we have a user ID, so lets attempt to get the path fro that from the registry
|
||
|
// if we get it then pass it back to the caller.
|
||
|
|
||
|
DWORD dwType;
|
||
|
DWORD cbBuffer = cchBuffer*sizeof(TCHAR);
|
||
|
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, pszUser, &dwType, pszBuffer, &cbBuffer))
|
||
|
{
|
||
|
fResult = ((dwType == REG_SZ) && cbBuffer); // did we get a value back?
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fResult)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::_GetSharedFolders(HDPA *phItems)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
HDPA hItems = DPA_Create(16);
|
||
|
if (hItems)
|
||
|
{
|
||
|
if (!IsUserAGuest()) // all other users' my documents folders should appear in my computer for non-guest users on workgroup machines
|
||
|
{
|
||
|
ILogonEnumUsers *peu;
|
||
|
hr = SHCoCreateInstance(NULL, &CLSID_ShellLogonEnumUsers, NULL, IID_PPV_ARG(ILogonEnumUsers, &peu));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
UINT cUsers, iUser;
|
||
|
hr = peu->get_length(&cUsers);
|
||
|
for (iUser = 0; (cUsers != iUser) && SUCCEEDED(hr); iUser++)
|
||
|
{
|
||
|
VARIANT varUser = {VT_I4};
|
||
|
InitVariantFromInt(&varUser, iUser);
|
||
|
|
||
|
ILogonUser *plu;
|
||
|
hr = peu->item(varUser, &plu);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// only show document folders for users that can log in
|
||
|
VARIANT_BOOL vbLogonAllowed;
|
||
|
hr = plu->get_interactiveLogonAllowed(&vbLogonAllowed);
|
||
|
if (SUCCEEDED(hr) && (vbLogonAllowed != VARIANT_FALSE))
|
||
|
{
|
||
|
// get the user name as this is our key to to the users documents path
|
||
|
VARIANT var = {0};
|
||
|
hr = plu->get_setting(L"LoginName", &var);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
#if FILTER_CURRENT_USER
|
||
|
if (!_szCurrentUser[0])
|
||
|
{
|
||
|
DWORD cchUser = ARRAYSIZE(_szCurrentUser);
|
||
|
if (!GetUserName(_szCurrentUser, &cchUser))
|
||
|
{
|
||
|
_szCurrentUser[0] = TEXT('\0');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!_szCurrentUser[0] || (StrCmpI(var.bstrVal, _szCurrentUser) != 0))
|
||
|
{
|
||
|
HRESULT hrT = _AddIDList(hItems, SHAREDID_USER, var.bstrVal);
|
||
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrT)
|
||
|
{
|
||
|
SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, var.bstrVal);
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
HRESULT hrT = _AddIDList(hItems, SHAREDID_USER, var.bstrVal);
|
||
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hrT)
|
||
|
{
|
||
|
SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_DOCFOLDERPATH, var.bstrVal);
|
||
|
}
|
||
|
#endif
|
||
|
VariantClear(&var);
|
||
|
}
|
||
|
}
|
||
|
plu->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
peu->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_AddIDList(hItems, SHAREDID_COMMON, NULL);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
*phItems = hItems;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// parsing support allows us to pick off SharedDocuments from the root
|
||
|
// of the shell namespace and navigate there - this a canonical name
|
||
|
// that we use for binding to the shared documents folder attached
|
||
|
// to the My Computer namespace.
|
||
|
|
||
|
HRESULT CSharedDocuments::ParseDisplayName(HWND hwnd, LPBC pbc, LPTSTR pszName, ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes)
|
||
|
{
|
||
|
HRESULT hr = E_INVALIDARG;
|
||
|
if (SHShowSharedFolders())
|
||
|
{
|
||
|
if (0 == StrCmpI(pszName, L"SharedDocuments"))
|
||
|
{
|
||
|
hr = _AllocIDList(SHAREDID_COMMON, NULL, ppidl);
|
||
|
if (SUCCEEDED(hr) && pdwAttributes)
|
||
|
{
|
||
|
hr = _GetAttributesOf(*ppidl, *pdwAttributes, pdwAttributes);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// enumerate the shared documents folders
|
||
|
|
||
|
HRESULT CSharedDocuments::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
|
||
|
{
|
||
|
*ppenumIDList = NULL; // no enumerator yet
|
||
|
|
||
|
HRESULT hr = S_FALSE;
|
||
|
if (SHShowSharedFolders())
|
||
|
{
|
||
|
HDPA hItems;
|
||
|
hr = _GetSharedFolders(&hItems);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = CSharedDocsEnum_CreateInstance(hItems, grfFlags, ppenumIDList);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DPA_FreeIDArray(hItems);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// return the display name for the folders that we have
|
||
|
|
||
|
HRESULT CSharedDocuments::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
TCHAR szName[MAX_PATH] = {0};
|
||
|
|
||
|
LPCSHAREDITEM psid = (LPCSHAREDITEM)pidl;
|
||
|
if (((uFlags & (SHGDN_INFOLDER|SHGDN_FORPARSING)) == SHGDN_INFOLDER) &&
|
||
|
(psid && (psid->dwType == SHAREDID_USER)))
|
||
|
{
|
||
|
// compute the <user>'s Documents name that we will show, we key this on
|
||
|
// the user name we have in the IDList and its display string.
|
||
|
|
||
|
USER_INFO_10 *pui;
|
||
|
TCHAR szUser[MAX_PATH];
|
||
|
if (NERR_Success == NetUserGetInfo(NULL, _GetUserFromIDList(pidl, szUser, ARRAYSIZE(szUser)), 10, (LPBYTE*)&pui))
|
||
|
{
|
||
|
if (*pui->usri10_full_name)
|
||
|
{
|
||
|
StrCpyN(szUser, pui->usri10_full_name, ARRAYSIZE(szUser));
|
||
|
}
|
||
|
NetApiBufferFree(pui);
|
||
|
}
|
||
|
|
||
|
TCHAR szFmt[MAX_PATH];
|
||
|
LoadString(g_hinst, IDS_LOCALGDN_FLD_THEIRDOCUMENTS, szFmt, ARRAYSIZE(szFmt));
|
||
|
wnsprintf(szName, ARRAYSIZE(szName), szFmt, szUser);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// all other scenarios dump down to the real folder to get their display
|
||
|
// name for this folder.
|
||
|
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
hr = _GetTarget(pidl, &pidlTarget);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = SHGetNameAndFlags(pidlTarget, uFlags, szName, ARRAYSIZE(szName), NULL);
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = StringToStrRet(szName, lpName);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
LONG CSharedDocuments::_GetAttributesOf(LPCITEMIDLIST pidl, DWORD rgfIn, DWORD *prgfOut)
|
||
|
{
|
||
|
DWORD dwResult = rgfIn;
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
HRESULT hr = _GetTarget(pidl, &pidlTarget);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
LPCITEMIDLIST pidlChild;
|
||
|
hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psf->GetAttributesOf(1, &pidlChild, &dwResult);
|
||
|
psf->Release();
|
||
|
}
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
|
||
|
if (!SHShowSharedFolders())
|
||
|
dwResult |= SFGAO_NONENUMERATED;
|
||
|
|
||
|
*prgfOut = *prgfOut & (dwResult & ~(SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_CANMOVE|SFGAO_CANCOPY));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut)
|
||
|
{
|
||
|
ULONG rgfOut = *rgfInOut;
|
||
|
|
||
|
if (!cidl || !apidl)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
for (UINT i = 0; i < cidl; i++)
|
||
|
_GetAttributesOf(apidl[i], *rgfInOut, &rgfOut);
|
||
|
|
||
|
*rgfInOut = rgfOut;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// bind through our folder
|
||
|
|
||
|
HRESULT CSharedDocuments::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
if (IsEqualIID(riid, IID_IShellIconOverlay))
|
||
|
{
|
||
|
hr = this->QueryInterface(riid, ppv);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidlFirst = ILCloneFirst(pidl);
|
||
|
if (pidlFirst)
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
hr = _CreateFolder(pbc, pidlFirst, IID_PPV_ARG(IShellFolder, &psf), TRUE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
LPCITEMIDLIST pidlNext = _ILNext(pidl);
|
||
|
if (ILIsEmpty(pidlNext))
|
||
|
{
|
||
|
hr = psf->QueryInterface(riid, ppv);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = psf->BindToObject(pidlNext, pbc, riid, ppv);
|
||
|
}
|
||
|
psf->Release();
|
||
|
}
|
||
|
ILFree(pidlFirst);
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// handle UI objects - for the most part we delegate to the real namespace implementation
|
||
|
|
||
|
HRESULT CSharedDocuments::s_FolderMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdo, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
CSharedDocuments *psd;
|
||
|
psf->QueryInterface(CLSID_SharedDocuments, (void **)&psd);
|
||
|
|
||
|
// defcm will only add the default handlers (eg. Open/Explore) if we have a callback
|
||
|
// and the DFM_MERGECONTEXTMENU is successful. so lets honor that so we can navigate
|
||
|
|
||
|
if (uMsg == DFM_MERGECONTEXTMENU)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
else if (uMsg == DFM_INVOKECOMMAND)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DFMICS *pdfmics = (DFMICS *)lParam;
|
||
|
switch (wParam)
|
||
|
{
|
||
|
case DFM_CMD_LINK:
|
||
|
hr = SHCreateLinks(hwnd, NULL, pdo, SHCL_CONFIRM|SHCL_USETEMPLATE|SHCL_USEDESKTOP, NULL);
|
||
|
break;
|
||
|
|
||
|
case DFM_CMD_PROPERTIES:
|
||
|
hr = SHLaunchPropSheet(CFSFolder_PropertiesThread, pdo, (LPCTSTR)lParam, NULL, (void *)&c_idlDesktop);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
hr = S_FALSE; // use the default handler for this item
|
||
|
break;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl, REFIID riid, UINT* prgfInOut, void **ppv)
|
||
|
{
|
||
|
if (cidl != 1)
|
||
|
return E_FAIL;
|
||
|
|
||
|
HRESULT hr = E_FAIL;
|
||
|
if (IsEqualIID(riid, IID_IContextMenu))
|
||
|
{
|
||
|
// we must construct our own context menu for this item, we do this using the
|
||
|
// shell default implementation and we pass it the information about a folder
|
||
|
// that way we can navigate up and down through the namespace.
|
||
|
|
||
|
IQueryAssociations *pqa;
|
||
|
hr = GetUIObjectOf(hwnd, 1, apidl, IID_PPV_ARG_NULL(IQueryAssociations, &pqa));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// this is broken for docfiles (shell\ext\stgfldr's keys work though)
|
||
|
// maybe because GetClassFile punts when it's not fs?
|
||
|
|
||
|
HKEY ahk[MAX_ASSOC_KEYS];
|
||
|
DWORD cKeys = SHGetAssocKeys(pqa, ahk, ARRAYSIZE(ahk));
|
||
|
hr = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl, this,
|
||
|
s_FolderMenuCB,
|
||
|
cKeys, ahk,
|
||
|
(IContextMenu **)ppv);
|
||
|
SHRegCloseKeys(ahk, cKeys);
|
||
|
pqa->Release();
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IDataObject))
|
||
|
{
|
||
|
hr = SHCreateFileDataObject(_pidl, cidl, apidl, NULL, (IDataObject **)ppv);
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IQueryInfo))
|
||
|
{
|
||
|
IQueryAssociations *pqa;
|
||
|
hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
WCHAR szCLSID[GUIDSTR_MAX];
|
||
|
SHStringFromGUIDW(CLSID_SharedDocuments, szCLSID, ARRAYSIZE(szCLSID));
|
||
|
hr = pqa->Init(0, szCLSID, NULL, NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
WCHAR szInfotip[INFOTIPSIZE];
|
||
|
DWORD cchInfotip = ARRAYSIZE(szInfotip);
|
||
|
hr = pqa->GetString(0, ASSOCSTR_INFOTIP, NULL, szInfotip, &cchInfotip);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = CreateInfoTipFromText(szInfotip, IID_IQueryInfo, ppv); // _the_ InfoTip COM object
|
||
|
}
|
||
|
}
|
||
|
pqa->Release();
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IQueryAssociations))
|
||
|
{
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
hr = _GetTarget(apidl[0], &pidlTarget);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = SHGetUIObjectOf(pidlTarget, hwnd, riid, ppv);
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
|
||
|
{
|
||
|
UINT iIcon = II_FOLDER;
|
||
|
UINT iIconOpen = II_FOLDEROPEN;
|
||
|
|
||
|
TCHAR szModule[MAX_PATH];
|
||
|
GetModuleFileName(HINST_THISDLL, szModule, ARRAYSIZE(szModule));
|
||
|
|
||
|
hr = SHCreateDefExtIcon(szModule, iIcon, iIconOpen, GIL_PERCLASS, -1, riid, ppv);
|
||
|
}
|
||
|
else if (IsEqualIID(riid, IID_IDropTarget))
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
hr = _CreateFolder(NULL, *apidl, IID_PPV_ARG(IShellFolder, &psf), TRUE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psf->CreateViewObject(hwnd, riid, ppv);
|
||
|
psf->Release();
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSharedDocuments::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
|
||
|
{
|
||
|
HRESULT hr = ResultFromShort(0);
|
||
|
|
||
|
// compare the contents of our IDLIST before we attemt to compare other elements
|
||
|
// within it.
|
||
|
|
||
|
LPCSHAREDITEM psid1 = (LPCSHAREDITEM)pidl1;
|
||
|
LPCSHAREDITEM psid2 = (LPCSHAREDITEM)pidl2;
|
||
|
|
||
|
if (psid1->dwType == psid2->dwType)
|
||
|
{
|
||
|
if (psid1->dwType == SHAREDID_USER)
|
||
|
{
|
||
|
hr = ResultFromShort(ualstrcmpi(psid1->wszID, psid2->wszID));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = ResultFromShort(0); // common item == common item?
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = ResultFromShort(psid1->dwType - psid2->dwType);
|
||
|
}
|
||
|
|
||
|
// if there was an exact match then lets compare the trailing elements of the IDLIST
|
||
|
// if there are some (by binding down) etc.
|
||
|
|
||
|
if (hr == ResultFromShort(0))
|
||
|
{
|
||
|
LPITEMIDLIST pidlNext1 = _ILNext(pidl1);
|
||
|
LPITEMIDLIST pidlNext2 = _ILNext(pidl2);
|
||
|
|
||
|
if (ILIsEmpty(pidlNext1))
|
||
|
{
|
||
|
if (ILIsEmpty(pidlNext2))
|
||
|
{
|
||
|
hr = ResultFromShort(0); // pidl1 == pidl2 (in length)
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = ResultFromShort(-1); // pidl1 < pidl2 (in length)
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if IDLIST2 is shorter then return > otherwise we should just
|
||
|
// recurse down the IDLIST and let the next level compare.
|
||
|
|
||
|
if (ILIsEmpty(pidlNext2))
|
||
|
{
|
||
|
hr = ResultFromShort(+1); // pidl1 > pidl2 (in lenght)
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidlFirst = ILCloneFirst(pidl1);
|
||
|
if (pidlFirst)
|
||
|
{
|
||
|
IShellFolder *psf;
|
||
|
hr = _CreateFolder(NULL, pidlFirst, IID_PPV_ARG(IShellFolder, &psf), FALSE);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psf->CompareIDs(lParam, pidlNext1, pidlNext2);
|
||
|
psf->Release();
|
||
|
}
|
||
|
ILFree(pidlFirst);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocuments::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
if (IsEqualSCID(SCID_DESCRIPTIONID, *pscid))
|
||
|
{
|
||
|
SHDESCRIPTIONID did = {0};
|
||
|
did.dwDescriptionId = SHDID_COMPUTER_SHAREDDOCS;
|
||
|
did.clsid = CLSID_NULL;
|
||
|
hr = InitVariantFromBuffer(pv, &did, sizeof(did));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
hr = _GetTarget(pidl, &pidlTarget);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IShellFolder2 *psf2;
|
||
|
LPCITEMIDLIST pidlChild;
|
||
|
hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellFolder2, &psf2), &pidlChild);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psf2->GetDetailsEx(pidlChild, pscid, pv);
|
||
|
psf2->Release();
|
||
|
}
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// icon overlay handling. deligate this to the right handler
|
||
|
|
||
|
HRESULT CSharedDocuments::_GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex, BOOL fGetIconIndex)
|
||
|
{
|
||
|
LPITEMIDLIST pidlTarget;
|
||
|
HRESULT hr = _GetTarget(pidl, &pidlTarget);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IShellIconOverlay *psio;
|
||
|
LPCITEMIDLIST pidlChild;
|
||
|
hr = SHBindToIDListParent(pidlTarget, IID_PPV_ARG(IShellIconOverlay, &psio), &pidlChild);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (fGetIconIndex)
|
||
|
{
|
||
|
hr = psio->GetOverlayIconIndex(pidlChild, pIndex);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = psio->GetOverlayIndex(pidlChild, pIndex);
|
||
|
}
|
||
|
psio->Release();
|
||
|
}
|
||
|
ILFree(pidlTarget);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// enumerator for listing all the shared documents in the system.
|
||
|
|
||
|
class CSharedDocsEnum : public IEnumIDList
|
||
|
{
|
||
|
private:
|
||
|
LONG _cRef;
|
||
|
HDPA _hItems;
|
||
|
DWORD _grfFlags;
|
||
|
int _index;
|
||
|
|
||
|
public:
|
||
|
CSharedDocsEnum(HDPA hItems, DWORD grf);
|
||
|
~CSharedDocsEnum();
|
||
|
|
||
|
// IUnknown
|
||
|
STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
|
||
|
STDMETHOD_(ULONG, AddRef)();
|
||
|
STDMETHOD_(ULONG, Release)();
|
||
|
|
||
|
// IEnumIDList
|
||
|
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
|
||
|
STDMETHODIMP Skip(ULONG celt)
|
||
|
{ return E_NOTIMPL; }
|
||
|
STDMETHODIMP Reset()
|
||
|
{ _index = 0; return S_OK; }
|
||
|
STDMETHODIMP Clone(IEnumIDList **ppenum)
|
||
|
{ return E_NOTIMPL; };
|
||
|
|
||
|
};
|
||
|
|
||
|
CSharedDocsEnum::CSharedDocsEnum(HDPA hItems, DWORD grfFlags) :
|
||
|
_cRef(1),
|
||
|
_hItems(hItems),
|
||
|
_grfFlags(grfFlags),
|
||
|
_index(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CSharedDocsEnum::~CSharedDocsEnum()
|
||
|
{
|
||
|
DPA_FreeIDArray(_hItems);
|
||
|
}
|
||
|
|
||
|
HRESULT CSharedDocsEnum_CreateInstance(HDPA hItems, DWORD grfFlags, IEnumIDList **ppenum)
|
||
|
{
|
||
|
CSharedDocsEnum *penum = new CSharedDocsEnum(hItems, grfFlags);
|
||
|
if (!penum)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
HRESULT hr = penum->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
|
||
|
penum->Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// IUnknown handling
|
||
|
|
||
|
STDMETHODIMP CSharedDocsEnum::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] =
|
||
|
{
|
||
|
QITABENT(CSharedDocsEnum, IEnumIDList), // IID_IEnumIDList
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedDocsEnum::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedDocsEnum::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// enumeration handling
|
||
|
|
||
|
HRESULT CSharedDocsEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
|
||
|
{
|
||
|
HRESULT hr = S_FALSE;
|
||
|
ULONG cFetched = 0;
|
||
|
|
||
|
if (_grfFlags & SHCONTF_FOLDERS)
|
||
|
{
|
||
|
// if we have more items to return and the buffer is still not full
|
||
|
// then lets ensure that we return them.
|
||
|
|
||
|
while (SUCCEEDED(hr) && (celt != cFetched) && (_index != DPA_GetPtrCount(_hItems)))
|
||
|
{
|
||
|
if (_index != DPA_GetPtrCount(_hItems))
|
||
|
{
|
||
|
hr = SHILClone((LPITEMIDLIST)DPA_GetPtr(_hItems, _index), &rgelt[cFetched]);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
cFetched++;
|
||
|
}
|
||
|
}
|
||
|
_index++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pceltFetched)
|
||
|
*pceltFetched = cFetched;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// handle system initialization of the shared documents objects
|
||
|
|
||
|
void _SetLocalizedName(INT csidl, LPTSTR pszResModule, INT idsRes)
|
||
|
{
|
||
|
TCHAR szPath[MAX_PATH];
|
||
|
if (SHGetSpecialFolderPath(NULL, szPath, csidl, TRUE))
|
||
|
{
|
||
|
SHSetLocalizedName(szPath, pszResModule, idsRes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT SHGetSampleMediaFolder(int nAllUsersMediaFolder, LPITEMIDLIST *ppidlSampleMedia);
|
||
|
#define PICTURES_BUYURL L"SamplePictures"
|
||
|
#define SAMPLEMUSIC_BUYURL L"http://windowsmedia.com/redir/xpsample.asp"
|
||
|
|
||
|
STDAPI_(void) InitializeSharedDocs(BOOL fWow64)
|
||
|
{
|
||
|
// ACL the DocFolder paths key so that users can touch the keys and store their paths
|
||
|
// for the document folders they have.
|
||
|
|
||
|
// we want the "Everyone" to have read/write access
|
||
|
SHELL_USER_PERMISSION supEveryone;
|
||
|
supEveryone.susID = susEveryone;
|
||
|
supEveryone.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
|
||
|
supEveryone.dwAccessMask = KEY_READ|KEY_WRITE;
|
||
|
supEveryone.fInherit = TRUE;
|
||
|
supEveryone.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
|
||
|
supEveryone.dwInheritAccessMask = GENERIC_READ;
|
||
|
|
||
|
// we want the "SYSTEM" to have full control
|
||
|
SHELL_USER_PERMISSION supSystem;
|
||
|
supSystem.susID = susSystem;
|
||
|
supSystem.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
|
||
|
supSystem.dwAccessMask = KEY_ALL_ACCESS;
|
||
|
supSystem.fInherit = TRUE;
|
||
|
supSystem.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
|
||
|
supSystem.dwInheritAccessMask = GENERIC_ALL;
|
||
|
|
||
|
// we want the "Administrators" to have full control
|
||
|
SHELL_USER_PERMISSION supAdministrators;
|
||
|
supAdministrators.susID = susAdministrators;
|
||
|
supAdministrators.dwAccessType = ACCESS_ALLOWED_ACE_TYPE;
|
||
|
supAdministrators.dwAccessMask = KEY_ALL_ACCESS;
|
||
|
supAdministrators.fInherit = TRUE;
|
||
|
supAdministrators.dwInheritMask = (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
|
||
|
supAdministrators.dwInheritAccessMask = GENERIC_ALL;
|
||
|
|
||
|
PSHELL_USER_PERMISSION aPerms[3] = {&supEveryone, &supSystem, &supAdministrators};
|
||
|
SECURITY_DESCRIPTOR* psd = GetShellSecurityDescriptor(aPerms, ARRAYSIZE(aPerms));
|
||
|
if (psd)
|
||
|
{
|
||
|
HKEY hk;
|
||
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DocFolderPaths"), 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hk, NULL) == ERROR_SUCCESS)
|
||
|
{
|
||
|
RegSetKeySecurity(hk, DACL_SECURITY_INFORMATION, psd);
|
||
|
RegCloseKey(hk);
|
||
|
}
|
||
|
LocalFree(psd);
|
||
|
}
|
||
|
|
||
|
// do file system initialization as needed so that the shared music/pictures folders
|
||
|
// have the correct display names.
|
||
|
|
||
|
if (!fWow64)
|
||
|
{
|
||
|
_SetLocalizedName(CSIDL_COMMON_PICTURES, TEXT("shell32.dll"), IDS_SHAREDPICTURES);
|
||
|
_SetLocalizedName(CSIDL_COMMON_MUSIC, TEXT("shell32.dll"), IDS_SHAREDMUSIC);
|
||
|
|
||
|
// Set the Sample Pictures buy URL
|
||
|
LPITEMIDLIST pidl;
|
||
|
if (SUCCEEDED(SHGetSampleMediaFolder(CSIDL_COMMON_PICTURES, &pidl)))
|
||
|
{
|
||
|
WCHAR szPath[MAX_PATH];
|
||
|
WCHAR szDesktopIni[MAX_PATH];
|
||
|
if (SUCCEEDED(SHGetPathFromIDList(pidl, szPath)) && PathCombine(szDesktopIni, szPath, L"desktop.ini"))
|
||
|
{
|
||
|
WritePrivateProfileString(L".ShellClassInfo", c_BuySamplePictures.szURLKey, PICTURES_BUYURL, szDesktopIni);
|
||
|
|
||
|
// Ensure this is a system folder
|
||
|
PathMakeSystemFolder(szPath);
|
||
|
}
|
||
|
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
|
||
|
// Set the Sample Music buy URL
|
||
|
if (SUCCEEDED(SHGetSampleMediaFolder(CSIDL_COMMON_MUSIC, &pidl)))
|
||
|
{
|
||
|
WCHAR szPath[MAX_PATH];
|
||
|
WCHAR szDesktopIni[MAX_PATH];
|
||
|
if (SUCCEEDED(SHGetPathFromIDList(pidl, szPath)) && PathCombine(szDesktopIni, szPath, L"desktop.ini"))
|
||
|
{
|
||
|
WritePrivateProfileString(L".ShellClassInfo", c_BuySampleMusic.szURLKey, SAMPLEMUSIC_BUYURL, szDesktopIni);
|
||
|
|
||
|
// Ensure this is a system folder
|
||
|
PathMakeSystemFolder(szPath);
|
||
|
}
|
||
|
|
||
|
ILFree(pidl);
|
||
|
}
|
||
|
}
|
||
|
}
|