从 C# 调用 C++ dll 函数:结构、字符串和 wchar_t 数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/680066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 13:10:37  来源:igfitidea点击:

Calling C++ dll function from C#: Of structs, strings and wchar_t arrays

c#c++structmarshallingdllimport

提问by Evgeny

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:

我有一个用 C++ 编写的示例应用程序,它调用 dll。这是相关的代码:

    //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.

现在,当我调试 C++ 代码时,它会做正确的事情 - 将一些 Unicode 数据写入数据结构。

Here is my attempt to do the same in C#

这是我尝试在 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?

我的猜测是我没有正确封送 RECO_DATA 结构,因为正是这个结构被 convertHKID_Name 函数写入。但是我应该如何修复它?

采纳答案by Curt Hagenlocher

I believe it should work if you

我相信它应该有效,如果你

  1. Change the declaration on convertHKID_Nameto CharSet.Ansi
  2. Remove the "ref" from the string parameter
  3. Pass the string numdirectly to convertHKID_Nameinstead of calling WideCharToMultiByte
  1. 将声明更改 convertHKID_NameCharSet.Ansi
  2. 从字符串参数中删除“ref”
  3. string num直接传递给convertHKID_Name而不是调用WideCharToMultiByte

回答by Evgeny

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

我用 C++ 为我的非托管 dll 编写了一个托管包装器,但又被卡住了。

Continued here

续到这里

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

将 C# 数据类型参数传递给用 C++ 编写的 dll?