📄 shelltree.cpp
字号:
/****************************************************************************
*
* FUNCTION: CreatePidl(UINT cbSize)
*
* PURPOSE: Allocates a PIDL
*
****************************************************************************/
LPITEMIDLIST CShellTree::CreatePidl(UINT cbSize)
{
LPMALLOC lpMalloc;
HRESULT hr;
LPITEMIDLIST pidl=NULL;
hr=SHGetMalloc(&lpMalloc);
if (FAILED(hr))
return 0;
pidl=(LPITEMIDLIST)lpMalloc->Alloc(cbSize);
if (pidl)
memset(pidl, 0, cbSize); // zero-init for external task alloc
if (lpMalloc) lpMalloc->Release();
return pidl;
}
/****************************************************************************
*
* FUNCTION: ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
*
* PURPOSE: Concatenates two PIDLs
*
****************************************************************************/
LPITEMIDLIST CShellTree::ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
LPITEMIDLIST pidlNew;
UINT cb1;
UINT cb2;
if (pidl1) //May be NULL
cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
else
cb1 = 0;
cb2 = GetSize(pidl2);
pidlNew = CreatePidl(cb1 + cb2);
if (pidlNew)
{
if (pidl1)
memcpy(pidlNew, pidl1, cb1);
memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
}
return pidlNew;
}
/****************************************************************************
*
* FUNCTION: CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
*
* PURPOSE: Copies the ITEMID
*
****************************************************************************/
LPITEMIDLIST CShellTree::CopyITEMID(LPMALLOC lpMalloc, LPITEMIDLIST lpi)
{
LPITEMIDLIST lpiTemp;
lpiTemp=(LPITEMIDLIST)lpMalloc->Alloc(lpi->mkid.cb+sizeof(lpi->mkid.cb));
CopyMemory((PVOID)lpiTemp, (CONST VOID *)lpi, lpi->mkid.cb+sizeof(lpi->mkid.cb));
return lpiTemp;
}
/****************************************************************************
*
* FUNCTION: GetName(LPSHELLFOLDER lpsf,LPITEMIDLIST lpi,DWORD dwFlags,
* LPSTR lpFriendlyName)
*
* PURPOSE: Gets the friendly name for the folder
*
****************************************************************************/
BOOL CShellTree::GetName(LPSHELLFOLDER lpsf,
LPITEMIDLIST lpi,
DWORD dwFlags,
LPSTR lpFriendlyName)
{
BOOL bSuccess=TRUE;
STRRET str;
if (NOERROR==lpsf->GetDisplayNameOf(lpi,dwFlags, &str))
{
switch (str.uType)
{
case STRRET_WSTR:
WideCharToMultiByte(CP_ACP, // CodePage
0, // dwFlags
str.pOleStr, // lpWideCharStr
-1, // cchWideChar
lpFriendlyName, // lpMultiByteStr
MAX_PATH,
//sizeof(lpFriendlyName), // cchMultiByte, wrong. sizeof on a pointer, psk, psk
NULL, // lpDefaultChar,
NULL); // lpUsedDefaultChar
break;
case STRRET_OFFSET:
lstrcpy(lpFriendlyName, (LPSTR)lpi+str.uOffset);
break;
case STRRET_CSTR:
lstrcpy(lpFriendlyName, (LPSTR)str.cStr);
break;
default:
bSuccess = FALSE;
break;
}
}
else
bSuccess = FALSE;
return bSuccess;
}
/****************************************************************************
*
* FUNCTION: GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
*
* PURPOSE: Gets the Fully qualified Pidls for the folder
*
****************************************************************************/
LPITEMIDLIST CShellTree::GetFullyQualPidl(LPSHELLFOLDER lpsf, LPITEMIDLIST lpi)
{
char szBuff[MAX_PATH];
OLECHAR szOleChar[MAX_PATH];
LPSHELLFOLDER lpsfDeskTop;
LPITEMIDLIST lpifq;
ULONG ulEaten, ulAttribs;
HRESULT hr;
if (!GetName(lpsf, lpi, SHGDN_FORPARSING, szBuff))
return NULL;
hr=SHGetDesktopFolder(&lpsfDeskTop);
if (FAILED(hr))
return NULL;
MultiByteToWideChar(CP_ACP,
MB_PRECOMPOSED,
szBuff,
-1,
(USHORT *)szOleChar,
sizeof(szOleChar));
hr=lpsfDeskTop->ParseDisplayName(NULL,
NULL,
szOleChar,
&ulEaten,
&lpifq,
&ulAttribs);
lpsfDeskTop->Release();
if (FAILED(hr))
return NULL;
return lpifq;
}
/////////////////////////////////////////////////////////////////////////////
// CShellTree message handlers
/****************************************************************************
*
* FUNCTION: OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
*
* PURPOSE: Reponds to an TVN_ITEMEXPANDING message in order to fill up
* subdirectories. Pass the parameters from OnItemExpanding() to
* this function. You need to do that or your folders won't
* expand.
*
* OTHER: It can also be used to update a corresponding listview. Seem MFCENUM
*
* MESSAGEMAP: TVN_ITEMEXPANDING
*
****************************************************************************/
void CShellTree::FolderExpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
LPTVITEMDATA lptvid; //Long pointer to TreeView item data
HRESULT hr;
LPSHELLFOLDER lpsf2=NULL;
static char szBuff[MAX_PATH];
TV_SORTCB tvscb;
NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE))
return;
lptvid=(LPTVITEMDATA)pnmtv->itemNew.lParam;
if (lptvid)
{
hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
0, IID_IShellFolder,(LPVOID *)&lpsf2);
if (SUCCEEDED(hr))
{
FillTreeView(lpsf2,
lptvid->lpifq,
pnmtv->itemNew.hItem);
}
tvscb.hParent = pnmtv->itemNew.hItem;
tvscb.lParam = 0;
tvscb.lpfnCompare = TreeViewCompareProc;
SortChildrenCB(&tvscb /*, FALSE*/);
}
*pResult = 0;
}
/****************************************************************************
*
* FUNCTION: FolderPopup(NMHDR* pNMHDR, LRESULT* pResult)
*
* PURPOSE: Diplays a popup menu for the folder selected. Pass the
* parameters from Rclick() to this function.
*
* MESSAGEMAP: NM_RCLICK;
*
****************************************************************************/
void CShellTree::FolderPopup(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
POINT pt;
LPTVITEMDATA lptvid; //Long pointer to TreeView item data
LPSHELLFOLDER lpsf2=NULL;
static char szBuff[MAX_PATH];
TV_HITTESTINFO tvhti;
TV_ITEM tvi;
// TODO: Add your control notification handler code here
::GetCursorPos((LPPOINT)&pt);
ScreenToClient(&pt);
tvhti.pt=pt;
HitTest(&tvhti);
SelectItem(tvhti.hItem);
if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
{
ClientToScreen(&pt);
tvi.mask=TVIF_PARAM;
tvi.hItem=tvhti.hItem;
if (!GetItem(&tvi)){
return;
}
lptvid=(LPTVITEMDATA)tvi.lParam;
DoTheMenuThing(::GetParent(m_hWnd),
lptvid->lpsfParent, lptvid->lpi, &pt);
}
*pResult = 0;
}
/****************************************************************************
*
* FUNCTION: FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath)
*
* PURPOSE: Call this function if for example you want to put the path of the folder
* selected inside a combobox or an edit window. You would pass the
* parameters from OnSelChanged() to this function along with a CString object
* that will hold the folder path. If the path is not
* in the filesystem(eg MyComputer) it returns false.
*
* MESSAGEMAP: TVN_SELCHANGED
*
****************************************************************************/
BOOL CShellTree::FolderSelected(NMHDR* pNMHDR, LRESULT* pResult, CString &szFolderPath)
{
// TODO: Add your control notification handler code here
POINT pt;
LPTVITEMDATA lptvid; //Long pointer to TreeView item data
LPSHELLFOLDER lpsf2=NULL;
static char szBuff[MAX_PATH];
TV_HITTESTINFO tvhti;
TV_ITEM tvi;
HRESULT hr;
BOOL bRet=false;
// TODO: Add your control notification handler code here
::GetCursorPos((LPPOINT)&pt);
ScreenToClient(&pt);
tvhti.pt=pt;
HitTest(&tvhti);
SelectItem(tvhti.hItem);
if (tvhti.flags & (TVHT_ONITEMLABEL|TVHT_ONITEMICON))
{
ClientToScreen(&pt);
tvi.mask=TVIF_PARAM;
tvi.hItem=tvhti.hItem;
if (!GetItem(&tvi))
return false;
lptvid=(LPTVITEMDATA)tvi.lParam;
if (lptvid && lptvid->lpsfParent && lptvid->lpi)
{
hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
0,IID_IShellFolder,(LPVOID *)&lpsf2);
if (SUCCEEDED(hr))
{
ULONG ulAttrs = SFGAO_FILESYSTEM;
// Determine what type of object we have.
lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
if (ulAttrs & (SFGAO_FILESYSTEM))
{
if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
szFolderPath = szBuff;
bRet = true;
}
}
}
}
if(lpsf2)
lpsf2->Release();
}
*pResult = 0;
return bRet;
}
/****************************************************************************
*
* FUNCTION: EnableImages()
*
* PURPOSE: Obtains a handle to the system image list and attaches it
* to the tree control. DO NOT DELETE the imagelist
*
* MESSAGEMAP: NONE
*
****************************************************************************/
void CShellTree::EnableImages()
{
// Get the handle to the system image list, for our icons
HIMAGELIST hImageList;
SHFILEINFO sfi;
hImageList = (HIMAGELIST)SHGetFileInfo((LPCSTR)"C:\\",
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
// Attach ImageList to TreeView
if (hImageList)
::SendMessage(m_hWnd, TVM_SETIMAGELIST, (WPARAM) TVSIL_NORMAL,
(LPARAM)hImageList);
}
/****************************************************************************
*
* FUNCTION: GetSelectedFolderPath(CString &szFolderPath)
*
* PURPOSE: Retrieves the path of the currently selected string.
* Pass a CString object that will hold the folder path.
* If the path is not in the filesystem(eg MyComputer)
* or none is selected it returns false.
*
* MESSAGEMAP: NONE
*
****************************************************************************/
BOOL CShellTree::GetSelectedFolderPath(CString &szFolderPath)
{
LPTVITEMDATA lptvid; //Long pointer to TreeView item data
LPSHELLFOLDER lpsf2=NULL;
static char szBuff[MAX_PATH];
HTREEITEM hItem;
HRESULT hr;
BOOL bRet=false;
if((hItem = GetSelectedItem()))
{
lptvid=(LPTVITEMDATA)GetItemData(hItem);
if (lptvid && lptvid->lpsfParent && lptvid->lpi)
{
hr=lptvid->lpsfParent->BindToObject(lptvid->lpi,
0,IID_IShellFolder,(LPVOID *)&lpsf2);
if (SUCCEEDED(hr))
{
ULONG ulAttrs = SFGAO_FILESYSTEM;
// Determine what type of object we have.
lptvid->lpsfParent->GetAttributesOf(1, (const struct _ITEMIDLIST **)&lptvid->lpi, &ulAttrs);
if (ulAttrs & (SFGAO_FILESYSTEM))
{
if(SHGetPathFromIDList(lptvid->lpifq,szBuff)){
szFolderPath = szBuff;
bRet = true;
}
}
}
}
if(lpsf2)
lpsf2->Release();
}
return bRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -