jscript: Added get_op_int helper.
[wine] / dlls / dsound / buffer.c
1 /*                      DirectSound
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2002 TransGaming Technologies, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "winternl.h"
31 #include "vfwmsgs.h"
32 #include "wine/debug.h"
33 #include "dsound.h"
34 #include "dsound_private.h"
35 #include "dsconf.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
38
39 /*******************************************************************************
40  *              IDirectSoundNotify
41  */
42
43 static inline struct IDirectSoundBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
44 {
45     return CONTAINING_RECORD(iface, struct IDirectSoundBufferImpl, IDirectSoundNotify_iface);
46 }
47
48 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
49         void **ppobj)
50 {
51     IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
52
53     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
54
55     return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
56 }
57
58 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
59 {
60     IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
61     ULONG ref = InterlockedIncrement(&This->refn);
62
63     TRACE("(%p) ref was %d\n", This, ref - 1);
64
65     if(ref == 1)
66         InterlockedIncrement(&This->numIfaces);
67
68     return ref;
69 }
70
71 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
72 {
73     IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
74     ULONG ref = InterlockedDecrement(&This->refn);
75
76     TRACE("(%p) ref was %d\n", This, ref + 1);
77
78     if (!ref && !InterlockedDecrement(&This->numIfaces))
79         secondarybuffer_destroy(This);
80
81     return ref;
82 }
83
84 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
85         DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
86 {
87         IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
88
89         TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
90
91         if (howmuch > 0 && notify == NULL) {
92             WARN("invalid parameter: notify == NULL\n");
93             return DSERR_INVALIDPARAM;
94         }
95
96         if (TRACE_ON(dsound)) {
97             unsigned int        i;
98             for (i=0;i<howmuch;i++)
99                 TRACE("notify at %d to %p\n",
100                     notify[i].dwOffset,notify[i].hEventNotify);
101         }
102
103         if (howmuch > 0) {
104             /* Make an internal copy of the caller-supplied array.
105              * Replace the existing copy if one is already present. */
106             HeapFree(GetProcessHeap(), 0, This->notifies);
107             This->notifies = HeapAlloc(GetProcessHeap(), 0,
108                         howmuch * sizeof(DSBPOSITIONNOTIFY));
109
110             if (This->notifies == NULL) {
111                     WARN("out of memory\n");
112                     return DSERR_OUTOFMEMORY;
113             }
114             CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
115             This->nrofnotifies = howmuch;
116         } else {
117            HeapFree(GetProcessHeap(), 0, This->notifies);
118            This->notifies = NULL;
119            This->nrofnotifies = 0;
120         }
121
122         return S_OK;
123 }
124
125 static const IDirectSoundNotifyVtbl dsnvt =
126 {
127     IDirectSoundNotifyImpl_QueryInterface,
128     IDirectSoundNotifyImpl_AddRef,
129     IDirectSoundNotifyImpl_Release,
130     IDirectSoundNotifyImpl_SetNotificationPositions,
131 };
132
133 /*******************************************************************************
134  *              IDirectSoundBuffer
135  */
136
137 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
138 {
139     return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
140 }
141
142 static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
143 {
144     return This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER ? TRUE : FALSE;
145 }
146
147 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
148         LPCWAVEFORMATEX wfex)
149 {
150     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
151
152     TRACE("(%p,%p)\n", iface, wfex);
153
154     if (is_primary_buffer(This))
155         return primarybuffer_SetFormat(This->device, wfex);
156     else {
157         WARN("not available for secondary buffers.\n");
158         return DSERR_INVALIDCALL;
159     }
160 }
161
162 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
163 {
164         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
165         LONG oldVol;
166
167         HRESULT hres = DS_OK;
168
169         TRACE("(%p,%d)\n",This,vol);
170
171         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
172                 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
173                 return DSERR_CONTROLUNAVAIL;
174         }
175
176         if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
177                 WARN("invalid parameter: vol = %d\n", vol);
178                 return DSERR_INVALIDPARAM;
179         }
180
181         /* **** */
182         RtlAcquireResourceExclusive(&This->lock, TRUE);
183
184         if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
185                 oldVol = This->ds3db_lVolume;
186                 This->ds3db_lVolume = vol;
187                 if (vol != oldVol)
188                         /* recalc 3d volume, which in turn recalcs the pans */
189                         DSOUND_Calc3DBuffer(This);
190         } else {
191                 oldVol = This->volpan.lVolume;
192                 This->volpan.lVolume = vol;
193                 if (vol != oldVol)
194                         DSOUND_RecalcVolPan(&(This->volpan));
195         }
196
197         RtlReleaseResource(&This->lock);
198         /* **** */
199
200         return hres;
201 }
202
203 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
204 {
205         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
206
207         TRACE("(%p,%p)\n",This,vol);
208
209         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
210                 WARN("control unavailable\n");
211                 return DSERR_CONTROLUNAVAIL;
212         }
213
214         if (vol == NULL) {
215                 WARN("invalid parameter: vol == NULL\n");
216                 return DSERR_INVALIDPARAM;
217         }
218
219         *vol = This->volpan.lVolume;
220
221         return DS_OK;
222 }
223
224 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
225 {
226         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
227         DWORD oldFreq;
228
229         TRACE("(%p,%d)\n",This,freq);
230
231         if (is_primary_buffer(This)) {
232                 WARN("not available for primary buffers.\n");
233                 return DSERR_CONTROLUNAVAIL;
234         }
235
236         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
237                 WARN("control unavailable\n");
238                 return DSERR_CONTROLUNAVAIL;
239         }
240
241         if (freq == DSBFREQUENCY_ORIGINAL)
242                 freq = This->pwfx->nSamplesPerSec;
243
244         if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
245                 WARN("invalid parameter: freq = %d\n", freq);
246                 return DSERR_INVALIDPARAM;
247         }
248
249         /* **** */
250         RtlAcquireResourceExclusive(&This->lock, TRUE);
251
252         oldFreq = This->freq;
253         This->freq = freq;
254         if (freq != oldFreq) {
255                 This->freqAdjust = This->freq / (float)This->device->pwfx->nSamplesPerSec;
256                 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
257                 DSOUND_RecalcFormat(This);
258         }
259
260         RtlReleaseResource(&This->lock);
261         /* **** */
262
263         return DS_OK;
264 }
265
266 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
267         DWORD reserved2, DWORD flags)
268 {
269         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
270         HRESULT hres = DS_OK;
271
272         TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
273
274         /* **** */
275         RtlAcquireResourceExclusive(&This->lock, TRUE);
276
277         This->playflags = flags;
278         if (This->state == STATE_STOPPED) {
279                 This->leadin = TRUE;
280                 This->state = STATE_STARTING;
281         } else if (This->state == STATE_STOPPING)
282                 This->state = STATE_PLAYING;
283
284         RtlReleaseResource(&This->lock);
285         /* **** */
286
287         return hres;
288 }
289
290 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
291 {
292         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
293         HRESULT hres = DS_OK;
294
295         TRACE("(%p)\n",This);
296
297         /* **** */
298         RtlAcquireResourceExclusive(&This->lock, TRUE);
299
300         if (This->state == STATE_PLAYING)
301                 This->state = STATE_STOPPING;
302         else if (This->state == STATE_STARTING)
303         {
304                 This->state = STATE_STOPPED;
305                 DSOUND_CheckEvent(This, 0, 0);
306         }
307
308         RtlReleaseResource(&This->lock);
309         /* **** */
310
311         return hres;
312 }
313
314 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
315 {
316     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
317     ULONG ref = InterlockedIncrement(&This->ref);
318
319     TRACE("(%p) ref was %d\n", This, ref - 1);
320
321     if(ref == 1)
322         InterlockedIncrement(&This->numIfaces);
323
324     return ref;
325 }
326
327 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
328 {
329     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
330     ULONG ref;
331
332     if (is_primary_buffer(This)){
333         ref = capped_refcount_dec(&This->ref);
334         if(!ref)
335             capped_refcount_dec(&This->numIfaces);
336         TRACE("(%p) ref is now: %d\n", This, ref);
337         return ref;
338     }
339
340     ref = InterlockedDecrement(&This->ref);
341     if (!ref && !InterlockedDecrement(&This->numIfaces))
342             secondarybuffer_destroy(This);
343
344     TRACE("(%p) ref is now %d\n", This, ref);
345
346     return ref;
347 }
348
349 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
350         DWORD *playpos, DWORD *writepos)
351 {
352         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
353         DWORD pos;
354
355         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
356
357         RtlAcquireResourceShared(&This->lock, TRUE);
358
359         pos = This->sec_mixpos;
360
361         /* sanity */
362         if (pos >= This->buflen){
363                 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
364                 pos %= This->buflen;
365         }
366
367         if (playpos)
368                 *playpos = pos;
369         if (writepos)
370                 *writepos = pos;
371
372         if (writepos && This->state != STATE_STOPPED) {
373                 /* apply the documented 10ms lead to writepos */
374                 *writepos += This->writelead;
375                 *writepos %= This->buflen;
376         }
377
378         RtlReleaseResource(&This->lock);
379
380         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
381                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
382
383         return DS_OK;
384 }
385
386 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
387 {
388         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
389
390         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
391
392         if (status == NULL) {
393                 WARN("invalid parameter: status = NULL\n");
394                 return DSERR_INVALIDPARAM;
395         }
396
397         *status = 0;
398         RtlAcquireResourceShared(&This->lock, TRUE);
399         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
400                 *status |= DSBSTATUS_PLAYING;
401                 if (This->playflags & DSBPLAY_LOOPING)
402                         *status |= DSBSTATUS_LOOPING;
403         }
404         RtlReleaseResource(&This->lock);
405
406         TRACE("status=%x\n", *status);
407         return DS_OK;
408 }
409
410
411 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
412         LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
413 {
414     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
415     DWORD size;
416
417     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
418
419     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
420
421     if (lpwf) { /* NULL is valid */
422         if (wfsize >= size) {
423             CopyMemory(lpwf,This->pwfx,size);
424             if (wfwritten)
425                 *wfwritten = size;
426         } else {
427             WARN("invalid parameter: wfsize too small\n");
428             CopyMemory(lpwf,This->pwfx,wfsize);
429             if (wfwritten)
430                 *wfwritten = wfsize;
431             return DSERR_INVALIDPARAM;
432         }
433     } else {
434         if (wfwritten)
435             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
436         else {
437             WARN("invalid parameter: wfwritten == NULL\n");
438             return DSERR_INVALIDPARAM;
439         }
440     }
441
442     return DS_OK;
443 }
444
445 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
446         DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
447         DWORD *audiobytes2, DWORD flags)
448 {
449         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
450         HRESULT hres = DS_OK;
451
452         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
453                 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
454
455         if (!audiobytes1)
456             return DSERR_INVALIDPARAM;
457
458         /* when this flag is set, writecursor is meaningless and must be calculated */
459         if (flags & DSBLOCK_FROMWRITECURSOR) {
460                 /* GetCurrentPosition does too much magic to duplicate here */
461                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
462                 if (hres != DS_OK) {
463                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
464                         return hres;
465                 }
466         }
467
468         /* when this flag is set, writebytes is meaningless and must be set */
469         if (flags & DSBLOCK_ENTIREBUFFER)
470                 writebytes = This->buflen;
471
472         if (writecursor >= This->buflen) {
473                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
474                      writecursor, This->buflen);
475                 return DSERR_INVALIDPARAM;
476         }
477
478         if (writebytes > This->buflen) {
479                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
480                      writebytes, This->buflen);
481                 return DSERR_INVALIDPARAM;
482         }
483
484         /* **** */
485         RtlAcquireResourceShared(&This->lock, TRUE);
486
487         if (writecursor+writebytes <= This->buflen) {
488                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
489                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
490                         WARN("Overwriting mixing position, case 1\n");
491                 *audiobytes1 = writebytes;
492                 if (lplpaudioptr2)
493                         *(LPBYTE*)lplpaudioptr2 = NULL;
494                 if (audiobytes2)
495                         *audiobytes2 = 0;
496                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
497                   *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
498                 TRACE("->%d.0\n",writebytes);
499         } else {
500                 DWORD remainder = writebytes + writecursor - This->buflen;
501                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
502                 *audiobytes1 = This->buflen-writecursor;
503                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
504                         WARN("Overwriting mixing position, case 2\n");
505                 if (lplpaudioptr2)
506                         *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
507                 if (audiobytes2)
508                         *audiobytes2 = writebytes-(This->buflen-writecursor);
509                 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
510                         WARN("Overwriting mixing position, case 3\n");
511                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
512         }
513
514         RtlReleaseResource(&This->lock);
515         /* **** */
516
517         return DS_OK;
518 }
519
520 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
521         DWORD newpos)
522 {
523         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
524         HRESULT hres = DS_OK;
525
526         TRACE("(%p,%d)\n",This,newpos);
527
528         /* **** */
529         RtlAcquireResourceExclusive(&This->lock, TRUE);
530
531         /* start mixing from this new location instead */
532         newpos %= This->buflen;
533         newpos -= newpos%This->pwfx->nBlockAlign;
534         This->sec_mixpos = newpos;
535
536         /* at this point, do not attempt to reset buffers, mess with primary mix position,
537            or anything like that to reduce latency. The data already prebuffered cannot be changed */
538
539         RtlReleaseResource(&This->lock);
540         /* **** */
541
542         return hres;
543 }
544
545 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
546 {
547         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
548         HRESULT hres = DS_OK;
549
550         TRACE("(%p,%d)\n",This,pan);
551
552         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
553                 WARN("invalid parameter: pan = %d\n", pan);
554                 return DSERR_INVALIDPARAM;
555         }
556
557         /* You cannot use both pan and 3D controls */
558         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
559             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
560                 WARN("control unavailable\n");
561                 return DSERR_CONTROLUNAVAIL;
562         }
563
564         /* **** */
565         RtlAcquireResourceExclusive(&This->lock, TRUE);
566
567         if (This->volpan.lPan != pan) {
568                 This->volpan.lPan = pan;
569                 DSOUND_RecalcVolPan(&(This->volpan));
570         }
571
572         RtlReleaseResource(&This->lock);
573         /* **** */
574
575         return hres;
576 }
577
578 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
579 {
580         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
581
582         TRACE("(%p,%p)\n",This,pan);
583
584         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
585                 WARN("control unavailable\n");
586                 return DSERR_CONTROLUNAVAIL;
587         }
588
589         if (pan == NULL) {
590                 WARN("invalid parameter: pan = NULL\n");
591                 return DSERR_INVALIDPARAM;
592         }
593
594         *pan = This->volpan.lPan;
595
596         return DS_OK;
597 }
598
599 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
600         void *p2, DWORD x2)
601 {
602         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
603         HRESULT hres = DS_OK;
604
605         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
606
607         if (!p2)
608                 x2 = 0;
609
610     if((p1 && ((BYTE*)p1 < This->buffer->memory ||
611                     (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
612             (p2 && ((BYTE*)p2 < This->buffer->memory ||
613                     (BYTE*)p2 >= This->buffer->memory + This->buflen)))
614         return DSERR_INVALIDPARAM;
615
616         if (x1 || x2)
617         {
618                 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
619                 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
620                 {
621                         RtlAcquireResourceShared(&iter->lock, TRUE);
622                         if (x1)
623                         {
624                             if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
625                               hres = DSERR_INVALIDPARAM;
626                         }
627                         RtlReleaseResource(&iter->lock);
628                 }
629                 RtlReleaseResource(&This->device->buffer_list_lock);
630         }
631
632         return hres;
633 }
634
635 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
636 {
637         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
638
639         FIXME("(%p):stub\n",This);
640         return DS_OK;
641 }
642
643 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
644 {
645         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
646
647         TRACE("(%p,%p)\n",This,freq);
648
649         if (freq == NULL) {
650                 WARN("invalid parameter: freq = NULL\n");
651                 return DSERR_INVALIDPARAM;
652         }
653
654         *freq = This->freq;
655         TRACE("-> %d\n", *freq);
656
657         return DS_OK;
658 }
659
660 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
661         LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
662 {
663         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
664         DWORD u;
665
666         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
667
668         if (pdwResultCodes)
669                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
670
671         WARN("control unavailable\n");
672         return DSERR_CONTROLUNAVAIL;
673 }
674
675 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
676         DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
677 {
678         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
679         DWORD u;
680
681         FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
682
683         if (pdwResultCodes)
684                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
685
686         WARN("control unavailable\n");
687         return DS_OK;
688 }
689
690 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
691         REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
692 {
693         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
694
695         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
696
697         WARN("control unavailable\n");
698         return DSERR_CONTROLUNAVAIL;
699 }
700
701 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
702         IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
703 {
704         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
705
706         WARN("(%p) already initialized\n", This);
707         return DSERR_ALREADYINITIALIZED;
708 }
709
710 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
711 {
712         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
713
714         TRACE("(%p)->(%p)\n",This,caps);
715
716         if (caps == NULL) {
717                 WARN("invalid parameter: caps == NULL\n");
718                 return DSERR_INVALIDPARAM;
719         }
720
721         if (caps->dwSize < sizeof(*caps)) {
722                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
723                 return DSERR_INVALIDPARAM;
724         }
725
726         caps->dwFlags = This->dsbd.dwFlags;
727         caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
728
729         caps->dwBufferBytes = This->buflen;
730
731         /* According to windows, this is zero*/
732         caps->dwUnlockTransferRate = 0;
733         caps->dwPlayCpuOverhead = 0;
734
735         return DS_OK;
736 }
737
738 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
739         void **ppobj)
740 {
741         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
742
743         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
744
745         if (ppobj == NULL) {
746                 WARN("invalid parameter\n");
747                 return E_INVALIDARG;
748         }
749
750         *ppobj = NULL;  /* assume failure */
751
752         if ( IsEqualGUID(riid, &IID_IUnknown) ||
753              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
754              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
755                 IDirectSoundBuffer8_AddRef(iface);
756                 *ppobj = iface;
757                 return S_OK;
758         }
759
760         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
761                 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
762                 *ppobj = &This->IDirectSoundNotify_iface;
763                 return S_OK;
764         }
765
766         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
767                 IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
768                 *ppobj = &This->IDirectSound3DBuffer_iface;
769                 return S_OK;
770         }
771
772         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
773                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
774                 return E_NOINTERFACE;
775         }
776
777         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
778                 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
779                 *ppobj = &This->IKsPropertySet_iface;
780                 return S_OK;
781         }
782
783         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
784
785         return E_NOINTERFACE;
786 }
787
788 static const IDirectSoundBuffer8Vtbl dsbvt =
789 {
790         IDirectSoundBufferImpl_QueryInterface,
791         IDirectSoundBufferImpl_AddRef,
792         IDirectSoundBufferImpl_Release,
793         IDirectSoundBufferImpl_GetCaps,
794         IDirectSoundBufferImpl_GetCurrentPosition,
795         IDirectSoundBufferImpl_GetFormat,
796         IDirectSoundBufferImpl_GetVolume,
797         IDirectSoundBufferImpl_GetPan,
798         IDirectSoundBufferImpl_GetFrequency,
799         IDirectSoundBufferImpl_GetStatus,
800         IDirectSoundBufferImpl_Initialize,
801         IDirectSoundBufferImpl_Lock,
802         IDirectSoundBufferImpl_Play,
803         IDirectSoundBufferImpl_SetCurrentPosition,
804         IDirectSoundBufferImpl_SetFormat,
805         IDirectSoundBufferImpl_SetVolume,
806         IDirectSoundBufferImpl_SetPan,
807         IDirectSoundBufferImpl_SetFrequency,
808         IDirectSoundBufferImpl_Stop,
809         IDirectSoundBufferImpl_Unlock,
810         IDirectSoundBufferImpl_Restore,
811         IDirectSoundBufferImpl_SetFX,
812         IDirectSoundBufferImpl_AcquireResources,
813         IDirectSoundBufferImpl_GetObjectInPath
814 };
815
816 HRESULT IDirectSoundBufferImpl_Create(
817         DirectSoundDevice * device,
818         IDirectSoundBufferImpl **pdsb,
819         LPCDSBUFFERDESC dsbd)
820 {
821         IDirectSoundBufferImpl *dsb;
822         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
823         HRESULT err = DS_OK;
824         DWORD capf = 0;
825         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
826
827         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
828                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
829                 *pdsb = NULL;
830                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
831         }
832
833         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
834
835         if (dsb == 0) {
836                 WARN("out of memory\n");
837                 *pdsb = NULL;
838                 return DSERR_OUTOFMEMORY;
839         }
840
841         TRACE("Created buffer at %p\n", dsb);
842
843         dsb->ref = 0;
844         dsb->refn = 0;
845         dsb->ref3D = 0;
846         dsb->refiks = 0;
847         dsb->numIfaces = 0;
848         dsb->device = device;
849         dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
850         dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
851         dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
852         dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
853
854         /* size depends on version */
855         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
856
857         dsb->pwfx = DSOUND_CopyFormat(wfex);
858         if (dsb->pwfx == NULL) {
859                 HeapFree(GetProcessHeap(),0,dsb);
860                 *pdsb = NULL;
861                 return DSERR_OUTOFMEMORY;
862         }
863
864         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
865                 dsb->buflen = dsbd->dwBufferBytes + 
866                         (dsbd->lpwfxFormat->nBlockAlign - 
867                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
868         else
869                 dsb->buflen = dsbd->dwBufferBytes;
870
871         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
872         dsb->notifies = NULL;
873         dsb->nrofnotifies = 0;
874
875         /* Check necessary hardware mixing capabilities */
876         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
877         else capf |= DSCAPS_SECONDARYMONO;
878         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
879         else capf |= DSCAPS_SECONDARY8BIT;
880
881         TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
882
883         /* Allocate an empty buffer */
884         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
885         if (dsb->buffer == NULL) {
886                 WARN("out of memory\n");
887                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
888                 HeapFree(GetProcessHeap(),0,dsb);
889                 *pdsb = NULL;
890                 return DSERR_OUTOFMEMORY;
891         }
892
893         /* Allocate system memory for buffer */
894         dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
895         if (dsb->buffer->memory == NULL) {
896                 WARN("out of memory\n");
897                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
898                 HeapFree(GetProcessHeap(),0,dsb->buffer);
899                 HeapFree(GetProcessHeap(),0,dsb);
900                 *pdsb = NULL;
901                 return DSERR_OUTOFMEMORY;
902         }
903
904         dsb->buffer->ref = 1;
905         list_init(&dsb->buffer->buffers);
906         list_add_head(&dsb->buffer->buffers, &dsb->entry);
907         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
908
909         /* It's not necessary to initialize values to zero since */
910         /* we allocated this structure with HEAP_ZERO_MEMORY... */
911         dsb->sec_mixpos = 0;
912         dsb->state = STATE_STOPPED;
913
914         dsb->freqAdjust = dsb->freq / (float)device->pwfx->nSamplesPerSec;
915         dsb->nAvgBytesPerSec = dsb->freq *
916                 dsbd->lpwfxFormat->nBlockAlign;
917
918         /* calculate fragment size and write lead */
919         DSOUND_RecalcFormat(dsb);
920
921         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
922                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
923                 dsb->ds3db_ds3db.vPosition.x = 0.0;
924                 dsb->ds3db_ds3db.vPosition.y = 0.0;
925                 dsb->ds3db_ds3db.vPosition.z = 0.0;
926                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
927                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
928                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
929                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
930                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
931                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
932                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
933                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
934                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
935                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
936                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
937                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
938
939                 dsb->ds3db_need_recalc = FALSE;
940                 DSOUND_Calc3DBuffer(dsb);
941         } else
942                 DSOUND_RecalcVolPan(&(dsb->volpan));
943
944         RtlInitializeResource(&dsb->lock);
945
946         /* register buffer if not primary */
947         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
948                 err = DirectSoundDevice_AddBuffer(device, dsb);
949                 if (err != DS_OK) {
950                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
951                         HeapFree(GetProcessHeap(),0,dsb->buffer);
952                         RtlDeleteResource(&dsb->lock);
953                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
954                         HeapFree(GetProcessHeap(),0,dsb);
955                         dsb = NULL;
956                 }
957         }
958
959         IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
960         *pdsb = dsb;
961         return err;
962 }
963
964 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
965 {
966     ULONG ref = InterlockedIncrement(&This->numIfaces);
967
968     if (ref > 1)
969         WARN("Destroying buffer with %u in use interfaces\n", ref - 1);
970
971     DirectSoundDevice_RemoveBuffer(This->device, This);
972     RtlDeleteResource(&This->lock);
973
974     This->buffer->ref--;
975     list_remove(&This->entry);
976     if (This->buffer->ref == 0) {
977         HeapFree(GetProcessHeap(), 0, This->buffer->memory);
978         HeapFree(GetProcessHeap(), 0, This->buffer);
979     }
980
981     HeapFree(GetProcessHeap(), 0, This->notifies);
982     HeapFree(GetProcessHeap(), 0, This->pwfx);
983     HeapFree(GetProcessHeap(), 0, This);
984
985     TRACE("(%p) released\n", This);
986 }
987
988 HRESULT IDirectSoundBufferImpl_Duplicate(
989     DirectSoundDevice *device,
990     IDirectSoundBufferImpl **ppdsb,
991     IDirectSoundBufferImpl *pdsb)
992 {
993     IDirectSoundBufferImpl *dsb;
994     HRESULT hres = DS_OK;
995     TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
996
997     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
998     if (dsb == NULL) {
999         WARN("out of memory\n");
1000         *ppdsb = NULL;
1001         return DSERR_OUTOFMEMORY;
1002     }
1003
1004     RtlAcquireResourceShared(&pdsb->lock, TRUE);
1005
1006     CopyMemory(dsb, pdsb, sizeof(*dsb));
1007
1008     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1009
1010     RtlReleaseResource(&pdsb->lock);
1011
1012     if (dsb->pwfx == NULL) {
1013         HeapFree(GetProcessHeap(),0,dsb);
1014         *ppdsb = NULL;
1015         return DSERR_OUTOFMEMORY;
1016     }
1017
1018     dsb->buffer->ref++;
1019     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1020     dsb->ref = 0;
1021     dsb->refn = 0;
1022     dsb->ref3D = 0;
1023     dsb->refiks = 0;
1024     dsb->numIfaces = 0;
1025     dsb->state = STATE_STOPPED;
1026     dsb->sec_mixpos = 0;
1027     dsb->notifies = NULL;
1028     dsb->nrofnotifies = 0;
1029     dsb->device = device;
1030     DSOUND_RecalcFormat(dsb);
1031
1032     RtlInitializeResource(&dsb->lock);
1033
1034     /* register buffer */
1035     hres = DirectSoundDevice_AddBuffer(device, dsb);
1036     if (hres != DS_OK) {
1037         RtlDeleteResource(&dsb->lock);
1038         list_remove(&dsb->entry);
1039         dsb->buffer->ref--;
1040         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1041         HeapFree(GetProcessHeap(),0,dsb);
1042         dsb = NULL;
1043     }
1044
1045     IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1046     *ppdsb = dsb;
1047     return hres;
1048 }
1049
1050 /*******************************************************************************
1051  *              IKsPropertySet
1052  */
1053
1054 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1055 {
1056     return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1057 }
1058
1059 /* IUnknown methods */
1060 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1061         void **ppobj)
1062 {
1063     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1064
1065     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1066
1067     return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1068 }
1069
1070 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1071 {
1072     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1073     ULONG ref = InterlockedIncrement(&This->refiks);
1074
1075     TRACE("(%p) ref was %d\n", This, ref - 1);
1076
1077     if(ref == 1)
1078         InterlockedIncrement(&This->numIfaces);
1079
1080     return ref;
1081 }
1082
1083 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1084 {
1085     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1086     ULONG ref;
1087
1088     if (is_primary_buffer(This)){
1089         ref = capped_refcount_dec(&This->refiks);
1090         if(!ref)
1091             capped_refcount_dec(&This->numIfaces);
1092         TRACE("(%p) ref is now: %d\n", This, ref);
1093         return ref;
1094     }
1095
1096     ref = InterlockedDecrement(&This->refiks);
1097     if (!ref && !InterlockedDecrement(&This->numIfaces))
1098         secondarybuffer_destroy(This);
1099
1100     TRACE("(%p) ref is now %d\n", This, ref);
1101
1102     return ref;
1103 }
1104
1105 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1106         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1107         ULONG cbPropData, ULONG *pcbReturned)
1108 {
1109     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1110
1111     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1112     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1113
1114     return E_PROP_ID_UNSUPPORTED;
1115 }
1116
1117 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1118         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1119         ULONG cbPropData)
1120 {
1121     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1122
1123     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1124
1125     return E_PROP_ID_UNSUPPORTED;
1126 }
1127
1128 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1129         ULONG dwPropID, ULONG *pTypeSupport)
1130 {
1131     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1132
1133     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1134
1135     return E_PROP_ID_UNSUPPORTED;
1136 }
1137
1138 const IKsPropertySetVtbl iksbvt = {
1139     IKsPropertySetImpl_QueryInterface,
1140     IKsPropertySetImpl_AddRef,
1141     IKsPropertySetImpl_Release,
1142     IKsPropertySetImpl_Get,
1143     IKsPropertySetImpl_Set,
1144     IKsPropertySetImpl_QuerySupport
1145 };