c# - C++ 到 C# : PInvoke\Marshaling a callback with a complex type

标签 c# c++ callback pinvoke marshalling

我正在使用 C++ SDK 将我的 C# 代码连接到一些闭路电视摄像机。我想使用 SDK 的方法设置一个回调,我可以从中检索帧信息。

.h 文件中的代码:

typedef struct _frame_info
{
    unsigned long       deviceID;
    unsigned long       channel;
    unsigned long       frameType;
    unsigned long       length;
    unsigned long       keyFrame;
    unsigned long       width;
    unsigned long       height;
    unsigned long       frameIndex;
    unsigned long       frameAttrib;
    unsigned long       streamID;
    long long           time;
    long long           relativeTime;
} FRAME_INFO;

typedef void (__stdcall *PLAY_DATA_CALLBACK)(long lPlayHandle,
    FRAME_INFO frameInfo, unsigned char *pBuffer, void *pUser);

extern "C" __declspec(dllimport) BOOL __stdcall SetPlayDataCallBack(
    long lPlayHandle, PLAY_DATA_CALLBACK fPlayDataCallBack, void *pUser);

PInvoke 代码:

[StructLayout(LayoutKind.Sequential, Pack = 0)]
public class FrameInfo
{
    public uint deviceID;
    public uint channel;
    public uint frameType;
    public uint length;
    public uint keyFrame;
    public uint width;
    public uint height;
    public uint frameIndex;
    public uint frameAttrib;
    public uint streamID;
    public long time;
    public long relativeTime;
}

public delegate void PlayDataCallback(int playbackHandle,
    FrameInfo frameInfo, IntPtr buffer, IntPtr userData);

[DllImport("SDK.dll")]
public static extern bool SetPlayDataCallBack(int playbackHandle,
    PlayDataCallback playDataCallback, IntPtr userData);

使用PInvoke代码的代码:

// Class member to keep the callback alive
PlayDataCallback _callbackDelegate;

// Assigning the callback
_callbackDelegate = new PlayDataCallback(MyCallback);

// Setting the callback
SetPlayDataCallBack(_playbackId, _callbackDelegate, IntPtr.Zero);

// The callback
private void MyCallback(int playbackHandle, FrameInfo frameInfo,
    IntPtr buffer, IntPtr userdata)
{
    // wishful thinking
}

当我运行代码时出现错误:“System.NullReferenceException 未处理 消息:对象引用未设置到对象的实例。”

我尝试将回调签名更改为以下内容(即使用 IntPtr 代替 FrameInfo)-

public delegate void PlayDataCallback(int playbackHandle, IntPtr frameInfo,
    IntPtr buffer, IntPtr userData);

结果 - 实际上调用了回调 (!) 但我无法使用 IntPtr frameInfo 做任何事情,例如尝试从回调中调用:

Marshal.PtrToStructure(frameInfo, typeof(FrameInfo));

var a = new IntPtr[14];
Marshal.Copy(frameInfo, a, 0, 1); // '1' is just an example, any number except '0' results in the same error

导致错误:“System.AccessViolationException 未处理 消息:尝试读取或写入 protected 内存。这通常表明其他内存已损坏。”

我还尝试在回调委托(delegate)上方使用 UnmanagedFunctionPointer 属性,但得到了同样的错误。

如您所见,我正在迈出处理托管代码和非托管代码的第一步。我读了一堆文章,听了几个看似相关但没有人谈到上述问题的 pluralsight 话题。 我认为我编码 FrameInfo 结构的方式有问题,但我已经成功编码了类似的结构,所以老实说,我不知道下一步该做什么。

我将不胜感激任何帮助。谢谢。

最佳答案

您将结构翻译为一个类。那是一个引用类型。这意味着它是通过引用传递的。但是,C++ 代码按值传递严格。

通过将 FrameInfo 声明为结构来解决此问题。

关于c# - C++ 到 C# : PInvoke\Marshaling a callback with a complex type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36732237/

相关文章:

javascript - 如何在 Javascript 中向 .submit() 添加回调函数?

java - 使用 Mockito,如何在 void 方法上拦截回调对象?

c++ - 如何将 C++ 中的字母组合增加到 'z' 之外?

c++ - 如何执行从 char* 缓冲区加载到内存中的代码?

c# - 使用 BeginInvoke 调试异常

c# - 为 "character"设计一种干净/灵活的方式来在角色扮演游戏中施放不同的法术

c++ - DirectX9 中的多个渲染目标

c# - XAudio2 OnVoiceProcessingPassStart回调卡顿播放

c# - WCF+ 计时器。不好的做法?

c# - 从 yahoo 凭据导入 yahoo 联系人