/**************************************************************************
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright 1997 Microsoft Corporation. All Rights Reserved.
**************************************************************************/
/**************************************************************************
File: ShlFldr.cpp
Description: Implements CShellFolder.
**************************************************************************/
/**************************************************************************
#include statements
**************************************************************************/
#include "ShlFldr.h"
#include "ShlView.h"
#include "InfoTip.h"
#include "ExtrIcon.h"
#include "ContMenu.h"
#include "Guid.h"
#include "resource.h"
/**************************************************************************
global variables
**************************************************************************/
HKEY g_ahKey[] = { HKEY_CLASSES_ROOT,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
HKEY_PERFORMANCE_DATA,
HKEY_CURRENT_CONFIG,
HKEY_DYN_DATA,
(HKEY)-1};
/**************************************************************************
CShellFolder::CShellFolder()
**************************************************************************/
CShellFolder::CShellFolder(CShellFolder *pParent, LPCITEMIDLIST pidl)
{
m_hKeyRoot = NULL;
m_lpszSubKey = NULL;
m_pSFParent = pParent;
if(m_pSFParent)
m_pSFParent->AddRef();
m_pPidlMgr = new CPidlMgr();
if(!m_pPidlMgr)
{
delete this;
return;
}
//get the shell's IMalloc pointer
//we'll keep this until we get destroyed
if(FAILED(SHGetMalloc(&m_pMalloc)))
{
delete this;
return;
}
m_pidlRel = m_pPidlMgr->Copy(pidl);
m_pidlFQ = NULL;
if(m_pidlRel)
{
//determine if this PIDL has an HKEY or a sub key string
if(m_pPidlMgr->IsRootKey(m_pidlRel))
{
//this is a root key
m_pPidlMgr->GetRootKey(m_pidlRel, &m_hKeyRoot);
}
DWORD dwSize = m_pPidlMgr->GetSubKeyText(m_pidlRel, NULL, 0);
m_lpszSubKey = new TCHAR[dwSize];
if(m_lpszSubKey)
{
m_pPidlMgr->GetSubKeyText(m_pidlRel, m_lpszSubKey, dwSize);
}
}
m_ObjRefCount = 1;
g_DllRefCount++;
}
/**************************************************************************
CShellFolder::~CShellFolder()
**************************************************************************/
CShellFolder::~CShellFolder()
{
if(m_pidlRel)
{
m_pPidlMgr->Delete(m_pidlRel);
m_pidlRel = NULL;
}
if(m_pidlFQ)
{
m_pPidlMgr->Delete(m_pidlFQ);
m_pidlFQ = NULL;
}
if(m_lpszSubKey)
delete m_lpszSubKey;
if(m_pSFParent)
m_pSFParent->Release();
if(m_pMalloc)
{
m_pMalloc->Release();
}
if(m_pPidlMgr)
{
delete m_pPidlMgr;
}
g_DllRefCount--;
}
///////////////////////////////////////////////////////////////////////////
//
// IUnknown Implementation
//
/**************************************************************************
CShellFolder::QueryInterface
**************************************************************************/
STDMETHODIMP CShellFolder::QueryInterface(REFIID riid, LPVOID *ppReturn)
{
*ppReturn = NULL;
//IUnknown
if(IsEqualIID(riid, IID_IUnknown))
{
*ppReturn = this;
}
//IPersistFolder
else if(IsEqualIID(riid, IID_IPersistFolder))
{
*ppReturn = (IPersistFolder*)this;
}
//IShellFolder
else if(IsEqualIID(riid, IID_IShellFolder))
{
*ppReturn = (IShellFolder*)this;
}
if(*ppReturn)
{
(*(LPUNKNOWN*)ppReturn)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
/**************************************************************************
CShellFolder::AddRef
**************************************************************************/
STDMETHODIMP_(DWORD) CShellFolder::AddRef()
{
return ++m_ObjRefCount;
}
/**************************************************************************
CShellFolder::Release
**************************************************************************/
STDMETHODIMP_(DWORD) CShellFolder::Release()
{
if(--m_ObjRefCount == 0)
{
delete this;
return 0;
}
return m_ObjRefCount;
}
///////////////////////////////////////////////////////////////////////////
//
// IPersist Implementation
//
/**************************************************************************
CShellView::GetClassID()
**************************************************************************/
STDMETHODIMP CShellFolder::GetClassID(LPCLSID lpClassID)
{
*lpClassID = CLSID_RegViewNameSpace;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
//
// IPersistFolder Implementation
//
/**************************************************************************
CShellView::Initialize()
**************************************************************************/
STDMETHODIMP CShellFolder::Initialize(LPCITEMIDLIST pidl)
{
if(m_pidlFQ)
{
m_pPidlMgr->Delete(m_pidlFQ);
m_pidlFQ = NULL;
}
m_pidlFQ = m_pPidlMgr->Copy(pidl);
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
//
// IShellFolder Implementation
//
/**************************************************************************
CShellFolder::BindToObject()
**************************************************************************/
STDMETHODIMP CShellFolder::BindToObject( LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut)
{
*ppvOut = NULL;
CShellFolder *pShellFolder = new CShellFolder(this, pidl);
if(!pShellFolder)
return E_OUTOFMEMORY;
LPITEMIDLIST pidlFQ;
pidlFQ = m_pPidlMgr->Concatenate(m_pidlFQ, pidl);
pShellFolder->Initialize(pidlFQ);
m_pPidlMgr->Delete(pidlFQ);
HRESULT hr = pShellFolder->QueryInterface(riid, ppvOut);
pShellFolder->Release();
return hr;
}
/**************************************************************************
CShellFolder::BindToStorage()
**************************************************************************/
STDMETHODIMP CShellFolder::BindToStorage( LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut)
{
*ppvOut = NULL;
return E_NOTIMPL;
}
/**************************************************************************
CShellFolder::CompareIDs()
**************************************************************************/
STDMETHODIMP CShellFolder::CompareIDs( LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2)
{
TCHAR szString1[MAX_PATH] = TEXT("");
TCHAR szString2[MAX_PATH] = TEXT("");
HKEY hkey1 = NULL,
hkey2 = NULL;
int nReturn;
/*
Special case - If one of the items is a key and the other is a value, always
make the key come before the value.
*/
LPCITEMIDLIST pidlTemp1 = pidl1,
pidlTemp2 = pidl2;
//get the last item in each list
while((m_pPidlMgr->GetNextItem(pidlTemp1))->mkid.cb)
pidlTemp1 = m_pPidlMgr->GetNextItem(pidlTemp1);
while((m_pPidlMgr->GetNextItem(pidlTemp2))->mkid.cb)
pidlTemp2 = m_pPidlMgr->GetNextItem(pidlTemp2);
//at this point, both pidlTemp1 and pidlTemp2 point to the last item in the list
if(m_pPidlMgr->IsValue(pidlTemp1) != m_pPidlMgr->IsValue(pidlTemp2))
{
if(m_pPidlMgr->IsValue(pidlTemp1))
return 1;
return -1;
}
//get the numeric value of the root key
m_pPidlMgr->GetRootKey(pidl1, &hkey1);
m_pPidlMgr->GetRootKey(pidl2, &hkey2);
//compare the root keys
if(hkey1 != hkey2)
{
return (int)((DWORD)hkey1 - (DWORD)hkey2);
}
//now compare the subkey strings
m_pPidlMgr->GetSubKeyText( pidl1,
szString1,
sizeof(szString1));
m_pPidlMgr->GetSubKeyText( pidl2,
szString2,
sizeof(szString2));
nReturn = lstrcmpi(szString1, szString2);
if(nReturn)
return nReturn;
//now compare the value strings
m_pPidlMgr->GetValueText( pidl1,
szString1,
sizeof(szString1));
m_pPidlMgr->GetValueText( pidl2,
szString2,
sizeof(szString2));
return lstrcmpi(szString1, szString2);
}
/**************************************************************************
CShellFolder::CreateViewObject()
**************************************************************************/
STDMETHODIMP CShellFolder::CreateViewObject( HWND hwndOwner,
REFIID riid,
LPVOID *ppvOut)
{
HRESULT hr;
CShellView *pShellView;
*ppvOut = NULL;
pShellView = new CShellView(this, m_pidlRel);
if(!pShellView)
return E_OUTOFMEMORY;
hr = pShellView->QueryInterface(riid, ppvOut);
pShellView->Release();
return hr;
}
/**************************************************************************
CShellFolder::EnumObjects()
**************************************************************************/
STDMETHODIMP CShellFolder::EnumObjects( HWND hwndOwner,
DWORD dwFlags,
LPENUMIDLIST *ppEnumIDList)
{
HRESULT hr;
*ppEnumIDList = NULL;
*ppEnumIDList = new CEnumIDList(GetRootKey(), m_lpszSubKey, dwFlags, &hr);
if(!*ppEnumIDList)
return hr;
return S_OK;
}
/**************************************************************************
CShellFolder::GetAttributesOf()
**************************************************************************/
STDMETHODIMP CShellFolder::GetAttributesOf( UINT uCount,
LPCITEMIDLIST aPidls[],
LPDWORD pdwAttribs)
{
UINT i;
*pdwAttribs = (DWORD)-1;
for(i = 0; i < uCount; i++)
{
DWORD dwAttribs = 0;
//flags common to all items
dwAttribs |= 0;
//is this item a key?
if(!m_pPidlMgr->IsValue(m_pPidlMgr->GetLastItem(aPidls[i])))
{
dwAttribs |= SFGAO_FOLDER;
//does this item have a sub folder?
if(m_pPidlMgr->HasSubKeys(GetRootKey(), m_lpszSubKey, aPidls[i]))
dwAttribs |= SFGAO_HASSUBFOLDER;
}
*pdwAttribs &= dwAttribs;
}
return S_OK;
}
/**************************************************************************
CShellFolder::GetUIObjectOf()
**************************************************************************/
STDMETHODIMP CShellFolder::GetUIObjectOf( HWND hwndOwner,
UINT uCount,
LPCITEMIDLIST *pPidl,
REFIID riid,
LPUINT puReserved,
LPVOID *ppvReturn)
{
*ppvReturn = NULL;
if(IsEqualIID(riid, IID_IContextMenu))
{
CContextMenu *pcm = new CContextMenu(this, pPidl, uCount);
if(pcm)
{
*ppvReturn = pcm;
return S_OK;
}
}
if(uCount != 1)
return E_FAIL;
if(IsEqualIID(riid, IID_IExtractIcon))
{
CExtractIcon *pei;
LPITEMIDLIST pidl;
pidl = m_pPidlMgr->Concatenate(m_pidlRel, pPidl[0]);
pei = new CExtractIcon(pidl);
/*
The temp PIDL can be deleted because the new CExtractIcon either failed or
made its own copy of it.
*/
m_pPidlMgr->Delete(pidl);
if(pei)
{
*ppvReturn = pei;
return S_OK;
}
return E_OUTOFMEMORY;
}
#if (_WIN32_IE >= 0x0400)
if(IsEqualIID(riid, IID_IQueryInfo))
{
CQueryInfo *pqit;
LPITEMIDLIST pidl;
pidl = m_pPidlMgr->Concatenate(m_pidlRel, pPidl[0]);
pqit = new CQueryInfo(pidl);
/*
The temp PIDL can be deleted because the new CQueryInfo either failed or
made its own copy of it.
*/
m_pPidlMgr->Delete(pidl);
if(pqit)
{
*ppvReturn = pqit;
return S_OK;
}
return E_OUTOFMEMORY;
}
#endif //#if (_WIN32_IE >= 0x0400)
return E_NOINTERFACE;
}
/**************************************************************************
CShellFolder::GetDisplayNameOf()
**************************************************************************/
#define GET_SHGDN_FOR(dwFlags) ((DWORD)dwFlags & (DWORD)0x0000FF00)
#define GET_SHGDN_RELATION(dwFlags) ((DWORD)dwFlags & (DWORD)0x000000FF)
STDMETHODIMP CShellFolder::GetDisplayNameOf( LPCITEMIDLIST pidl,
DWORD dwFlags,
LPSTRRET lpName)
{
TCHAR szText[MAX_PATH];
int cchOleStr;
switch(GET_SHGDN_RELATION(dwFlags))
{
case SHGDN_NORMAL:
//get the full name
m_pPidlMgr->GetPidlPath(pidl, szText, sizeof(szText));
//If the text is NULL and this is a value, get the default item name.
if(!*szText && m_pPidlMgr->IsValue(m_pPidlMgr->GetLastItem(pidl)))
{
LoadString(g_hInst, IDS_DEFAULT, szText, sizeof(szText));
}
break;
case SHGDN_INFOLDER:
{
LPITEMIDLIST pidlTemp = m_pPidlMgr->GetLastItem(pidl);
//get the relative name
m_pPidlMgr->GetItemText(pidlTemp, szText, sizeof(szText));
//If the text is NULL and this is a value, get the default item name.
if(!*szText && m_pPidlMgr->IsValue(pidlTemp))
{
LoadString(g_hInst, IDS_DEFAULT, szText, sizeof(szText));
}
}
break;
default:
return E_INVALIDARG;
}
//get the number of characters required
cchOleStr = lstrlen(szText) + 1;
//allocate the wide character string
lpName->pOleStr = (LPWSTR)m_pMalloc->Alloc(cchOleStr * sizeof(WCHAR));
if(!lpName->pOleStr)
return E_OUTOFMEMORY;
lpName->uType = STRRET_WSTR;
LocalToWideChar(lpName->pOleStr, szText, cchOleStr);
return S_OK;
}
/**************************************************************************
CShellFolder::ParseDisplayName()
**************************************************************************/
STDMETHODIMP CShellFolder::ParseDisplayName( HWND hwndOwner,
LPBC pbcReserved,
LPOLESTR lpDisplayName,
LPDWORD pdwEaten,
LPITEMIDLIST *pPidlNew,
LPDWORD pdwAttributes)
{
HRESULT hr = E_OUTOFMEMORY;
LPITEMIDLIST pidlFull = NULL;
DWORD dwChars = lstrlenW(lpDisplayName) + 1;
LPTSTR pszTemp = (LPTSTR)GlobalAlloc(GPTR, dwChars * sizeof(TCHAR));
if(pszTemp)
{
hr = E_FAIL;
WideCharToLocal(pszTemp, lpDisplayName, dwChars);
if(*pszTemp)
{
LPTSTR pszNext;
TCHAR szElement[MAX_PATH];
int i;
BOOL fValue;
//get the root key
pszNext = GetNextRegElement(pszTemp, szElement, ARRAYSIZE(szElement));
for(i = 0; (-1 != (int)g_ahKey[i]) && !pidlFull; i++)
{
TCHAR szKeyText[MAX_PATH];
GetRootKeyText(g_ahKey[i], szKeyText, ARRAYSIZE(szKeyText));
if(0 == lstrcmpi(szElement, szKeyText))
{
pidlFull = m_pPidlMgr->CreateRootKey(g_ahKey[i]);
}
}
if(pidlFull)
{
LPITEMIDLIST pidlTemp = NULL;
LPITEMIDLIST pidlOld = NULL;
HKEY hKey;
//check to see if the last item is a value or a key
if(NOERROR == RegOpenKeyEx( g_ahKey[i],
pszNext,
0,
KEY_READ,
&hKey))
{
fValue = FALSE;
RegCloseKey(hKey);
}
else
fValue = TRUE;
//get the remaining keys
while(pszNext = GetNextRegElement(pszNext, szElement, ARRAYSIZE(szElement)))
{
//if this is the last element, check to see if it is a value or a key
if(!*pszNext && fValue)
pidlTemp = m_pPidlMgr->CreateValue(szElement);
else
pidlTemp = m_pPidlMgr->CreateSubKey(szElement);
pidlOld = pidlFull;
pidlFull = m_pPidlMgr->Concatenate(pidlFull, pidlTemp);
m_pPidlMgr->Delete(pidlOld);
}
hr = S_OK;
}
}
GlobalFree((HGLOBAL)pszTemp);
}
*pPidlNew = pidlFull;
return hr;
}
/**************************************************************************
CShellFolder::SetNameOf()
**************************************************************************/
STDMETHODIMP CShellFolder::SetNameOf( HWND hwndOwner,
LPCITEMIDLIST pidl,
LPCOLESTR lpName,
DWORD dw,
LPITEMIDLIST *pPidlOut)
{
return E_NOTIMPL;
}
/**************************************************************************
CShellFolder::GetFolderPath()
**************************************************************************/
BOOL CShellFolder::GetFolderPath(LPTSTR lpszOut, DWORD dwOutSize)
{
TCHAR szTemp[MAX_PATH] = TEXT("");
DWORD dwSize;
if(!lpszOut)
return FALSE;
*lpszOut = 0;
//get the text for the root key
GetRootKeyText(m_hKeyRoot, szTemp, sizeof(szTemp));
dwSize = lstrlen(szTemp);
if(m_lpszSubKey)
dwSize += lstrlen(m_lpszSubKey) + 1;
//is the output buffer big enough?
if(dwSize > dwOutSize)
return FALSE;
//add the text we already have
lstrcpy(lpszOut, szTemp);
//add this folder's text if present
if(m_lpszSubKey && *m_lpszSubKey)
{
lstrcat(lpszOut, TEXT("\\"));
lstrcat(lpszOut, m_lpszSubKey);
}
return TRUE;
}
/**************************************************************************
CShellFolder::GetFolderText()
**************************************************************************/
BOOL CShellFolder::GetFolderText(LPTSTR lpszOut, DWORD dwOutSize)
{
if(!lpszOut)
return FALSE;
*lpszOut = 0;
//add this folder's text if present
if(m_lpszSubKey && *m_lpszSubKey)
{
lstrcpyn(lpszOut, m_lpszSubKey, dwOutSize);
}
return TRUE;
}
/**************************************************************************
CShellFolder::GetRootKey()
**************************************************************************/
HKEY CShellFolder::GetRootKey(void)
{
HKEY hkReturn = NULL;
CShellFolder *pTemp = this;
while(pTemp)
{
if(pTemp->m_hKeyRoot)
{
hkReturn = pTemp->m_hKeyRoot;
break;
}
pTemp = pTemp->m_pSFParent;
}
return hkReturn;
}