views:

4087

answers:

2

Here's a simple problem I need to solve, but it makes me feel my hair turning gray as all my attempts are returning me the same error:

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

I have a sample app written in C++ which makes a call to the dll. Here is the relevant code:

    //function I need to call
bool convertHKID_Name(char *code,RECO_DATA *o_data); //hkid 

//struct definition
struct RECO_DATA{
 wchar_t FirstName[200];
 wchar_t Surname[200];
};

//how it is used in C++ code
CString code;
RECO_DATA data;
GetDlgItemText(IDC_CODE,code);
char _code[200];
WideCharToMultiByte(CP_UTF8, 0, code, -1, (char *)_code, 200, NULL, NULL);
ocr->convertHKID_Name(_code,&data)

Now when I debug the C++ code, it does the proper thing - writes some Unicode data into the data struct.

Here is my attempt to do the same in C#

    //my C# wrapper class
public class cnOCRsdk
{
    [StructLayout(LayoutKind.Sequential, Size=400, CharSet=CharSet.Unicode), Serializable]
    public struct RECO_DATA
    {
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)]
        public string FirstName;
        [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 200)]
        public string Surname;
    };

    [DllImport(@"cnOCRsdk.dll", CharSet=CharSet.Auto, EntryPoint = "?convertHKID_Name@CcnOCRsdk@@QAE_NPADPAURECO_DATA@@@Z")]
    public static extern bool convertHKID_Name(ref string num, ref RECO_DATA o_data);

    [DllImport("Kernel32.dll")]
    public static extern int WideCharToMultiByte(uint CodePage, uint dwFlags,
        [In, MarshalAs(UnmanagedType.LPWStr)]string lpWideCharStr,
        int cchWideChar,
        [Out, MarshalAs(UnmanagedType.LPStr)]StringBuilder lpMultiByteStr,
        int cbMultiByte,
        IntPtr lpDefaultChar, // Defined as IntPtr because in most cases is better to pass
        IntPtr lpUsedDefaultChar // NULL
        );
}

//my attempt to call the function from the dll
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string num = "262125355174";
StringBuilder sb = new StringBuilder(200, 200);
cnOCRsdk.WideCharToMultiByte(65001, 0, num, -1, sb, 200, IntPtr.Zero, IntPtr.Zero);
string sbTostring = sb.ToString();
//the next line generates the 'Attempted to read or write protected memory' error
bool res = cnOCRsdk.convertHKID_Name(ref sbTostring, out recoData);

My guess is that I'm not marshaling the RECO_DATA structure properly, because it is this struct that gets written to by the convertHKID_Name function. But how should I fix it?

+2  A: 

I believe it should work if you

  1. Change the declaration on convertHKID_Name to CharSet.Ansi
  2. Remove the "ref" from the string parameter
  3. Pass the string num directly to convertHKID_Name instead of calling WideCharToMultiByte
Curt Hagenlocher
Did not work yet, I still think there must be a problem with marshaling the structure.What is the reason by passing the string directly without ref, the function C++ declaration accepts char* code, and I assume a char pointer means the value has to be passed by reference?
Evgeny
A string is always passed by address. "By reference" means that you're going to update the value and expect the modified value to be returned to the calling program.
Curt Hagenlocher
Oh, and try declaring the RECO_DATA parameter as "out" instead of "ref" -- again, you only want it marshaled in one direction.
Curt Hagenlocher
You may also need to specify CallingConvention = CallingConvention.Cdecl on the convertHKID_Name declaration
Curt Hagenlocher
Curt Hagenlocher
Oh well, could you point me to the proper direction pls?
Evgeny
You'll have to wrap the functionality -- either by creating a global function in native C++ that you can call using p/Invoke from C#, or by using Managed C++ to create a managed wrapper on top of the native class. I don't have any specific references to help you with for either.
Curt Hagenlocher
Go download WinDbg and attach to the process then debug the native C++ side. Also, use extern 'C'
Paul Betts
A: 

I wrote a managed wrapper in C++ for my unmanaged dll, but got stuck a bit again.

Continued here

Passing C# data type parameters to dll written in C++?

Evgeny