none
C# Interop to C++ System.AccessViolationException RRS feed

  • Question

  • Hi all. I am at wits end. I've tried numerous suggested solutions on other threads similar to my problem, but I am getting nowhere.

    Anyway, I have an 'example' C++ project provided to me by a 3rd party SDK, and I'm trying to get a working copy of it in C#.

    Right now, I have 2 methods: findDevice(), and getDeviceError(). findDevice returns a long, that if isn't equal to 0 (zero), then an error has occurred with the device. I don't have a physical device so this is always going to return an error number, which is fine. Where I am failing is in the method that is supposed to take the long, and return a structure that has an error code & error message always gives me a System.AccessViolationException and that I am basically trying to access protected memory.

    To make the matter more complex, instead of passing in a single structure, the DLL is expecting an array of the structures as it can return multiple error codes at once. I've tried various declarations of the function. I've tried marshalling the array into a byte array and passing in a IntPtr, I've always tried passing in the structure array by reference, I've tried doing it as [In, Out] in the declaration. I've tried all sorts of things and I always get the same error, so I'm thinking I have a wrong declaration.

    Any help would be appreciated!

    Here is the C++ declaration/code in the example project:

    Pulled from one of the header files:

    typedef struct _DEVICEERRORINFO
    {
    	unsigned short ErrCode;
    	char		   Message[80];
    } DEVICEERRORINFO;
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    EXPORT_ short getDeviceError(long Err, DEVICEERRORINFO* ErrInfo, 
    							unsigned short* ErrCount);
    


    From one of the code files:

    void CheckError(long ErrCode)
    {
    	DEVICEERRORINFO ErrInfo[10];
    	unsigned short Count = 0, i = 0;
    
    	getDeviceError(ErrCode, ErrInfo, &Count);
    	if (Count > 10)
    	{
    		Count = 10;
    	}
    	for (i = 0; i < Count; i++)
    	{
    		printf("\nError %d: ", ErrInfo[i].ErrCode);
    		printf("%s\n", ErrInfo[i].Message);
    	}
    }
    

    Here's the last thing I've tried in C#:

            [DllImport("Device.dll")] static extern ushort getDeviceError(long Err, [MarshalAs(UnmanagedType.LPArray)] ref DEVICEERRORINFO[] ErrInfo, ref ushort ErrCount);
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            public struct DEVICEERRORINFO
            {
                public ushort ErrCode;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst=80)] public string Message;
            }
    
                try
                {
                    // This returns a long value, and it doesn't cause a memory access error.
                    result = findDevice(name, hostID, sID);
    
                    if (result != 0)
                    {
                        // This always fails with a memory access error for some reason.
                        getVidarError(result, ref einfo, ref ecount);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
    


    • Moved by Leo Liu - MSFT Monday, November 7, 2011 7:13 AM Moved for better support. (From:Visual C# General)
    Friday, November 4, 2011 5:48 PM

Answers

  • I've fixed it! Thanks for your help! I finally got their example project to load (it was trying to call some special tool during compile to auto-increment the version number so I was having trouble even testing their example project).

    Anyway, stepping through their code, on the findDevice method, in their code it was returning a '-1' which they were passing to the getDeviceError method. In C# sharp, it was returning a value of '4294967295'. Looking at my declaration, I changed the return type of 'static extern long findDevice' to 'static extern Int32 findDevice' so apparently I wasn't even getting back the right variable type. Additionally, the 'getDeviceError' signature I have was 'getDeviceError(long Err, ...' so I changed that to a Int32 as well, and now I get back the array I was expecting, and the same 2 errors their example returns.

    Monday, November 7, 2011 11:15 PM

All replies

  • Didn't paste part by accident, before the Try/Catch block:

     

                long result;
                DEVICEERRORINFO[] einfo = new DEVICEERRORINFO[10];
                ushort ecount;
    

    name, hostID, sID are declared elsewhere and not really relevant.

    Friday, November 4, 2011 5:52 PM
  • Hi TheeBOBJohnson,

    Your problem is about .NET Platform Interop, I am moving your thread into the Common Language Runtime Forum for specialized support.
    Have a nice day,

    Leo Liu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, November 7, 2011 7:14 AM
  • Hello ThreeBobJohnson,

    A Few Clarifications.

    I have some idea as to why the call to getDeviceError() failed. However, first I have some questions to ask you :

    1. From the example code of CheckError(), it seems clear that the getDeviceError() API sets the field values of each of the DEVICEERRORINFO structure of the ErrInfo array.

    2. It is also clear that when getDeviceError() returns, the 3rd parameter "Count" will be set to a value indicating the actual number of DEVICEERRORINFO structures it intended to modify.

    3. However, it is not clear how the getDeviceError() API gets informed of the initial number of elements contained in the ErrInfo array when it is first called. The "Count" parameter is apparently set to 0 on entry to getDeviceError().

    4. Also, if the returned value in "Count" is larger than the initial size of the ErrInfo array, does the getDeviceError() API re-assign the size of the array ? This does not seem possible because the ErrInfo array is a local variable of the CheckError() function and so it is allocated on the stack.

    - Bio.

     


    Please visit my blog : http://limbioliong.wordpress.com/
    Monday, November 7, 2011 12:44 PM
  • Thanks for the reply.

     

    From their example code provided the CheckError seems to declare an array with a size of 10 for the error structures. They set count = 0, and pass it in by reference. The example doesn't inform the API what the initial size of the array is. From their example code it would appear that it can resize the array and pass it back, but their example only views the first 10 errors.

    It would make more sense (to me anyway) that I pass in something like 'getDeviceError(ErrCode, ref IntPtr, ref Count)', and then I would take the count, and the intptr and go to memory and copy the array structure out. I've tried that as well but still gives the same memory error.

    Monday, November 7, 2011 10:52 PM
  • I've fixed it! Thanks for your help! I finally got their example project to load (it was trying to call some special tool during compile to auto-increment the version number so I was having trouble even testing their example project).

    Anyway, stepping through their code, on the findDevice method, in their code it was returning a '-1' which they were passing to the getDeviceError method. In C# sharp, it was returning a value of '4294967295'. Looking at my declaration, I changed the return type of 'static extern long findDevice' to 'static extern Int32 findDevice' so apparently I wasn't even getting back the right variable type. Additionally, the 'getDeviceError' signature I have was 'getDeviceError(long Err, ...' so I changed that to a Int32 as well, and now I get back the array I was expecting, and the same 2 errors their example returns.

    Monday, November 7, 2011 11:15 PM