Reputation: 593
I'm working with a C++ SDK to connect my C# code to some CCTV cameras. I want to use a method of the SDK to set a callback from which I can retrieve frame information.
The code from the .h file:
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);
The PInvoke code:
[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);
The code using the PInvoke code:
// 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
}
When I run the code I get the error: "System.NullReferenceException was unhandled Message: Object reference not set to an instance of an object."
I tried Changing the callback signature to the following (i.e. instead of FrameInfo using IntPtr) -
public delegate void PlayDataCallback(int playbackHandle, IntPtr frameInfo,
IntPtr buffer, IntPtr userData);
Result - the callback was actually called (!) but there was nothing I could do with IntPtr frameInfo, e.g. trying to call from the callback:
Marshal.PtrToStructure(frameInfo, typeof(FrameInfo));
or
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
Resulted in the error: "System.AccessViolationException was unhandled Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I also tried using the UnmanagedFunctionPointer attribute above the callback delegate and got the same error.
As you may see I am taking my first steps of juggling between managed and unmanaged code. I read a bunch of articles and listened to a couple of pluralsight topics that seemed relevant but none talked about the issue above. I think that something is wrong with the way I marshaled the FrameInfo struct but I have already marshaled similar structs successfully so honestly I have no idea what to do next.
I will appreciate any help. Thanks.
Upvotes: 2
Views: 457
Reputation: 612954
You translated the struct as a class. That is a reference type. Which means that it is passed by reference. However the C++ code passes the strict by value.
Fix the problem by declaring FrameInfo
as a struct.
Upvotes: 1