2010-01-03 48 views
0

有人能指出我什麼是錯與此代碼嗎?我在混合使用C++和MC++方面有非常艱苦的經驗。我已經閱讀了很多有關這個主題的博客和教程(通過代表),但現在看起來我的代碼是好的(編譯並且在調試模式下一步一步地運行良好)會崩潰。傳遞一個代表回調到本地C++ API調用

的主要問題是,它需要有一個代表是一個成員函數(其需要訪問其他類成員)。

我記得那裏有waveInProc文檔中的一張紙條,上面說,回調中你不能調用任何系統功能。應該是因爲它試圖使用其他成員,並且託管環境發生在這裏調用其他系統方法,所以應用程序崩潰了?

ref class CWaveIn 
{ 
public: 
void CWaveIn::Open(int currentInputDeviceId) 
private: 
void AllocateBuffer(void); 
void WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); 
delegate void CallBack(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); 
CallBack^ myDelegate; 
protected: 
WAVEFORMATEX* waveFormat; 
int bufferDuration; // in seconds 
BYTE* waveInBuffer; 
int bufferSize; 
}; 

void CWaveIn::AllocateBuffer(void) 
{ 
free(waveInBuffer); 
bufferSize = waveFormat->nAvgBytesPerSec * bufferDuration; 
waveInBuffer = new BYTE[bufferSize]; 
Debug::WriteLine("BufferSize: " + bufferSize); 
} 

void CWaveIn::WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 
{ 
switch(uMsg) { 
    case WIM_CLOSE: 
    Debug::WriteLine("WIM_CLOSE"); 
    break; 
    case WIM_DATA: 
    for(int i=0;i<bufferSize; i++) { 
    Debug::Write(waveInBuffer[i] + " "); 
    } 
    Debug::WriteLine("WIM_DATA"); 
    break; 
    case WIM_OPEN: 
    Debug::WriteLine("WIM_OPEN"); 
    break; 
} 
} 

void CWaveIn::Open(int currentInputDeviceId) 
{ 
MMRESULT result = ::waveInOpen(0, currentInputDeviceId, waveFormat, 0, 0, WAVE_FORMAT_QUERY); 
Debug::WriteLine(L"CWaveIn::Open() WAVE_FORMAT_QUERY: device " + currentInputDeviceId.ToString()); 
DebugError(result); 
if(result == MMSYSERR_NOERROR) 
{ 
    myDelegate = gcnew CallBack(this, &CWaveIn::WaveInProc); 
    pin_ptr<CallBack^> ptrMyDelegate= &myDelegate; 
    IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(myDelegate); 

    HWAVEIN hWaveIn; 
    MMRESULT result = ::waveInOpen(&hWaveIn, currentInputDeviceId, waveFormat, (DWORD_PTR)delegatePointer.ToPointer(), 0, CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT); 
    Debug::WriteLine(L"CWaveIn::Open() : device " + currentInputDeviceId.ToString()); 
    DebugError(result); 

    AllocateBuffer(); 

    WAVEHDR WaveInHdr; 
    WaveInHdr.lpData = (LPSTR)waveInBuffer; 
    WaveInHdr.dwBufferLength = bufferSize; 
    WaveInHdr.dwBytesRecorded=0; 
    WaveInHdr.dwUser = 0L; 
    WaveInHdr.dwFlags = 0L; 
    WaveInHdr.dwLoops = 0L; 
    ::waveInPrepareHeader(hWaveIn, &WaveInHdr, sizeof(WAVEHDR)); 
    result = ::waveInAddBuffer(hWaveIn, &WaveInHdr, sizeof(WAVEHDR)); 

    result = ::waveInStart(hWaveIn); 
    Debug::WriteLine(L"CWaveIn::Start() : device " + currentInputDeviceId.ToString()); 
    DebugError(result); 
} 
} 
+0

它可以幫助,如果將提供關於你從調試器獲取時墜毀消息,上線堆棧轉儲ECT一些更多的信息。 – Alon 2010-01-03 09:18:40

+0

現在我想到的一點是,當CWaveIn :: Open調用完成時,pin_ptr超出範圍。那麼,我怎麼能把它固定在課堂上呢? – 2010-01-03 09:20:07

+0

異常碼是C0000005 ACCESS_VIOLATION。 錯誤模塊名稱:msvcrt.dll。 沒有關於該行的信息。在調用回調函數時,可能發生在waveInOpen內部。 它有幫助嗎? – 2010-01-03 09:23:56

回答

0

您的聲明在託管堆中pin_ptr,然後你把它傳遞給一個未管理功能 所有這個指針管理引用內部CWaveIn::Open(int currentInputDeviceId) 所以我想GC認爲沒有理由把這個對象在CWaveIn::Open之後退出。

嘗試在類範圍,而不是函數範圍

+0

對,謝謝。這是我的觀點。我不知道如何執行此操作。編譯器不喜歡將一個pin_ptr聲明爲數據成員。 – 2010-01-03 09:41:25

+0

你會得到什麼錯誤? – Alon 2010-01-03 09:49:39

+0

將此行添加到CWaveIn :: Open的末尾,看起來像現在可以工作。 ((WaveInHdr.dwFlags&WHDR_DONE)!= WHDR_DONE){}; 不是上帝的解決方案,它導致我們到一個。它所做的就是留在open()中,直到記錄回調完成。 – 2010-01-03 09:51:03