|
|
/*++
Implements IShellFolder.
IUnknown IPersist IPersistFolder IShellFolder IExtractIcon
Soon:
IContextMenu IDataObject IShellPropSheetExt ?
--*/
#include <windows.h>
#include <shlobj.h>
#include <docobj.h> // IOleCommandTarget
#include "pstore.h"
#include "enumid.h"
#include "utility.h"
#include "shfolder.h"
#include "shview.h"
#include "icon.h" // icon handling
#include "guid.h"
#include "resource.h"
extern HINSTANCE g_hInst; extern LONG g_DllRefCount;
CShellFolder::CShellFolder( CShellFolder *pParent, LPCITEMIDLIST pidl ) {
m_pSFParent = pParent; if(m_pSFParent) { m_pSFParent->AddRef(); }
//
// get the shell's IMalloc pointer
// we'll keep this until we get destroyed
//
if(FAILED(SHGetMalloc(&m_pMalloc))) delete this;
//
// make a copy of the pidl in it's entirety. We do this so we are free
// to look at the pidl later.
//
m_pidl = CopyPidl(m_pMalloc, pidl);
m_ObjRefCount = 1; InterlockedIncrement(&g_DllRefCount); }
CShellFolder::~CShellFolder() { if(m_pSFParent) m_pSFParent->Release();
if(m_pidl) m_pMalloc->Free(m_pidl);
if(m_pMalloc) m_pMalloc->Release();
InterlockedDecrement(&g_DllRefCount); }
STDMETHODIMP CShellFolder::QueryInterface( REFIID riid, LPVOID *ppReturn ) { *ppReturn = NULL;
if(IsEqualIID(riid, IID_IUnknown)) *ppReturn = (IUnknown*)(IShellFolder*)this; else if(IsEqualIID(riid, IID_IPersistFolder)) *ppReturn = (IPersistFolder*)(CShellFolder*)this; else if(IsEqualIID(riid, IID_IShellFolder)) *ppReturn = (CShellFolder*)this;
if(*ppReturn == NULL) return E_NOINTERFACE;
(*(LPUNKNOWN*)ppReturn)->AddRef(); return S_OK; }
STDMETHODIMP_(DWORD) CShellFolder::AddRef() { return InterlockedIncrement(&m_ObjRefCount); }
STDMETHODIMP_(DWORD) CShellFolder::Release() { LONG lDecremented = InterlockedDecrement(&m_ObjRefCount);
if(lDecremented == 0) delete this;
return lDecremented; }
STDMETHODIMP CShellFolder::GetClassID( LPCLSID lpClassID ) /*++
IPersist::GetClassID
--*/ { *lpClassID = CLSID_PStoreNameSpace;
return S_OK; }
STDMETHODIMP CShellFolder::Initialize( LPCITEMIDLIST pidl ) /*++
IPersistFolder::Initialize
--*/ { return S_OK; }
STDMETHODIMP CShellFolder::BindToObject( LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut ) /*++
Creates an IShellFolder object for a subfolder.
--*/ { CShellFolder *pShellFolder;
pShellFolder = new CShellFolder(this, pidl); if(pShellFolder == NULL) return E_OUTOFMEMORY;
HRESULT hr = pShellFolder->QueryInterface(riid, ppvOut);
pShellFolder->Release();
return hr; }
STDMETHODIMP CShellFolder::CompareIDs( LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2 ) /*++
Determines the relative ordering of two file objects or folders, given their item identifier lists.
Returns a handle to a result code. If this method is successful, the CODE field of the status code (SCODE) has the following meaning:
Less than zero The first item should precede the second (pidl1 < pidl2). Greater than zero The first item should follow the second (pidl1 > pidl2) Zero The two items are the same (pidl1 = pidl2).
Passing 0 as the lParam indicates sort by name. 0x00000001-0x7fffffff are for folder specific sorting rules. 0x80000000-0xfffffff are used by the system.
--*/ { LPCWSTR szString1; LPCWSTR szString2; DWORD cbLength1; DWORD cbLength2; DWORD dwCompare;
//
// compare strings first, then GUID if equality is encountered
// this is important because we do not want to return a value indicating
// equality based on display string only; we also want to account for the
// GUID associated with the display name, since we can have multiple GUIDs
// with the same display name. If we just compared the string values,
// the shell would not display all types/subtypes.
//
szString1 = GetPidlText(pidl1); szString2 = GetPidlText(pidl2);
cbLength1 = lstrlenW(szString1) ; cbLength2 = lstrlenW(szString2) ;
//
// check via shortest length string
//
if(cbLength2 < cbLength1) cbLength1 = cbLength2;
cbLength1 *= sizeof(WCHAR);
dwCompare = memcmp(szString1, szString2, cbLength1);
if(dwCompare == 0) { GUID *guid1; GUID *guid2;
//
// now compare the GUIDs.
//
guid1 = GetPidlGuid(pidl1); guid2 = GetPidlGuid(pidl2);
dwCompare = memcmp(guid1, guid2, sizeof(GUID)); }
//
// still equal? sort by PST_KEY_CURRENT_USER, then PST_KEY_LOCAL_MACHINE
//
if(dwCompare == 0) { dwCompare = GetPidlKeyType(pidl1) - GetPidlKeyType(pidl2); }
return ResultFromDWORD(dwCompare); }
STDMETHODIMP CShellFolder::CreateViewObject( HWND hwndOwner, REFIID riid, LPVOID *ppvOut ) /*++
CreateViewWindow creates a view window. This can be either the right pane of the Explorer or the client window of a folder window.
--*/ { HRESULT hr; CShellView *pShellView;
pShellView = new CShellView(this, m_pidl); if(pShellView == NULL) return E_OUTOFMEMORY;
hr = pShellView->QueryInterface(riid, ppvOut);
pShellView->Release();
return hr; }
STDMETHODIMP CShellFolder::EnumObjects( HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList ) /*++
Determines the contents of a folder by creating an item enumeration object (a set of item identifiers) that can be retrieved using the IEnumIDList interface.
--*/ { *ppEnumIDList = new CEnumIDList(m_pidl, FALSE); if(*ppEnumIDList == NULL) return E_FAIL;
return NOERROR; }
STDMETHODIMP CShellFolder::GetAttributesOf( UINT uCount, LPCITEMIDLIST aPidls[], ULONG *pulAttribs ) /*++
Retrieves the attributes of one or more file objects or subfolders.
Builds a ULONG value that specifies the common (logically AND'ed) attributes of specified file objects, which is supplied to the caller via the pdwAttribs parameter.
--*/ { UINT i;
*pulAttribs = (ULONG)-1; // assume all in common initially
for(i = 0; i < uCount; i++) { DWORD dwSubFolder = SFGAO_CANDELETE | SFGAO_HASPROPSHEET;
if(HasSubFolders(aPidls[i])) dwSubFolder |= SFGAO_HASSUBFOLDER;
*pulAttribs &= (SFGAO_FOLDER | dwSubFolder); }
return NOERROR; }
BOOL CShellFolder::HasSubFolders( LPCITEMIDLIST pidl ) /*++
This function is used to test if the specified pidl has subfolders.
The combination of this->m_pidl and the supplied pidl can be used to make this determination.
--*/ { //
// If we are at the subtype level, then no subfolders exist
//
if(GetPidlType(pidl) >= PIDL_TYPE_SUBTYPE) return FALSE;
//
// TODO: is there anyway to check if the root has subfolders?
// m_pidl == NULL or pidl == NULL ???
// then try to enum providers.
//
//
// make a fully qualified (absolute) pidl out of m_pidl and pidl,
// then call the enum interface to see if subfolders exist.
//
LPITEMIDLIST pidlNew = CopyCatPidl(m_pidl, pidl); if(pidlNew == NULL) return FALSE;
BOOL bSubfolder = FALSE;
LPENUMIDLIST pEnumIDList = new CEnumIDList(pidlNew, FALSE); if(pEnumIDList != NULL) {
ULONG ulFetched; LPITEMIDLIST pidl = NULL;
if( NOERROR == pEnumIDList->Next(1, &pidl, &ulFetched) && ulFetched == 1) { FreePidl(pidl); bSubfolder = TRUE; }
pEnumIDList->Release(); }
FreePidl(pidlNew);
return bSubfolder; }
STDMETHODIMP CShellFolder::GetDisplayNameOf( LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET lpName ) /*++
Retrieves the display name for the specified file object or subfolder, returning it in a STRRET structure.
If the ID contains the display name (in the local character set), it returns the offset to the name. If not, it returns a pointer to the display name string (UNICODE) allocated by the task allocator, or it fills in a buffer. The type of string returned depends on the type of display specified.
Values identifying different types of display names are contained in the enumeration SHGNO.
--*/ { switch(dwFlags) { case SHGDN_NORMAL: case SHGDN_INFOLDER: case SHGDN_FORPARSING: { LPCWSTR szDisplay; DWORD cbDisplay; LPWSTR pOleStr;
szDisplay = GetPidlText(pidl); cbDisplay = (lstrlenW(szDisplay) + 1) * sizeof(WCHAR);
pOleStr = (LPWSTR)CoTaskMemAlloc(cbDisplay); if(pOleStr == NULL) return E_OUTOFMEMORY;
CopyMemory(pOleStr, szDisplay, cbDisplay);
lpName->uType = STRRET_WSTR; lpName->pOleStr = pOleStr;
return NOERROR; }
default: return E_INVALIDARG; } }
BOOL CShellFolder::GetPidlFullText( LPCITEMIDLIST pidl, LPTSTR lpszOut, DWORD dwOutSize ) /*++
This function returns a string containing the full-text associated with the supplied pidl. The full text will consist of a "full path" string, similiar to a fully qualified directory entry.
--*/ {
return FALSE; }
STDMETHODIMP CShellFolder::BindToStorage( LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut ) /*++
...Reserved for a future use. This method should return E_NOTIMPL. ...
--*/ { return E_NOTIMPL; }
STDMETHODIMP CShellFolder::GetUIObjectOf( HWND hwndOwner, UINT cidl, LPCITEMIDLIST *pPidl, REFIID riid, LPUINT puReserved, LPVOID *ppvReturn ) /*++
Creates a COM object that can be used to carry out actions on the specified file objects or folders, typically, to create context menus or carry out drag-and-drop operations.
--*/ { *ppvReturn = NULL;
if(IsEqualIID(riid, IID_IExtractIcon)) { if(cidl != 1) return E_INVALIDARG; *ppvReturn = (IExtractIcon*)( new CExtractIcon( pPidl[0] ) ); } else if(IsEqualIID(riid, IID_IContextMenu)) { if(cidl == 0) return E_INVALIDARG; } else if(IsEqualIID(riid, IID_IDataObject)) { if(cidl == 0) return E_INVALIDARG; }
if(*ppvReturn == NULL) return E_NOINTERFACE;
(*(LPUNKNOWN*)ppvReturn)->AddRef(); return NOERROR; }
STDMETHODIMP CShellFolder::ParseDisplayName( HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpDisplayName, LPDWORD pdwEaten, LPITEMIDLIST *pPidlNew, LPDWORD pdwAttributes ) { return E_NOTIMPL; }
STDMETHODIMP CShellFolder::SetNameOf( HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dw, LPITEMIDLIST *pPidlOut ) { return E_NOTIMPL; }
|