Hi all,
I am facing an AccessViolationException and I can't seem to pinpoint where have I gone wrong. I hope the experts here are able to provide me with an answer.
Scenario:
A C# WinForms (.net 2.0) program that creates a background/worker thread to call a C++ function via Interop (static extern method). The C++ function will internally do a loop, that will "break" out of the loop once a flag in the C# program is triggered.
Now, issue is that it works for a few times before the AccessViolationException kicks in. The VS debugger points to the C++ function call as the culprit.
C++ Function:
_declspec
(dllexport) bool StartCall( unsigned int *position, unsigned int *maxLength,unsigned int *flag, char* fileName )
{
while( (*position) < (*maxLength) && (*flag)==1 )
{
//do processing, e.g. play sound, calculations
(*position)++;
}
return true;
}
C# Function:
[
DllImport( "MYCPP.dll" , ExactSpelling = true , CallingConvention = CallingConvention.Cdecl )]private static extern bool StartCall( IntPtr ptrPosition , IntPtr ptrMaxLength, IntPtr ptrFlag,[In] string fileName );
private const int FLAG_ON = 1;
private const int FLAG_STOP = 2;
private const int FLAG_NEXT = 3;
private Thread tThread = null;
private int iCurrentIndex = 0;
private string[] arrFiles = new string[] { "file1.txt", "file2.txt", "file3.txt", "file4.txt" };
private IntPtr ptrPosition = IntPtr.Zero;
private IntPtr ptrMaxLength = IntPtr.Zero;
private IntPtr ptrFlag = IntPtr.Zero;
private
void Form_Load( object sender , EventArgs e ){
}
private void btnStop_Click( object sender , EventArgs e )
{
Marshal.WriteInt32( this.ptrFlag , FLAG_STOP );
}
private void btnStart_Click( object sender , EventArgs e )
{
btnStart.Enabled = false;
tThread = new Thread( new ThreadStart( MyThread_Run ) );
tThread.IsBackground = true;
tThread.Start();
}
private void btnNext_Click( object sender , EventArgs e )
{
Marshal.WriteInt32( this.ptrFlag , FLAG_NEXT );
}
private
void MyThread_Run(){
GCHandle hGCPosition = GCHandle.Alloc( 0 , GCHandleType.Pinned );
GCHandle hGCMaxLength = GCHandle.Alloc( 100 , GCHandleType.Pinned );
GCHandle hGCFlag = GCHandle.Alloc( FLAG_ON , GCHandleType.Pinned ); this.ptrPosition = hGCPosition.AddrOfPinnedObject();
this.ptrMaxLength = hGCMaxLength.AddrOfPinnedObject();
this.ptrFlag = hGCFlag.AddrOfPinnedObject();
while
( Marshal.ReadInt32( ptrFlag ) != FLAG_STOP ){
StartCall( ptrPosition, ptrMaxLength, ptrFlag, arrFiles[iCurrentIndex] );
if ( Marshal.ReadInt32( ptrFlag ) == FLAG_NEXT )
{
iCurrentIndex++;
if ( iCurrentIndex >= arrFiles.Length )
iCurrentIndex = 0;
Marshal.WriteInt32( ptrPosition, 0 );
Marshal.WriteInt32( this.ptrFlag , FLAG_ON );
}
}
ptrPosition = IntPtr.Zero;
ptrMaxLength = IntPtr.Zero;
ptrFlag = IntPtr.Zero;
hGCPosition.Free();
hGCMaxLength.Free();
hGCFlag.Free();
}
I am making use of a Pointer (integer value) to act as a flag to alert the C++ function to stop. Apparently after a random number of times of clicking Next, it will throw the exception.
Anyone
knave

AccessViolationException when sharing a pointer between C# and C++ DLLimport problem.
Jason Beck
On a side note, when I enabled Unmanaged Debugging mode, at every startup of the program, VS2005 will throw up an alert message on some Marshalling problem. (something like "Problem found in Marshalling XXX from UInt32 to UInt32" kind of messages).
Not sure if it may be the culprit, but it throws the same message for every marshalling parameter.
Knave
mcmcom
Malay Roy
nobugz:
According to the docs (for GCHandleType) this should not be a problem:
This handle type is similar to Normal
michaelleewebb
Try something like this instead:
object flag = new int();
(int)flag = FLAG_ON;
GCHandle hGCFlag = GCHandle.Alloc(flag, GCHandleType.Pinned );
this.ptrFlag = hGCFlag.AddrOfPinnedObject();
Same pattern for the other two arguments.
Jb4e
Sad to say, its extremely hard to crash in debug mode shielded by vshost process.
The release build crashes much faster and easier. Perhaps it is the method that I using that is causing such problems Or does any one have a better solution to my targeted output instead of using a pointer like this
knave.
zille
One possible problem is that you click Next while that thread is not running. When the thread is not running ptrFlag points to random memory and if you write to it anything can happen.
If this is not problem it would be useful to tell us where in the C++ function the debugger shows that the exception is thrown (if possible).
Regmo
Nope. that is not the issue.
The debugger only stops at StartCall(). I can't dive in.
while ( Marshal.ReadInt32( ptrFlag ) != FLAG_STOP )
{
--> StartCall( ptrPosition, ptrMaxLength, ptrFlag, arrFiles[iCurrentIndex] );
knave
gumtoo
Hi Nobugz,
I had did something similar to your suggestion before (minus the boxing to an object part) as I had suspected the same thing as you have, and it still didn't work. :( However, I will give the boxing idea a try.
Knave.
Ian Jorgensen
Hmm... you should be able to dive in StartCall. I suppose you copied the mycpp.dll file to the same dir where the C# exe is. Did you also copied the pdb file
A kid
I tried setting "SetLastError=true" at the declaration portion and the relevent Win32 error message was "operation saved successfully".
If I do a Try/Catch statement over the StartCall(..) interop call, it will prevent the crashing, but it causes memory lockage (as the C++ function is using some File IO before it throws the exception). Anyone has any idea how to release the lock + the memory
Knave.
Pradeep Gupta
nobugz is correct. GCHandles are not meant to be used with constants.
I have a blog post that describes this issue here:
http://blogs.msdn.com/clyon/archive/2004/09/17/230985.aspx
From the article:
Hope that helps
-Chris