Jerome Guilmette

Hi

I'm importing in my C# program an unmanaged dll containing C functions. One of those functions needs a structure as an argument. This function gets a structure that has been sent on the network. The function was first designed to pass char*, so I used unsafe environment to pass my structure.

Everything my code first works except that I got two exceptions coming out everytime the GetMsg function has run for about 15 times. Those exceptions are :

'System.AccessViolationException' occurred in mscorlib.dll
'System.StackOverflowException' occurred in mscorlib.dllHere's what I've done :

I know it works, because I can get the data. The exceptions always sent me back at the second code snippet, so it must be something with the marshaling I use. I wanna know if what I've done is OK or if something is missing or if there are any other ways of doing this.

Here's what I've done so far :

I first import the dll :
Code Snippet

[DllImport(PATH_TO_DLL, CharSet = CharSet.Ansi, PreserveSig = true)]
unsafe static extern int MDComAPI_getMsg(
[In, Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr queue,
[In, Out, MarshalAs(UnmanagedType.Struct)] ref MSG_INFO pMsgInfo,
char** ppData,
[In, Out, MarshalAs(UnmanagedType.U4)] ref UInt32 pDataLength,
int timeOut);


Then I use the function I imported:
Code Snippet

unsafe static public int GetMsg(IntPtr queue, ref MSG_INFO pMsgInfo, char* pData, ref UInt32 pDataLength, int timeOut)
{
int Ret = MDComAPI_getMsg(queue, ref pMsgInfo, &pData, ref pDataLength, timeOut);
return Ret;
}


This function is used to get messages on a network. Later on, I passed a structure and I want to get the structure and display different statuses. All of this is done on a backgroundworker

Code Snippet

// information structure to be passed as an argument in the imported dll function

struct MSG_INFO

{

...

};


// Structure that has been sent on the network and that I need to get with the
// imported dll function

struct Status

{

...

};



MSG_INFO msgInfo = new MSG_INFO();

while (true)
{
char[] recbuf = new char[100];
fixed (char* pRecBuf = recbuf)
{
UInt32 bufLength = Convert.ToUInt32(recbuf.Length);
{
try
{
// Look until the message queue (recQueue) is empty
while(AppsIPTCom.GetMsg(recQueue, ref msgInfo, pRecBuf, ref bufLength, 0) == 1)
{
if (msgInfo.msgType == DATA)
{
if (bufLength == sizeof(Status))
{
// A message has been received...
Status* lStatus = (Status*)pRecBuf;
// CALL THE RICHTEXTBOXSTATUS FROM AN INVOKE FUNCTION

MessageBox.Show("State: " + lStatus->State);

// etc.

}
}
}
}
catch (Exception e_)
{
MessageBox.Show(e_.Message, STR_ERROR_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
}
Thread.Sleep(500);
}


If you have any clues, please help.

Thank you,

Jerome


Re: Visual C# General Struct pointer to unmanaged code - exceptions generated

OmegaMan

What if you replaced the original unmanaged code with something safe and test your code. If the same happens, it would be an indicator that the problem lies in the managed area. If it does not, then its something about how the C code is playing/being consumed by the unamanaged.





Re: Visual C# General Struct pointer to unmanaged code - exceptions generated

Martin Platt

could this be a garbage collector issue

You have an unmanaged dll that perhaps is doing something, or reacting to something on the network

Or perhaps, if you have a buffer and data is being written to it

I've seen issues with the buffer being destroyed because the garbage collector collecting the unmanaged code before the operation finishes

It might be worth a look at

Is your unmanaged code wrapped in a managed class, or imported directly I would recommend wrapping the class. Then if the class still isn't behaving, perhaps try commenting the bit that references the unmanaged code, and see how it goes then If that works, then it's something to do with the managed / unmanaged work, and quite possibly the garbage collector.

I hope that helps,

Martin.






Re: Visual C# General Struct pointer to unmanaged code - exceptions generated

Jerome Guilmette

Thanks for the informations

I'll look into it and get back to you if there is any development.

Regards,

Jerome




Re: Visual C# General Struct pointer to unmanaged code - exceptions generated

Jerome Guilmette

I'm now working in manage code. Using
Status lStatus = (Status)Marshal.PtrToStructure(pData, typeofStatus));
and
out IntPtr

But it is still not working. I still have a stackOverflow Exception... I know that it is not the unmanaged function who isn't working because it works perfectly well on my C test program.

The last thing that I see that might cause trouble is the strcuture passed as a parameter pMsgInfo which is described as follow in C# :

Code Snippet

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MSG_INFO
{
[MarshalAs(UnmanagedType.U4)] public UInt32 comID;
[MarshalAs(UnmanagedType.U2)] public UInt16 msgType;
public IntPtr pCallerRef;
[MarshalAs(UnmanagedType.U4)] public UInt32 sessionId;
[MarshalAs(UnmanagedType.U4)] public UInt32 srcIpAddress;
[MarshalAs(UnmanagedType.I4)] public int resultCode;
[MarshalAs(UnmanagedType.I4)] public int noOfResponses;
[MarshalAs(UnmanagedType.U2)] public UInt16 UserStatus;
[MarshalAs(UnmanagedType.U4)] public UInt32 ResponseTimeout;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)] public string DestURI;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)] public string SrcURI;
}


