我正嘗試使用XAudio2音頻系統以異步方式播放循環聲音。它的功能,但是當DLL被卸載時(這裏的代碼在另一個程序加載的DLL中),我在父應用程序中遇到了訪問衝突異常。XAudio2卸載時出現訪問衝突異常
我注意到我沒有收到任何錯誤,直到我將混音中的主控聲音添加進來,但是我不知道我會怎麼做。
的代碼如下:
在soundengine.h
#include <Windows.h>
#include <xaudio2.h>
#include <fstream>
#define SAFE_DELETE(p) if(p) {delete p; p = NULL;}
#define SAFE_DELETE_ARRAY(p) if(p) {delete[] p; p = NULL;}
#define DXTRACE_ERR(str,hr) DXTrace(__FILE__,(DWORD)__LINE__,hr,str, FALSE)
using namespace std;
#define XA2SE_PLAY_LOOP 1
#define XA2SE_PLAY_STD 0
#define XA2SE_ERROR_NOTPLAYING -1
#define XA2SE_ERROR_COULD_NOT_OPEN_FILE -2
#define XA2SE_ERROR_NOT_WAVE_FILE -3
#define XA2SE_ERROR_COULD_NOT_SEEK -4
#define XA2SE_ERROR_COULD_NOT_DESCEND -5
#define XA2SE_ERROR_COULD_NOT_RESET -6
#define XA2SE_ERROR_RIFF_ERROR -7
#define XA2SE_ERROR_SIZE_ERROR -8
#define XA2SE_ERROR_COULD_NOT_READ -9
#define XA2SE_ERROR_UNEXPECTED_NULL_VALUE -10
#define XA2SE_ERROR_COULD_NOT_ASCEND -11
#define XA2SE_ERROR_COULD_NOT_GET_INFO -12
#define XA2SE_ERROR_COULD_NOT_ADVANCE -13
#define XA2SE_ERROR_COULD_NOT_READEND -14
#define XA2SE_ERROR_COULD_NOT_SET_INFO -15
#define XA2SE_ERROR_COULD_NOT_CREATE_VOICE -16
#define XA2SE_COULD_NOT_SUBMIT_BUFFER -17
#define WAVEFILE_READ 0x001
class XA2SoundEngine {
public:
IXAudio2MasteringVoice* mv;
IXAudio2SourceVoice* sv;
IXAudio2* pXA2;
XA2SoundEngine();
~XA2SoundEngine();
BOOL Play(LPWSTR file, int mode);
};
class WaveFile {
public:
WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
HMMIO m_hmmio; // MM I/O handle for the WAVE
MMCKINFO m_ck; // Multimedia RIFF chunk
MMCKINFO m_ckRiff; // Use in opening a WAVE file
DWORD m_dwSize; // The size of the wave file
MMIOINFO m_mmioinfoOut;
BYTE* m_pbData;
BYTE* m_pbDataCur;
ULONG m_ulDataSize;
CHAR* m_pResourceBuffer;
protected:
HRESULT ReadMMIO();
HRESULT WriteMMIO(WAVEFORMATEX* pwfxDest);
public:
WaveFile();
~WaveFile();
HRESULT Open(LPWSTR strFileName);
HRESULT Close();
HRESULT Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead);
HRESULT Write(UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote);
DWORD GetSize();
HRESULT ResetFile();
WAVEFORMATEX* GetFormat() {
return m_pwfx;
};
};
extern XA2SoundEngine* soundengine;
在soundengine.cpp
#include "soundengine.h"
struct async_play_params {
LPWSTR file;
int mode;
};
DWORD _stdcall async_play_routine(void* param);
XA2SoundEngine::XA2SoundEngine() {
HRESULT hr;
CoInitializeEx(NULL,COINIT_MULTITHREADED);
pXA2 = NULL;
sv = NULL;
if(FAILED(hr = XAudio2Create(&pXA2))) {
MessageBoxW(NULL,L"The TFDi 737 Extreme Sound system failed to initialize the XAudio2 engine.\r\n\r\nError: FAILED(hr = XAudio2Create(&pXA2, flags))",L"TFDi 737XS Sound Error",MB_OK + MB_ICONERROR);
return;
}
if(FAILED(hr = pXA2->CreateMasteringVoice(&mv))) {
MessageBoxW(NULL,L"The TFDi 737 Extreme Sound system failed to initialize the XAudio2 mastering voice.\r\n\r\nError: FAILED(hr = pXA2->CreateMasteringVoice(&mv))",L"TFDi 737XS Sound Error",MB_OK + MB_ICONERROR);
return;
}
}
XA2SoundEngine::~XA2SoundEngine() {
if(sv)
sv->DestroyVoice();
if(mv)
mv->DestroyVoice();
if(pXA2)
pXA2->Release();
CoUninitialize();
}
BOOL XA2SoundEngine::Play(LPWSTR file, int mode) {
HRESULT hr;
WaveFile wf;
if(FAILED(hr = wf.Open(file)))
return XA2SE_ERROR_COULD_NOT_OPEN_FILE;
WAVEFORMATEX* pwfx = wf.GetFormat();
DWORD wavesize = wf.GetSize();
BYTE* wavedata = new BYTE[wavesize];
if(FAILED(hr = wf.Read(wavedata, wavesize, &wavesize)))
return XA2SE_ERROR_COULD_NOT_READ;
if(soundengine->sv != NULL) {
soundengine->sv->FlushSourceBuffers();
soundengine->sv->DestroyVoice();
}
if(FAILED(hr = soundengine->pXA2->CreateSourceVoice(&soundengine->sv,pwfx))) {
SAFE_DELETE(wavedata);
return XA2SE_ERROR_COULD_NOT_CREATE_VOICE;
}
XAUDIO2_BUFFER buffer = {0};
buffer.pAudioData = wavedata;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = wavesize;
buffer.LoopBegin = 0;
double nos = (double)wavesize/((pwfx->wBitsPerSample * pwfx->nChannels)/pwfx->nSamplesPerSec);
buffer.LoopLength = (unsigned int)nos;
buffer.LoopLength = 0;
buffer.LoopCount = (mode == XA2SE_PLAY_LOOP ? XAUDIO2_LOOP_INFINITE : 0);
if(FAILED(hr = soundengine->sv->SubmitSourceBuffer(&buffer))) {
SAFE_DELETE_ARRAY(wavedata);
return XA2SE_COULD_NOT_SUBMIT_BUFFER;
}
hr = soundengine->sv->Start(0);
//SAFE_DELETE_ARRAY(wavedata);
return TRUE;
}
WaveFile::WaveFile() {
m_pwfx = NULL;
m_hmmio = NULL;
m_pResourceBuffer = NULL;
m_dwSize = 0;
}
WaveFile::~WaveFile() {
Close();
SAFE_DELETE_ARRAY(m_pwfx);
}
HRESULT WaveFile::Open(LPWSTR strFileName)
{
HRESULT hr;
if(strFileName == NULL)
return E_INVALIDARG;
SAFE_DELETE_ARRAY(m_pwfx);
m_hmmio = mmioOpenW(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ);
if(NULL == m_hmmio) {
return XA2SE_ERROR_COULD_NOT_OPEN_FILE;
}
if(FAILED(hr = ReadMMIO())) {
// ReadMMIO will fail if its an not a wave file
mmioClose(m_hmmio, 0);
return XA2SE_ERROR_NOT_WAVE_FILE;
}
if(FAILED(hr = ResetFile()))
return XA2SE_ERROR_COULD_NOT_RESET;
// After the reset, the size of the wav file is m_ck.cksize so store it now
m_dwSize = m_ck.cksize;
return hr;
}
HRESULT WaveFile::ReadMMIO()
{
MMCKINFO ckIn; // chunk info. for general use.
PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
memset(&ckIn, 0, sizeof(ckIn));
m_pwfx = NULL;
if((0 != mmioDescend(m_hmmio,&m_ckRiff,NULL,0)))
return XA2SE_ERROR_COULD_NOT_DESCEND;
// Check to make sure this is a valid wave file
if((m_ckRiff.ckid != FOURCC_RIFF) || (m_ckRiff.fccType != mmioFOURCC('W','A','V','E')))
return XA2SE_ERROR_RIFF_ERROR;
// Search the input file for for the 'fmt ' chunk.
ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
if(0 != mmioDescend(m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK))
return XA2SE_ERROR_COULD_NOT_DESCEND;
// Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
// if there are extra parameters at the end, we'll ignore them
if(ckIn.cksize < (LONG)sizeof(PCMWAVEFORMAT))
return XA2SE_ERROR_SIZE_ERROR;
// Read the 'fmt ' chunk into <pcmWaveFormat>.
if(mmioRead(m_hmmio, (HPSTR)&pcmWaveFormat,
sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat))
return XA2SE_ERROR_COULD_NOT_READ;
// Allocate the waveformatex, but if its not pcm format, read the next
// word, and thats how many extra bytes to allocate.
if(pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM)
{
m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
if(NULL == m_pwfx)
return XA2SE_ERROR_UNEXPECTED_NULL_VALUE;
// Copy the bytes from the pcm structure to the waveformatex structure
memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat));
m_pwfx->cbSize = 0;
}
else
{
// Read in length of extra bytes.
WORD cbExtraBytes = 0L;
if(mmioRead(m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD))
return XA2SE_ERROR_COULD_NOT_READ;
m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
if(NULL == m_pwfx)
return XA2SE_ERROR_UNEXPECTED_NULL_VALUE;
// Copy the bytes from the pcm structure to the waveformatex structure
memcpy(m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat));
m_pwfx->cbSize = cbExtraBytes;
// Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
if(mmioRead(m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize)) + sizeof(WORD)),
cbExtraBytes) != cbExtraBytes)
{
SAFE_DELETE(m_pwfx);
return XA2SE_ERROR_COULD_NOT_READ;
}
}
// Ascend the input file out of the 'fmt ' chunk.
if(0 != mmioAscend(m_hmmio, &ckIn, 0))
{
SAFE_DELETE(m_pwfx);
return XA2SE_ERROR_COULD_NOT_ASCEND;
}
return S_OK;
}
DWORD WaveFile::GetSize() {
return m_dwSize;
}
HRESULT WaveFile::ResetFile() {
if(m_hmmio == NULL)
return CO_E_NOTINITIALIZED;
// Seek to the data
if(-1 == mmioSeek(m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
SEEK_SET))
return XA2SE_ERROR_COULD_NOT_SEEK;
// Search the input file for the 'data' chunk.
m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
if(0 != mmioDescend(m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK))
return XA2SE_ERROR_COULD_NOT_DESCEND;
return S_OK;
}
HRESULT WaveFile::Read(BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead) {
MMIOINFO mmioinfoIn; // current status of m_hmmio
if(m_hmmio == NULL)
return CO_E_NOTINITIALIZED;
if(pBuffer == NULL || pdwSizeRead == NULL)
return E_INVALIDARG;
*pdwSizeRead = 0;
if(0 != mmioGetInfo(m_hmmio, &mmioinfoIn, 0))
return XA2SE_ERROR_COULD_NOT_GET_INFO;
UINT cbDataIn = dwSizeToRead;
if(cbDataIn > m_ck.cksize)
cbDataIn = m_ck.cksize;
m_ck.cksize -= cbDataIn;
for(DWORD cT = 0; cT < cbDataIn; cT++)
{
// Copy the bytes from the io to the buffer.
if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
{
if(0 != mmioAdvance(m_hmmio, &mmioinfoIn, MMIO_READ))
return XA2SE_ERROR_COULD_NOT_ADVANCE;
if(mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
return XA2SE_ERROR_COULD_NOT_READEND;
}
// Actual copy.
*((BYTE*)pBuffer + cT) = *((BYTE*)mmioinfoIn.pchNext);
mmioinfoIn.pchNext++;
}
if(0 != mmioSetInfo(m_hmmio, &mmioinfoIn, 0))
return XA2SE_ERROR_COULD_NOT_SET_INFO;
*pdwSizeRead = cbDataIn;
return S_OK;
}
HRESULT WaveFile::Close() {
if (m_hmmio != NULL) {
mmioClose(m_hmmio, 0);
m_hmmio = NULL;
}
SAFE_DELETE_ARRAY(m_pResourceBuffer);
return S_OK;
}
我實施了您的解決方案,但是,我仍然有相同的崩潰。該DLL正在被Flight Simulator X加載,看起來該sim正在做一些事情。我在飛行模擬器環境之外測試了庫,沒有錯。 –
我添加了一個檢查,確保CoUninitialize函數在調用析構函數之前不會被擊中,並且永遠不會被調用。它似乎掛在最後的某個地方,永遠不會擊中析構者或完成工作,因此錯誤。 –
@CollinBiedenkapp不知道爲什麼析構函數從未被擊中。您必須爲您的Flight Simulator進行調試。總的來說,應該總是在卸載DLL之前調用析構函數(這是如何工作的),所以可能是因爲你並沒有首先刪除對象。嘗試審查一些事情。 – 2013-04-17 06:10:20