📄 shellpidl.cpp
字号:
//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// You may use this source code, compile or redistribute it as part of your application
// for free. You cannot redistribute it as a part of a software development
// library without the agreement of the author. If the sources are
// distributed along with the application, you should leave the original
// copyright notes in the source code without any changes.
// This code can be used WITHOUT ANY WARRANTIES at your own risk.
//
// For the latest updates to this code, check this site:
// http://www.masmex.com
// after Sept 2000
//
// Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
//*******************************************************************************
// ShellPidl.cpp: implementation of the CShellPidl class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ShellPidl.h"
#include "UIMessages.h"
#include <intshcut.h>
#include <subsmgr.h>
#include <ExDisp.h>
#include "ShellContextMenu.h"
#include "UICoolMenu.h"
#include "cbformats.h"
#define SF_DRAGDROP_FLAGS SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANLINK;
UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
UINT CF_SHELLURL = RegisterClipboardFormat(CFSTR_SHELLURL);
#define TPM_FLAGS (TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CShellPidl::CShellPidl()
{
SHGetMalloc(&m_pMalloc);
SHGetDesktopFolder(&m_psfDesktop);
ZeroMemory(&m_EmptyPidl,sizeof(ITEMIDLIST));
}
CShellPidl::~CShellPidl()
{
if (m_pMalloc)
m_pMalloc->Release();
if (m_psfDesktop)
m_psfDesktop->Release();
}
IMalloc *CShellPidl::GetMalloc()
{
return m_pMalloc;
}
DWORD CShellPidl::GetDragDropAttributes(LPLVITEMDATA plvid)
{
return GetDragDropAttributes(plvid->lpsfParent,plvid->lpi);
}
DWORD CShellPidl::GetDragDropAttributes(LPTVITEMDATA ptvid)
{
return GetDragDropAttributes(ptvid->lpsfParent,ptvid->lpi);
}
DWORD CShellPidl::GetDragDropAttributes(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl)
{
if (pFolder == NULL)
pFolder = m_psfDesktop;
DWORD dwAttrs=SF_DRAGDROP_FLAGS;
HRESULT hr = pFolder->GetAttributesOf(1,(LPCITEMIDLIST*)&pidl,&dwAttrs);
if (FAILED(hr))
dwAttrs = SF_DRAGDROP_FLAGS;
return dwAttrs;
}
DWORD CShellPidl::GetDragDropAttributes(COleDataObject *pDataObject)
{
IDataObject *pDataObj = pDataObject->m_lpDataObject;
STGMEDIUM stgm;
ZeroMemory(&stgm, sizeof(stgm));
FORMATETC fetc;
fetc.cfFormat = CF_IDLIST;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
DWORD dwAttrs=DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK;
HRESULT hr = pDataObj->QueryGetData(&fetc);
if (FAILED(hr))
return dwAttrs;
hr = pDataObj->GetData(&fetc, &stgm);
if (FAILED(hr))
return dwAttrs;
DWORD pData = (DWORD)GlobalLock(stgm.hGlobal);
LPIDA pIDList = (LPIDA)pData;
UINT nFolderOffset = pIDList->aoffset[0];
TRACE2("PIDL(%u) offfset=%u\n",0,nFolderOffset);
DWORD pFolder = pData+nFolderOffset;
LPITEMIDLIST pidl = (LPITEMIDLIST)pFolder;
LPSHELLFOLDER psfParent = GetFolder(pidl);
if (psfParent)
{
// get attributes for the children
TRACE1("PIDL count=%u\n",pIDList->cidl);
for(UINT i=1;i < (pIDList->cidl+1);i++)
{
UINT nListOffset = pIDList->aoffset[i];
TRACE2("PIDL(%u) offfset=%u\n",i,nListOffset);
ULONG ulAttrs = SF_DRAGDROP_FLAGS;
DWORD dwPidl = pData+nListOffset;
LPITEMIDLIST pidlist = (LPITEMIDLIST)dwPidl;
psfParent->GetAttributesOf(1,(LPCITEMIDLIST*)&pidlist,&ulAttrs);
#ifdef _DEBUG
CString sPath;
SHPidlToPathEx(pidlist,sPath,psfParent);
TRACE2("Drag drop source path=%s Attributes=%u\n",sPath,ulAttrs);
#endif
if (ulAttrs)
dwAttrs = dwAttrs & ulAttrs;
}
psfParent->Release();
}
GlobalUnlock(stgm.hGlobal);
ReleaseStgMedium(&stgm);
return dwAttrs;
}
LPCITEMIDLIST CShellPidl::GetEmptyPidl()
{
return &m_EmptyPidl;
}
bool CShellPidl::IsDesktopFolder(LPSHELLFOLDER psFolder)
{
return psFolder == NULL || psFolder == m_psfDesktop;
}
LPSHELLFOLDER CShellPidl::GetDesktopFolder()
{
return m_psfDesktop;
}
LPSHELLFOLDER CShellPidl::GetFolder(LPITEMIDLIST pidl)
{
if (pidl == NULL || pidl->mkid.cb == 0)
return m_psfDesktop;
LPSHELLFOLDER pFolder=NULL;
if (FAILED(m_psfDesktop->BindToObject(pidl, 0, IID_IShellFolder,(LPVOID*)&pFolder)))
return NULL;
return pFolder;
}
// CopyItemID - creates an item identifier list containing the first
// item identifier in the specified list.
// Returns a PIDL if successful, or NULL if out of memory.
LPITEMIDLIST CShellPidl::CopyItemID(LPITEMIDLIST pidl,int n)
{
// Get the size of the specified item identifier.
ASSERT(pidl);
if (n == 0)
{
int cb = pidl->mkid.cb;
int nSize = cb + sizeof(pidl->mkid.cb);
// Allocate a new item identifier list.
LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize);
ZeroMemory(pidlNew,nSize);
if (pidlNew == NULL)
return NULL;
// Copy the specified item identifier.
CopyMemory(pidlNew, pidl, nSize-sizeof(pidl->mkid.cb));
return pidlNew;
}
else
{
LPITEMIDLIST pidl_index=NULL;
for(int i=0;i < n && pidl->mkid.cb;i++)
{
pidl_index = pidl;
pidl = Next(pidl);
}
return pidl_index ? CopyItemID(pidl_index,0) : NULL;
}
return NULL;
}
// Returns a PIDL if successful, or NULL if out of memory.
LPITEMIDLIST CShellPidl::CopyLastItemID(LPITEMIDLIST pidl)
{
// Get the size of the specified item identifier.
ASSERT(pidl);
if (pidl == NULL)
return NULL;
LPITEMIDLIST last_pidl=pidl;
while (pidl->mkid.cb)
{
last_pidl = pidl;
pidl = Next(pidl);
}
if (last_pidl == NULL)
return NULL;
return CopyItemID(last_pidl);
}
// copies the absolute pidl up till n
LPITEMIDLIST CShellPidl::CopyAbsItemID(LPITEMIDLIST pidl,int n)
{
// Get the size of the specified item identifier.
ASSERT(pidl);
if (pidl == NULL)
return NULL;
LPITEMIDLIST first_pidl=NULL;
LPITEMIDLIST abs_pidl=NULL;
LPITEMIDLIST new_abs_pidl=NULL;
for(int i=0;i < n && pidl && pidl->mkid.cb;i++)
{
first_pidl = CopyItemID(pidl);
new_abs_pidl = ConcatPidl(abs_pidl,first_pidl);
if (abs_pidl)
{
m_pMalloc->Free(abs_pidl);
}
abs_pidl = new_abs_pidl;
if (first_pidl)
{
m_pMalloc->Free(first_pidl);
}
pidl = Next(pidl);
}
return new_abs_pidl;
}
// Makes a copy of an ITEMIDLIST
LPITEMIDLIST CShellPidl::CopyItemIDList(LPITEMIDLIST pidl)
{
// Allocate a new item identifier list.
int nSize = GetSize(pidl);
LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(nSize);
ZeroMemory(pidlNew,nSize);
if (pidlNew == NULL)
return NULL;
// Copy the specified item identifier.
CopyMemory(pidlNew, pidl, nSize);
return pidlNew;
}
bool CShellPidl::CompareMemPidls(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
{
// Allocate a new item identifier list.
if (pidl1 == NULL || pidl2 == NULL)
return false;
return memcmp(pidl1,pidl2,(size_t)GetSize(pidl1)) == 0;
}
// Returns true if lists are the same
bool CShellPidl::ComparePidls(LPSHELLFOLDER pFolder,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2)
{
// Allocate a new item identifier list.
if (pFolder == NULL)
pFolder = GetDesktopFolder();
if (pidl1 == NULL || pidl2 == NULL)
return false;
return (short)pFolder->CompareIDs(0,pidl1,pidl2) == 0;
}
void CShellPidl::Free(void *pv)
{
if (m_pMalloc)
m_pMalloc->Free(pv);
}
void CShellPidl::FreePidl(LPITEMIDLIST pidl)
{
if (m_pMalloc)
m_pMalloc->Free(pidl);
}
UINT CShellPidl::GetCount(LPCITEMIDLIST pidl)
{
UINT nCount = 0;
if (pidl)
{
while (pidl->mkid.cb)
{
pidl = Next(pidl);
nCount++;
}
}
return nCount;
}
UINT CShellPidl::GetSize(LPCITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb)
{
cbTotal += pidl->mkid.cb;
pidl = Next(pidl);
}
}
return cbTotal;
}
LPITEMIDLIST CShellPidl::Next(LPCITEMIDLIST pidl)
{
LPSTR lpMem=(LPSTR)pidl;
lpMem+=pidl->mkid.cb;
return (LPITEMIDLIST)lpMem;
}
LPITEMIDLIST CShellPidl::ConcatPidl(LPITEMIDLIST pidlDest,LPITEMIDLIST pidlSrc)
{
// Get the size of the specified item identifier.
UINT cbDest=0;
UINT cbSrc=0;
if (pidlDest) //May be NULL
cbDest = GetSize(pidlDest) - sizeof(pidlDest->mkid.cb);
cbSrc = GetSize(pidlSrc);
// Allocate a new item identifier list.
LPITEMIDLIST pidlNew = (LPITEMIDLIST)m_pMalloc->Alloc(cbSrc+cbDest);
if (pidlNew == NULL)
return NULL;
ZeroMemory(pidlNew,cbSrc+cbDest);
// Copy the specified item identifier.
if (pidlDest)
CopyMemory(pidlNew, pidlDest, cbDest);
CopyMemory(((USHORT*)(((LPBYTE)pidlNew)+cbDest)), pidlSrc, cbSrc);
return pidlNew;
}
int CShellPidl::GetIcon(LPITEMIDLIST lpi, UINT uFlags)
{
SHFILEINFO sfi;
ZeroMemory(&sfi,sizeof(sfi));
if (uFlags == 0)
uFlags |= (SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
uFlags |= SHGFI_PIDL;
SHGetFileInfo((LPCTSTR)lpi, 0, &sfi, sizeof(SHFILEINFO), uFlags);
return sfi.iIcon;
}
STDMETHODIMP CShellPidl::SHPidlToPathEx(LPCITEMIDLIST pidl, CString &sPath, LPSHELLFOLDER pFolder, DWORD dwFlags)
{
STRRET StrRetFilePath;
LPTSTR pszFilePath = NULL;
HRESULT hr=E_FAIL;
if (pFolder == NULL)
pFolder = GetDesktopFolder();
if (pFolder == NULL)
return E_FAIL;
hr = pFolder->GetDisplayNameOf(pidl, dwFlags, &StrRetFilePath);
if (SUCCEEDED(hr))
{
StrRetToStr(StrRetFilePath, &pszFilePath, (LPITEMIDLIST)pidl);
sPath = pszFilePath;
}
if (pszFilePath)
m_pMalloc->Free(pszFilePath);
return hr;
}
STDMETHODIMP CShellPidl::SHPathToPidlEx(LPCTSTR szPath, LPITEMIDLIST* ppidl, LPSHELLFOLDER pFolder)
{
OLECHAR wszPath[MAX_PATH] = {0};
ULONG nCharsParsed = 0;
LPSHELLFOLDER pShellFolder = NULL;
BOOL bFreeOnExit = FALSE;
#ifdef UNICODE
lstrcpy(wszPath,szPath);
#else
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH);
#endif
// Use the desktop's IShellFolder by default
if(pFolder == NULL)
{
SHGetDesktopFolder(&pShellFolder);
bFreeOnExit = TRUE;
}
else
pShellFolder = pFolder;
HRESULT hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL);
if(bFreeOnExit)
pShellFolder->Release();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -