Я пытаюсь использовать аудиосистему 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