dmusic: Replace debugstr_DMUS_OBJECTDESC by a specific dump function to avoid debug...
[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 = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / 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 = InterlockedDecrement(&This->ref);
331
332     TRACE("(%p) ref was %d\n", This, ref + 1);
333
334     if (!ref && !InterlockedDecrement(&This->numIfaces)) {
335         if (is_primary_buffer(This))
336             primarybuffer_destroy(This);
337         else
338             secondarybuffer_destroy(This);
339     }
340     return ref;
341 }
342
343 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
344         DWORD *playpos, DWORD *writepos)
345 {
346         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
347         DWORD pos;
348
349         TRACE("(%p,%p,%p)\n",This,playpos,writepos);
350
351         RtlAcquireResourceShared(&This->lock, TRUE);
352
353         pos = This->sec_mixpos;
354
355         /* sanity */
356         if (pos >= This->buflen){
357                 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
358                 pos %= This->buflen;
359         }
360
361         if (playpos)
362                 *playpos = pos;
363         if (writepos)
364                 *writepos = pos;
365
366         if (writepos && This->state != STATE_STOPPED) {
367                 /* apply the documented 10ms lead to writepos */
368                 *writepos += This->writelead;
369                 *writepos %= This->buflen;
370         }
371
372         RtlReleaseResource(&This->lock);
373
374         TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
375                 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
376
377         return DS_OK;
378 }
379
380 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
381 {
382         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
383
384         TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
385
386         if (status == NULL) {
387                 WARN("invalid parameter: status = NULL\n");
388                 return DSERR_INVALIDPARAM;
389         }
390
391         *status = 0;
392         RtlAcquireResourceShared(&This->lock, TRUE);
393         if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
394                 *status |= DSBSTATUS_PLAYING;
395                 if (This->playflags & DSBPLAY_LOOPING)
396                         *status |= DSBSTATUS_LOOPING;
397         }
398         RtlReleaseResource(&This->lock);
399
400         TRACE("status=%x\n", *status);
401         return DS_OK;
402 }
403
404
405 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
406         LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
407 {
408     IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
409     DWORD size;
410
411     TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
412
413     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
414
415     if (lpwf) { /* NULL is valid */
416         if (wfsize >= size) {
417             CopyMemory(lpwf,This->pwfx,size);
418             if (wfwritten)
419                 *wfwritten = size;
420         } else {
421             WARN("invalid parameter: wfsize too small\n");
422             CopyMemory(lpwf,This->pwfx,wfsize);
423             if (wfwritten)
424                 *wfwritten = wfsize;
425             return DSERR_INVALIDPARAM;
426         }
427     } else {
428         if (wfwritten)
429             *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
430         else {
431             WARN("invalid parameter: wfwritten == NULL\n");
432             return DSERR_INVALIDPARAM;
433         }
434     }
435
436     return DS_OK;
437 }
438
439 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
440         DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
441         DWORD *audiobytes2, DWORD flags)
442 {
443         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
444         HRESULT hres = DS_OK;
445
446         TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
447                 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
448
449         if (!audiobytes1)
450             return DSERR_INVALIDPARAM;
451
452         /* when this flag is set, writecursor is meaningless and must be calculated */
453         if (flags & DSBLOCK_FROMWRITECURSOR) {
454                 /* GetCurrentPosition does too much magic to duplicate here */
455                 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
456                 if (hres != DS_OK) {
457                         WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
458                         return hres;
459                 }
460         }
461
462         /* when this flag is set, writebytes is meaningless and must be set */
463         if (flags & DSBLOCK_ENTIREBUFFER)
464                 writebytes = This->buflen;
465
466         if (writecursor >= This->buflen) {
467                 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
468                      writecursor, This->buflen);
469                 return DSERR_INVALIDPARAM;
470         }
471
472         if (writebytes > This->buflen) {
473                 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
474                      writebytes, This->buflen);
475                 return DSERR_INVALIDPARAM;
476         }
477
478         /* **** */
479         RtlAcquireResourceShared(&This->lock, TRUE);
480
481         if (writecursor+writebytes <= This->buflen) {
482                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
483                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
484                         WARN("Overwriting mixing position, case 1\n");
485                 *audiobytes1 = writebytes;
486                 if (lplpaudioptr2)
487                         *(LPBYTE*)lplpaudioptr2 = NULL;
488                 if (audiobytes2)
489                         *audiobytes2 = 0;
490                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
491                   *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
492                 TRACE("->%d.0\n",writebytes);
493         } else {
494                 DWORD remainder = writebytes + writecursor - This->buflen;
495                 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
496                 *audiobytes1 = This->buflen-writecursor;
497                 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
498                         WARN("Overwriting mixing position, case 2\n");
499                 if (lplpaudioptr2)
500                         *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
501                 if (audiobytes2)
502                         *audiobytes2 = writebytes-(This->buflen-writecursor);
503                 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
504                         WARN("Overwriting mixing position, case 3\n");
505                 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
506         }
507
508         RtlReleaseResource(&This->lock);
509         /* **** */
510
511         return DS_OK;
512 }
513
514 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
515         DWORD newpos)
516 {
517         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
518         HRESULT hres = DS_OK;
519         DWORD oldpos;
520
521         TRACE("(%p,%d)\n",This,newpos);
522
523         /* **** */
524         RtlAcquireResourceExclusive(&This->lock, TRUE);
525
526         oldpos = This->sec_mixpos;
527
528         /* start mixing from this new location instead */
529         newpos %= This->buflen;
530         newpos -= newpos%This->pwfx->nBlockAlign;
531         This->sec_mixpos = newpos;
532
533         /* at this point, do not attempt to reset buffers, mess with primary mix position,
534            or anything like that to reduce latency. The data already prebuffered cannot be changed */
535
536         /* position HW buffer if applicable, else just start mixing from new location instead */
537         if (oldpos != newpos)
538                 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
539
540         RtlReleaseResource(&This->lock);
541         /* **** */
542
543         return hres;
544 }
545
546 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
547 {
548         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
549         HRESULT hres = DS_OK;
550
551         TRACE("(%p,%d)\n",This,pan);
552
553         if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
554                 WARN("invalid parameter: pan = %d\n", pan);
555                 return DSERR_INVALIDPARAM;
556         }
557
558         /* You cannot use both pan and 3D controls */
559         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
560             (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
561                 WARN("control unavailable\n");
562                 return DSERR_CONTROLUNAVAIL;
563         }
564
565         /* **** */
566         RtlAcquireResourceExclusive(&This->lock, TRUE);
567
568         if (This->volpan.lPan != pan) {
569                 This->volpan.lPan = pan;
570                 DSOUND_RecalcVolPan(&(This->volpan));
571         }
572
573         RtlReleaseResource(&This->lock);
574         /* **** */
575
576         return hres;
577 }
578
579 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
580 {
581         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
582
583         TRACE("(%p,%p)\n",This,pan);
584
585         if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
586                 WARN("control unavailable\n");
587                 return DSERR_CONTROLUNAVAIL;
588         }
589
590         if (pan == NULL) {
591                 WARN("invalid parameter: pan = NULL\n");
592                 return DSERR_INVALIDPARAM;
593         }
594
595         *pan = This->volpan.lPan;
596
597         return DS_OK;
598 }
599
600 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
601         void *p2, DWORD x2)
602 {
603         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
604         HRESULT hres = DS_OK;
605
606         TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
607
608         if (!p2)
609                 x2 = 0;
610
611     if((p1 && ((BYTE*)p1 < This->buffer->memory ||
612                     (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
613             (p2 && ((BYTE*)p2 < This->buffer->memory ||
614                     (BYTE*)p2 >= This->buffer->memory + This->buflen)))
615         return DSERR_INVALIDPARAM;
616
617         if (x1 || x2)
618         {
619                 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
620                 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
621                 {
622                         RtlAcquireResourceShared(&iter->lock, TRUE);
623                         if (x1)
624                         {
625                             if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
626                               hres = DSERR_INVALIDPARAM;
627                         }
628                         RtlReleaseResource(&iter->lock);
629                 }
630                 RtlReleaseResource(&This->device->buffer_list_lock);
631         }
632
633         return hres;
634 }
635
636 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
637 {
638         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
639
640         FIXME("(%p):stub\n",This);
641         return DS_OK;
642 }
643
644 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
645 {
646         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
647
648         TRACE("(%p,%p)\n",This,freq);
649
650         if (freq == NULL) {
651                 WARN("invalid parameter: freq = NULL\n");
652                 return DSERR_INVALIDPARAM;
653         }
654
655         *freq = This->freq;
656         TRACE("-> %d\n", *freq);
657
658         return DS_OK;
659 }
660
661 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
662         LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
663 {
664         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
665         DWORD u;
666
667         FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
668
669         if (pdwResultCodes)
670                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
671
672         WARN("control unavailable\n");
673         return DSERR_CONTROLUNAVAIL;
674 }
675
676 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
677         DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
678 {
679         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
680         DWORD u;
681
682         FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
683
684         if (pdwResultCodes)
685                 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
686
687         WARN("control unavailable\n");
688         return DS_OK;
689 }
690
691 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
692         REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
693 {
694         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
695
696         FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
697
698         WARN("control unavailable\n");
699         return DSERR_CONTROLUNAVAIL;
700 }
701
702 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
703         IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
704 {
705         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
706
707         WARN("(%p) already initialized\n", This);
708         return DSERR_ALREADYINITIALIZED;
709 }
710
711 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
712 {
713         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
714
715         TRACE("(%p)->(%p)\n",This,caps);
716
717         if (caps == NULL) {
718                 WARN("invalid parameter: caps == NULL\n");
719                 return DSERR_INVALIDPARAM;
720         }
721
722         if (caps->dwSize < sizeof(*caps)) {
723                 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
724                 return DSERR_INVALIDPARAM;
725         }
726
727         caps->dwFlags = This->dsbd.dwFlags;
728         caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
729
730         caps->dwBufferBytes = This->buflen;
731
732         /* According to windows, this is zero*/
733         caps->dwUnlockTransferRate = 0;
734         caps->dwPlayCpuOverhead = 0;
735
736         return DS_OK;
737 }
738
739 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
740         void **ppobj)
741 {
742         IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
743
744         TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
745
746         if (ppobj == NULL) {
747                 WARN("invalid parameter\n");
748                 return E_INVALIDARG;
749         }
750
751         *ppobj = NULL;  /* assume failure */
752
753         if ( IsEqualGUID(riid, &IID_IUnknown) ||
754              IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
755              IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
756                 IDirectSoundBuffer8_AddRef(iface);
757                 *ppobj = iface;
758                 return S_OK;
759         }
760
761         if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
762                 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
763                 *ppobj = &This->IDirectSoundNotify_iface;
764                 return S_OK;
765         }
766
767         if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
768                 IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
769                 *ppobj = &This->IDirectSound3DBuffer_iface;
770                 return S_OK;
771         }
772
773         if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
774                 ERR("app requested IDirectSound3DListener on secondary buffer\n");
775                 return E_NOINTERFACE;
776         }
777
778         if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
779                 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
780                 *ppobj = &This->IKsPropertySet_iface;
781                 return S_OK;
782         }
783
784         FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
785
786         return E_NOINTERFACE;
787 }
788
789 static const IDirectSoundBuffer8Vtbl dsbvt =
790 {
791         IDirectSoundBufferImpl_QueryInterface,
792         IDirectSoundBufferImpl_AddRef,
793         IDirectSoundBufferImpl_Release,
794         IDirectSoundBufferImpl_GetCaps,
795         IDirectSoundBufferImpl_GetCurrentPosition,
796         IDirectSoundBufferImpl_GetFormat,
797         IDirectSoundBufferImpl_GetVolume,
798         IDirectSoundBufferImpl_GetPan,
799         IDirectSoundBufferImpl_GetFrequency,
800         IDirectSoundBufferImpl_GetStatus,
801         IDirectSoundBufferImpl_Initialize,
802         IDirectSoundBufferImpl_Lock,
803         IDirectSoundBufferImpl_Play,
804         IDirectSoundBufferImpl_SetCurrentPosition,
805         IDirectSoundBufferImpl_SetFormat,
806         IDirectSoundBufferImpl_SetVolume,
807         IDirectSoundBufferImpl_SetPan,
808         IDirectSoundBufferImpl_SetFrequency,
809         IDirectSoundBufferImpl_Stop,
810         IDirectSoundBufferImpl_Unlock,
811         IDirectSoundBufferImpl_Restore,
812         IDirectSoundBufferImpl_SetFX,
813         IDirectSoundBufferImpl_AcquireResources,
814         IDirectSoundBufferImpl_GetObjectInPath
815 };
816
817 HRESULT IDirectSoundBufferImpl_Create(
818         DirectSoundDevice * device,
819         IDirectSoundBufferImpl **pdsb,
820         LPCDSBUFFERDESC dsbd)
821 {
822         IDirectSoundBufferImpl *dsb;
823         LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
824         HRESULT err = DS_OK;
825         DWORD capf = 0;
826         TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
827
828         if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
829                 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
830                 *pdsb = NULL;
831                 return DSERR_INVALIDPARAM; /* FIXME: which error? */
832         }
833
834         dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
835
836         if (dsb == 0) {
837                 WARN("out of memory\n");
838                 *pdsb = NULL;
839                 return DSERR_OUTOFMEMORY;
840         }
841
842         TRACE("Created buffer at %p\n", dsb);
843
844         dsb->ref = 0;
845         dsb->refn = 0;
846         dsb->ref3D = 0;
847         dsb->refiks = 0;
848         dsb->numIfaces = 0;
849         dsb->device = device;
850         dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
851         dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
852         dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
853         dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
854
855         /* size depends on version */
856         CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
857
858         dsb->pwfx = DSOUND_CopyFormat(wfex);
859         if (dsb->pwfx == NULL) {
860                 HeapFree(GetProcessHeap(),0,dsb);
861                 *pdsb = NULL;
862                 return DSERR_OUTOFMEMORY;
863         }
864
865         if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
866                 dsb->buflen = dsbd->dwBufferBytes + 
867                         (dsbd->lpwfxFormat->nBlockAlign - 
868                         (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
869         else
870                 dsb->buflen = dsbd->dwBufferBytes;
871
872         dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
873         dsb->notifies = NULL;
874         dsb->nrofnotifies = 0;
875
876         /* Check necessary hardware mixing capabilities */
877         if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
878         else capf |= DSCAPS_SECONDARYMONO;
879         if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
880         else capf |= DSCAPS_SECONDARY8BIT;
881
882         TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
883
884         /* Allocate an empty buffer */
885         dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
886         if (dsb->buffer == NULL) {
887                 WARN("out of memory\n");
888                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
889                 HeapFree(GetProcessHeap(),0,dsb);
890                 *pdsb = NULL;
891                 return DSERR_OUTOFMEMORY;
892         }
893
894         /* Allocate system memory for buffer */
895         dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
896         if (dsb->buffer->memory == NULL) {
897                 WARN("out of memory\n");
898                 HeapFree(GetProcessHeap(),0,dsb->pwfx);
899                 HeapFree(GetProcessHeap(),0,dsb->buffer);
900                 HeapFree(GetProcessHeap(),0,dsb);
901                 *pdsb = NULL;
902                 return DSERR_OUTOFMEMORY;
903         }
904
905         dsb->buffer->ref = 1;
906         list_init(&dsb->buffer->buffers);
907         list_add_head(&dsb->buffer->buffers, &dsb->entry);
908         FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
909
910         /* It's not necessary to initialize values to zero since */
911         /* we allocated this structure with HEAP_ZERO_MEMORY... */
912         dsb->buf_mixpos = dsb->sec_mixpos = 0;
913         dsb->state = STATE_STOPPED;
914
915         dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
916         dsb->nAvgBytesPerSec = dsb->freq *
917                 dsbd->lpwfxFormat->nBlockAlign;
918
919         /* calculate fragment size and write lead */
920         DSOUND_RecalcFormat(dsb);
921
922         if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
923                 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
924                 dsb->ds3db_ds3db.vPosition.x = 0.0;
925                 dsb->ds3db_ds3db.vPosition.y = 0.0;
926                 dsb->ds3db_ds3db.vPosition.z = 0.0;
927                 dsb->ds3db_ds3db.vVelocity.x = 0.0;
928                 dsb->ds3db_ds3db.vVelocity.y = 0.0;
929                 dsb->ds3db_ds3db.vVelocity.z = 0.0;
930                 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
931                 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
932                 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
933                 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
934                 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
935                 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
936                 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
937                 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
938                 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
939
940                 dsb->ds3db_need_recalc = FALSE;
941                 DSOUND_Calc3DBuffer(dsb);
942         } else
943                 DSOUND_RecalcVolPan(&(dsb->volpan));
944
945         RtlInitializeResource(&dsb->lock);
946
947         /* register buffer if not primary */
948         if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
949                 err = DirectSoundDevice_AddBuffer(device, dsb);
950                 if (err != DS_OK) {
951                         HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
952                         HeapFree(GetProcessHeap(),0,dsb->buffer);
953                         RtlDeleteResource(&dsb->lock);
954                         HeapFree(GetProcessHeap(),0,dsb->pwfx);
955                         HeapFree(GetProcessHeap(),0,dsb);
956                         dsb = NULL;
957                 }
958         }
959
960         IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
961         *pdsb = dsb;
962         return err;
963 }
964
965 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
966 {
967     ULONG ref = InterlockedIncrement(&This->numIfaces);
968
969     if (ref > 1)
970         WARN("Destroying buffer with %u in use interfaces\n", ref - 1);
971
972     DirectSoundDevice_RemoveBuffer(This->device, This);
973     RtlDeleteResource(&This->lock);
974
975     This->buffer->ref--;
976     list_remove(&This->entry);
977     if (This->buffer->ref == 0) {
978         HeapFree(GetProcessHeap(), 0, This->buffer->memory);
979         HeapFree(GetProcessHeap(), 0, This->buffer);
980     }
981
982     HeapFree(GetProcessHeap(), 0, This->notifies);
983     HeapFree(GetProcessHeap(), 0, This->pwfx);
984     HeapFree(GetProcessHeap(), 0, This);
985
986     TRACE("(%p) released\n", This);
987 }
988
989 HRESULT IDirectSoundBufferImpl_Duplicate(
990     DirectSoundDevice *device,
991     IDirectSoundBufferImpl **ppdsb,
992     IDirectSoundBufferImpl *pdsb)
993 {
994     IDirectSoundBufferImpl *dsb;
995     HRESULT hres = DS_OK;
996     TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
997
998     dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
999     if (dsb == NULL) {
1000         WARN("out of memory\n");
1001         *ppdsb = NULL;
1002         return DSERR_OUTOFMEMORY;
1003     }
1004
1005     RtlAcquireResourceShared(&pdsb->lock, TRUE);
1006
1007     CopyMemory(dsb, pdsb, sizeof(*dsb));
1008
1009     dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1010
1011     RtlReleaseResource(&pdsb->lock);
1012
1013     if (dsb->pwfx == NULL) {
1014         HeapFree(GetProcessHeap(),0,dsb);
1015         *ppdsb = NULL;
1016         return DSERR_OUTOFMEMORY;
1017     }
1018
1019     dsb->buffer->ref++;
1020     list_add_head(&dsb->buffer->buffers, &dsb->entry);
1021     dsb->ref = 0;
1022     dsb->refn = 0;
1023     dsb->ref3D = 0;
1024     dsb->refiks = 0;
1025     dsb->numIfaces = 0;
1026     dsb->state = STATE_STOPPED;
1027     dsb->buf_mixpos = dsb->sec_mixpos = 0;
1028     dsb->notifies = NULL;
1029     dsb->nrofnotifies = 0;
1030     dsb->device = device;
1031     DSOUND_RecalcFormat(dsb);
1032
1033     RtlInitializeResource(&dsb->lock);
1034
1035     /* register buffer */
1036     hres = DirectSoundDevice_AddBuffer(device, dsb);
1037     if (hres != DS_OK) {
1038         RtlDeleteResource(&dsb->lock);
1039         list_remove(&dsb->entry);
1040         dsb->buffer->ref--;
1041         HeapFree(GetProcessHeap(),0,dsb->pwfx);
1042         HeapFree(GetProcessHeap(),0,dsb);
1043         dsb = NULL;
1044     }
1045
1046     IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1047     *ppdsb = dsb;
1048     return hres;
1049 }
1050
1051 /*******************************************************************************
1052  *              IKsPropertySet
1053  */
1054
1055 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1056 {
1057     return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1058 }
1059
1060 /* IUnknown methods */
1061 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1062         void **ppobj)
1063 {
1064     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1065
1066     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1067
1068     return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1069 }
1070
1071 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1072 {
1073     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1074     ULONG ref = InterlockedIncrement(&This->refiks);
1075
1076     TRACE("(%p) ref was %d\n", This, ref - 1);
1077
1078     if(ref == 1)
1079         InterlockedIncrement(&This->numIfaces);
1080
1081     return ref;
1082 }
1083
1084 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1085 {
1086     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1087     ULONG ref = InterlockedDecrement(&This->refiks);
1088
1089     TRACE("(%p) ref was %d\n", This, ref + 1);
1090
1091     if (!ref && !InterlockedDecrement(&This->numIfaces)) {
1092         if (is_primary_buffer(This))
1093             primarybuffer_destroy(This);
1094         else
1095             secondarybuffer_destroy(This);
1096     }
1097     return ref;
1098 }
1099
1100 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1101         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1102         ULONG cbPropData, ULONG *pcbReturned)
1103 {
1104     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1105
1106     TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1107     This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1108
1109     return E_PROP_ID_UNSUPPORTED;
1110 }
1111
1112 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1113         ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1114         ULONG cbPropData)
1115 {
1116     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1117
1118     TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1119
1120     return E_PROP_ID_UNSUPPORTED;
1121 }
1122
1123 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1124         ULONG dwPropID, ULONG *pTypeSupport)
1125 {
1126     IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1127
1128     TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1129
1130     return E_PROP_ID_UNSUPPORTED;
1131 }
1132
1133 const IKsPropertySetVtbl iksbvt = {
1134     IKsPropertySetImpl_QueryInterface,
1135     IKsPropertySetImpl_AddRef,
1136     IKsPropertySetImpl_Release,
1137     IKsPropertySetImpl_Get,
1138     IKsPropertySetImpl_Set,
1139     IKsPropertySetImpl_QuerySupport
1140 };