Trouble with C#<->C++ DLLImport "Attempted to read or write protected memory."

12,834

Solution 1

Try changing [In] to [In, Out]. I'm also not sure about using both the ref and [In, Out] keywords together on a single argument. (Edit: Hans Passant has a good explanation of the differences between the two in his comment below.)

See this MSDN article for more information, especially the passage, "By default, reference types (classes, arrays, strings, and interfaces) passed by value are marshaled as In parameters for performance reasons. You do not see changes to these types unless you apply InAttribute and OutAttribute (or just OutAttribute) to the method parameter."

Solution 2

I started getting this exception durring native interop periodically after upgrading to Windows 7. The code had always worked on XP and has fewer issues on Win 7 if I ran my app in XP compatibility mode.

After some research and experimentation I discovered that the reason I was getting this exception had to do with calling a native function that returned a string (WCHAR*).

I don’t believe there is currently a fix for this as even updating to .Net 3.5 didn’t fix the issue… However I did find the following work around.

Example of what works on XP but doesn’t work on Win 7:

[DllImport("NativeBin.dll")]
public static extern String GetWCharStr();

Example of what works for me on Win 7 and XP:

[DllImport("NativeBin.dll")]
private static extern IntPtr GetWCharStr();
public static String GetString()
{
    return Marshal.PtrToStringUni(GetWCharStr());
}
Share:
12,834
Chris
Author by

Chris

“You will never come across a greater adversary than your own potential.”

Updated on July 25, 2022

Comments

  • Chris
    Chris almost 2 years

    I have a C++ dll which has a function within it I am trying to call from a C# application.

    Here's the code in the C++ header file

    extern "C" _declspec(dllexport) int LabelStoringSSDsim(int devNum, UCHAR serial[40], UCHAR wwn[40],
                    UCHAR ConfigID[5], UCHAR FrmRev[8], UCHAR DevName[40], int eCode);
    

    Here's the code in the C++ source file

    int LabelStoringSSDsim(int devNum, UCHAR serialLbl[40], UCHAR wwnLbl[40],
                    UCHAR ConfigID[5], UCHAR FrmRev[8], UCHAR DevName[40], int eCode)
    {
    
        string strConfigID="12111";                                     //5 bytes
        string strFrmRev="1.25....";                                    //8 bytes
        string strDevName="ABC-123.................................";   //40 bytes
    
        for (int i=0;i<5;i++)
            ConfigID[i] = strConfigID[i];
    
        for (int i=0;i<8;i++)
            FrmRev[i] = strFrmRev[i];
    
        for (int i=0;i<40;i++)
            DevName[i] = strDevName[i];
        return eCode;
    }
    

    Here's the C# relevant code

    [DllImport("LabelStoring.dll")]
    static extern int LabelStoringSSDsim(
        int devNum,
        byte[] strserial,
        byte[] strwwn,
        [In] ref byte[] ConfigID,
        [In] ref byte[] FrmRev,
        [In] ref byte[] DevName,
        int eCode
    );
    
    
    int errNum = LabelStoringSSDsim(devNum, bserial, bwwn, ref ConfigID, ref FrmRev, ref DevName, 123123);
    

    So when I get to the last bit of code there I get the "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." error.

    I have no prior experience in importing DLL's like this and I've done a lot of searching but cannot seem to find a solution to the problem.

    I tried starting over from scratch with a simple function returning an integer, and that worked. Then I added an int for me to pass to the function and it still worked. Then I added a byte array for me to pass, which worked. Then I attempted to turn that byte array into a reference and it failed. So my guess is I'm getting the data back incorrectly.

    Any help is greatly appreciated.

  • Chris
    Chris over 13 years
    That produces the following error: Exception of type 'System.ExecutionEngineException' was thrown.
  • Sam Skuce
    Sam Skuce over 13 years
    @Chris, I think I had a syntax error. Try my new improved version above.
  • Chris
    Chris over 13 years
    Sorry, still the same thing :X -- The error occurrs at that last bit of code in place of the previous error.
  • Chris
    Chris over 13 years
    Your tip to remove the ref while adding the [In, Out] has given me success. Thank you so very much. I can't seem to 1up your answer due to a lack of reputation. You have my gratitude.
  • Sam Skuce
    Sam Skuce over 13 years
    @Chris, you can still hit that green checkbox to mark my answer as "accepted", which will let other visitors to this site know it's the right one.
  • Sam Skuce
    Sam Skuce over 13 years
    @Hans Passant, thanks. Your seem to be a knowledgeable fellow - Do you know why having ref and [In, Out] together caused a crash? Is it akin to using a ** when you really just needed a * in C/C++?
  • user1703401
    user1703401 over 13 years
    Yes, that's it. The ref or out specifier (pass by reference) makes it a pointer to a pointer since an array is already a reference type. [In] and [Out] have otherwise no effect, they just tell the marshaller when it needs to copy the pointed-to value. [In, Out] is the default, omit [Out] if you don't care for any modifications made by the unmanaged code. It's an optimization.
  • Sam Skuce
    Sam Skuce over 13 years
    @Hans Passant, that's good to know. The article at msdn.microsoft.com/en-us/library/77e6taeh%28v=VS.100%29.aspx makes it sound like the [Out] and ref modifiers are identical, when in fact they have some very important distinctions, which you described for us.