1 /* 2 * Queue Manager (BITS) Job Enumerator 3 * 4 * Copyright 2007 Google (Roy Shea) 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 IEnumBackgroundCopyJobs IEnumBackgroundCopyJobs_iface; 29 LONG ref; 30 IBackgroundCopyJob3 **jobs; 31 ULONG numJobs; 32 ULONG indexJobs; 33 } EnumBackgroundCopyJobsImpl; 34 35 static inline EnumBackgroundCopyJobsImpl *impl_from_IEnumBackgroundCopyJobs(IEnumBackgroundCopyJobs *iface) 36 { 37 return CONTAINING_RECORD(iface, EnumBackgroundCopyJobsImpl, IEnumBackgroundCopyJobs_iface); 38 } 39 40 static HRESULT WINAPI EnumBackgroundCopyJobs_QueryInterface(IEnumBackgroundCopyJobs *iface, 41 REFIID riid, void **ppv) 42 { 43 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 44 45 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); 46 47 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumBackgroundCopyJobs)) 48 { 49 *ppv = iface; 50 IEnumBackgroundCopyJobs_AddRef(iface); 51 return S_OK; 52 } 53 54 *ppv = NULL; 55 return E_NOINTERFACE; 56 } 57 58 static ULONG WINAPI EnumBackgroundCopyJobs_AddRef(IEnumBackgroundCopyJobs *iface) 59 { 60 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 61 ULONG ref = InterlockedIncrement(&This->ref); 62 63 TRACE("(%p)->(%d)\n", This, ref); 64 65 return ref; 66 } 67 68 static ULONG WINAPI EnumBackgroundCopyJobs_Release(IEnumBackgroundCopyJobs *iface) 69 { 70 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 71 ULONG ref = InterlockedDecrement(&This->ref); 72 ULONG i; 73 74 TRACE("(%p)->(%d)\n", This, ref); 75 76 if (ref == 0) { 77 for(i = 0; i < This->numJobs; i++) 78 IBackgroundCopyJob3_Release(This->jobs[i]); 79 HeapFree(GetProcessHeap(), 0, This->jobs); 80 HeapFree(GetProcessHeap(), 0, This); 81 } 82 83 return ref; 84 } 85 86 static HRESULT WINAPI EnumBackgroundCopyJobs_Next(IEnumBackgroundCopyJobs *iface, ULONG celt, 87 IBackgroundCopyJob **rgelt, ULONG *pceltFetched) 88 { 89 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 90 ULONG fetched; 91 ULONG i; 92 IBackgroundCopyJob3 *job; 93 94 TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched); 95 96 fetched = min(celt, This->numJobs - This->indexJobs); 97 if (pceltFetched) 98 *pceltFetched = fetched; 99 else 100 { 101 /* We need to initialize this array if the caller doesn't request 102 the length because length_is will default to celt. */ 103 for (i = 0; i < celt; ++i) 104 rgelt[i] = NULL; 105 106 /* pceltFetched can only be NULL if celt is 1 */ 107 if (celt != 1) 108 return E_INVALIDARG; 109 } 110 111 /* Fill in the array of objects */ 112 for (i = 0; i < fetched; ++i) 113 { 114 job = This->jobs[This->indexJobs++]; 115 IBackgroundCopyJob3_AddRef(job); 116 rgelt[i] = (IBackgroundCopyJob *)job; 117 } 118 119 return fetched == celt ? S_OK : S_FALSE; 120 } 121 122 static HRESULT WINAPI EnumBackgroundCopyJobs_Skip(IEnumBackgroundCopyJobs *iface, ULONG celt) 123 { 124 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 125 126 TRACE("(%p)->(%d)\n", This, celt); 127 128 if (This->numJobs - This->indexJobs < celt) 129 { 130 This->indexJobs = This->numJobs; 131 return S_FALSE; 132 } 133 134 This->indexJobs += celt; 135 return S_OK; 136 } 137 138 static HRESULT WINAPI EnumBackgroundCopyJobs_Reset(IEnumBackgroundCopyJobs *iface) 139 { 140 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 141 142 TRACE("(%p)\n", This); 143 144 This->indexJobs = 0; 145 return S_OK; 146 } 147 148 static HRESULT WINAPI EnumBackgroundCopyJobs_Clone(IEnumBackgroundCopyJobs *iface, 149 IEnumBackgroundCopyJobs **ppenum) 150 { 151 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 152 FIXME("(%p)->(%p): stub\n", This, ppenum); 153 return E_NOTIMPL; 154 } 155 156 static HRESULT WINAPI EnumBackgroundCopyJobs_GetCount(IEnumBackgroundCopyJobs *iface, 157 ULONG *puCount) 158 { 159 EnumBackgroundCopyJobsImpl *This = impl_from_IEnumBackgroundCopyJobs(iface); 160 161 TRACE("(%p)->(%p)\n", This, puCount); 162 163 *puCount = This->numJobs; 164 return S_OK; 165 } 166 167 static const IEnumBackgroundCopyJobsVtbl EnumBackgroundCopyJobsVtbl = 168 { 169 EnumBackgroundCopyJobs_QueryInterface, 170 EnumBackgroundCopyJobs_AddRef, 171 EnumBackgroundCopyJobs_Release, 172 EnumBackgroundCopyJobs_Next, 173 EnumBackgroundCopyJobs_Skip, 174 EnumBackgroundCopyJobs_Reset, 175 EnumBackgroundCopyJobs_Clone, 176 EnumBackgroundCopyJobs_GetCount 177 }; 178 179 HRESULT enum_copy_job_create(BackgroundCopyManagerImpl *qmgr, IEnumBackgroundCopyJobs **enumjob) 180 { 181 EnumBackgroundCopyJobsImpl *This; 182 BackgroundCopyJobImpl *job; 183 ULONG i; 184 185 TRACE("%p, %p)\n", qmgr, enumjob); 186 187 This = HeapAlloc(GetProcessHeap(), 0, sizeof *This); 188 if (!This) 189 return E_OUTOFMEMORY; 190 This->IEnumBackgroundCopyJobs_iface.lpVtbl = &EnumBackgroundCopyJobsVtbl; 191 This->ref = 1; 192 193 /* Create array of jobs */ 194 This->indexJobs = 0; 195 196 EnterCriticalSection(&qmgr->cs); 197 This->numJobs = list_count(&qmgr->jobs); 198 199 if (0 < This->numJobs) 200 { 201 This->jobs = HeapAlloc(GetProcessHeap(), 0, 202 This->numJobs * sizeof *This->jobs); 203 if (!This->jobs) 204 { 205 LeaveCriticalSection(&qmgr->cs); 206 HeapFree(GetProcessHeap(), 0, This); 207 return E_OUTOFMEMORY; 208 } 209 } 210 else 211 This->jobs = NULL; 212 213 i = 0; 214 LIST_FOR_EACH_ENTRY(job, &qmgr->jobs, BackgroundCopyJobImpl, entryFromQmgr) 215 { 216 IBackgroundCopyJob3_AddRef(&job->IBackgroundCopyJob3_iface); 217 This->jobs[i++] = &job->IBackgroundCopyJob3_iface; 218 } 219 LeaveCriticalSection(&qmgr->cs); 220 221 *enumjob = &This->IEnumBackgroundCopyJobs_iface; 222 return S_OK; 223 } 224