2025-11-27 16:46:48 +09:00

1578 lines
49 KiB
C++
Raw Blame History

// OXShellNamespaceNavigator.cpp : implementation file
//
// Version: 9.3
#include "stdafx.h"
#include "OXShellNamespaceNavigator.h"
#include "UTBStrOp.h"
#include <atlbase.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// COXShellNamespaceNavigator
COXShellNamespaceNavigator::COXShellNamespaceNavigator()
{
//get the shell's IMalloc pointer
//we'll keep this until we get destroyed
if(FAILED(SHGetMalloc(&m_pMalloc)))
{
AfxThrowMemoryException();
return;
}
m_pOwnerWnd=NULL;
m_lpeidl=NULL;
m_bEnumeratorInitialized=FALSE;
m_lpEnumerateFolder=NULL;
m_lpEnumerateParentFullIDL=NULL;
m_bAutoCleanUp=FALSE;
}
COXShellNamespaceNavigator::~COXShellNamespaceNavigator()
{
if(m_pMalloc)
{
if(m_bAutoCleanUp)
{
// free memory allocated for objects
POSITION pos=m_mapObjectsToFree.GetStartPosition();
while(pos!=NULL)
{
DWORD_PTR dwKey=NULL;
DWORD_PTR dwData=NULL;
m_mapObjectsToFree.GetNextAssoc(pos,dwKey,dwData);
m_pMalloc->Free((void*)dwKey);
}
}
// release IMalloc interface
m_pMalloc->Release();
}
if(m_bAutoCleanUp)
{
// release requested interfaces
POSITION pos=m_mapIShellFolderToRelease.GetStartPosition();
while(pos!=NULL)
{
DWORD_PTR dwKey=NULL;
DWORD_PTR dwData=NULL;
m_mapIShellFolderToRelease.GetNextAssoc(pos,dwKey,dwData);
((LPSHELLFOLDER)dwKey)->Release();
}
}
// release enumerator
if(m_bEnumeratorInitialized)
ReleaseObjectsEnumerator();
}
/////////////////////////////////////////////////////////////////////////////
int CALLBACK COXShellNamespaceNavigator::CompareObjectsProc(LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
UNREFERENCED_PARAMETER(lParamSort);
LPNAMESPACEOBJECT lpFolder1=(LPNAMESPACEOBJECT)lParam1;
LPNAMESPACEOBJECT lpFolder2=(LPNAMESPACEOBJECT)lParam2;
ASSERT(lpFolder1->lpsfParent==lpFolder2->lpsfParent);
// Use IShellBrowser::CompareIDs method to compare two folders.
// The first argument have to be zero.
// If this method is successful, the CODE field of the status code (SCODE)
// contains one of the following values:
// 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).
//
// If this method is unsuccessful, it returns an OLE-defined error code.
HRESULT hResult=lpFolder1->lpsfParent->
CompareIDs(0,lpFolder1->lpRelativeIDL,lpFolder2->lpRelativeIDL);
// if above method failed let's take it as items are equal
if(FAILED(hResult))
return 0;
// return CODE field of status code of result value
return (short)SCODE_CODE(GetScode(hResult));
}
/////////////////////////////////////////////////////////////////////////////
HIMAGELIST COXShellNamespaceNavigator::
GetShellImageList(BOOL bSmallIcon/*=TRUE*/) const
{
// Retrieves the handle to the system image list
// Use SHGetFileInfo function in order to do that
//
/*
WINSHELLAPI DWORD WINAPI SHGetFileInfo(
LPCTSTR pszPath,
DWORD dwFileAttributes,
SHFILEINFO FAR *psfi,
UINT cbFileInfo,
UINT uFlags
);
Retrieves information about an object in the file system, such as a file, a folder,
a directory, or a drive root.
If uFlags contains SHGFI_SYSICONINDEX, the return value is the handle to the system
image list that contains the large icon images. If SHGFI_SMALLICON is included with
SHGFI_SYSICONINDEX, the return value is the handle to the image list that contains
the small icon images.
pszPath - Address of a buffer that contains the path and file name. Both
absolute and relative paths are valid. This string can use either
short (the 8.3 form) or long file names.
dwFileAttributes- Combination of one or more file attribute flags (FILE_ATTRIBUTE_
values). If uFlags does not include the SHGFI_USEFILEATTRIBUTES
flag, this parameter is ignored.
psfi - Address of a SHFILEINFO structure to receive the file information.
cbFileInfo - Size, in bytes, of the SHFILEINFO structure pointed to by the
psfi parameter.
uFlags - Flags that specify the file information to retrieve. This
parameter can be a combination of the following values (not all
of them are listed):
SHGFI_ICON - Retrieve the handle to the icon that
represents the file and the index of the
icon within the system image list. The
handle is copied to the hIcon member of
the structure specified by psfi, and the
index is copied to the iIcon member. The
return value is the handle to the system
image list.
SHGFI_ICONLOCATION - Retrieve the name of the file that
contains the icon representing the file.
The name is copied to the szDisplayName
member of the structure specified in psfi.
SHGFI_LARGEICON - Modify SHGFI_ICON, causing the function
to retrieve the file's large icon.
SHGFI_LINKOVERLAY - Modify SHGFI_ICON, causing the function
to add the link overlay to the file's icon.
SHGFI_OPENICON - Modify SHGFI_ICON, causing the function
to retrieve the file's open icon.
A container object displays an open icon
to indicate that the container is open.
SHGFI_SELECTED - Modify SHGFI_ICON, causing the function
to blend the file's icon with the system
highlight color.
SHGFI_SHELLICONSIZE - Modify SHGFI_ICON, causing the function
to retrieve a shell-sized icon. If this
flag is not specified the function sizes
the icon according to the system metric
values.
SHGFI_SMALLICON - Modify SHGFI_ICON, causing the function
to retrieve the file's small icon.
SHGFI_SYSICONINDEX - Retrieve the index of the icon within the
system image list. The index is copied to
the iIcon member of the structure
specified by psfi. The return value is
the handle to the system image list.
*/
SHFILEINFO shfi;
// use fake path, ignore dwFileAttributes and set uFlags to retrieve
// small icons
HIMAGELIST hImageList=(HIMAGELIST)SHGetFileInfo(/*_T("C:\\")*/_T(""),0,
&shfi,sizeof(SHFILEINFO),SHGFI_SYSICONINDEX|
(bSmallIcon ? SHGFI_SMALLICON : SHGFI_LARGEICON));
return hImageList;
}
LPSHELLFOLDER COXShellNamespaceNavigator::
GetShellFolder(CString sFolderFullPath) const
{
// First of all get the Desktop's IShellFolder interface.
LPSHELLFOLDER lpDesktopFolder;
if(FAILED(SHGetDesktopFolder(&lpDesktopFolder)))
return NULL;
// If lpcsFolderFullPath is NULL then just return the Desktop's IShellFolder
if(sFolderFullPath.IsEmpty())
{
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
// Now we should try to get IShellFolder interface of the folder full path of
// which is lpcsFolderFullPath. In order to do that we use
// IShellFolder::ParseDisplayName method:
//
/*
HRESULT ParseDisplayName(
HWND hwndOwner,
LPBC pbcReserved,
LPOLESTR lpszDisplayName,
ULONG *pchEaten,
LPITEMIDLIST *ppidl,
ULONG *pdwAttributes
);
Translates a file object's or folder's display name into an item identifier list.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
hwndOwner - Handle to the owner window that the client should specify if it
displays a dialog box or message box.
pbcReserved - Reserved; this parameter is always NULL.
lpszDisplayName - Address of a null-terminated UNICODE string specifying the display
name. This parameter must be a display name for parsing<6E>that is,
a display name retrieved using the SHGDN_FORPARSING value.
pchEaten - Address of a ULONG value that receives the number of characters
of the display name that was parsed.
ppidl - Address of a pointer to the new item identifier list for the
object. If an error occurs, NULL is returned in this address.
The returned item identifier list specifies the relative path
(from the parent folder) that corresponds to the specified
display name. It contains only one SHITEMID structure followed
by a terminating zero.
pdwAttributes - Address of the attributes of the file object. Can be NULL if the
caller does not need attribute data.
*/
//
// Note that the display name should be in UNICODE and that resulting PIDL is
// relative to parent folder
//
// The MultiByteToWideChar function maps a character string to a wide-character
// (Unicode) string. The character string mapped by this function is not
// necessarily from a multibyte character set.
// Use CP_ACP as indicator of translating from ANSI code page. Refer to the
// documentation to get info on other parameters.
//
OLECHAR unicodeFolderPath[MAX_PATH];
#ifndef _UNICODE
UTBStr::mbstowcs(unicodeFolderPath,MAX_PATH,sFolderFullPath,MAX_PATH);
#else
UTBStr::tcscpy(unicodeFolderPath, MAX_PATH, sFolderFullPath);
#endif
ULONG chEaten;
LPITEMIDLIST lpidl;
ULONG dwAttributes;
HRESULT hResult=lpDesktopFolder->
ParseDisplayName(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL,
NULL,unicodeFolderPath,&chEaten,&lpidl,&dwAttributes);
if(FAILED(hResult))
{
m_pMalloc->Free(lpidl);
// just return the desktop folder
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
// After we get IDL of lpcsFolderFullPath we should retrieve its IShellFolder
// interface. We accomplish it using IShellFolder::BindToObject
//
/*
HRESULT BindToObject(
LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut
);
Retrieves an IShellFolder object for a subfolder.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
pidl - Address of an ITEMIDLIST structure that identifies the subfolder
relative to its parent folder.
pbcReserved - Reserved. Callers should specify NULL for this parameter; those
called should ignore it.
riid - Identifier of the interface to return. This parameter must point to
the IID_IShellFolder interface identifier.
ppvOut - Address that receives the interface pointer. If an error occurs,
a NULL pointer is returned in this address.
*/
//
// Note that pidl have to be relative to its parent folder but as long as we are
// going to call this method of desktop folder interface then the fully qualified
// pidl we got using ParseDisplayName method can be used.
//
LPSHELLFOLDER lpFolder;
hResult=lpDesktopFolder->
BindToObject(lpidl,0, IID_IShellFolder,(LPVOID*)&lpFolder);
m_pMalloc->Free(lpidl);
if(FAILED(hResult))
{
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
else
{
// release desktop folder
lpDesktopFolder->Release();
ASSERT(lpFolder!=NULL);
if(lpFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpFolder,NULL);
return lpFolder;
}
}
LPSHELLFOLDER COXShellNamespaceNavigator::GetShellFolder(LPCITEMIDLIST pidlFull) const
{
// First of all get the Desktop's IShellFolder interface.
LPSHELLFOLDER lpDesktopFolder;
if(FAILED(SHGetDesktopFolder(&lpDesktopFolder)))
return NULL;
// If pidlFull is NULL then just return the Desktop's IShellFolder
if(pidlFull==NULL)
{
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
// If we have valid IDL we should retrieve its IShellFolder interface. We accomplish it
// using IShellFolder::BindToObject
//
/*
HRESULT BindToObject(
LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut
);
Retrieves an IShellFolder object for a subfolder.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
pidl - Address of an ITEMIDLIST structure that identifies the subfolder
relative to its parent folder.
pbcReserved - Reserved. Callers should specify NULL for this parameter; those
called should ignore it.
riid - Identifier of the interface to return. This parameter must point to
the IID_IShellFolder interface identifier.
ppvOut - Address that receives the interface pointer. If an error occurs,
a NULL pointer is returned in this address.
*/
//
// Note that pidl have to be relative to its parent folder but as long as we are
// going to call this method of desktop folder interface then the fully qualified
// pidl we got using ParseDisplayName method can be used.
//
LPSHELLFOLDER lpFolder;
HRESULT hResult=lpDesktopFolder->
BindToObject(pidlFull,0,IID_IShellFolder,(LPVOID*)&lpFolder);
if(FAILED(hResult))
{
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
else
{
// release desktop folder
lpDesktopFolder->Release();
ASSERT(lpFolder!=NULL);
if(lpFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpFolder,NULL);
return lpFolder;
}
}
LPSHELLFOLDER COXShellNamespaceNavigator::
GetShellFolder(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL) const
{
ASSERT(lpParentFolder!=NULL);
LPSHELLFOLDER lpsf;
// We use IShellFolder::BindToObject method to get IShellFolder interface
// of expanded item. Don't forget that this interface take relative PIDL as
// an argument
HRESULT hResult=lpParentFolder->BindToObject(lpRelativeIDL,0,
IID_IShellFolder,(LPVOID*)&lpsf);
if(SUCCEEDED(hResult))
return lpsf;
else
return NULL;
}
BOOL COXShellNamespaceNavigator::
GetShellFolderFullIDL(CString sFolderFullPath,
LPITEMIDLIST* ppidlFull) const
{
ASSERT(ppidlFull!=NULL);
// If lpcsFolderFullPath is NULL then just return the Desktop's IDL which is NULL
if(sFolderFullPath.IsEmpty())
{
*ppidlFull=NULL;
return TRUE;
}
// First of all get the Desktop's IShellFolder interface.
LPSHELLFOLDER lpDesktopFolder;
if(FAILED(SHGetDesktopFolder(&lpDesktopFolder)))
return FALSE;
OLECHAR unicodeFolderPath[MAX_PATH];
#ifndef _UNICODE
UTBStr::mbstowcs(unicodeFolderPath,MAX_PATH,sFolderFullPath,MAX_PATH);
#else
UTBStr::tcscpy(unicodeFolderPath, MAX_PATH, sFolderFullPath);
#endif
LPITEMIDLIST lpidl;
ULONG chEaten;
ULONG dwAttributes;
HRESULT hResult=lpDesktopFolder->
ParseDisplayName(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL,
NULL,unicodeFolderPath,&chEaten,&lpidl,&dwAttributes);
if(FAILED(hResult))
{
lpDesktopFolder->Release();
m_pMalloc->Free(lpidl);
return FALSE;
}
*ppidlFull=CopyPIDL(lpidl);
lpDesktopFolder->Release();
m_pMalloc->Free(lpidl);
return TRUE;
}
BOOL COXShellNamespaceNavigator::
GetShellFolderRelativeIDL(const LPSHELLFOLDER lpParentFolder,
CString sFolderRelativePath,
LPITEMIDLIST* ppidlRelative) const
{
ASSERT(lpParentFolder!=NULL);
ASSERT(ppidlRelative!=NULL);
OLECHAR unicodeFolderPath[MAX_PATH];
#ifndef _UNICODE
UTBStr::mbstowcs(unicodeFolderPath,MAX_PATH,sFolderRelativePath,MAX_PATH);
#else
UTBStr::tcscpy(unicodeFolderPath, MAX_PATH, sFolderRelativePath);
#endif
LPITEMIDLIST lpidl;
ULONG chEaten;
ULONG dwAttributes;
HRESULT hResult=lpParentFolder->
ParseDisplayName(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL,
NULL,unicodeFolderPath,&chEaten,&lpidl,&dwAttributes);
if(FAILED(hResult))
{
m_pMalloc->Free(lpidl);
return FALSE;
}
*ppidlRelative=CopyPIDL(lpidl);
m_pMalloc->Free(lpidl);
return TRUE;
}
BOOL COXShellNamespaceNavigator::
InitObjectsEnumerator(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpParentFullIDL,
DWORD dwFlags/*=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|
SHCONTF_INCLUDEHIDDEN*/)
{
ASSERT(lpParentFolder!=NULL);
if(m_bEnumeratorInitialized)
{
TRACE(_T("COXShellNamespaceNavigator::InitObjectsEnumerator: folder items enumerator has already been initialized.\n"));
TRACE(_T("call COXShellNamespaceNavigator::ReleaseObjectsEnumerator() before.\n"));
return FALSE;
}
// To enumerate object within given folder we use IShellFolder::EnumObjects
// method to get a pointer to IEnumIDList interface.
//
/*
HRESULT EnumObjects(
HWND hwndOwner,
DWORD grfFlags,
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.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
hwndOwner - Handle to the owner window that the client should specify if it
displays a dialog box or message box.
grfFlags - Flags indicating which items to include in the enumeration.
SHCONTF_FOLDERS - Include items that are folders in the
enumeration.
SHCONTF_NONFOLDERS - Include items that are not folders in
the enumeration.
SHCONTF_INCLUDEHIDDEN - Include hidden items in the
enumeration.
ppenumIDList - Address that receives a pointer to the IEnumIDList interface
created by this method. If an error occurs, a NULL pointer is
returned in this address.
*/
ASSERT(m_lpeidl==NULL);
ASSERT(m_lpEnumerateFolder==NULL);
HRESULT hResult=lpParentFolder->
EnumObjects(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL,
dwFlags,&m_lpeidl);
if(FAILED(hResult))
return FALSE;
// Call IEnumIDList::Reset() method to make sure we are at the begining of
// the enumerating list
m_lpeidl->Reset();
// After we get pointer to IEnumIDList interface we can use its methods to
// retrieve information about all objects of given lpFolder
//
m_lpEnumerateFolder=lpParentFolder;
m_bEnumeratorInitialized=TRUE;
m_lpEnumerateParentFullIDL=lpParentFullIDL;
return TRUE;
}
BOOL COXShellNamespaceNavigator::ReleaseObjectsEnumerator()
{
if(!m_bEnumeratorInitialized)
{
TRACE(_T("COXShellNamespaceNavigator::ReleaseObjectsEnumerator: there is nothing to release.\n"));
return FALSE;
}
ASSERT(m_lpeidl!=NULL);
m_lpeidl->Release();
m_lpeidl=NULL;
ASSERT(m_lpEnumerateFolder!=NULL);
m_lpEnumerateFolder=NULL;
m_lpEnumerateParentFullIDL=NULL;
m_bEnumeratorInitialized=FALSE;
return TRUE;
}
LPNAMESPACEOBJECT COXShellNamespaceNavigator::
EnumerateObjectNext(BOOL& bLastReached)
{
ASSERT(m_bEnumeratorInitialized);
ASSERT(m_lpeidl!=NULL);
bLastReached=FALSE;
// Loop throught the list using IEnumIDList::Next method
/*
HRESULT Next(
ULONG celt,
LPITEMIDLIST *rgelt,
ULONG *pceltFetched
);
Retrieves the specified number of item identifiers in the enumeration sequence and
advances the current position by the number of items retrieved.
Returns NOERROR if successful, S_FALSE if there are no more items in the enumeration
sequence, or an OLE-defined error value otherwise.
celt - Specifies the number of elements in the array pointed to by the
rgelt parameter.
rgelt - Address of an array of ITEMIDLIST pointers that receives the
item identifiers. The implementation must allocate these item
identifiers using the shell's allocator (retrieved by the
SHGetMalloc function). The calling application is responsible
for freeing the item identifiers using the shell's allocator.
pceltFetched - Address of a value that receives a count of the item identifiers
actually returned in rgelt. The count can be smaller than the
value specified in the celt parameter. This parameter can be
NULL only if celt is one.
If this method returns any value other than NOERROR, no entries in the rgelt array
are valid on exit. They are all in an indeterminate state.
*/
LPITEMIDLIST lpidl;
ULONG celtFetched;
if(m_lpeidl->Next(1,&lpidl,&celtFetched)!=S_OK)
{
bLastReached=TRUE;
return NULL;
}
LPNAMESPACEOBJECT lpNameSpaceObject=
GetNameSpaceObject(m_lpEnumerateFolder,lpidl,
ConcatenatePIDLs(m_lpEnumerateParentFullIDL,lpidl));
m_pMalloc->Free(lpidl);
return lpNameSpaceObject;
}
LPNAMESPACEOBJECT COXShellNamespaceNavigator::
GetNameSpaceObject(const LPSHELLFOLDER lpsfParent,
const LPITEMIDLIST lpRelativeIDL,
const LPITEMIDLIST lpFullIDL) const
{
ASSERT(lpsfParent!=NULL);
ASSERT(lpRelativeIDL!=NULL);
// Information about currently enumerated object can be retrieved using
// IShellFolder::GetAttributesOf method
//
/*
HRESULT GetAttributesOf(
UINT cidl,
LPCITEMIDLIST *apidl,
ULONG *rgfInOut
);
Retrieves the attributes of one or more file objects or subfolders.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
cidl - Number of file objects from which to retrieve attributes.
apidl - Address of an array of pointers to ITEMIDLIST structures, each
of which uniquely identifies a file object relative to the parent
folder. Each ITEMIDLIST structure must contain exactly one
SHITEMID structure followed by a terminating zero.
rgfInOut - Address of a single ULONG value that, on entry, contains the
attributes that the caller is requesting. On exit, this value
contains the requested attributes that are common to all of the
specified objects. Note that this is the address of a single
ULONG value, not an array of ULONG values. The lists below
describe the possible flags for this parameter.
For list of flags refer to the documentation. I list here only ones we are
particular interested in:
SFGAO_HASSUBFOLDER - The specified folders have subfolders (and are, therefore,
expandable in the left pane of Windows Explorer).
SFGAO_FILESYSTEM - The specified folders or file objects are part of the
file system (that is, they are files, directories, or
root directories).
SFGAO_FILESYSANCESTOR - The specified folders contain one or more file system
folders.
SFGAO_FOLDER - The specified items are folders.
SFGAO_REMOVABLE - The specified file objects or folders are on removable
media.
SFGAO_VALIDATE - Validate cached information. The shell will validate that
the objects specified in a pidl still exist and will not
used cached information when retrieving the attributes.
If one or more of the items specified in a pidl no longer
exist, this method will return an error code. If cidl is
zero, the shell will discard all cached information for
the shell folder. This is similar to doing a refresh of
the folder.
*/
DWORD dwFilter=0xffffffff;
lpsfParent->GetAttributesOf(1,(LPCITEMIDLIST*)&lpRelativeIDL,&dwFilter);
// First of all, allocate memory for NAMESPACEOBJECT structure
// using our m_pMalloc object
LPNAMESPACEOBJECT lpNameSpaceObject=(LPNAMESPACEOBJECT)m_pMalloc->
Alloc(sizeof(NAMESPACEOBJECT));
// IMalloc::Alloc returns NULL if insufficient memory
if(lpNameSpaceObject==NULL)
return NULL;
// store parent folder's IShellFolder
lpNameSpaceObject->lpsfParent=lpsfParent;
// whenever you save a pointer to COM object don't forget to
// add reference
lpsfParent->AddRef();
// make copy of enumerated shell object relative PIDL to save
// it in NAMESPACEOBJECT structure
lpNameSpaceObject->lpRelativeIDL=CopyPIDL(lpRelativeIDL);
// Create full qualified PIDL by concatenating parent's full
// qualified PIDL lpParentFullIDL with current relative PIDL lpidl
lpNameSpaceObject->lpFullIDL=CopyPIDL(lpFullIDL);
// We save text, images (including selected) and filter flags
// for the object
lpNameSpaceObject->dwFlags=dwFilter;
// The item text is the display name of the object.
CString sDisplayName=GetDisplayName(lpsfParent,lpRelativeIDL);
if(sDisplayName.IsEmpty())
return NULL;
lstrcpy(lpNameSpaceObject->szDisplayName,(LPCTSTR)sDisplayName);
// The last thing we have to get are item's icons for normal
// and selected state. Use COXShellNamespaceNavigator::GetShellImageList
// function in order to retrieve image list of all icons used to
// display shell objects. Now we need to request item index of
// particular shell object. To accomplish this task we use
// SHGetFileInfo function (remember that we have to use fully qualified
// PIDL with that function)
//
// SHFILEINFO structure to be used with SH* functions
SHFILEINFO sfi;
// Request icon index for normal state
SHGetFileInfo((LPCTSTR)lpNameSpaceObject->lpFullIDL,0,&sfi,
sizeof(SHFILEINFO),SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON);
lpNameSpaceObject->nImageSmall=sfi.iIcon;
// Request icon index for selected state
SHGetFileInfo((LPCTSTR)lpNameSpaceObject->lpFullIDL,0,&sfi,
sizeof(SHFILEINFO),SHGFI_PIDL|SHGFI_SYSICONINDEX|
SHGFI_SMALLICON|SHGFI_OPENICON);
lpNameSpaceObject->nImageSelectedSmall=sfi.iIcon;
// Request icon index for normal state
SHGetFileInfo((LPCTSTR)lpNameSpaceObject->lpFullIDL,0,&sfi,
sizeof(SHFILEINFO),SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_LARGEICON);
lpNameSpaceObject->nImage=sfi.iIcon;
// Request icon index for selected state
SHGetFileInfo((LPCTSTR)lpNameSpaceObject->lpFullIDL,0,&sfi,
sizeof(SHFILEINFO),SHGFI_PIDL|SHGFI_SYSICONINDEX|
SHGFI_LARGEICON|SHGFI_OPENICON);
lpNameSpaceObject->nImageSelected=sfi.iIcon;
return lpNameSpaceObject;
}
HMENU COXShellNamespaceNavigator::
GetObjectContextMenu(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL, DWORD dwFlags) const
{
// We can request IContextMenu interface using
// IShellFolder::GetUIObjectOf method.
//
/*
HRESULT GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST *apidl,
REFIID riid,
UINT *prgfInOut,
LPVOID *ppvOut
);
Retrieves an OLE interface that can be used to carry out actions on the specified
file objects or folders.
Returns NOERROR if successful, E_NOINTERFACE if the interface is not supported, or an
OLE-defined error value otherwise.
hwndOwner - Handle to the owner window that the client should specify if it
displays a dialog box or message box.
cidl - Number of file objects or subfolders specified in the apidl
parameter.
apidl - Address of an array of pointers to ITEMIDLIST structures, each of
which uniquely identifies a file object or subfolder relative to
the parent folder. Each item identifier list must contain exactly
one SHITEMID structure followed by a terminating zero.
riid - Identifier of the COM interface object to return. This can be any
valid interface identifier that can be created for an item. The
most common identifiers used by the shell are listed in the
comments at the end of this reference.
prgfInOut - Reserved.
ppvOut - Address that receives the interface pointer. If an error occurs,
a NULL pointer is returned in this address.
If cidl is greater than one, the GetUIObjectOf implementation should only succeed if
it can create one object for all items specified in apidl. If the implementation
cannot create one object for all items, this method should fail.
The following are the most common interface identifiers the shell uses when
requesting an interface from this method. The list also indicates if cidl can be
greater than one for the requested interface.
Interface Identifier Allowed cidl Value
IContextMenu The cidl parameter can be greater than or equal to one.
IContextMenu2 The cidl parameter can be greater than or equal to one.
IDataObject The cidl parameter can be greater than or equal to one.
IDropTarget The cidl parameter can only be one.
IExtractIcon The cidl parameter can only be one.
IQueryInfo The cidl parameter can only be one.
*/
LPCONTEXTMENU lpcm;
HRESULT hResult=lpParentFolder->
GetUIObjectOf(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL, 1,
(const struct _ITEMIDLIST**)&(lpRelativeIDL),IID_IContextMenu,0,
(LPVOID*)&lpcm);
if(FAILED(hResult))
return NULL;
// Use IContextMenu::QueryContextMenu method to get handle to popup menu.
//
/*
HRESULT QueryContextMenu(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
);
Adds menu items to the specified menu. The menu items should be inserted in the menu
at the position specified by indexMenu, and their menu item identifiers must be
between the idCmdFirst and idCmdLast parameter values.
Returns an HRESULT structure in which, if the method is successful, the code member
contains the menu identifier of the last menu item added plus one.
hmenu - Handle to the menu. The handler should specify this handle when
adding menu items.
indexMenu - Zero-based position at which to insert the first menu item.
idCmdFirst - Minimum value that the handler can specify for a menu item identifier.
idCmdLast - Maximum value that the handler can specify for a menu item identifier.
uFlags - Optional flags specifying how the context menu can be changed. Can be
any combination of the following values:
CMF_CANRENAME - This flag is set if the calling application
supports renaming of items. A context menu
extension or drag-and-drop handler should
ignore this flag. A namespace extension should
add a rename item to the menu if applicable.
CMF_DEFAULTONLY - This flag is set when the user is activating
the default action, typically by
double-clicking. This flag provides a hint for
the context menu extension to add nothing if
it does not modify the default item in the
menu. A context menu extension or
drag-and-drop handler should not add any menu
items if this value is specified. A namespace
extension should add only the default item
(if any).
CMF_EXPLORE - This flag is set when Windows Explorer's tree
window is present. Context menu handlers
should ignore this value.
CMF_INCLUDESTATIC - This flag is set when a static menu is being
constructed. Only the browser should use this
flag. All other context menu extensions should
ignore this flag.
CMF_NODEFAULT - This flag is set if no item in the menu should
be the default item. A context menu extension
or drag-and-drop handler should ignore this
flag. A namespace extension should not set
any of the menu items to the default.
CMF_NORMAL - Indicates normal operation. A context menu
extension, namespace extension, or
drag-and-drop handler can add all menu items.
CMF_NOVERBS - This flag is set for items displayed in the
"Send To:" menu. Context menu handlers should
ignore this value.
CMF_VERBSONLY - This flag is set if the context menu is for a
shortcut object. Context menu handlers should
ignore this value.
The remaining bits of the low-order word are reserved by the system. The high-order
word may be used for context-specific communications. The CMF_RESERVED value can be
used to mask out the low-order word.
The actual identifier of each menu item should be idCmdFirst plus a menu identifier
offset in the range zero through (idCmdLast ... idCmdFirst).
*/
//
// Create popup menu and populate it using above described method
HMENU hMenu=::CreatePopupMenu();
if(hMenu==NULL)
{
TRACE(_T("COXShellNamespaceNavigator::GetObjectContextMenu: CreatePopupMenu() failed\n"));
return NULL;
}
hResult=lpcm->QueryContextMenu(hMenu,0,1,0x7fff,dwFlags);
if(FAILED(hResult))
{
TRACE(_T("COXShellNamespaceNavigator::GetObjectContextMenu: QueryContextMenu() failed\n"));
return NULL;
}
lpcm->Release();
return hMenu;
}
BOOL COXShellNamespaceNavigator::InvokeCommand(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL,
UINT nCmdID, DWORD dwFlags) const
{
// If any command from popup menu was selected then it should be
// applied to corresponding shell object.
// So we have to fill CMINVOKECOMMANDINFO structure
CMINVOKECOMMANDINFO cmici={ sizeof(CMINVOKECOMMANDINFO) };
cmici.fMask=0;
cmici.hwnd=m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL;
cmici.lpVerb=LPCSTR((UINT_PTR)nCmdID-1);
cmici.lpParameters=NULL;
cmici.lpDirectory=NULL;
cmici.nShow=SW_SHOWNORMAL;
cmici.dwHotKey=0;
cmici.hIcon=NULL;
// We can request IContextMenu interface using
// IShellFolder::GetUIObjectOf method.
//
/*
HRESULT GetUIObjectOf(
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST *apidl,
REFIID riid,
UINT *prgfInOut,
LPVOID *ppvOut
);
Retrieves an OLE interface that can be used to carry out actions on the specified
file objects or folders.
Returns NOERROR if successful, E_NOINTERFACE if the interface is not supported, or an
OLE-defined error value otherwise.
hwndOwner - Handle to the owner window that the client should specify if it
displays a dialog box or message box.
cidl - Number of file objects or subfolders specified in the apidl
parameter.
apidl - Address of an array of pointers to ITEMIDLIST structures, each of
which uniquely identifies a file object or subfolder relative to
the parent folder. Each item identifier list must contain exactly
one SHITEMID structure followed by a terminating zero.
riid - Identifier of the COM interface object to return. This can be any
valid interface identifier that can be created for an item. The
most common identifiers used by the shell are listed in the
comments at the end of this reference.
prgfInOut - Reserved.
ppvOut - Address that receives the interface pointer. If an error occurs,
a NULL pointer is returned in this address.
If cidl is greater than one, the GetUIObjectOf implementation should only succeed if
it can create one object for all items specified in apidl. If the implementation
cannot create one object for all items, this method should fail.
The following are the most common interface identifiers the shell uses when
requesting an interface from this method. The list also indicates if cidl can be
greater than one for the requested interface.
Interface Identifier Allowed cidl Value
IContextMenu The cidl parameter can be greater than or equal to one.
IContextMenu2 The cidl parameter can be greater than or equal to one.
IDataObject The cidl parameter can be greater than or equal to one.
IDropTarget The cidl parameter can only be one.
IExtractIcon The cidl parameter can only be one.
IQueryInfo The cidl parameter can only be one.
*/
LPCONTEXTMENU lpcm;
HRESULT hResult=lpParentFolder->
GetUIObjectOf(m_pOwnerWnd!=NULL ? m_pOwnerWnd->GetSafeHwnd() : NULL, 1,
(const struct _ITEMIDLIST**)&(lpRelativeIDL), IID_IContextMenu, 0,
(LPVOID*)&lpcm);
if(FAILED(hResult))
return FALSE;
// In order to apply specified command we use
// IContextMenu::InvokeCommand() method.
/*
HRESULT InvokeCommand(
LPCMINVOKECOMMANDINFO lpici
);
Carries out the command associated with a context menu item.
Returns NOERROR if successful, or an OLE-defined error code otherwise.
lpici - Address of a CMINVOKECOMMANDINFO structure containing information about
the command.
typedef struct _CMInvokeCommandInfo{
DWORD cbSize;
DWORD fMask;
HWND hwnd;
LPCSTR lpVerb;
LPCSTR lpParameters;
LPCSTR lpDirectory;
int nShow;
DWORD dwHotKey;
HANDLE hIcon;
} CMINVOKECOMMANDINFO, *LPCMINVOKECOMMANDINFO;
Contains information about a context menu command.
cbSize - Contains the size of this structure, in bytes.
fMask - Zero, or one or more of the following flags:
CMIC_MASK_HOTKEY - The dwHotKey member is valid.
CMIC_MASK_ICON - The hIcon member is valid.
CMIC_MASK_FLAG_NO_UI- The system is prevented from
displaying user interface
elements (for example, error
messages) while carrying out
a command.
hwnd - Handle of the window that is the owner of the context
menu. An extension can also use this handle as the
owner of any message boxes or dialog boxes it displays.
lpVerb - A 32-bit value that contains zero in the high-order
word and a menu-identifier offset of the command to
carry out in the low-order word. The shell specifies
this value (using the MAKEINTRESOURCE macro) when the
user chooses a menu command. If the high-order word
is not zero, this member is the address of a
null-terminated string specifying the
language-independent name of the command to carry out.
This member is typically a string when a command is
being activated by an application. The system provides
predefined constant values for the following command
strings.
Value String
CMDSTR_NEWFOLDER "NewFolder"
CMDSTR_VIEWDETAILS "ViewDetails"
CMDSTR_VIEWLIST "ViewList"
lpParameters - Optional parameters. This member is always NULL for
menu items inserted by a shell extension.
lpDirectory - Optional working directory name. This member is always
NULL for menu items inserted by a shell extension.
nShow - Set of SW_ values to pass to the ShowWindow function
if the command displays a window or starts an
application.
dwHotKey - Optional hot key to assign to any application
activated by the command. If the fMask parameter does
not specify CMIC_MASK_HOTKEY, this member is ignored.
hIcon - Icon to use for any application activated by the
command. If the fMask member does not specify
CMIC_MASK_ICON, this member is ignored.
The shell calls this method when the user chooses a command that the handler added
to a context menu. This method may also be called by an application without any
corresponding user action.
*/
HMENU hMenu=::CreatePopupMenu();
if(hMenu==NULL)
{
TRACE(_T("COXShellNamespaceNavigator::GetObjectContextMenu: CreatePopupMenu() failed\n"));
return NULL;
}
hResult=lpcm->QueryContextMenu(hMenu,0,1,0x7fff,dwFlags);
if(FAILED(hResult))
{
TRACE(_T("COXShellNamespaceNavigator::GetObjectContextMenu: QueryContextMenu() failed\n"));
::DestroyMenu(hMenu);
return NULL;
}
hResult=lpcm->InvokeCommand(&cmici);
::DestroyMenu(hMenu);
lpcm->Release();
if(FAILED(hResult))
{
TRACE(_T("COXShellNamespaceNavigator::InvokeCommand: InvokeCommand() failed\n"));
return FALSE;
}
return TRUE;
}
BOOL COXShellNamespaceNavigator::InvokeDefaultCommand(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL) const
{
// retrieve the default command ID
HMENU hMenu=GetObjectContextMenu(lpParentFolder,lpRelativeIDL,CMF_DEFAULTONLY);
if(hMenu==NULL)
{
TRACE(_T("COXShellNamespaceNavigator::InvokeDefaultCommand: GetObjectContextMenu() failed\n"));
return FALSE;
}
CMenu menuPopup;
VERIFY(menuPopup.Attach(hMenu));
if(menuPopup.GetMenuItemCount()==0)
{
TRACE(_T("COXShellNamespaceNavigator::InvokeDefaultCommand: there is no context menu for the specified object\n"));
return FALSE;
}
int nDefaultCmdID=-1;
#if _MFC_VER > 0x0421
nDefaultCmdID=menuPopup.GetDefaultItem(GMDI_GOINTOPOPUPS,FALSE);
#else
nDefaultCmdID=::GetMenuDefaultItem(menuPopup.GetSafeHmenu(),
FALSE,GMDI_GOINTOPOPUPS);
#endif
if(nDefaultCmdID==-1)
{
TRACE(_T("COXShellNamespaceNavigator::InvokeDefaultCommand: there is no default menu item for the specified object\n"));
return FALSE;
}
VERIFY(menuPopup.DestroyMenu());
return InvokeCommand(lpParentFolder,lpRelativeIDL,nDefaultCmdID,CMF_DEFAULTONLY);
}
CString COXShellNamespaceNavigator::GetDisplayName(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL) const
{
ASSERT(lpParentFolder!=NULL);
// To get the display name we
// can use IShellFolder::GetDisplayNameOf method.
/*
HRESULT GetDisplayNameOf(
LPCITEMIDLIST pidl,
DWORD uFlags,
LPSTRRET lpName
);
Retrieves the display name for the specified file object or subfolder, returning it
in a STRRET structure.
Returns NOERROR if successful, or an OLE-defined error value otherwise.
pidl - Address of an ITEMIDLIST structure that uniquely identifies the file
object or subfolder relative to the parent folder.
uFlags - Flags indicating the type of display name to return. This enumeration
consists of two sets of values. The first set is contained in bits 0
through 7 and specifies if the name is relative to this folder or if the
name is a full name. The following are valid values in this set:
SHGDN_NORMAL - Name is a full name. That is, the name is
relative to the desktop and not to any
specific folder.
SHGDN_INFOLDER - Name is relative to the folder that is
processing the name.
The second set of values is contained in bits 8 through 15. These values
are modifiers to the first set and specify the name retrieval options.
The following are valid values in this set:
SHGDN_NORMAL - Name will be used for generic display.
SHGDN_FORADDRESSBAR - Name will be used for display in the address
bar combo box.
SHGDN_FORPARSING - Name will be used for parsing. That is, it can
be passed to ParseDisplayName.
SHGDN_INCLUDE_NONFILESYS- If this flag is set, the calling application
is interested in names of any types of items.
If this flag is not set, the calling
application is only interested in items that
are part of the file system. If this flag is
not set and the item is not part of the file
system, this method should fail.
lpName - Address of a STRRET structure in which to return the display name. The
string returned in this structure depends on the type of display name
requested.
If the identifier 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.
*/
//
// Note that result display name could be in different
// character set so we have to convert it.
STRRET strRet;
HRESULT hResult=lpParentFolder->
GetDisplayNameOf(lpRelativeIDL,SHGDN_NORMAL,&strRet);
if(FAILED(hResult))
{
return _T("");
}
TCHAR szDisplayName[MAX_PATH];
// buffer for getting display name of shell object
switch (strRet.uType)
{
#ifndef _UNICODE
case STRRET_WSTR:
{
WideCharToMultiByte(CP_ACP,0,strRet.pOleStr,-1,
szDisplayName,MAX_PATH,NULL,NULL);
break;
}
case STRRET_OFFSET:
{
lstrcpy(szDisplayName,(char*)lpRelativeIDL+
strRet.uOffset);
break;
}
case STRRET_CSTR:
{
lstrcpy(szDisplayName,strRet.cStr);
break;
}
#else
case STRRET_WSTR:
{
lstrcpyn(szDisplayName,strRet.pOleStr,MAX_PATH);
break;
}
case STRRET_OFFSET:
{
_mbstowcsz(szDisplayName,(char*)lpRelativeIDL+
strRet.uOffset,MAX_PATH);
break;
}
case STRRET_CSTR:
{
_mbstowcsz(szDisplayName,strRet.cStr,MAX_PATH);
break;
}
#endif
default:
{
ASSERT(FALSE);
break;
}
}
CString sResult=szDisplayName;
return sResult;
}
////////////////////////////////////////////////////////////////////////////
/*
LPITEMIDLIST COXShellNamespaceNavigator::ConcatenatePIDLs(const LPCITEMIDLIST pidl1,
const LPCITEMIDLIST pidl2) const
{
LPITEMIDLIST pidlNew;
UINT cb1, cb2;
cb1=cb2=0;
//are both of these NULL?
if(!pidl1 && !pidl2)
return NULL;
//if pidl1 is NULL, just return a copy of pidl2
if(!pidl1)
{
pidlNew=CopyPIDL(pidl2);
return pidlNew;
}
//if pidl2 is NULL, just return a copy of pidl1
if(!pidl2)
{
pidlNew=CopyPIDL(pidl1);
return pidlNew;
}
cb1=GetIDLSize(pidl1)-sizeof(ITEMIDLIST);
cb2=GetIDLSize(pidl2);
//create the new PIDL
pidlNew=(LPITEMIDLIST)m_pMalloc->Alloc(cb1+cb2);
if(pidlNew)
{
//copy the first PIDL
CopyMemory(pidlNew,pidl1,cb1);
//copy the second PIDL
CopyMemory(((LPBYTE)pidlNew)+cb1,pidl2,cb2);
}
return pidlNew;
}
UINT COXShellNamespaceNavigator::GetIDLSize(const LPCITEMIDLIST pidl) const
{
UINT cbTotal=0;
LPITEMIDLIST pidlTemp=(LPITEMIDLIST)pidl;
while(pidlTemp)
{
cbTotal+=pidlTemp->mkid.cb;
pidlTemp=GetNextIDLItem(pidlTemp);
}
//add the size of the NULL terminating ITEMIDLIST
cbTotal+=sizeof(ITEMIDLIST);
return (cbTotal);
}
*/
LPITEMIDLIST COXShellNamespaceNavigator::ConcatenatePIDLs(LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2) const
{
LPITEMIDLIST pidlNew;
UINT cb1, cb2;
cb1=cb2=0;
//are both of these NULL?
if(!pidl1 && !pidl2)
return NULL;
//if pidl1 is NULL, just return a copy of pidl2
if(!pidl1)
{
pidlNew=CopyPIDL(pidl2);
return pidlNew;
}
//if pidl2 is NULL, just return a copy of pidl1
if(!pidl2)
{
pidlNew=CopyPIDL(pidl1);
return pidlNew;
}
cb1=GetIDLSize(pidl1)-sizeof(pidl1->mkid.cb);
cb2=GetIDLSize(pidl2);
//create the new PIDL
pidlNew=(LPITEMIDLIST)m_pMalloc->Alloc(cb1+cb2);
if(pidlNew)
{
//copy the first PIDL
CopyMemory(pidlNew,pidl1,cb1);
//copy the second PIDL
CopyMemory(((LPBYTE)pidlNew)+cb1,pidl2,cb2);
}
return pidlNew;
}
UINT COXShellNamespaceNavigator::GetIDLSize(LPCITEMIDLIST pidl) const
{
UINT cbTotal=0;
LPITEMIDLIST pidlTemp=(LPITEMIDLIST)pidl;
if(pidlTemp!=NULL)
{
// add the size of the NULL terminating mkid.cb - !!!!2 bytes!!!!
cbTotal += sizeof(pidlTemp->mkid.cb);
while(pidlTemp && pidlTemp->mkid.cb)
{
cbTotal += pidlTemp->mkid.cb;
pidlTemp = GetNextIDLItem(pidlTemp);
}
}
return cbTotal;
}
LPITEMIDLIST COXShellNamespaceNavigator::CopyPIDL(LPCITEMIDLIST pidlSource) const
{
LPITEMIDLIST pidlTarget=NULL;
UINT cbSource=0;
if(NULL==pidlSource)
return (NULL);
// Allocate the new pidl
cbSource=GetIDLSize(pidlSource);
pidlTarget=(LPITEMIDLIST)m_pMalloc->Alloc(cbSource);
if(!pidlTarget)
return (NULL);
// Copy the source to the target
CopyMemory(pidlTarget,pidlSource,cbSource);
return pidlTarget;
}
LPITEMIDLIST COXShellNamespaceNavigator::GetNextIDLItem(LPCITEMIDLIST pidl) const
{
if(pidl && pidl->mkid.cb!=0)
{
LPITEMIDLIST pidlNext=(LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) +
pidl->mkid.cb);
if(pidlNext->mkid.cb==0)
return NULL;
else
return pidlNext;
}
else
return (NULL);
}
void COXShellNamespaceNavigator::FreeShellObject(void* pVoid) const
{
ASSERT(m_pMalloc!=NULL);
m_pMalloc->Free(pVoid);
}
CString COXShellNamespaceNavigator::GetSpecialFolderPath(int nFolder,
CWnd* pWndOwner/*=NULL*/) const
{
CString sPath(_T(""));
LPITEMIDLIST lpFullIDL;
if(FAILED(SHGetSpecialFolderLocation(
pWndOwner==NULL ? NULL : pWndOwner->GetSafeHwnd(),nFolder,&lpFullIDL)))
{
return sPath;
}
TCHAR buffer[MAX_PATH];
if(SHGetPathFromIDList(lpFullIDL,buffer))
{
sPath=(LPCTSTR)buffer;
}
m_pMalloc->Free(lpFullIDL);
return sPath;
}
BOOL COXShellNamespaceNavigator::RenameShellObject(const LPSHELLFOLDER lpParentFolder,
const LPITEMIDLIST lpRelativeIDL,
LPITEMIDLIST* lppNewRelativeIDL,
LPCTSTR lpszNewName) const
{
ASSERT(lpParentFolder!=NULL);
ASSERT(lpRelativeIDL!=NULL);
ASSERT(lppNewRelativeIDL!=NULL);
OLECHAR unicodeNewName[MAX_PATH];
#ifndef _UNICODE
UTBStr::mbstowcs(unicodeNewName,MAX_PATH,lpszNewName,MAX_PATH);
#else
UTBStr::tcscpy(unicodeNewName, MAX_PATH, lpszNewName);
#endif
if(FAILED(lpParentFolder->
SetNameOf((m_pOwnerWnd==NULL ? NULL : m_pOwnerWnd->GetSafeHwnd()),
lpRelativeIDL,unicodeNewName,SHGDN_INFOLDER/*|SHGDN_INCLUDE_NONFILESYS*/,
lppNewRelativeIDL)))
{
TRACE(_T("COXShellNamespaceNavigator::RenameShellObject: failed to set new name for the specified object\n"));
return FALSE;
}
ASSERT(*lppNewRelativeIDL!=NULL);
return TRUE;
}
LPSHELLFOLDER COXShellNamespaceNavigator::
GetParentShellFolder(LPCITEMIDLIST pidlFull, LPITEMIDLIST* lppRelativeIDL) const
{
ASSERT(lppRelativeIDL!=NULL);
if(pidlFull==NULL)
{
// Retrieve the Desktop's IShellFolder interface.
LPSHELLFOLDER lpDesktopFolder;
if(FAILED(SHGetDesktopFolder(&lpDesktopFolder)))
return NULL;
ASSERT(lpDesktopFolder!=NULL);
if(lpDesktopFolder!=NULL)
m_mapIShellFolderToRelease.SetAt((DWORD_PTR)lpDesktopFolder,NULL);
return lpDesktopFolder;
}
UINT cbTotal=0;
LPITEMIDLIST pidlTemp=(LPITEMIDLIST)pidlFull;
// add the size of the NULL terminating mkid.cb - !!!!2 bytes!!!!
cbTotal+=sizeof(pidlTemp->mkid.cb);
while(pidlTemp && pidlTemp->mkid.cb)
{
LPITEMIDLIST pidlLast=pidlTemp;
UINT cb=pidlTemp->mkid.cb;
cbTotal+=cb;
pidlTemp=GetNextIDLItem(pidlTemp);
if(pidlTemp==NULL)
{
cbTotal-=cb;
*lppRelativeIDL=CopyPIDL(pidlLast);
}
}
LPITEMIDLIST pidlTarget=(LPITEMIDLIST)m_pMalloc->Alloc(cbTotal);
if(!pidlTarget)
return (NULL);
::memset(pidlTarget,0,cbTotal);
// Copy the source to the target
CopyMemory(pidlTarget,(LPITEMIDLIST)pidlFull,cbTotal-sizeof(pidlTemp->mkid.cb));
LPSHELLFOLDER pShellFolder=GetShellFolder(pidlTarget);
m_pMalloc->Free(pidlTarget);
return pShellFolder;
}