C++ 卸载时XAudio2访问冲突异常

C++ 卸载时XAudio2访问冲突异常,c++,windows,exception,directx,access-violation,C++,Windows,Exception,Directx,Access Violation,我正在尝试使用XAudio2音频系统异步播放循环声音。它可以工作,但是当卸载DLL时(这里的代码在另一个程序加载的DLL中),我在父应用程序中得到一个访问冲突异常 我已经注意到,在我将主控音添加到混音中之前,我没有收到任何错误,但我不知道我可能会用它做错什么 代码如下: 在soundengine.h中 #include <Windows.h> #include <xaudio2.h> #include <fstream> #define SAFE_DELETE

我正在尝试使用XAudio2音频系统异步播放循环声音。它可以工作,但是当卸载DLL时(这里的代码在另一个程序加载的DLL中),我在父应用程序中得到一个访问冲突异常

我已经注意到,在我将主控音添加到混音中之前,我没有收到任何错误,但我不知道我可能会用它做错什么

代码如下:

在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;
#包括
#包括
#包括
#如果(p){DELETE p;p=NULL;}
#如果(p){DELETE[]p;p=NULL;}
#定义DXTRACE\u ERR(str,hr)DXTRACE(\uuuu FILE\uuuu,(DWORD)\uuuuu LINE\uu,hr,str,FALSE)
使用名称空间std;
#定义XA2SE\u PLAY\u循环1
#定义XA2SE\U播放\U标准0
#定义XA2SE\u错误\u不播放-1
#定义XA2SE\u错误\u无法\u打开\u文件-2
#定义XA2SE\u错误\u非\u波形\u文件-3
#定义XA2SE\u错误\u无法\u查找-4
#定义XA2SE\u错误\u无法\u下降-5
#定义XA2SE\u错误\u无法\u重置-6
#定义XA2SE_错误\u RIFF_错误-7
#定义XA2SE_错误大小_错误-8
#定义XA2SE\u错误\u无法\u读取-9
#定义XA2SE\u错误\u意外\u空值\u值-10
#定义XA2SE\u错误\u无法\u上升-11
#定义XA2SE\u错误\u无法\u获取\u信息-12
#定义XA2SE\u错误\u无法\u前进-13
#定义XA2SE\u错误\u无法\u读取结束-14
#定义XA2SE\u错误\u无法\u设置\u信息-15
#定义XA2SE\u错误\u无法\u创建\u语音-16
#定义XA2SE\u无法\u提交\u缓冲区-17
#定义波形文件读取0x001
XA2SoundEngine类{
公众:
IXAudio2MasteringVoice*mv;
IXAudio2SourceVoice*sv;
IX2*pXA2;
XA2SoundEngine();
~XA2SoundEngine();
布尔播放(LPWSTR文件,int模式);
};
类波文件{
公众:
WAVEFORMATEX*m_pwfx;//指向WAVEFORMATEX结构的指针
HMMIO m_HMMIO;//MM波的I/O句柄
MMCKINFO m_ck;//多媒体RIFF块
MMCKINFO m_ckRiff;//用于打开波形文件
DWORD m_dwSize;//波形文件的大小
mmoinfo m_mmoinfoout;
字节*m_pbData;
字节*m_pbDataCur;
ULONG m_ulDataSize;
CHAR*m_资源前缓冲区;
受保护的:
HRESULT ReadMMIO();
HRESULT WRITEMIO(波形格式*pwfxDest);
公众:
波形文件();
~WaveFile();
HRESULT Open(LPWSTR strFileName);
HRESULT Close();
HRESULT Read(字节*pBuffer,DWORD dwSizeToRead,DWORD*pdwSizeRead);
HRESULT写入(UINT nSizeToWrite,字节*pbData,UINT*pnsizewrite);
DWORD GetSize();
HRESULT ResetFile();
WAVEFORMATEX*GetFormat(){
返回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;
}
#包括“soundengine.h”
结构异步\u播放\u参数{
LPWSTR文件;
int模式;
};
DWORD标准调用异步播放例程(void*param);
XA2SoundEngine::XA2SoundEngine(){
HRESULT-hr;
CoInitializeX(空,Conit_多线程);
pXA2=NULL;
sv=NULL;
if(失败(hr=XAudio2Create(&pXA2))){
MessageBoxW(NULL,L“TFDi 737极限声音系统未能初始化XAudio2引擎。\r\n\r\n错误:失败(hr=XAudio2Create(&pXA2,标志))”,L“TFDi 737XS声音错误”,MB_OK+MB_ICONROR);
返回;
}   
如果(失败(hr=pXA2->CreateMasteringVoice(&mv))){
MessageBoxW(NULL,L“TFDi 737极限声音系统未能初始化XAudio2主控语音。\r\n\r\n错误:失败(hr=pXA2->CreateMasteringVoice(&mv)),L“TFDi 737XS声音错误”,MB_OK+MB_ICONERROR);
返回;
}   
}
XA2SoundEngine::~XA2SoundEngine(){
if(sv)
sv->破坏语音();
中频(毫伏)
mv->破坏语音();
if(pXA2)
pXA2->Release();
coninitialize();
}
boolxa2soundengine::Play(LPWSTR文件,int模式){
HRESULT-hr;
波形文件wf;
如果(失败(hr=wf.Open(文件)))
返回XA2SE\u错误\u无法\u打开\u文件;
WAVEFORMATEX*pwfx=wf.GetFormat();
DWORD wavesize=wf.GetSize();
字节*wavedata=新字节[wavesize];
if(失败(hr=wf.Read(wavedata、wavesize和wavesize)))
返回XA2SE\u错误\u无法\u读取;
如果(声音引擎->sv!=NULL){
soundengine->sv->FlushSourceBuffers();
soundengine->sv->DestroyVoice();
}
如果(失败(hr=soundengine->pXA2->CreateSourceVoice(&soundengine->sv,pwfx))){
安全删除(wavedata);
返回XA2SE\u错误\u无法\u创建\u语音;
}
XAUDIO2_缓冲区={0};
buffer.pAudioData=wavedata;
buffer.Flags=XAUDIO2\u\u\u流的结束\u;
buffer.AudioBytes=波大小;
buffer.LoopBegin=0;
双编号=(双)波长/((pwfx->wBitsPerSample*pwfx->nChannels)/pwfx->nSamplesPerSec);
buffer.LoopLength=(无符号整数)个;
buffer.LoopLength=0;
buffer.LoopCount=(模式==XA2SE\u PLAY\u LOOP?XAUDIO2\u LOOP\u INFINITE:0);
如果(失败(hr=soundengine->sv->SubmitSourceBuffer(&buffer)){
安全删除数组(wavedata);
返回XA2SE\u无法\u提交\u缓冲区;
}
hr=声音引擎->sv->启动(0);
//安全删除数组(wavedata);
返回TRUE;
}
波形文件::波形文件(){
m_pwfx=NULL;
m_hmmio=NULL;
m_pResourceBuffer=NULL;
m_dwSize=0;
}
波形文件::~WaveFile(){
Close();
安全删除数组(m_pwfx);
}
HRESULT波形文件::打开(LPWSTR strFileName)
{
HRESULT-hr;
if(strFileName==NULL)
返回E_INVALIDARG;
安全删除数组(m_pwfx);
m_hmmio=mmioOpenW(strFileName,NULL,MMIO_ALLOCBUF | MMIO_READ);
if(NULL==m_hmmio){
返回XA2SE\u错误\u无法\u打开\u文件;
}
如果(失败(hr=ReadMMIO()){
//如果ReadMMIO不是wave文件,它将失败
mmioClose(m_hmmio,0);
返回XA2SE\u错误\u非\u波形\u文件;
}
如果(失败(hr=ResetFile())
返回
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;

}
SafeRelease(&m_musicEngine);
SafeRelease(&m_soundEffectEngine);
template <class T> void SafeRelease(T **ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = NULL;
    }
}
void  _stdcall AudioEngineCallbacks::OnCriticalError(HRESULT Error)
// This [...] used to tell when the audio system
// is experiencing critial errors.
// XAudio2 gives a critical error when the user unplugs
// the headphones and a new speaker configuration is generated.