在考虑使用字符串参数时,C#P / Invoke AccessViolationException

时间:2017-01-20 16:06:00

标签: c# c++ pinvoke marshalling

我试图包装一个我只有头文件的C ++ dll。我正在努力工作的功能是给我一个AccessViolationException

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

C ++函数原型是:

RunSimulation( LPCSTR, LPSTR);

同时,我的C#包装器是:

[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, ref string outputID);

我怀疑问题出在C#函数上,特别是字符串的实现方式。由于我对平台调用相对较新,我不确定如何继续。

字符串参数应该指向字符串的位置吗?或者包装器可能还有其他问题吗?

修改

这是在托管端的事件上调用函数的方式:

string outputID = "";

try
{
    RunSimulation(id, ref outputID);
}
catch (Exception e)
{
    Logging.Log_Warning.SendException("Threw an exception", e);
}

编辑2:

将第二个参数更改为StringBuilder时,会发生相同的异常。唯一的区别是异常中断不会在调用函数的行停止,Visual Studio会打开一个新的" Break"标签说发生了异常。函数文档建议设置16个字节或更多字节,因此我使用容量构造函数值1024和4096进行测试。

编辑3:

执行清理和重建后,问题表现为驱动程序错误。由于这表明API正在运行,因此解决方案确实是按照评论中的建议将ref string参数更改为StringBuilder

1 个答案:

答案 0 :(得分:0)

我的问题的解决方案最终是使用StringBuilder而不是String来确保内存中的空间是提前分配的。所以我的签名最终看起来像:

[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, StringBuilder outputID);

使用它:

string id = "someID";
int requiredSize = 512;
StringBuilder outputID = new StringBuilder(requiredSize);

RunSimulation(id, outputID);

希望有所帮助!