1 /* 2 * Queue Manager (BITS) File Enumerator 3 * 4 * Copyright 2007, 2008 Google (Roy Shea, Dan Hipschman) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "qmgr.h" 22 #include "wine/debug.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(qmgr); 25 26 typedef struct 27 { 28 IEnumBackgroundCopyFiles IEnumBackgroundCopyFiles_iface; 29 LONG ref; 30 IBackgroundCopyFile2 **files; 31 ULONG numFiles; 32 ULONG indexFiles; 33 } EnumBackgroundCopyFilesImpl; 34 35 static inline EnumBackgroundCopyFilesImpl *impl_from_IEnumBackgroundCopyFiles(IEnumBackgroundCopyFiles *iface) 36 { 37 return CONTAINING_RECORD(iface, EnumBackgroundCopyFilesImpl, IEnumBackgroundCopyFiles_iface); 38 } 39 40 static HRESULT WINAPI EnumBackgroundCopyFiles_QueryInterface(IEnumBackgroundCopyFiles *iface, 41 REFIID riid, void **ppv) 42 { 43 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 44 45 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); 46 47 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumBackgroundCopyFiles)) 48 { 49 *ppv = iface; 50 IEnumBackgroundCopyFiles_AddRef(iface); 51 return S_OK; 52 } 53 54 *ppv = NULL; 55 return E_NOINTERFACE; 56 } 57 58 static ULONG WINAPI EnumBackgroundCopyFiles_AddRef(IEnumBackgroundCopyFiles *iface) 59 { 60 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 61 ULONG ref = InterlockedIncrement(&This->ref); 62 63 TRACE("(%p)->(%d)\n", This, ref); 64 return ref; 65 } 66 67 static ULONG WINAPI EnumBackgroundCopyFiles_Release(IEnumBackgroundCopyFiles *iface) 68 { 69 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 70 ULONG ref = InterlockedDecrement(&This->ref); 71 ULONG i; 72 73 TRACE("(%p)->(%d)\n", This, ref); 74 75 if (ref == 0) 76 { 77 for(i = 0; i < This->numFiles; i++) 78 IBackgroundCopyFile2_Release(This->files[i]); 79 HeapFree(GetProcessHeap(), 0, This->files); 80 HeapFree(GetProcessHeap(), 0, This); 81 } 82 83 return ref; 84 } 85 86 /* Return reference to one or more files in the file enumerator */ 87 static HRESULT WINAPI EnumBackgroundCopyFiles_Next(IEnumBackgroundCopyFiles *iface, 88 ULONG celt, IBackgroundCopyFile **rgelt, ULONG *pceltFetched) 89 { 90 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 91 ULONG fetched; 92 ULONG i; 93 IBackgroundCopyFile2 *file; 94 95 TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched); 96 97 /* Despite documented behavior, Windows (tested on XP) is not verifying 98 that the caller set pceltFetched to zero. No check here. */ 99 100 fetched = min(celt, This->numFiles - This->indexFiles); 101 if (pceltFetched) 102 *pceltFetched = fetched; 103 else 104 { 105 /* We need to initialize this array if the caller doesn't request 106 the length because length_is will default to celt. */ 107 for (i = 0; i < celt; i++) 108 rgelt[i] = NULL; 109 110 /* pceltFetched can only be NULL if celt is 1 */ 111 if (celt != 1) 112 return E_INVALIDARG; 113 } 114 115 /* Fill in the array of objects */ 116 for (i = 0; i < fetched; i++) 117 { 118 file = This->files[This->indexFiles++]; 119 IBackgroundCopyFile2_AddRef(file); 120 rgelt[i] = (IBackgroundCopyFile *)file; 121 } 122 123 return fetched == celt ? S_OK : S_FALSE; 124 } 125 126 /* Skip over one or more files in the file enumerator */ 127 static HRESULT WINAPI EnumBackgroundCopyFiles_Skip(IEnumBackgroundCopyFiles *iface, 128 ULONG celt) 129 { 130 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 131 132 TRACE("(%p)->(%d)\n", This, celt); 133 134 if (celt > This->numFiles - This->indexFiles) 135 { 136 This->indexFiles = This->numFiles; 137 return S_FALSE; 138 } 139 140 This->indexFiles += celt; 141 return S_OK; 142 } 143 144 static HRESULT WINAPI EnumBackgroundCopyFiles_Reset(IEnumBackgroundCopyFiles *iface) 145 { 146 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 147 148 TRACE("(%p)\n", This); 149 150 This->indexFiles = 0; 151 return S_OK; 152 } 153 154 static HRESULT WINAPI EnumBackgroundCopyFiles_Clone(IEnumBackgroundCopyFiles *iface, 155 IEnumBackgroundCopyFiles **ppenum) 156 { 157 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 158 FIXME("(%p)->(%p): stub\n", This, ppenum); 159 return E_NOTIMPL; 160 } 161 162 static HRESULT WINAPI EnumBackgroundCopyFiles_GetCount(IEnumBackgroundCopyFiles *iface, 163 ULONG *puCount) 164 { 165 EnumBackgroundCopyFilesImpl *This = impl_from_IEnumBackgroundCopyFiles(iface); 166 TRACE("(%p)->(%p)\n", This, puCount); 167 *puCount = This->numFiles; 168 return S_OK; 169 } 170 171 static const IEnumBackgroundCopyFilesVtbl EnumBackgroundCopyFilesVtbl = 172 { 173 EnumBackgroundCopyFiles_QueryInterface, 174 EnumBackgroundCopyFiles_AddRef, 175 EnumBackgroundCopyFiles_Release, 176 EnumBackgroundCopyFiles_Next, 177 EnumBackgroundCopyFiles_Skip, 178 EnumBackgroundCopyFiles_Reset, 179 EnumBackgroundCopyFiles_Clone, 180 EnumBackgroundCopyFiles_GetCount 181 }; 182 183 HRESULT EnumBackgroundCopyFilesConstructor(BackgroundCopyJobImpl *job, IEnumBackgroundCopyFiles **enum_files) 184 { 185 EnumBackgroundCopyFilesImpl *This; 186 BackgroundCopyFileImpl *file; 187 ULONG i; 188 189 TRACE("%p, %p)\n", job, enum_files); 190 191 This = HeapAlloc(GetProcessHeap(), 0, sizeof *This); 192 if (!This) 193 return E_OUTOFMEMORY; 194 195 This->IEnumBackgroundCopyFiles_iface.lpVtbl = &EnumBackgroundCopyFilesVtbl; 196 This->ref = 1; 197 198 /* Create array of files */ 199 This->indexFiles = 0; 200 EnterCriticalSection(&job->cs); 201 This->numFiles = list_count(&job->files); 202 This->files = NULL; 203 if (This->numFiles > 0) 204 { 205 This->files = HeapAlloc(GetProcessHeap(), 0, 206 This->numFiles * sizeof This->files[0]); 207 if (!This->files) 208 { 209 LeaveCriticalSection(&job->cs); 210 HeapFree(GetProcessHeap(), 0, This); 211 return E_OUTOFMEMORY; 212 } 213 } 214 215 i = 0; 216 LIST_FOR_EACH_ENTRY(file, &job->files, BackgroundCopyFileImpl, entryFromJob) 217 { 218 IBackgroundCopyFile2_AddRef(&file->IBackgroundCopyFile2_iface); 219 This->files[i] = &file->IBackgroundCopyFile2_iface; 220 ++i; 221 } 222 LeaveCriticalSection(&job->cs); 223 224 *enum_files = &This->IEnumBackgroundCopyFiles_iface; 225 return S_OK; 226 } 227