将委托作为回调传递给本机C ++ API调用

时间:2010-01-03 08:59:23

标签: c++ winapi audio delegates managed-c++

有人能指出我这个代码有什么问题吗?我在混合C ++和MC ++方面有着非常丰富的经验。我已经阅读了很多关于这个主题的博客和教程(传递代表),但现在看起来我的代码是正常的(它在编译时运行良好并且在调试模式下一步一步运行)它会崩溃。

主要问题是它需要一个Delegate,它是一个成员函数(需要访问其他类成员)。

我记得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);
 }
}

2 个答案:

答案 0 :(得分:1)

您需要使用GCHandle而不是pin_ptr。见http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.80).aspx

答案 1 :(得分:0)

您正在声明托管堆上的pin_ptr,然后将其传递给未管理的函数 对此指针的所有托管引用都在CWaveIn::Open(int currentInputDeviceId)内 所以我猜GC在CWaveIn::Open退出后没有理由保留此对象。

尝试在类范围而不是函数范围

中创建它