Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbuffer.c
Go to the documentation of this file.
00001 /* DirectSound 00002 * 00003 * Copyright 1998 Marcus Meissner 00004 * Copyright 1998 Rob Riggs 00005 * Copyright 2000-2002 TransGaming Technologies, Inc. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <stdarg.h> 00023 00024 #define NONAMELESSSTRUCT 00025 #define NONAMELESSUNION 00026 #include "windef.h" 00027 #include "winbase.h" 00028 #include "winuser.h" 00029 #include "mmsystem.h" 00030 #include "winternl.h" 00031 #include "wine/debug.h" 00032 #include "dsound.h" 00033 #include "dsdriver.h" 00034 #include "dsound_private.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(dsound); 00037 00038 static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb); 00039 00040 /******************************************************************************* 00041 * IDirectSoundNotify 00042 */ 00043 00044 struct IDirectSoundNotifyImpl 00045 { 00046 /* IUnknown fields */ 00047 const IDirectSoundNotifyVtbl *lpVtbl; 00048 LONG ref; 00049 IDirectSoundBufferImpl* dsb; 00050 }; 00051 00052 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb, 00053 IDirectSoundNotifyImpl **pdsn); 00054 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn); 00055 00056 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface( 00057 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj 00058 ) { 00059 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; 00060 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); 00061 00062 if (This->dsb == NULL) { 00063 WARN("invalid parameter\n"); 00064 return E_INVALIDARG; 00065 } 00066 00067 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj); 00068 } 00069 00070 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) 00071 { 00072 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; 00073 ULONG ref = InterlockedIncrement(&(This->ref)); 00074 TRACE("(%p) ref was %d\n", This, ref - 1); 00075 return ref; 00076 } 00077 00078 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) 00079 { 00080 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; 00081 ULONG ref = InterlockedDecrement(&(This->ref)); 00082 TRACE("(%p) ref was %d\n", This, ref + 1); 00083 00084 if (!ref) { 00085 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb); 00086 This->dsb->notify = NULL; 00087 HeapFree(GetProcessHeap(), 0, This); 00088 TRACE("(%p) released\n", This); 00089 } 00090 return ref; 00091 } 00092 00093 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions( 00094 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify 00095 ) { 00096 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; 00097 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify); 00098 00099 if (howmuch > 0 && notify == NULL) { 00100 WARN("invalid parameter: notify == NULL\n"); 00101 return DSERR_INVALIDPARAM; 00102 } 00103 00104 if (TRACE_ON(dsound)) { 00105 unsigned int i; 00106 for (i=0;i<howmuch;i++) 00107 TRACE("notify at %d to %p\n", 00108 notify[i].dwOffset,notify[i].hEventNotify); 00109 } 00110 00111 if (This->dsb->hwnotify) { 00112 HRESULT hres; 00113 hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify); 00114 if (hres != DS_OK) 00115 WARN("IDsDriverNotify_SetNotificationPositions failed\n"); 00116 return hres; 00117 } else if (howmuch > 0) { 00118 /* Make an internal copy of the caller-supplied array. 00119 * Replace the existing copy if one is already present. */ 00120 HeapFree(GetProcessHeap(), 0, This->dsb->notifies); 00121 This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0, 00122 howmuch * sizeof(DSBPOSITIONNOTIFY)); 00123 00124 if (This->dsb->notifies == NULL) { 00125 WARN("out of memory\n"); 00126 return DSERR_OUTOFMEMORY; 00127 } 00128 CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY)); 00129 This->dsb->nrofnotifies = howmuch; 00130 } else { 00131 HeapFree(GetProcessHeap(), 0, This->dsb->notifies); 00132 This->dsb->notifies = NULL; 00133 This->dsb->nrofnotifies = 0; 00134 } 00135 00136 return S_OK; 00137 } 00138 00139 static const IDirectSoundNotifyVtbl dsnvt = 00140 { 00141 IDirectSoundNotifyImpl_QueryInterface, 00142 IDirectSoundNotifyImpl_AddRef, 00143 IDirectSoundNotifyImpl_Release, 00144 IDirectSoundNotifyImpl_SetNotificationPositions, 00145 }; 00146 00147 static HRESULT IDirectSoundNotifyImpl_Create( 00148 IDirectSoundBufferImpl * dsb, 00149 IDirectSoundNotifyImpl **pdsn) 00150 { 00151 IDirectSoundNotifyImpl * dsn; 00152 TRACE("(%p,%p)\n",dsb,pdsn); 00153 00154 dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn)); 00155 00156 if (dsn == NULL) { 00157 WARN("out of memory\n"); 00158 return DSERR_OUTOFMEMORY; 00159 } 00160 00161 dsn->ref = 0; 00162 dsn->lpVtbl = &dsnvt; 00163 dsn->dsb = dsb; 00164 dsb->notify = dsn; 00165 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); 00166 00167 *pdsn = dsn; 00168 return DS_OK; 00169 } 00170 00171 static HRESULT IDirectSoundNotifyImpl_Destroy( 00172 IDirectSoundNotifyImpl *pdsn) 00173 { 00174 TRACE("(%p)\n",pdsn); 00175 00176 while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0); 00177 00178 return DS_OK; 00179 } 00180 00181 /******************************************************************************* 00182 * IDirectSoundBuffer 00183 */ 00184 00185 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat( 00186 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex 00187 ) { 00188 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00189 00190 TRACE("(%p,%p)\n",This,wfex); 00191 /* This method is not available on secondary buffers */ 00192 WARN("invalid call\n"); 00193 return DSERR_INVALIDCALL; 00194 } 00195 00196 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume( 00197 LPDIRECTSOUNDBUFFER8 iface,LONG vol 00198 ) { 00199 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00200 LONG oldVol; 00201 HRESULT hres = DS_OK; 00202 00203 TRACE("(%p,%d)\n",This,vol); 00204 00205 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { 00206 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags); 00207 return DSERR_CONTROLUNAVAIL; 00208 } 00209 00210 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { 00211 WARN("invalid parameter: vol = %d\n", vol); 00212 return DSERR_INVALIDPARAM; 00213 } 00214 00215 /* **** */ 00216 RtlAcquireResourceExclusive(&This->lock, TRUE); 00217 00218 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) { 00219 oldVol = This->ds3db_lVolume; 00220 This->ds3db_lVolume = vol; 00221 if (vol != oldVol) 00222 /* recalc 3d volume, which in turn recalcs the pans */ 00223 DSOUND_Calc3DBuffer(This); 00224 } else { 00225 oldVol = This->volpan.lVolume; 00226 This->volpan.lVolume = vol; 00227 if (vol != oldVol) 00228 DSOUND_RecalcVolPan(&(This->volpan)); 00229 } 00230 00231 if (vol != oldVol) { 00232 if (This->hwbuf) { 00233 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); 00234 if (hres != DS_OK) 00235 WARN("IDsDriverBuffer_SetVolumePan failed\n"); 00236 } 00237 } 00238 00239 RtlReleaseResource(&This->lock); 00240 /* **** */ 00241 00242 return hres; 00243 } 00244 00245 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume( 00246 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol 00247 ) { 00248 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00249 TRACE("(%p,%p)\n",This,vol); 00250 00251 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { 00252 WARN("control unavailable\n"); 00253 return DSERR_CONTROLUNAVAIL; 00254 } 00255 00256 if (vol == NULL) { 00257 WARN("invalid parameter: vol == NULL\n"); 00258 return DSERR_INVALIDPARAM; 00259 } 00260 00261 *vol = This->volpan.lVolume; 00262 00263 return DS_OK; 00264 } 00265 00266 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency( 00267 LPDIRECTSOUNDBUFFER8 iface,DWORD freq 00268 ) { 00269 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00270 DWORD oldFreq; 00271 00272 TRACE("(%p,%d)\n",This,freq); 00273 00274 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) { 00275 WARN("control unavailable\n"); 00276 return DSERR_CONTROLUNAVAIL; 00277 } 00278 00279 if (freq == DSBFREQUENCY_ORIGINAL) 00280 freq = This->pwfx->nSamplesPerSec; 00281 00282 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) { 00283 WARN("invalid parameter: freq = %d\n", freq); 00284 return DSERR_INVALIDPARAM; 00285 } 00286 00287 /* **** */ 00288 RtlAcquireResourceExclusive(&This->lock, TRUE); 00289 00290 oldFreq = This->freq; 00291 This->freq = freq; 00292 if (freq != oldFreq) { 00293 This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec; 00294 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign; 00295 DSOUND_RecalcFormat(This); 00296 DSOUND_MixToTemporary(This, 0, This->buflen, FALSE); 00297 } 00298 00299 RtlReleaseResource(&This->lock); 00300 /* **** */ 00301 00302 return DS_OK; 00303 } 00304 00305 static HRESULT WINAPI IDirectSoundBufferImpl_Play( 00306 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags 00307 ) { 00308 HRESULT hres = DS_OK; 00309 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00310 TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags); 00311 00312 /* **** */ 00313 RtlAcquireResourceExclusive(&This->lock, TRUE); 00314 00315 This->playflags = flags; 00316 if (This->state == STATE_STOPPED && !This->hwbuf) { 00317 This->leadin = TRUE; 00318 This->state = STATE_STARTING; 00319 } else if (This->state == STATE_STOPPING) 00320 This->state = STATE_PLAYING; 00321 if (This->hwbuf) { 00322 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags); 00323 if (hres != DS_OK) 00324 WARN("IDsDriverBuffer_Play failed\n"); 00325 else 00326 This->state = STATE_PLAYING; 00327 } 00328 00329 RtlReleaseResource(&This->lock); 00330 /* **** */ 00331 00332 return hres; 00333 } 00334 00335 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) 00336 { 00337 HRESULT hres = DS_OK; 00338 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00339 TRACE("(%p)\n",This); 00340 00341 /* **** */ 00342 RtlAcquireResourceExclusive(&This->lock, TRUE); 00343 00344 if (This->state == STATE_PLAYING) 00345 This->state = STATE_STOPPING; 00346 else if (This->state == STATE_STARTING) 00347 { 00348 This->state = STATE_STOPPED; 00349 DSOUND_CheckEvent(This, 0, 0); 00350 } 00351 if (This->hwbuf) { 00352 hres = IDsDriverBuffer_Stop(This->hwbuf); 00353 if (hres != DS_OK) 00354 WARN("IDsDriverBuffer_Stop failed\n"); 00355 else 00356 This->state = STATE_STOPPED; 00357 } 00358 00359 RtlReleaseResource(&This->lock); 00360 /* **** */ 00361 00362 return hres; 00363 } 00364 00365 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) 00366 { 00367 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00368 ULONG ref = InterlockedIncrement(&(This->ref)); 00369 TRACE("(%p) ref was %d\n", This, ref - 1); 00370 return ref; 00371 } 00372 00373 static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) 00374 { 00375 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00376 ULONG ref = InterlockedDecrement(&(This->ref)); 00377 TRACE("(%p) ref was %d\n", This, ref + 1); 00378 00379 if (!ref) { 00380 DirectSoundDevice_RemoveBuffer(This->device, This); 00381 RtlDeleteResource(&This->lock); 00382 00383 if (This->hwbuf) 00384 IDsDriverBuffer_Release(This->hwbuf); 00385 if (!This->hwbuf || (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)) { 00386 This->buffer->ref--; 00387 list_remove(&This->entry); 00388 if (This->buffer->ref==0) { 00389 HeapFree(GetProcessHeap(),0,This->buffer->memory); 00390 HeapFree(GetProcessHeap(),0,This->buffer); 00391 } 00392 } 00393 00394 HeapFree(GetProcessHeap(), 0, This->tmp_buffer); 00395 HeapFree(GetProcessHeap(), 0, This->notifies); 00396 HeapFree(GetProcessHeap(), 0, This->pwfx); 00397 HeapFree(GetProcessHeap(), 0, This); 00398 00399 TRACE("(%p) released\n", This); 00400 } 00401 return ref; 00402 } 00403 00404 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( 00405 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos 00406 ) { 00407 HRESULT hres; 00408 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00409 TRACE("(%p,%p,%p)\n",This,playpos,writepos); 00410 00411 RtlAcquireResourceShared(&This->lock, TRUE); 00412 if (This->hwbuf) { 00413 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos); 00414 if (hres != DS_OK) { 00415 WARN("IDsDriverBuffer_GetPosition failed\n"); 00416 return hres; 00417 } 00418 } else { 00419 DWORD pos = This->sec_mixpos; 00420 00421 /* sanity */ 00422 if (pos >= This->buflen){ 00423 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen); 00424 pos %= This->buflen; 00425 } 00426 00427 if (playpos) 00428 *playpos = pos; 00429 if (writepos) 00430 *writepos = pos; 00431 } 00432 if (writepos && This->state != STATE_STOPPED && (!This->hwbuf || !(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD))) { 00433 /* apply the documented 10ms lead to writepos */ 00434 *writepos += This->writelead; 00435 *writepos %= This->buflen; 00436 } 00437 RtlReleaseResource(&This->lock); 00438 00439 TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n", 00440 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount()); 00441 00442 return DS_OK; 00443 } 00444 00445 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus( 00446 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status 00447 ) { 00448 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00449 TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId()); 00450 00451 if (status == NULL) { 00452 WARN("invalid parameter: status = NULL\n"); 00453 return DSERR_INVALIDPARAM; 00454 } 00455 00456 *status = 0; 00457 RtlAcquireResourceShared(&This->lock, TRUE); 00458 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) { 00459 *status |= DSBSTATUS_PLAYING; 00460 if (This->playflags & DSBPLAY_LOOPING) 00461 *status |= DSBSTATUS_LOOPING; 00462 } 00463 RtlReleaseResource(&This->lock); 00464 00465 TRACE("status=%x\n", *status); 00466 return DS_OK; 00467 } 00468 00469 00470 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat( 00471 LPDIRECTSOUNDBUFFER8 iface, 00472 LPWAVEFORMATEX lpwf, 00473 DWORD wfsize, 00474 LPDWORD wfwritten) 00475 { 00476 DWORD size; 00477 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00478 TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten); 00479 00480 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize; 00481 00482 if (lpwf) { /* NULL is valid */ 00483 if (wfsize >= size) { 00484 CopyMemory(lpwf,This->pwfx,size); 00485 if (wfwritten) 00486 *wfwritten = size; 00487 } else { 00488 WARN("invalid parameter: wfsize too small\n"); 00489 CopyMemory(lpwf,This->pwfx,wfsize); 00490 if (wfwritten) 00491 *wfwritten = wfsize; 00492 return DSERR_INVALIDPARAM; 00493 } 00494 } else { 00495 if (wfwritten) 00496 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize; 00497 else { 00498 WARN("invalid parameter: wfwritten == NULL\n"); 00499 return DSERR_INVALIDPARAM; 00500 } 00501 } 00502 00503 return DS_OK; 00504 } 00505 00506 static HRESULT WINAPI IDirectSoundBufferImpl_Lock( 00507 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags 00508 ) { 00509 HRESULT hres = DS_OK; 00510 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00511 00512 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", 00513 This, 00514 writecursor, 00515 writebytes, 00516 lplpaudioptr1, 00517 audiobytes1, 00518 lplpaudioptr2, 00519 audiobytes2, 00520 flags, 00521 GetTickCount() 00522 ); 00523 00524 if (!audiobytes1) 00525 return DSERR_INVALIDPARAM; 00526 00527 /* when this flag is set, writecursor is meaningless and must be calculated */ 00528 if (flags & DSBLOCK_FROMWRITECURSOR) { 00529 /* GetCurrentPosition does too much magic to duplicate here */ 00530 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor); 00531 if (hres != DS_OK) { 00532 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n"); 00533 return hres; 00534 } 00535 } 00536 00537 /* when this flag is set, writebytes is meaningless and must be set */ 00538 if (flags & DSBLOCK_ENTIREBUFFER) 00539 writebytes = This->buflen; 00540 00541 if (writecursor >= This->buflen) { 00542 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n", 00543 writecursor, This->buflen); 00544 return DSERR_INVALIDPARAM; 00545 } 00546 00547 if (writebytes > This->buflen) { 00548 WARN("Invalid parameter, writebytes: %u > buflen: %u\n", 00549 writebytes, This->buflen); 00550 return DSERR_INVALIDPARAM; 00551 } 00552 00553 /* **** */ 00554 RtlAcquireResourceShared(&This->lock, TRUE); 00555 00556 if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { 00557 hres = IDsDriverBuffer_Lock(This->hwbuf, 00558 lplpaudioptr1, audiobytes1, 00559 lplpaudioptr2, audiobytes2, 00560 writecursor, writebytes, 00561 0); 00562 if (hres != DS_OK) { 00563 WARN("IDsDriverBuffer_Lock failed\n"); 00564 RtlReleaseResource(&This->lock); 00565 return hres; 00566 } 00567 } else { 00568 if (writecursor+writebytes <= This->buflen) { 00569 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; 00570 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) 00571 WARN("Overwriting mixing position, case 1\n"); 00572 *audiobytes1 = writebytes; 00573 if (lplpaudioptr2) 00574 *(LPBYTE*)lplpaudioptr2 = NULL; 00575 if (audiobytes2) 00576 *audiobytes2 = 0; 00577 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", 00578 *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor); 00579 TRACE("->%d.0\n",writebytes); 00580 } else { 00581 DWORD remainder = writebytes + writecursor - This->buflen; 00582 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; 00583 *audiobytes1 = This->buflen-writecursor; 00584 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) 00585 WARN("Overwriting mixing position, case 2\n"); 00586 if (lplpaudioptr2) 00587 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory; 00588 if (audiobytes2) 00589 *audiobytes2 = writebytes-(This->buflen-writecursor); 00590 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING) 00591 WARN("Overwriting mixing position, case 3\n"); 00592 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor); 00593 } 00594 } 00595 00596 RtlReleaseResource(&This->lock); 00597 /* **** */ 00598 00599 return DS_OK; 00600 } 00601 00602 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition( 00603 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos 00604 ) { 00605 HRESULT hres = DS_OK; 00606 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00607 DWORD oldpos; 00608 TRACE("(%p,%d)\n",This,newpos); 00609 00610 /* **** */ 00611 RtlAcquireResourceExclusive(&This->lock, TRUE); 00612 00613 oldpos = This->sec_mixpos; 00614 00615 /* start mixing from this new location instead */ 00616 newpos %= This->buflen; 00617 newpos -= newpos%This->pwfx->nBlockAlign; 00618 This->sec_mixpos = newpos; 00619 00620 /* at this point, do not attempt to reset buffers, mess with primary mix position, 00621 or anything like that to reduce latancy. The data already prebuffered cannot be changed */ 00622 00623 /* position HW buffer if applicable, else just start mixing from new location instead */ 00624 if (This->hwbuf) { 00625 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos); 00626 if (hres != DS_OK) 00627 WARN("IDsDriverBuffer_SetPosition failed\n"); 00628 } 00629 else if (oldpos != newpos) 00630 /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */ 00631 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL); 00632 00633 RtlReleaseResource(&This->lock); 00634 /* **** */ 00635 00636 return hres; 00637 } 00638 00639 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan( 00640 LPDIRECTSOUNDBUFFER8 iface,LONG pan 00641 ) { 00642 HRESULT hres = DS_OK; 00643 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00644 00645 TRACE("(%p,%d)\n",This,pan); 00646 00647 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { 00648 WARN("invalid parameter: pan = %d\n", pan); 00649 return DSERR_INVALIDPARAM; 00650 } 00651 00652 /* You cannot use both pan and 3D controls */ 00653 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) || 00654 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) { 00655 WARN("control unavailable\n"); 00656 return DSERR_CONTROLUNAVAIL; 00657 } 00658 00659 /* **** */ 00660 RtlAcquireResourceExclusive(&This->lock, TRUE); 00661 00662 if (This->volpan.lPan != pan) { 00663 This->volpan.lPan = pan; 00664 DSOUND_RecalcVolPan(&(This->volpan)); 00665 00666 if (This->hwbuf) { 00667 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); 00668 if (hres != DS_OK) 00669 WARN("IDsDriverBuffer_SetVolumePan failed\n"); 00670 } 00671 } 00672 00673 RtlReleaseResource(&This->lock); 00674 /* **** */ 00675 00676 return hres; 00677 } 00678 00679 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan( 00680 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan 00681 ) { 00682 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00683 TRACE("(%p,%p)\n",This,pan); 00684 00685 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { 00686 WARN("control unavailable\n"); 00687 return DSERR_CONTROLUNAVAIL; 00688 } 00689 00690 if (pan == NULL) { 00691 WARN("invalid parameter: pan = NULL\n"); 00692 return DSERR_INVALIDPARAM; 00693 } 00694 00695 *pan = This->volpan.lPan; 00696 00697 return DS_OK; 00698 } 00699 00700 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock( 00701 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 00702 ) { 00703 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface, *iter; 00704 HRESULT hres = DS_OK; 00705 00706 TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2); 00707 00708 /* **** */ 00709 RtlAcquireResourceShared(&This->lock, TRUE); 00710 00711 if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { 00712 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2); 00713 if (hres != DS_OK) 00714 WARN("IDsDriverBuffer_Unlock failed\n"); 00715 } 00716 00717 RtlReleaseResource(&This->lock); 00718 /* **** */ 00719 00720 if (!p2) 00721 x2 = 0; 00722 00723 if (!This->hwbuf && (x1 || x2)) 00724 { 00725 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE); 00726 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry ) 00727 { 00728 RtlAcquireResourceShared(&iter->lock, TRUE); 00729 if (x1) 00730 { 00731 if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen) 00732 hres = DSERR_INVALIDPARAM; 00733 else 00734 DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE); 00735 } 00736 if (x2) 00737 DSOUND_MixToTemporary(iter, 0, x2, FALSE); 00738 RtlReleaseResource(&iter->lock); 00739 } 00740 RtlReleaseResource(&This->device->buffer_list_lock); 00741 } 00742 00743 return hres; 00744 } 00745 00746 static HRESULT WINAPI IDirectSoundBufferImpl_Restore( 00747 LPDIRECTSOUNDBUFFER8 iface 00748 ) { 00749 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00750 FIXME("(%p):stub\n",This); 00751 return DS_OK; 00752 } 00753 00754 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency( 00755 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq 00756 ) { 00757 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00758 TRACE("(%p,%p)\n",This,freq); 00759 00760 if (freq == NULL) { 00761 WARN("invalid parameter: freq = NULL\n"); 00762 return DSERR_INVALIDPARAM; 00763 } 00764 00765 *freq = This->freq; 00766 TRACE("-> %d\n", *freq); 00767 00768 return DS_OK; 00769 } 00770 00771 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX( 00772 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes 00773 ) { 00774 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00775 DWORD u; 00776 00777 FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); 00778 00779 if (pdwResultCodes) 00780 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN; 00781 00782 WARN("control unavailable\n"); 00783 return DSERR_CONTROLUNAVAIL; 00784 } 00785 00786 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources( 00787 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes 00788 ) { 00789 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00790 DWORD u; 00791 00792 FIXME("(%p,%08u,%u,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes); 00793 00794 if (pdwResultCodes) 00795 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN; 00796 00797 WARN("control unavailable\n"); 00798 return DSERR_CONTROLUNAVAIL; 00799 } 00800 00801 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath( 00802 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject 00803 ) { 00804 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00805 00806 FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject); 00807 00808 WARN("control unavailable\n"); 00809 return DSERR_CONTROLUNAVAIL; 00810 } 00811 00812 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize( 00813 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd 00814 ) { 00815 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00816 WARN("(%p) already initialized\n", This); 00817 return DSERR_ALREADYINITIALIZED; 00818 } 00819 00820 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps( 00821 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps 00822 ) { 00823 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00824 TRACE("(%p)->(%p)\n",This,caps); 00825 00826 if (caps == NULL) { 00827 WARN("invalid parameter: caps == NULL\n"); 00828 return DSERR_INVALIDPARAM; 00829 } 00830 00831 if (caps->dwSize < sizeof(*caps)) { 00832 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize); 00833 return DSERR_INVALIDPARAM; 00834 } 00835 00836 caps->dwFlags = This->dsbd.dwFlags; 00837 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; 00838 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; 00839 00840 caps->dwBufferBytes = This->buflen; 00841 00842 /* According to windows, this is zero*/ 00843 caps->dwUnlockTransferRate = 0; 00844 caps->dwPlayCpuOverhead = 0; 00845 00846 return DS_OK; 00847 } 00848 00849 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface( 00850 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj 00851 ) { 00852 IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; 00853 00854 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); 00855 00856 if (ppobj == NULL) { 00857 WARN("invalid parameter\n"); 00858 return E_INVALIDARG; 00859 } 00860 00861 *ppobj = NULL; /* assume failure */ 00862 00863 if ( IsEqualGUID(riid, &IID_IUnknown) || 00864 IsEqualGUID(riid, &IID_IDirectSoundBuffer) || 00865 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) { 00866 if (!This->secondary) 00867 SecondaryBufferImpl_Create(This, &(This->secondary)); 00868 if (This->secondary) { 00869 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary); 00870 *ppobj = This->secondary; 00871 return S_OK; 00872 } 00873 WARN("IID_IDirectSoundBuffer\n"); 00874 return E_NOINTERFACE; 00875 } 00876 00877 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { 00878 if (!This->notify) 00879 IDirectSoundNotifyImpl_Create(This, &(This->notify)); 00880 if (This->notify) { 00881 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify); 00882 *ppobj = This->notify; 00883 return S_OK; 00884 } 00885 WARN("IID_IDirectSoundNotify\n"); 00886 return E_NOINTERFACE; 00887 } 00888 00889 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { 00890 if (!This->ds3db) 00891 IDirectSound3DBufferImpl_Create(This, &(This->ds3db)); 00892 if (This->ds3db) { 00893 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db); 00894 *ppobj = This->ds3db; 00895 return S_OK; 00896 } 00897 WARN("IID_IDirectSound3DBuffer\n"); 00898 return E_NOINTERFACE; 00899 } 00900 00901 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) { 00902 ERR("app requested IDirectSound3DListener on secondary buffer\n"); 00903 return E_NOINTERFACE; 00904 } 00905 00906 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { 00907 if (!This->iks) 00908 IKsBufferPropertySetImpl_Create(This, &(This->iks)); 00909 if (This->iks) { 00910 IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks); 00911 *ppobj = This->iks; 00912 return S_OK; 00913 } 00914 WARN("IID_IKsPropertySet\n"); 00915 return E_NOINTERFACE; 00916 } 00917 00918 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); 00919 00920 return E_NOINTERFACE; 00921 } 00922 00923 static const IDirectSoundBuffer8Vtbl dsbvt = 00924 { 00925 IDirectSoundBufferImpl_QueryInterface, 00926 IDirectSoundBufferImpl_AddRef, 00927 IDirectSoundBufferImpl_Release, 00928 IDirectSoundBufferImpl_GetCaps, 00929 IDirectSoundBufferImpl_GetCurrentPosition, 00930 IDirectSoundBufferImpl_GetFormat, 00931 IDirectSoundBufferImpl_GetVolume, 00932 IDirectSoundBufferImpl_GetPan, 00933 IDirectSoundBufferImpl_GetFrequency, 00934 IDirectSoundBufferImpl_GetStatus, 00935 IDirectSoundBufferImpl_Initialize, 00936 IDirectSoundBufferImpl_Lock, 00937 IDirectSoundBufferImpl_Play, 00938 IDirectSoundBufferImpl_SetCurrentPosition, 00939 IDirectSoundBufferImpl_SetFormat, 00940 IDirectSoundBufferImpl_SetVolume, 00941 IDirectSoundBufferImpl_SetPan, 00942 IDirectSoundBufferImpl_SetFrequency, 00943 IDirectSoundBufferImpl_Stop, 00944 IDirectSoundBufferImpl_Unlock, 00945 IDirectSoundBufferImpl_Restore, 00946 IDirectSoundBufferImpl_SetFX, 00947 IDirectSoundBufferImpl_AcquireResources, 00948 IDirectSoundBufferImpl_GetObjectInPath 00949 }; 00950 00951 HRESULT IDirectSoundBufferImpl_Create( 00952 DirectSoundDevice * device, 00953 IDirectSoundBufferImpl **pdsb, 00954 LPCDSBUFFERDESC dsbd) 00955 { 00956 IDirectSoundBufferImpl *dsb; 00957 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat; 00958 HRESULT err = DS_OK; 00959 DWORD capf = 0; 00960 int use_hw, alloc_size, cp_size; 00961 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd); 00962 00963 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) { 00964 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes); 00965 *pdsb = NULL; 00966 return DSERR_INVALIDPARAM; /* FIXME: which error? */ 00967 } 00968 00969 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); 00970 00971 if (dsb == 0) { 00972 WARN("out of memory\n"); 00973 *pdsb = NULL; 00974 return DSERR_OUTOFMEMORY; 00975 } 00976 00977 TRACE("Created buffer at %p\n", dsb); 00978 00979 dsb->ref = 0; 00980 dsb->secondary = 0; 00981 dsb->device = device; 00982 dsb->lpVtbl = &dsbvt; 00983 dsb->iks = NULL; 00984 00985 /* size depends on version */ 00986 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize); 00987 00988 /* variable sized struct so calculate size based on format */ 00989 if (wfex->wFormatTag == WAVE_FORMAT_PCM) { 00990 alloc_size = sizeof(WAVEFORMATEX); 00991 cp_size = sizeof(PCMWAVEFORMAT); 00992 } else 00993 alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize; 00994 00995 dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size); 00996 if (dsb->pwfx == NULL) { 00997 WARN("out of memory\n"); 00998 HeapFree(GetProcessHeap(),0,dsb); 00999 *pdsb = NULL; 01000 return DSERR_OUTOFMEMORY; 01001 } 01002 01003 CopyMemory(dsb->pwfx, wfex, cp_size); 01004 01005 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign) 01006 dsb->buflen = dsbd->dwBufferBytes + 01007 (dsbd->lpwfxFormat->nBlockAlign - 01008 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)); 01009 else 01010 dsb->buflen = dsbd->dwBufferBytes; 01011 01012 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec; 01013 dsb->notify = NULL; 01014 dsb->notifies = NULL; 01015 dsb->nrofnotifies = 0; 01016 dsb->hwnotify = 0; 01017 01018 /* Check necessary hardware mixing capabilities */ 01019 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO; 01020 else capf |= DSCAPS_SECONDARYMONO; 01021 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT; 01022 else capf |= DSCAPS_SECONDARY8BIT; 01023 01024 use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE); 01025 TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags); 01026 if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver)) 01027 { 01028 if (device->driver) 01029 WARN("Format not supported for hardware buffer\n"); 01030 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01031 HeapFree(GetProcessHeap(),0,dsb); 01032 *pdsb = NULL; 01033 if ((device->drvcaps.dwFlags & capf) != capf) 01034 return DSERR_BADFORMAT; 01035 return DSERR_GENERIC; 01036 } 01037 01038 /* FIXME: check hardware sample rate mixing capabilities */ 01039 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */ 01040 /* FIXME: check whether any hardware buffers are left */ 01041 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */ 01042 01043 /* Allocate an empty buffer */ 01044 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer))); 01045 if (dsb->buffer == NULL) { 01046 WARN("out of memory\n"); 01047 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01048 HeapFree(GetProcessHeap(),0,dsb); 01049 *pdsb = NULL; 01050 return DSERR_OUTOFMEMORY; 01051 } 01052 01053 /* Allocate system memory for buffer if applicable */ 01054 if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) { 01055 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen); 01056 if (dsb->buffer->memory == NULL) { 01057 WARN("out of memory\n"); 01058 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01059 HeapFree(GetProcessHeap(),0,dsb->buffer); 01060 HeapFree(GetProcessHeap(),0,dsb); 01061 *pdsb = NULL; 01062 return DSERR_OUTOFMEMORY; 01063 } 01064 } 01065 01066 /* Allocate the hardware buffer */ 01067 if (use_hw) { 01068 err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0, 01069 &(dsb->buflen),&(dsb->buffer->memory), 01070 (LPVOID*)&(dsb->hwbuf)); 01071 if (FAILED(err)) 01072 { 01073 WARN("Failed to create hardware secondary buffer: %08x\n", err); 01074 if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) 01075 HeapFree(GetProcessHeap(),0,dsb->buffer->memory); 01076 HeapFree(GetProcessHeap(),0,dsb->buffer); 01077 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01078 HeapFree(GetProcessHeap(),0,dsb); 01079 *pdsb = NULL; 01080 return DSERR_GENERIC; 01081 } 01082 } 01083 01084 dsb->buffer->ref = 1; 01085 list_init(&dsb->buffer->buffers); 01086 list_add_head(&dsb->buffer->buffers, &dsb->entry); 01087 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0); 01088 01089 /* It's not necessary to initialize values to zero since */ 01090 /* we allocated this structure with HEAP_ZERO_MEMORY... */ 01091 dsb->buf_mixpos = dsb->sec_mixpos = 0; 01092 dsb->state = STATE_STOPPED; 01093 01094 dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec; 01095 dsb->nAvgBytesPerSec = dsb->freq * 01096 dsbd->lpwfxFormat->nBlockAlign; 01097 01098 /* calculate fragment size and write lead */ 01099 DSOUND_RecalcFormat(dsb); 01100 01101 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) { 01102 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); 01103 dsb->ds3db_ds3db.vPosition.x = 0.0; 01104 dsb->ds3db_ds3db.vPosition.y = 0.0; 01105 dsb->ds3db_ds3db.vPosition.z = 0.0; 01106 dsb->ds3db_ds3db.vVelocity.x = 0.0; 01107 dsb->ds3db_ds3db.vVelocity.y = 0.0; 01108 dsb->ds3db_ds3db.vVelocity.z = 0.0; 01109 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE; 01110 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE; 01111 dsb->ds3db_ds3db.vConeOrientation.x = 0.0; 01112 dsb->ds3db_ds3db.vConeOrientation.y = 0.0; 01113 dsb->ds3db_ds3db.vConeOrientation.z = 0.0; 01114 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; 01115 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE; 01116 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; 01117 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL; 01118 01119 dsb->ds3db_need_recalc = FALSE; 01120 DSOUND_Calc3DBuffer(dsb); 01121 } else 01122 DSOUND_RecalcVolPan(&(dsb->volpan)); 01123 01124 RtlInitializeResource(&dsb->lock); 01125 01126 /* register buffer if not primary */ 01127 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) { 01128 err = DirectSoundDevice_AddBuffer(device, dsb); 01129 if (err != DS_OK) { 01130 HeapFree(GetProcessHeap(),0,dsb->buffer->memory); 01131 HeapFree(GetProcessHeap(),0,dsb->buffer); 01132 RtlDeleteResource(&dsb->lock); 01133 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01134 HeapFree(GetProcessHeap(),0,dsb); 01135 dsb = NULL; 01136 } 01137 } 01138 01139 *pdsb = dsb; 01140 return err; 01141 } 01142 01143 HRESULT IDirectSoundBufferImpl_Destroy( 01144 IDirectSoundBufferImpl *pdsb) 01145 { 01146 TRACE("(%p)\n",pdsb); 01147 01148 /* This keeps the *_Destroy functions from possibly deleting 01149 * this object until it is ready to be deleted */ 01150 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb); 01151 01152 if (pdsb->iks) { 01153 WARN("iks not NULL\n"); 01154 IKsBufferPropertySetImpl_Destroy(pdsb->iks); 01155 pdsb->iks = NULL; 01156 } 01157 01158 if (pdsb->ds3db) { 01159 WARN("ds3db not NULL\n"); 01160 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db); 01161 pdsb->ds3db = NULL; 01162 } 01163 01164 if (pdsb->notify) { 01165 WARN("notify not NULL\n"); 01166 IDirectSoundNotifyImpl_Destroy(pdsb->notify); 01167 pdsb->notify = NULL; 01168 } 01169 01170 if (pdsb->secondary) { 01171 WARN("dsb not NULL\n"); 01172 SecondaryBufferImpl_Destroy(pdsb->secondary); 01173 pdsb->secondary = NULL; 01174 } 01175 01176 while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); 01177 01178 return S_OK; 01179 } 01180 01181 HRESULT IDirectSoundBufferImpl_Duplicate( 01182 DirectSoundDevice *device, 01183 IDirectSoundBufferImpl **ppdsb, 01184 IDirectSoundBufferImpl *pdsb) 01185 { 01186 IDirectSoundBufferImpl *dsb; 01187 HRESULT hres = DS_OK; 01188 int size; 01189 TRACE("(%p,%p,%p)\n", device, pdsb, pdsb); 01190 01191 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); 01192 01193 if (dsb == NULL) { 01194 WARN("out of memory\n"); 01195 *ppdsb = NULL; 01196 return DSERR_OUTOFMEMORY; 01197 } 01198 01199 CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl)); 01200 01201 if (pdsb->hwbuf) { 01202 TRACE("duplicating hardware buffer\n"); 01203 01204 hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf, 01205 (LPVOID *)&dsb->hwbuf); 01206 if (FAILED(hres)) { 01207 WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres); 01208 HeapFree(GetProcessHeap(),0,dsb); 01209 *ppdsb = NULL; 01210 return hres; 01211 } 01212 } 01213 01214 dsb->buffer->ref++; 01215 list_add_head(&dsb->buffer->buffers, &dsb->entry); 01216 dsb->ref = 0; 01217 dsb->state = STATE_STOPPED; 01218 dsb->buf_mixpos = dsb->sec_mixpos = 0; 01219 dsb->device = device; 01220 dsb->ds3db = NULL; 01221 dsb->iks = NULL; /* FIXME? */ 01222 dsb->secondary = NULL; 01223 dsb->tmp_buffer = NULL; 01224 DSOUND_RecalcFormat(dsb); 01225 DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE); 01226 01227 /* variable sized struct so calculate size based on format */ 01228 size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize; 01229 01230 dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size); 01231 if (dsb->pwfx == NULL) { 01232 WARN("out of memory\n"); 01233 HeapFree(GetProcessHeap(),0,dsb->buffer); 01234 HeapFree(GetProcessHeap(),0,dsb); 01235 *ppdsb = NULL; 01236 return DSERR_OUTOFMEMORY; 01237 } 01238 01239 CopyMemory(dsb->pwfx, pdsb->pwfx, size); 01240 01241 RtlInitializeResource(&dsb->lock); 01242 01243 /* register buffer */ 01244 hres = DirectSoundDevice_AddBuffer(device, dsb); 01245 if (hres != DS_OK) { 01246 RtlDeleteResource(&dsb->lock); 01247 HeapFree(GetProcessHeap(),0,dsb->tmp_buffer); 01248 HeapFree(GetProcessHeap(),0,dsb->buffer); 01249 HeapFree(GetProcessHeap(),0,dsb->pwfx); 01250 HeapFree(GetProcessHeap(),0,dsb); 01251 *ppdsb = 0; 01252 } 01253 01254 *ppdsb = dsb; 01255 return hres; 01256 } 01257 01258 /******************************************************************************* 01259 * SecondaryBuffer 01260 */ 01261 01262 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface( 01263 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj) 01264 { 01265 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01266 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); 01267 01268 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj); 01269 } 01270 01271 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) 01272 { 01273 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01274 ULONG ref = InterlockedIncrement(&(This->ref)); 01275 TRACE("(%p) ref was %d\n", This, ref - 1); 01276 return ref; 01277 } 01278 01279 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) 01280 { 01281 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01282 ULONG ref; 01283 TRACE("(%p)\n", This); 01284 ref = InterlockedDecrement(&(This->ref)); 01285 TRACE("ref was %d\n", ref + 1); 01286 01287 if (!ref) { 01288 This->dsb->secondary = NULL; 01289 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb); 01290 HeapFree(GetProcessHeap(), 0, This); 01291 TRACE("(%p) released\n", This); 01292 } 01293 return ref; 01294 } 01295 01296 static HRESULT WINAPI SecondaryBufferImpl_GetCaps( 01297 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps) 01298 { 01299 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01300 TRACE("(%p)->(%p)\n",This,caps); 01301 01302 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps); 01303 } 01304 01305 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition( 01306 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos) 01307 { 01308 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01309 TRACE("(%p,%p,%p)\n",This,playpos,writepos); 01310 01311 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos); 01312 } 01313 01314 static HRESULT WINAPI SecondaryBufferImpl_GetFormat( 01315 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten) 01316 { 01317 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01318 TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten); 01319 01320 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten); 01321 } 01322 01323 static HRESULT WINAPI SecondaryBufferImpl_GetVolume( 01324 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol) 01325 { 01326 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01327 TRACE("(%p,%p)\n",This,vol); 01328 01329 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); 01330 } 01331 01332 static HRESULT WINAPI SecondaryBufferImpl_GetPan( 01333 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan) 01334 { 01335 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01336 TRACE("(%p,%p)\n",This,pan); 01337 01338 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); 01339 } 01340 01341 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency( 01342 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq) 01343 { 01344 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01345 TRACE("(%p,%p)\n",This,freq); 01346 01347 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); 01348 } 01349 01350 static HRESULT WINAPI SecondaryBufferImpl_GetStatus( 01351 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status) 01352 { 01353 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01354 TRACE("(%p,%p)\n",This,status); 01355 01356 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status); 01357 } 01358 01359 static HRESULT WINAPI SecondaryBufferImpl_Initialize( 01360 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd) 01361 { 01362 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01363 TRACE("(%p,%p,%p)\n",This,dsound,dbsd); 01364 01365 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd); 01366 } 01367 01368 static HRESULT WINAPI SecondaryBufferImpl_Lock( 01369 LPDIRECTSOUNDBUFFER8 iface, 01370 DWORD writecursor, 01371 DWORD writebytes, 01372 LPVOID *lplpaudioptr1, 01373 LPDWORD audiobytes1, 01374 LPVOID *lplpaudioptr2, 01375 LPDWORD audiobytes2, 01376 DWORD dwFlags) 01377 { 01378 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01379 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n", 01380 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); 01381 01382 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb, 01383 writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); 01384 } 01385 01386 static HRESULT WINAPI SecondaryBufferImpl_Play( 01387 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags) 01388 { 01389 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01390 TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags); 01391 01392 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags); 01393 } 01394 01395 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition( 01396 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos) 01397 { 01398 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01399 TRACE("(%p,%d)\n",This,newpos); 01400 01401 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos); 01402 } 01403 01404 static HRESULT WINAPI SecondaryBufferImpl_SetFormat( 01405 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex) 01406 { 01407 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01408 TRACE("(%p,%p)\n",This,wfex); 01409 01410 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex); 01411 } 01412 01413 static HRESULT WINAPI SecondaryBufferImpl_SetVolume( 01414 LPDIRECTSOUNDBUFFER8 iface,LONG vol) 01415 { 01416 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01417 TRACE("(%p,%d)\n",This,vol); 01418 01419 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); 01420 } 01421 01422 static HRESULT WINAPI SecondaryBufferImpl_SetPan( 01423 LPDIRECTSOUNDBUFFER8 iface,LONG pan) 01424 { 01425 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01426 TRACE("(%p,%d)\n",This,pan); 01427 01428 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); 01429 } 01430 01431 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency( 01432 LPDIRECTSOUNDBUFFER8 iface,DWORD freq) 01433 { 01434 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01435 TRACE("(%p,%d)\n",This,freq); 01436 01437 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); 01438 } 01439 01440 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) 01441 { 01442 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01443 TRACE("(%p)\n",This); 01444 01445 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb); 01446 } 01447 01448 static HRESULT WINAPI SecondaryBufferImpl_Unlock( 01449 LPDIRECTSOUNDBUFFER8 iface, 01450 LPVOID lpvAudioPtr1, 01451 DWORD dwAudioBytes1, 01452 LPVOID lpvAudioPtr2, 01453 DWORD dwAudioBytes2) 01454 { 01455 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01456 TRACE("(%p,%p,%d,%p,%d)\n", 01457 This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); 01458 01459 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb, 01460 lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2); 01461 } 01462 01463 static HRESULT WINAPI SecondaryBufferImpl_Restore( 01464 LPDIRECTSOUNDBUFFER8 iface) 01465 { 01466 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01467 TRACE("(%p)\n",This); 01468 01469 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb); 01470 } 01471 01472 static HRESULT WINAPI SecondaryBufferImpl_SetFX( 01473 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes) 01474 { 01475 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01476 TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); 01477 01478 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes); 01479 } 01480 01481 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources( 01482 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes) 01483 { 01484 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01485 TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes); 01486 01487 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes); 01488 } 01489 01490 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath( 01491 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject) 01492 { 01493 SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; 01494 TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject); 01495 01496 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject); 01497 } 01498 01499 static const IDirectSoundBuffer8Vtbl sbvt = 01500 { 01501 SecondaryBufferImpl_QueryInterface, 01502 SecondaryBufferImpl_AddRef, 01503 SecondaryBufferImpl_Release, 01504 SecondaryBufferImpl_GetCaps, 01505 SecondaryBufferImpl_GetCurrentPosition, 01506 SecondaryBufferImpl_GetFormat, 01507 SecondaryBufferImpl_GetVolume, 01508 SecondaryBufferImpl_GetPan, 01509 SecondaryBufferImpl_GetFrequency, 01510 SecondaryBufferImpl_GetStatus, 01511 SecondaryBufferImpl_Initialize, 01512 SecondaryBufferImpl_Lock, 01513 SecondaryBufferImpl_Play, 01514 SecondaryBufferImpl_SetCurrentPosition, 01515 SecondaryBufferImpl_SetFormat, 01516 SecondaryBufferImpl_SetVolume, 01517 SecondaryBufferImpl_SetPan, 01518 SecondaryBufferImpl_SetFrequency, 01519 SecondaryBufferImpl_Stop, 01520 SecondaryBufferImpl_Unlock, 01521 SecondaryBufferImpl_Restore, 01522 SecondaryBufferImpl_SetFX, 01523 SecondaryBufferImpl_AcquireResources, 01524 SecondaryBufferImpl_GetObjectInPath 01525 }; 01526 01527 HRESULT SecondaryBufferImpl_Create( 01528 IDirectSoundBufferImpl *dsb, 01529 SecondaryBufferImpl **psb) 01530 { 01531 SecondaryBufferImpl *sb; 01532 TRACE("(%p,%p)\n",dsb,psb); 01533 01534 sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb)); 01535 01536 if (sb == 0) { 01537 WARN("out of memory\n"); 01538 *psb = NULL; 01539 return DSERR_OUTOFMEMORY; 01540 } 01541 sb->ref = 0; 01542 sb->dsb = dsb; 01543 sb->lpVtbl = &sbvt; 01544 01545 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb); 01546 *psb = sb; 01547 return S_OK; 01548 } 01549 01550 static HRESULT SecondaryBufferImpl_Destroy( 01551 SecondaryBufferImpl *pdsb) 01552 { 01553 TRACE("(%p)\n",pdsb); 01554 01555 while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); 01556 01557 return S_OK; 01558 } Generated on Sat May 26 2012 04:20:06 for ReactOS by
1.7.6.1
|