P/Invoke System.AccessViolationException:尝试读取或写入受保护的内存。这通常表明其他内存已损坏

问题描述 投票:0回答:1

我的代码引发了

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
异常。我正在使用 P/Invoke 从 .NET 项目调用一些 C API。

这是一个 void 函数,它接受一个基元结构的输入。我有几种有效的 API 方法,其中有几种不同的结构(更“复杂”)正在工作。

设置: VS 17 2022 C++20 .NET 框架 4.7.2

它在调试和发布模式下都会发生。

C/C++ 方面

typedef struct
{
    float visibility; //[m] Visibility range
    float thickness; //[m] Thickness of the fog layer
    // int placeholder;
} Fog;

extern "C" __declspec(dllexport) void SetFogData(const Fog* fog, int regionId);

C#方面

[StructLayout(LayoutKind.Sequential)]
public struct Fog
{
    public float Visibility; // [m] Visibility range
    public float Thickness;  // [m] Thickness of the fog
    // int placeholder;
}

[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
public static extern void SetFogData(Fog fog, int regionId);

// main.cs

Fog fog = new Fog();
fog.Thickness = 50.0f;
fog.Visibility = 250.0f;
SetFogData(fog, 0);

此代码会生成错误。如果我取消注释

int placeholder
字段(在两个结构 obv 中),它就会开始工作,并且通过 P/Invoke 提供的数据是正确的。我对由
enum
(带有 int 说明符)和
int
组成的结构有相同的行为,其中我必须添加第三个
int
成员才能在标题中得到异常。

c# c++ .net pinvoke marshalling
1个回答
0
投票

你的 C 函数需要一个

Fog*
(所以,一个指针):

extern "C" __declspec(dllexport) void SetFogData(const Fog* fog, int regionId);

但是您的 P/Invoke 声明按值采用

Fog

public static extern void SetFogData(Fog fog, int regionId);

这是一个结构体,它是 cdecl,所以它会被复制到堆栈上。然后本机端尝试将

fog
对象解释为指针,结果出了问题。或者至少这是一个猜测,实际上这是我们的好老朋友未定义的行为

如果您想传递指针,请传递引用并让编组器将其转换为指针:

public static extern void SetFogData(ref Fog fog, int regionId);

然后,稍后:

SetFogData(ref fog, 0);
© www.soinside.com 2019 - 2024. All rights reserved.