|
|
/*++
Implements IEnumIDList.
--*/
#include <windows.h>
#include <shlobj.h>
#include "pstore.h"
#include "utility.h"
#include "enumid.h"
#include "shfolder.h"
extern LONG g_DllRefCount;
CEnumIDList::CEnumIDList( LPITEMIDLIST pidl, BOOL bEnumItems ) {
m_pIEnumProviders = NULL; m_pIPStoreProvider = NULL; m_pIEnumTypes = NULL; m_pIEnumTypesGlobal = NULL; m_pIEnumSubtypes = NULL; m_pIEnumItems = NULL;
m_bEnumItems = bEnumItems;
//
// get the shell's IMalloc pointer
// we'll keep this until we get destroyed
//
if(FAILED(SHGetMalloc(&m_pMalloc))) delete this;
m_KeyType = PST_KEY_CURRENT_USER;
if(pidl == NULL) {
if( PStoreEnumProviders(0, &m_pIEnumProviders) != S_OK ) m_pIEnumProviders = NULL;
m_dwType = PIDL_TYPE_PROVIDER; // top-level
} else { m_dwType = GetLastPidlType(pidl) + 1; // parent + 1
}
//
// get provider interface
//
if(m_dwType > PIDL_TYPE_PROVIDER) { PST_PROVIDERID *ProviderId = GetPidlGuid(pidl); if(PStoreCreateInstance(&m_pIPStoreProvider, ProviderId, NULL, 0) != S_OK) m_pIPStoreProvider = NULL; }
//
// prepare two type enumerators, if appropriate:
// PST_KEY_CURRENT_USER and PST_KEY_LOCAL_MACHINE
//
if(m_dwType == PIDL_TYPE_TYPE && m_pIPStoreProvider) { m_pIPStoreProvider->EnumTypes(PST_KEY_CURRENT_USER, 0, &m_pIEnumTypes); m_pIPStoreProvider->EnumTypes(PST_KEY_LOCAL_MACHINE, 0, &m_pIEnumTypesGlobal); }
//
// prepare subtype enumerator
//
if(m_dwType == PIDL_TYPE_SUBTYPE && m_pIPStoreProvider) { GUID *pguidType;
m_KeyType = GetLastPidlKeyType(pidl); pguidType = GetLastPidlGuid(pidl); CopyMemory(&m_guidType, pguidType, sizeof(GUID));
m_pIPStoreProvider->EnumSubtypes( m_KeyType, pguidType, 0, &m_pIEnumSubtypes ); }
//
// prepare item enumerator if appropriate.
//
if(m_dwType == PIDL_TYPE_ITEM && m_bEnumItems && m_pIPStoreProvider) { GUID *pguidType; GUID *pguidSubtype;
m_KeyType = GetLastPidlKeyType(pidl); pguidSubtype = GetLastPidlGuid(pidl); CopyMemory(&m_guidSubtype, pguidSubtype, sizeof(GUID));
pguidType = GetPidlGuid(SearchPidlByType(pidl, PIDL_TYPE_TYPE)); CopyMemory(&m_guidType, pguidType, sizeof(GUID));
m_pIPStoreProvider->EnumItems( m_KeyType, pguidType, pguidSubtype, 0, &m_pIEnumItems ); }
m_ulCurrent = 0; m_ObjRefCount = 1;
InterlockedIncrement(&g_DllRefCount); }
CEnumIDList::~CEnumIDList() { //
// free any interfaces we established.
//
if(m_pIEnumProviders) { m_pIEnumProviders->Release(); m_pIEnumProviders = NULL; }
if(m_pIPStoreProvider) { m_pIPStoreProvider->Release(); m_pIPStoreProvider = NULL; }
if(m_pIEnumTypes) { m_pIEnumTypes->Release(); m_pIEnumTypes = NULL; }
if(m_pIEnumTypesGlobal) { m_pIEnumTypesGlobal->Release(); m_pIEnumTypesGlobal = NULL; }
if(m_pIEnumSubtypes) { m_pIEnumSubtypes->Release(); m_pIEnumSubtypes = NULL; }
if(m_pIEnumItems) { m_pIEnumItems->Release(); m_pIEnumItems = NULL; }
if(m_pMalloc) { m_pMalloc->Release(); m_pMalloc = NULL; }
InterlockedDecrement(&g_DllRefCount); }
STDMETHODIMP CEnumIDList::QueryInterface( REFIID riid, LPVOID *ppReturn ) { *ppReturn = NULL;
if(IsEqualIID(riid, IID_IUnknown)) *ppReturn = (IUnknown*)(CEnumIDList*)this; else if(IsEqualIID(riid, IID_IEnumIDList)) *ppReturn = (CEnumIDList*)this;
if(*ppReturn == NULL) return E_NOINTERFACE;
(*(LPUNKNOWN*)ppReturn)->AddRef(); return S_OK; }
STDMETHODIMP_(DWORD) CEnumIDList::AddRef() { return InterlockedIncrement(&m_ObjRefCount); }
STDMETHODIMP_(DWORD) CEnumIDList::Release() { LONG lDecremented = InterlockedDecrement(&m_ObjRefCount);
if(lDecremented == 0) delete this;
return lDecremented; }
STDMETHODIMP CEnumIDList::Next( ULONG ulElements, LPITEMIDLIST *pPidl, ULONG *pulFetched ) /*++
Retrieves the specified number of item identifiers in the enumeration sequence and advances the current position.
Returns the NOERROR value if successful, Returns S_FALSE value if there are no more items in the enumeration or an OLE-defined error value if an error occurs.
--*/ { HRESULT hr;
*pPidl = NULL; *pulFetched = 0;
if(m_bEnumItems) { if(m_dwType > PIDL_TYPE_ITEM) return S_FALSE; } else { if(m_dwType > PIDL_TYPE_SUBTYPE) return S_FALSE; // nothing left to enumerate
}
if(m_dwType == PIDL_TYPE_PROVIDER && m_pIEnumProviders) { PPST_PROVIDERINFO pProvInfo;
if( m_pIEnumProviders->Next(1, &pProvInfo, &m_ulCurrent) != S_OK ) {
//
// enumeration of providers complete
//
return S_FALSE; }
hr = CreateIDList(m_dwType, m_KeyType, &(pProvInfo->ID), pProvInfo->szProviderName, pPidl);
CoTaskMemFree(pProvInfo);
if(hr != S_OK) return S_FALSE;
*pulFetched = 1; return NOERROR; }
//
// must have a valid provider interface at this point
//
if(m_pIPStoreProvider == NULL) return S_FALSE;
if(m_dwType == PIDL_TYPE_TYPE) {
IEnumPStoreTypes *pIEnumTypes; PST_KEY KeyType = PST_KEY_CURRENT_USER; GUID guidType;
type_enum:
if(KeyType == PST_KEY_LOCAL_MACHINE) pIEnumTypes = m_pIEnumTypesGlobal; else pIEnumTypes = m_pIEnumTypes;
if(pIEnumTypes == NULL) return S_FALSE;
if(pIEnumTypes->Next(1, &guidType, &m_ulCurrent) != S_OK) {
//
// if enumeration at PST_KEY_CURRENT_USER level complete,
// continue at the PST_KEY_LOCAL_MACHINE level.
//
if(KeyType == PST_KEY_CURRENT_USER) { KeyType = PST_KEY_LOCAL_MACHINE; goto type_enum; }
//
// enumeration of types complete
//
return S_FALSE; }
PST_TYPEINFO *pTypeInfo = NULL;
if(S_OK != m_pIPStoreProvider->GetTypeInfo( KeyType, &guidType, &pTypeInfo, 0 )) return S_FALSE;
hr = CreateIDList(m_dwType, KeyType, &guidType, pTypeInfo->szDisplayName, pPidl);
//
// free pTypeInfo data
//
CoTaskMemFree(pTypeInfo);
if(hr != S_OK) return S_FALSE;
*pulFetched = 1; return NOERROR; }
if (m_dwType == PIDL_TYPE_SUBTYPE && m_pIEnumSubtypes) {
GUID guidSubtype; GUID *pguidType = &m_guidType;
if(m_pIEnumSubtypes->Next(1, &guidSubtype, &m_ulCurrent) != S_OK) {
//
// enumeration of types complete
//
return S_FALSE; }
PST_TYPEINFO *pTypeInfo = NULL;
if(m_pIPStoreProvider->GetSubtypeInfo(m_KeyType, pguidType, &guidSubtype, &pTypeInfo, 0) != S_OK) return S_FALSE;
hr = CreateIDList(m_dwType, m_KeyType, &guidSubtype, pTypeInfo->szDisplayName, pPidl);
//
// free pTypeInfo data
//
CoTaskMemFree(pTypeInfo);
if(hr != S_OK) return S_FALSE;
*pulFetched = 1; return NOERROR; }
if(m_dwType == PIDL_TYPE_ITEM && m_pIEnumItems) {
LPWSTR pszItem;
//
// enumerate and add items associated with specified subtype
//
if(m_pIEnumItems->Next(1, &pszItem, &m_ulCurrent) != S_OK) {
//
// enumeration of items complete
//
return S_FALSE; }
hr = CreateIDList( m_dwType, m_KeyType, NULL, // no item guid
pszItem, pPidl );
//
// free pszItem data
//
CoTaskMemFree(pszItem);
if(hr != S_OK) return S_FALSE;
*pulFetched = 1; return NOERROR; }
return S_FALSE; }
STDMETHODIMP CEnumIDList::CreateIDList( DWORD dwType, PST_KEY KeyType, GUID *guid, LPCWSTR szString, LPITEMIDLIST *pPidlOut ) { DWORD cbString = 0; DWORD cbPidlContent;
if(szString) { cbString = lstrlenW(szString); }
cbString = (cbString + 1) * sizeof(WCHAR);
cbPidlContent = sizeof(PIDL_CONTENT) + cbString;
//
// allocate the memory
//
*pPidlOut = (LPITEMIDLIST)m_pMalloc->Alloc( sizeof(ITEMIDLIST) + // this item's ITEMIDLIST
cbPidlContent + // this item's data
sizeof(ITEMIDLIST) // terminal ITEMIDLIST
);
if(*pPidlOut == NULL) return E_OUTOFMEMORY;
LPITEMIDLIST pidlTemp = *pPidlOut; LPPIDL_CONTENT pidlContent = (LPPIDL_CONTENT)&(pidlTemp->mkid.abID);
//
// set the size of this item
//
pidlTemp->mkid.cb = (unsigned short)(sizeof(ITEMIDLIST) + cbPidlContent);
//
// set the data for this item
//
pidlContent->dwType = dwType; pidlContent->KeyType = KeyType;
if( guid ) { CopyMemory(&(pidlContent->guid), guid, sizeof(GUID)); } else { ZeroMemory(&(pidlContent->guid), sizeof(GUID)); }
if(szString) { CopyMemory((LPBYTE)(pidlContent+1), szString, cbString); } else { ((LPWSTR)(pidlContent+1))[0] = L'\0'; }
//
// advance and terminate item ID list
//
pidlTemp = (LPITEMIDLIST)GetPidlNextItem(*pPidlOut); pidlTemp->mkid.cb = 0; pidlTemp->mkid.abID[0] = 0;
return NOERROR; }
STDMETHODIMP CEnumIDList::Skip( ULONG ulSkip ) { m_ulCurrent += ulSkip;
return NOERROR; }
STDMETHODIMP CEnumIDList::Reset( void ) { m_ulCurrent = 0;
return NOERROR; }
STDMETHODIMP CEnumIDList::Clone( LPENUMIDLIST *ppEnum ) { return E_NOTIMPL; }
|