2013-04-17 82 views
0

我正嘗試使用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; 
} 

回答

0

我碰巧使用XAudio某些事情,我檢查了我的代碼。奇怪的是,我有一條評論說,不要在AudioDevice析構函數本身中使用CoUninitialize();,並且我記得原因:

您正在使用CoInitializeEx(NULL, COINIT_MULTITHREADED);初始化COM。這意味着除了應用程序之外,還有其他線程(特別是其他XAudio線程)在您的控制之外運行。當您在XA2SoundEngine的析構函數中使用CoUninitialize()時,該線程可能沒有退出或完成清理其資源。從本質上講,你要求COM做一些殺戮,可能沒有做好準備(這是我最好的猜測,因爲我自己一直在收到訪問衝突)。

我固定它的方式只是而不是CoUninitialize()。微軟在更新版本的XAudio2中意識到,當它正在使用的線程正在生成或正在死亡時不會告訴你,所以XAudio2(2.8,我相信,在Windows 8上)爲你做了CoInitializeExCoUninitialize。如果你在那個環境中,你不應該首先調用這些方法。

如果這恰好在DLL中,那麼當DLL附着時,可以安全地調用CoUninitialize和CoInitializeEx。它會正常運行:

BOOL APIENTRY DllMain (HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { 

    switch (dwReason) { 

    case DLL_PROCESS_ATTACH: 
     CoInitializeEx(NULL, COINIT_MULTITHREADED); 
     break; 
    case DLL_THREAD_ATTACH: 
     CoInitializeEx(NULL, COINIT_MULTITHREADED); 
     break; 
    case DLL_THREAD_DETACH: 
     CoUninitialize(); 
     break; 
    case DLL_PROCESS_DETACH: 
     CoUninitialize(); 
     break; 
    default: 
     // Wat... 
     break; 
    } 

    return TRUE; 

} 

也許COM專家可以告訴我,如果我做錯了,但到目前爲止上述工作已經爲我工作。

祝你好運!

+0

我實施了您的解決方案,但是,我仍然有相同的崩潰。該DLL正在被Flight Simulator X加載,看起來該sim正在做一些事情。我在飛行模擬器環境之外測試了庫,沒有錯。 –

+0

我添加了一個檢查,確保CoUninitialize函數在調用析構函數之前不會被擊中,並且永遠不會被調用。它似乎掛在最後的某個地方,永遠不會擊中析構者或完成工作,因此錯誤。 –

+0

@CollinBiedenkapp不知道爲什麼析構函數從未被擊中。您必須爲您的Flight Simulator進行調試。總的來說,應該總是在卸載DLL之前調用析構函數(這是如何工作的),所以可能是因爲你並沒有首先刪除對象。嘗試審查一些事情。 – 2013-04-17 06:10:20

0

這個問題最終成爲一堆事情,包括我在基於DirectX9的環境中使用Windows 8版本的XAudio2,錯誤地使用了CoInitialize()函數,以及我從未明確稱過'刪除soundengine'。我已經修改了一下這個類,現在它工作的很好。

謝謝你們!