Here is the components of the struct in C :
Code Snippet

UINT32 ComID
UINT16 MsgType
void *pCallerRef
UINT32 SessionId
UINT32 SrcIpAddress
int ResultCode
int Responses
UINT16 UserStatus
UINT32 ResponseTimeout
char Destination[15]
char Src[15]


I've tried to pass an IntPtr instead of a ref MSG_INFO, but it doesn't work the way I want telling me about the blittable thing, but I can't really change my manage to have blittable data...

Code Snippet

IntPtr pTest = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(AppsIPTCom.MSG_INFO)));
Marshal.StructureToPtr(typeof(AppsIPTCom.MSG_INFO), pTest, false);



Here's the reste of my code which is now managed, if you "see" something that might cause a stack overflow, please advise me if not I'll try another way or contact the entreprise of has done this code.

Thank you

Code Snippet

static extern int MDComAPI_getMsg(
[In, Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr queue,
[In, Out, MarshalAs(UnmanagedType.Struct)] ref MSG_INFO pMsgInfo,
out IntPtr ppData, //instead of char** ppData,
[In, Out, MarshalAs(UnmanagedType.U4)] ref UInt32 pDataLength,
int timeOut);



Code Snippet

static public int GetMsg(IntPtr queue, ref MSG_INFO pMsgInfo, out IntPtr ppData, ref UInt32 pDataLength, int timeOut)
{
int Ret = MDComAPI_getMsg(queue, ref pMsgInfo, out ppData, ref pDataLength, timeOut);
return Ret;
}



Code Snippet

while (true)
{
UInt32 bufLength = Convert.ToUInt32(100);
try
{
IntPtr pData = Marshal.AllocHGlobal(100);
// Look until the message queue (recQueue) is empty
while (AppsIPTCom.GetMsg(recQueue, ref msgInfo, out pData/*pRecBuf*/, ref bufLength, 0) == 1)
{
if (msgInfo.msgType == DATA)
{
if (bufLength == Marshal.SizeOf(typeof(Status)))
{
// A message has been received...
Status lStatus = (Status)Marshal.PtrToStructure(pData, typeofStatus));

// CALL THE RICHTEXTBOXSTATUS FROM AN INVOKE FUNCTION
MessageBox.Show("State: " + lStatus->State);

// }
//}
Marshal.FreeHGlobal(pData);
}
catch (Exception e_)
{
MessageBox.Show(e_.Message, STR_ERROR_TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Thread.Sleep(500);
}




Re: Visual C# General Struct pointer to unmanaged code - exceptions generated

OmegaMan

The managed portion has a comment that says look til message queue is empty....Could the problem be when the queue is empty but the processing wigs out in unexpected ways everytime it calls an empty queue

Also do you have to continue to create the pointer pData Couldn't you reuse it Use Perfmon and monitor the private bytes of the application to see if you have a memory issue. (Check my blog on how to do it within your program Monitor Threads, Handles and Bytes on the Status Strip) if it is a winform.