/* * IEnumMoniker implementation for DEVENUM.dll * * Copyright (C) 2002 Robert Shearman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES ON THIS FILE: * - Implements IEnumMoniker interface which enumerates through moniker * objects created from HKEY_CLASSES/CLSID/{DEVICE_CLSID}/Instance */ #include "devenum_private.h" #include "oleauto.h" #include "ocidl.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(devenum); typedef struct { IEnumMoniker IEnumMoniker_iface; LONG ref; DWORD index; HKEY hkey; } EnumMonikerImpl; typedef struct { IPropertyBag IPropertyBag_iface; LONG ref; HKEY hkey; } RegPropBagImpl; static inline RegPropBagImpl *impl_from_IPropertyBag(IPropertyBag *iface) { return CONTAINING_RECORD(iface, RegPropBagImpl, IPropertyBag_iface); } static HRESULT WINAPI DEVENUM_IPropertyBag_QueryInterface( LPPROPERTYBAG iface, REFIID riid, LPVOID *ppvObj) { RegPropBagImpl *This = impl_from_IPropertyBag(iface); TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObj); if (This == NULL || ppvObj == NULL) return E_POINTER; if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IPropertyBag)) { *ppvObj = iface; IPropertyBag_AddRef(iface); return S_OK; } FIXME("- no interface IID: %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } /********************************************************************** * DEVENUM_IPropertyBag_AddRef (also IUnknown) */ static ULONG WINAPI DEVENUM_IPropertyBag_AddRef(LPPROPERTYBAG iface) { RegPropBagImpl *This = impl_from_IPropertyBag(iface); TRACE("(%p)->() AddRef from %d\n", iface, This->ref); return InterlockedIncrement(&This->ref); } /********************************************************************** * DEVENUM_IPropertyBag_Release (also IUnknown) */ static ULONG WINAPI DEVENUM_IPropertyBag_Release(LPPROPERTYBAG iface) { RegPropBagImpl *This = impl_from_IPropertyBag(iface); ULONG ref; TRACE("(%p)->() ReleaseThis->ref from %d\n", iface, This->ref); ref = InterlockedDecrement(&This->ref); if (ref == 0) { RegCloseKey(This->hkey); CoTaskMemFree(This); DEVENUM_UnlockModule(); } return ref; } static HRESULT WINAPI DEVENUM_IPropertyBag_Read( LPPROPERTYBAG iface, LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) { LPVOID pData = NULL; DWORD received; DWORD type = 0; RegPropBagImpl *This = impl_from_IPropertyBag(iface); HRESULT res = S_OK; LONG reswin32; TRACE("(%p)->(%s, %p, %p)\n", This, debugstr_w(pszPropName), pVar, pErrorLog); if (!pszPropName || !pVar) return E_POINTER; reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, NULL, NULL, &received); res = HRESULT_FROM_WIN32(reswin32); if (SUCCEEDED(res)) { pData = HeapAlloc(GetProcessHeap(), 0, received); /* work around a GCC bug that occurs here unless we use the reswin32 variable as well */ reswin32 = RegQueryValueExW(This->hkey, pszPropName, NULL, &type, pData, &received); res = HRESULT_FROM_WIN32(reswin32); } if (SUCCEEDED(res)) { res = E_INVALIDARG; /* assume we cannot coerce into right type */ TRACE("Read %d bytes (%s)\n", received, type == REG_SZ ? debugstr_w(pData) : "binary data"); switch (type) { case REG_SZ: switch (V_VT(pVar)) { case VT_LPWSTR: V_UNION(pVar, bstrVal) = CoTaskMemAlloc(received); memcpy(V_UNION(pVar, bstrVal), pData, received); res = S_OK; break; case VT_EMPTY: V_VT(pVar) = VT_BSTR; /* fall through */ case VT_BSTR: V_UNION(pVar, bstrVal) = SysAllocStringLen(pData, received/sizeof(WCHAR) - 1); res = S_OK; break; } break; case REG_DWORD: TRACE("REG_DWORD: %x\n", *(DWORD *)pData); switch (V_VT(pVar)) { case VT_EMPTY: V_VT(pVar) = VT_I4; /* fall through */ case VT_I4: case VT_UI4: V_UNION(pVar, ulVal) = *(DWORD *)pData; res = S_OK; break; } break; case REG_BINARY: { SAFEARRAYBOUND bound; void * pArrayElements; bound.lLbound = 0; bound.cElements = received; TRACE("REG_BINARY: len = %d\n", received); switch (V_VT(pVar)) { case VT_EMPTY: V_VT(pVar) = VT_ARRAY | VT_UI1; /* fall through */ case VT_ARRAY | VT_UI1: if (!(V_UNION(pVar, parray) = SafeArrayCreate(VT_UI1, 1, &bound))) res = E_OUTOFMEMORY; else res = S_OK; break; } if (res == E_INVALIDARG) break; res = SafeArrayAccessData(V_UNION(pVar, parray), &pArrayElements); if (FAILED(res)) break; CopyMemory(pArrayElements, pData, received); res = SafeArrayUnaccessData(V_UNION(pVar, parray)); break; } } if (res == E_INVALIDARG) FIXME("Variant type %x not supported for regtype %x\n", V_VT(pVar), type); } HeapFree(GetProcessHeap(), 0, pData); TRACE("<- %x\n", res); return res; } static HRESULT WINAPI DEVENUM_IPropertyBag_Write( LPPROPERTYBAG iface, LPCOLESTR pszPropName, VARIANT* pVar) { RegPropBagImpl *This = impl_from_IPropertyBag(iface); LPVOID lpData = NULL; DWORD cbData = 0; DWORD dwType = 0; HRESULT res = S_OK; TRACE("(%p)->(%s, %p)\n", This, debugstr_w(pszPropName), pVar); switch (V_VT(pVar)) { case VT_BSTR: TRACE("writing %s\n", debugstr_w(V_UNION(pVar, bstrVal))); lpData = V_UNION(pVar, bstrVal); dwType = REG_SZ; cbData = (lstrlenW(V_UNION(pVar, bstrVal)) + 1) * sizeof(WCHAR); break; case VT_I4: case VT_UI4: TRACE("writing %u\n", V_UNION(pVar, ulVal)); lpData = &V_UNION(pVar, ulVal); dwType = REG_DWORD; cbData = sizeof(DWORD); break; case VT_ARRAY | VT_UI1: { LONG lUbound = 0; LONG lLbound = 0; dwType = REG_BINARY; res = SafeArrayGetLBound(V_UNION(pVar, parray), 1, &lLbound); res = SafeArrayGetUBound(V_UNION(pVar, parray), 1, &lUbound); cbData = (lUbound - lLbound + 1) /* * sizeof(BYTE)*/; TRACE("cbData: %d\n", cbData); res = SafeArrayAccessData(V_UNION(pVar, parray), &lpData); break; } default: FIXME("Variant type %d not handled\n", V_VT(pVar)); return E_FAIL; } if (RegSetValueExW(This->hkey, pszPropName, 0, dwType, lpData, cbData) != ERROR_SUCCESS) res = E_FAIL; if (V_VT(pVar) & VT_ARRAY) res = SafeArrayUnaccessData(V_UNION(pVar, parray)); return res; } static const IPropertyBagVtbl IPropertyBag_Vtbl = { DEVENUM_IPropertyBag_QueryInterface, DEVENUM_IPropertyBag_AddRef, DEVENUM_IPropertyBag_Release, DEVENUM_IPropertyBag_Read, DEVENUM_IPropertyBag_Write }; static HRESULT DEVENUM_IPropertyBag_Construct(HANDLE hkey, IPropertyBag **ppBag) { RegPropBagImpl * rpb = CoTaskMemAlloc(sizeof(RegPropBagImpl)); if (!rpb) return E_OUTOFMEMORY; rpb->IPropertyBag_iface.lpVtbl = &IPropertyBag_Vtbl; rpb->ref = 1; rpb->hkey = hkey; *ppBag = &rpb->IPropertyBag_iface; DEVENUM_LockModule(); return S_OK; } static inline MediaCatMoniker *impl_from_IMoniker(IMoniker *iface) { return CONTAINING_RECORD(iface, MediaCatMoniker, IMoniker_iface); } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv) { TRACE("\n\tIID:\t%s\n",debugstr_guid(riid)); if (!ppv) return E_POINTER; if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistStream) || IsEqualGUID(riid, &IID_IMoniker)) { *ppv = iface; IMoniker_AddRef(iface); return S_OK; } FIXME("- no interface IID: %s\n", debugstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } static ULONG WINAPI DEVENUM_IMediaCatMoniker_AddRef(IMoniker *iface) { MediaCatMoniker *This = impl_from_IMoniker(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG WINAPI DEVENUM_IMediaCatMoniker_Release(IMoniker *iface) { MediaCatMoniker *This = impl_from_IMoniker(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if (ref == 0) { RegCloseKey(This->hkey); CoTaskMemFree(This); DEVENUM_UnlockModule(); } return ref; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetClassID(IMoniker *iface, CLSID *pClassID) { MediaCatMoniker *This = impl_from_IMoniker(iface); FIXME("(%p)->(%p): stub\n", This, pClassID); if (pClassID == NULL) return E_POINTER; return E_NOTIMPL; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsDirty(IMoniker *iface) { FIXME("(%p)->(): stub\n", iface); return S_FALSE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Load(IMoniker *iface, IStream *pStm) { FIXME("(%p)->(%p): stub\n", iface, pStm); return E_NOTIMPL; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty) { FIXME("(%p)->(%p, %s): stub\n", iface, pStm, fClearDirty ? "true" : "false"); return STG_E_CANTSAVE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize) { FIXME("(%p)->(%p): stub\n", iface, pcbSize); ZeroMemory(pcbSize, sizeof(*pcbSize)); return S_OK; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult) { MediaCatMoniker *This = impl_from_IMoniker(iface); IUnknown * pObj = NULL; IPropertyBag * pProp = NULL; CLSID clsID; VARIANT var; HRESULT res = E_FAIL; TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riidResult), ppvResult); VariantInit(&var); *ppvResult = NULL; if(pmkToLeft==NULL) { /* first activation of this class */ LPVOID pvptr; res=IMoniker_BindToStorage(iface, NULL, NULL, &IID_IPropertyBag, &pvptr); pProp = pvptr; if (SUCCEEDED(res)) { V_VT(&var) = VT_LPWSTR; res = IPropertyBag_Read(pProp, clsid_keyname, &var, NULL); } if (SUCCEEDED(res)) { res = CLSIDFromString(V_UNION(&var,bstrVal), &clsID); CoTaskMemFree(V_UNION(&var, bstrVal)); } if (SUCCEEDED(res)) { res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IUnknown,&pvptr); pObj = pvptr; } } if (pObj!=NULL) { /* get the requested interface from the loaded class */ res = S_OK; if (pProp) { HRESULT res2; LPVOID ppv = NULL; res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv); if (SUCCEEDED(res2)) { res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL); IPersistPropertyBag_Release((IPersistPropertyBag *) ppv); } } if (SUCCEEDED(res)) res= IUnknown_QueryInterface(pObj,riidResult,ppvResult); IUnknown_Release(pObj); } if (pProp) { IPropertyBag_Release(pProp); } TRACE("<- 0x%x\n", res); return res; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppvObj) { MediaCatMoniker *This = impl_from_IMoniker(iface); TRACE("(%p)->(%p, %p, %s, %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObj); *ppvObj = NULL; if (pbc || pmkToLeft) return MK_E_NOSTORAGE; if (IsEqualGUID(riid, &IID_IPropertyBag)) { HANDLE hkey; DuplicateHandle(GetCurrentProcess(), This->hkey, GetCurrentProcess(), &hkey, 0, 0, DUPLICATE_SAME_ACCESS); return DEVENUM_IPropertyBag_Construct(hkey, (IPropertyBag**)ppvObj); } return MK_E_NOSTORAGE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced) { TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pbc, dwReduceHowFar, ppmkToLeft, ppmkReduced); if (ppmkToLeft) *ppmkToLeft = NULL; *ppmkReduced = iface; return MK_S_REDUCED_TO_SELF; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight, BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite) { FIXME("(%p)->(%p, %s, %p): stub\n", iface, pmkRight, fOnlyIfNotGeneric ? "true" : "false", ppmkComposite); /* FIXME: use CreateGenericComposite? */ *ppmkComposite = NULL; return E_NOTIMPL; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Enum(IMoniker *iface, BOOL fForward, IEnumMoniker **ppenumMoniker) { FIXME("(%p)->(%s, %p): stub\n", iface, fForward ? "true" : "false", ppenumMoniker); *ppenumMoniker = NULL; return S_OK; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker) { FIXME("(%p)->(%p): stub\n", iface, pmkOtherMoniker); return E_NOTIMPL; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Hash(IMoniker *iface, DWORD *pdwHash) { TRACE("(%p)->(%p)\n", iface, pdwHash); *pdwHash = 0; return S_OK; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning) { FIXME("(%p)->(%p, %p, %p): stub\n", iface, pbc, pmkToLeft, pmkNewlyRunning); return S_FALSE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime) { TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, pFileTime); pFileTime->dwLowDateTime = 0xFFFFFFFF; pFileTime->dwHighDateTime = 0x7FFFFFFF; return MK_E_UNAVAILABLE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_Inverse(IMoniker *iface, IMoniker **ppmk) { TRACE("(%p)->(%p)\n", iface, ppmk); *ppmk = NULL; return MK_E_NOINVERSE; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOtherMoniker, IMoniker **ppmkPrefix) { TRACE("(%p)->(%p, %p)\n", iface, pmkOtherMoniker, ppmkPrefix); *ppmkPrefix = NULL; return MK_E_NOPREFIX; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther, IMoniker **ppmkRelPath) { TRACE("(%p)->(%p, %p)\n", iface, pmkOther, ppmkRelPath); *ppmkRelPath = pmkOther; return MK_S_HIM; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName) { MediaCatMoniker *This = impl_from_IMoniker(iface); WCHAR wszBuffer[MAX_PATH]; static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0}; LONG received = sizeof(wszFriendlyName); TRACE("(%p)->(%p, %p, %p)\n", iface, pbc, pmkToLeft, ppszDisplayName); *ppszDisplayName = NULL; /* FIXME: should this be the weird stuff we have to parse in IParseDisplayName? */ if (RegQueryValueW(This->hkey, wszFriendlyName, wszBuffer, &received) == ERROR_SUCCESS) { *ppszDisplayName = CoTaskMemAlloc(received); strcpyW(*ppszDisplayName, wszBuffer); return S_OK; } return E_FAIL; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) { FIXME("(%p)->(%p, %p, %s, %p, %p)\n", iface, pbc, pmkToLeft, debugstr_w(pszDisplayName), pchEaten, ppmkOut); *pchEaten = 0; *ppmkOut = NULL; return MK_E_SYNTAX; } static HRESULT WINAPI DEVENUM_IMediaCatMoniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys) { TRACE("(%p)->(%p)\n", iface, pdwMksys); return S_FALSE; } static const IMonikerVtbl IMoniker_Vtbl = { DEVENUM_IMediaCatMoniker_QueryInterface, DEVENUM_IMediaCatMoniker_AddRef, DEVENUM_IMediaCatMoniker_Release, DEVENUM_IMediaCatMoniker_GetClassID, DEVENUM_IMediaCatMoniker_IsDirty, DEVENUM_IMediaCatMoniker_Load, DEVENUM_IMediaCatMoniker_Save, DEVENUM_IMediaCatMoniker_GetSizeMax, DEVENUM_IMediaCatMoniker_BindToObject, DEVENUM_IMediaCatMoniker_BindToStorage, DEVENUM_IMediaCatMoniker_Reduce, DEVENUM_IMediaCatMoniker_ComposeWith, DEVENUM_IMediaCatMoniker_Enum, DEVENUM_IMediaCatMoniker_IsEqual, DEVENUM_IMediaCatMoniker_Hash, DEVENUM_IMediaCatMoniker_IsRunning, DEVENUM_IMediaCatMoniker_GetTimeOfLastChange, DEVENUM_IMediaCatMoniker_Inverse, DEVENUM_IMediaCatMoniker_CommonPrefixWith, DEVENUM_IMediaCatMoniker_RelativePathTo, DEVENUM_IMediaCatMoniker_GetDisplayName, DEVENUM_IMediaCatMoniker_ParseDisplayName, DEVENUM_IMediaCatMoniker_IsSystemMoniker }; MediaCatMoniker * DEVENUM_IMediaCatMoniker_Construct(void) { MediaCatMoniker * pMoniker = NULL; pMoniker = CoTaskMemAlloc(sizeof(MediaCatMoniker)); if (!pMoniker) return NULL; pMoniker->IMoniker_iface.lpVtbl = &IMoniker_Vtbl; pMoniker->ref = 0; pMoniker->hkey = NULL; DEVENUM_IMediaCatMoniker_AddRef(&pMoniker->IMoniker_iface); DEVENUM_LockModule(); return pMoniker; } static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface) { return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface); } static HRESULT WINAPI DEVENUM_IEnumMoniker_QueryInterface(IEnumMoniker *iface, REFIID riid, void **ppv) { TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); if (!ppv) return E_POINTER; if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumMoniker)) { *ppv = iface; IEnumMoniker_AddRef(iface); return S_OK; } FIXME("- no interface IID: %s\n", debugstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } static ULONG WINAPI DEVENUM_IEnumMoniker_AddRef(IEnumMoniker *iface) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG WINAPI DEVENUM_IEnumMoniker_Release(IEnumMoniker *iface) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if (!ref) { RegCloseKey(This->hkey); CoTaskMemFree(This); DEVENUM_UnlockModule(); return 0; } return ref; } static HRESULT WINAPI DEVENUM_IEnumMoniker_Next(IEnumMoniker *iface, ULONG celt, IMoniker **rgelt, ULONG *pceltFetched) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); WCHAR buffer[MAX_PATH + 1]; LONG res; ULONG fetched = 0; MediaCatMoniker * pMoniker; TRACE("(%p)->(%d, %p, %p)\n", iface, celt, rgelt, pceltFetched); while (fetched < celt) { res = RegEnumKeyW(This->hkey, This->index, buffer, sizeof(buffer) / sizeof(WCHAR)); if (res != ERROR_SUCCESS) { break; } pMoniker = DEVENUM_IMediaCatMoniker_Construct(); if (!pMoniker) return E_OUTOFMEMORY; if (RegOpenKeyW(This->hkey, buffer, &pMoniker->hkey) != ERROR_SUCCESS) { IMoniker_Release(&pMoniker->IMoniker_iface); break; } rgelt[fetched] = &pMoniker->IMoniker_iface; fetched++; } This->index += fetched; TRACE("-- fetched %d\n", fetched); if (pceltFetched) *pceltFetched = fetched; if (fetched != celt) return S_FALSE; else return S_OK; } static HRESULT WINAPI DEVENUM_IEnumMoniker_Skip(IEnumMoniker *iface, ULONG celt) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); DWORD subKeys; TRACE("(%p)->(%d)\n", iface, celt); /* Before incrementing, check if there are any more values to run through. Some programs use the Skip() function to get the number of devices */ if(RegQueryInfoKeyW(This->hkey, NULL, NULL, NULL, &subKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) { return S_FALSE; } if((This->index + celt) >= subKeys) { return S_FALSE; } This->index += celt; return S_OK; } static HRESULT WINAPI DEVENUM_IEnumMoniker_Reset(IEnumMoniker *iface) { EnumMonikerImpl *This = impl_from_IEnumMoniker(iface); TRACE("(%p)->()\n", iface); This->index = 0; return S_OK; } static HRESULT WINAPI DEVENUM_IEnumMoniker_Clone(IEnumMoniker *iface, IEnumMoniker **ppenum) { FIXME("(%p)->(%p): stub\n", iface, ppenum); return E_NOTIMPL; } /********************************************************************** * IEnumMoniker_Vtbl */ static const IEnumMonikerVtbl IEnumMoniker_Vtbl = { DEVENUM_IEnumMoniker_QueryInterface, DEVENUM_IEnumMoniker_AddRef, DEVENUM_IEnumMoniker_Release, DEVENUM_IEnumMoniker_Next, DEVENUM_IEnumMoniker_Skip, DEVENUM_IEnumMoniker_Reset, DEVENUM_IEnumMoniker_Clone }; HRESULT DEVENUM_IEnumMoniker_Construct(HKEY hkey, IEnumMoniker ** ppEnumMoniker) { EnumMonikerImpl * pEnumMoniker = CoTaskMemAlloc(sizeof(EnumMonikerImpl)); if (!pEnumMoniker) return E_OUTOFMEMORY; pEnumMoniker->IEnumMoniker_iface.lpVtbl = &IEnumMoniker_Vtbl; pEnumMoniker->ref = 1; pEnumMoniker->index = 0; pEnumMoniker->hkey = hkey; *ppEnumMoniker = &pEnumMoniker->IEnumMoniker_iface; DEVENUM_LockModule(); return S_OK; }