C#<->C++ DLLImport出现问题:“尝试读取或写入受保护的内存。”

9
我是一名有用的助手,可以为您翻译文本。
我有一个C++ dll,其中包含一个函数,我正在尝试从C#应用程序中调用该函数。
以下是C++头文件中的代码。
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);

这是C++源文件中的代码

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;
}

这是与C#相关的代码

[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);

所以当我到达代码的最后一部分时,我会收到“尝试读取或写入受保护的内存。这通常是其他内存损坏的指示。”错误。
我之前没有导入DLL的经验,并且我已经做了很多搜索,但似乎找不到解决问题的方法。
我尝试从头开始使用返回整数的简单函数,它起作用了。然后我添加了一个整数让我传递给函数,它仍然有效。然后我添加了一个字节数组让我传递,这也起作用了。然后我尝试将该字节数组转换为引用,但失败了。所以我的猜测是我没有正确地获取数据。
非常感谢任何帮助。
2个回答

7
尝试将[In]更改为[In, Out]。我也不确定在单个参数上同时使用ref[In, Out]关键字是否合适。(编辑:Hans Passant在下面的评论中有一个很好的解释,介绍了两者之间的差异。)请参阅此MSDN文章以获取更多信息,特别是这一段:“默认情况下,按值传递的引用类型(类、数组、字符串和接口)出于性能原因作为In参数进行编组。除非您对方法参数应用InAttribute和OutAttribute(或只是OutAttribute),否则您不会看到这些类型的更改。”

抱歉,还是一样的问题 :X -- 错误发生在代码的最后一部分,取代了之前的错误。 - Chris
1
您提供的去除 ref 并添加 [In, Out] 的技巧让我成功了。非常感谢您。由于声望不足,我无法为您的答案点赞。但是我对您心怀感激。 - Chris
@Chris,你仍然可以点击那个绿色的复选框将我的答案标记为“已接受”,这将让其他访问者知道它是正确的。 - Sam Skuce
@Hans Passant,谢谢。您似乎是一位很有见识的人 - 您知道为什么同时使用ref[In, Out]会导致崩溃吗?这是否类似于在C/C++中需要一个*而实际上使用了**的情况? - Sam Skuce
2
是的,就是这样。ref或out修饰符(按引用传递)使其成为指向指针的指针,因为数组已经是引用类型了。[In]和[Out]没有其他影响,它们只告诉编组器何时需要复制所指向的值。[In,Out]是默认值,如果您不关心非托管代码所做的任何修改,请省略[Out]。这是一种优化。 - Hans Passant
显示剩余3条评论

2

升级到Windows 7后,我在本机互操作期间经常遇到此异常。在XP上代码一直运行正常,在Win 7上如果我在XP兼容模式下运行应用程序,则问题较少。

经过一些研究和实验,我发现造成此异常的原因与调用返回字符串(WCHAR*)的本机函数有关。

我认为目前还没有解决此问题的方法,即使更新至.Net 3.5也无法解决此问题......不过,我找到了以下解决方法。

在XP上有效但在Win 7上无效的示例:

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

以下是在Windows 7和XP上适用的示例:

[DllImport("NativeBin.dll")]
private static extern IntPtr GetWCharStr();
public static String GetString()
{
    return Marshal.PtrToStringUni(GetWCharStr());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接