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

发布于 2024-08-16 06:33:55 字数 2702 浏览 8 评论 0原文

有人可以指出我这段代码有什么问题吗?我在混合 C++ 和 MC++ 方面经历了非常艰难的经历。我已经阅读了很多关于这个主题的博客和教程(传递委托),但现在看起来我的代码没问题(在调试模式下一步步编译和运行良好)它崩溃了。

主要问题是它需要有一个作为成员函数的委托(需要访问其他类成员)。

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

Could someone point me whats wrong with this code please? I'm having a very hard experience in mixing C++ and MC++. I have read a lot of blogs and tutorial regarding this subject (passing delegates) but now that looks my code is ok (its compiling and runs well when in debug mode and step by step) it crashs.

The main problem is that it needs to have a Delegate that is a member function (which needs to access other class members).

I remembered that theres a note in waveInProc documentation which says that inside the callback you cannot call any system function. Should be this what's crashing the application since it tryies to use other members and the managed environment takes place here calling other system methods?

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);
 }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

多彩岁月 2024-08-23 06:33:55

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

You need to use a GCHandle rather than pin_ptr. See http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.80).aspx

橘虞初梦 2024-08-23 06:33:55

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

尝试在类作用域而不是函数作用域中创建它

your are declaring the pin_ptr on the managed heap and then you pass it to an un-managed function
all the managed references to this pointer are inside CWaveIn::Open(int currentInputDeviceId)
so I guess the GC sees no reason to keep this object after CWaveIn::Open exits.

try to create it in the class scope instead of the function scope

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文