Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

516 lines
10 KiB

/*++
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;
}