Trouble with C#<->C++ DLLImport "Attempted to read or write protected memory."
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());
}
Chris
“You will never come across a greater adversary than your own potential.”
Updated on July 25, 2022Comments
-
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 over 13 yearsThat produces the following error: Exception of type 'System.ExecutionEngineException' was thrown.
-
Sam Skuce over 13 years@Chris, I think I had a syntax error. Try my new improved version above.
-
Chris over 13 yearsSorry, still the same thing :X -- The error occurrs at that last bit of code in place of the previous error.
-
Chris over 13 yearsYour 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 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 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 over 13 yearsYes, 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 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]
andref
modifiers are identical, when in fact they have some very important distinctions, which you described for us.