quartz: Hold a reference on the PullPin's filter while the processing thread is alive.
[wine] / dlls / quartz / enumpins.c
1 /*
2  * Implementation of IEnumPins Interface
3  *
4  * Copyright 2003 Robert Shearman
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 "quartz_private.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
26
27 typedef struct IEnumPinsImpl
28 {
29     const IEnumPinsVtbl * lpVtbl;
30     LONG refCount;
31     ENUMPINDETAILS enumPinDetails;
32     ULONG uIndex;
33 } IEnumPinsImpl;
34
35 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
36
37 HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum)
38 {
39     IEnumPinsImpl * pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
40     if (!pEnumPins)
41     {
42         *ppEnum = NULL;
43         return E_OUTOFMEMORY;
44     }
45     pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
46     pEnumPins->refCount = 1;
47     pEnumPins->uIndex = 0;
48     CopyMemory(&pEnumPins->enumPinDetails, pDetails, sizeof(ENUMPINDETAILS));
49     *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
50
51     TRACE("Created new enumerator (%p)\n", *ppEnum);
52     return S_OK;
53 }
54
55 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
56 {
57     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
58
59     *ppv = NULL;
60
61     if (IsEqualIID(riid, &IID_IUnknown))
62         *ppv = (LPVOID)iface;
63     else if (IsEqualIID(riid, &IID_IEnumPins))
64         *ppv = (LPVOID)iface;
65
66     if (*ppv)
67     {
68         IUnknown_AddRef((IUnknown *)(*ppv));
69         return S_OK;
70     }
71
72     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
73
74     return E_NOINTERFACE;
75 }
76
77 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
78 {
79     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
80     ULONG refCount = InterlockedIncrement(&This->refCount);
81
82     TRACE("(%p)->() AddRef from %d\n", This, refCount - 1);
83
84     return refCount;
85 }
86
87 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
88 {
89     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
90     ULONG refCount = InterlockedDecrement(&This->refCount);
91
92     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
93     
94     if (!refCount)
95     {
96         CoTaskMemFree(This);
97         return 0;
98     }
99     else
100         return refCount;
101 }
102
103 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
104 {
105     ULONG cFetched; 
106     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
107
108     cFetched = min(This->enumPinDetails.cPins, This->uIndex + cPins) - This->uIndex;
109
110     TRACE("(%u, %p, %p)\n", cPins, ppPins, pcFetched);
111
112     if (cFetched > 0)
113     {
114         ULONG i;
115         for (i = 0; i < cFetched; i++) {
116             IPin_AddRef(This->enumPinDetails.ppPins[This->uIndex + i]);
117             ppPins[i] = This->enumPinDetails.ppPins[This->uIndex + i];
118         }
119     }
120
121     if ((cPins != 1) || pcFetched)
122         *pcFetched = cFetched;
123
124     This->uIndex += cFetched;
125
126     if (cFetched != cPins)
127         return S_FALSE;
128     return S_OK;
129 }
130
131 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
132 {
133     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
134
135     TRACE("(%u)\n", cPins);
136
137     if (This->uIndex + cPins < This->enumPinDetails.cPins)
138     {
139         This->uIndex += cPins;
140         return S_OK;
141     }
142     return S_FALSE;
143 }
144
145 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
146 {
147     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
148
149     TRACE("IEnumPinsImpl::Reset()\n");
150
151     This->uIndex = 0;
152     return S_OK;
153 }
154
155 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
156 {
157     HRESULT hr;
158     IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
159
160     TRACE("(%p)\n", ppEnum);
161
162     hr = IEnumPinsImpl_Construct(&This->enumPinDetails, ppEnum);
163     if (FAILED(hr))
164         return hr;
165     return IEnumPins_Skip(*ppEnum, This->uIndex);
166 }
167
168 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
169 {
170     IEnumPinsImpl_QueryInterface,
171     IEnumPinsImpl_AddRef,
172     IEnumPinsImpl_Release,
173     IEnumPinsImpl_Next,
174     IEnumPinsImpl_Skip,
175     IEnumPinsImpl_Reset,
176     IEnumPinsImpl_Clone
177 };