-1

I am trying to call a C function from C# code:

typedef char IPTriggerNameType[256];
typedef unsigned long COMM_HANDLE;
typedef BYTE GUID_TYPE[16];
typedef long LONGINT;

typedef struct  {
    GUID_TYPE           Guid;   
    IPTriggerNameType   Name; 
}IPCAM_GENERIC_EVENT_ID;

typedef struct  {
    IPCAM_GENERIC_EVENT_ID      EventId;   
    LONGINT                     RelatedTriggerId;
    LONGINT                     ObsoleteEvent;
}IPCAM_GENERIC_EVENT_INFO;

typedef struct
{
    LONGINT                     NumOfEvents;
    IPCAM_GENERIC_EVENT_INFO    *GenericEventsList;
}VID_CHANNEL_GENERIC_EVENTS_STRUCT;


int __stdcall GetGenericEvents( 
/*  Inputs: */
    COMM_HANDLE                         Handle,                         
    LONGINT                             MaxNumOfChannelsInTable,
    LONGINT                             MaxNumOfEventsPerChannel,

/*  Outputs: */    
    LONGINT                             *NumOfChannels,
    VID_CHANNEL_GENERIC_EVENTS_STRUCT   *ChannelsEventsTable);

and the C# equivalent is as follows:

[StructLayout(LayoutKind.Sequential)]
    public struct IPCAM_GENERIC_EVENT_ID
    {
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 16)]
        public byte[] Guid;

        [MarshalAs(UnmanagedType.LPArray, SizeConst = 256)]
        public char[] Name;
    };

    [StructLayout(LayoutKind.Sequential)]
    public struct IPCAM_GENERIC_EVENT_INFO
    {
        public IPCAM_GENERIC_EVENT_ID EventId;
        public int RelatedTriggerId;
        public int ObsoleteEvent;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct VID_CHANNEL_GENERIC_EVENTS_STRUCT
    {
        public int NumOfEvents;

        [MarshalAs(UnmanagedType.LPArray, SizeConst = 100)]
        public IPCAM_GENERIC_EVENT_INFO[] GenericEventsList;
    }

    [DllImport(dllName)]
public static extern int GetGenericEvents(
    /*  Inputs: */
    int Handle,
    int MaxNumOfChannelsInTable,
    int MaxNumOfEventsPerChannel,

    /*  Outputs: */
    out int NumOfChannels,
    out VID_CHANNEL_GENERIC_EVENTS_STRUCT[] ChannelsEventsTable);


int numOfChannels = 16, actualNumOfChannels = 0;
int maxNumOfEvents = 100;

VID_CHANNEL_GENERIC_EVENTS_STRUCT[] genericEventsList = new VID_CHANNEL_GENERIC_EVENTS_STRUCT[numOfChannels];
for (int i = 0; i < numOfChannels; i++)
{
    genericEventsList[i].GenericEventsList = new IPCAM_GENERIC_EVENT_INFO[maxNumOfEvents];
}

GetGenericEvents(conn, numOfChannels, maxNumOfEvents, out actualNumOfChannels, out genericEventsList);

when calling the C# method I get exception which crashes the application:

Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'My.exe'.

Additional information: The runtime has encountered a fatal error. The address of the error was at 0x72a6cf41, on thread 0x5a98. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

What am I doing wrong ?

Roman Gin
  • 36
  • 5
  • `SizeConst = 100` means C# will always try to read 100 items, which is most probably an out-of bounds access (possible access violation). Besides, a `char` is one byte in C++, but it's 2 bytes in C#. – Lucas Trzesniewski Feb 08 '16 at 08:50
  • There are many errors in your code. But it's not actually possible to tell you what the code should be because you don't say how the C++ code is to be called. Knowing the definition of the types is not enough. You need to know the semantics too. You'll need to consult the documentation and some example C++ code that calls these functions. If you have the source of the C++ code that will help. I'll leave my answer for a little while but it really should be deleted since the question can't readily be answered in full. – David Heffernan Feb 08 '16 at 09:00

1 Answers1

-1

The field:

VID_CHANNEL_GENERIC_EVENTS_STRUCT.GenericEventsList

is a pointer, declared as:

IPCAM_GENERIC_EVENT_INFO *GenericEventsList

But you are declaring it as an array, included in the struct:

[MarshalAs(UnmanagedType.LPArray, SizeConst = 100)]
public IPCAM_GENERIC_EVENT_INFO[] GenericEventsList;

You may try to use an IntPtr and Marshal.AllocHGlobal. Check this out: How use pinvoke for C struct array pointer to C#

Community
  • 1
  • 1
Cecilio Pardo
  • 1,717
  • 10
  • 13