gpt4 book ai didi

c# - 将 C++ 结构编码(marshal)到 C# 类时出现 AccessViolationException

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:55:33 25 4
gpt4 key购买 nike

我正在尝试使用 PInvoke 将 C++ 库 (libclang) 包装到 C# 包装器中。

一切都很顺利,直到我尝试调用一个返回结构的 C++ 方法。我做了一切by the book ,但是当调用此方法时,我得到 AccessViolationException。

现在,我读到这可能是因为对象的内存镜像出现问题。我检查并仔细检查了我是否已经放置了所有的 arrtibutes 和什么不是无处不在,但异常不会消失。 (我已经看这段代码好几个小时了,所以我可能错过了一些东西,你们不会)。

C++ 部分(不是我的代码,但我确定它可以工作):

CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {

/* Parse the hell out of a lot of data, an then make a string
In the end, string gets wrapped in a custom struct: CXString.
*/

return createCXString(Out.str(), true);

}

这是 CXString:

typedef struct {
void *data;
unsigned private_flags;
} CXString;

所以我有我的 C# 类来表示包装的 C++ 原件:

public class Diagnostic 
{
private IntPtr _nativeObject;
internal IntPtr NativeObject { get { return _nativeObject; } }

[DllImport("libclang.dll", EntryPoint = "clang_formatDiagnostic")]
[return: MarshalAs(UnmanagedType.LPStruct)]
private static extern CXString FormatDiagnostic(IntPtr diag, uint options);

public Diagnostic(IntPtr native)
{
_nativeObject = native;
}

public string GetString(DiagnosticDisplayOptions options = DiagnosticDisplayOptions.DisplaySourceLocation)
{
var cxstr = FormatDiagnostic(_nativeObject, (uint)options); //<-- I get the exception here
return cxstr.GetString();
}
}

我需要的功能也以 C 风格(全局)实现,因此,我可以在我的 C# 类中留下 OO 的印象,但实际上我存储了 C++ 对象的 IntPtr 表示(_nativeObject)。所以我很确定,存储在 _nativeObject 中的对象实际上是一个 CXDiagnostic(我得到了从同一库的另一个函数返回的引用)。

我尝试使用 FormatDiagnostic 方法的实际对象是从另一个包装类 (TranslationUnit) 的构造函数初始化的:

public TranslationUnit(/*lots of params to init the unit*/)
{
//... there are some int conversions and initialization failsafe codes here

//this is a property of TranslationUnit
Diagnostics = new List<Diagnostic>();

//GetDiagnosticsCount is also PInvoke to count CXDiagnostic objects related to the TranslationUnit
var dgCnt = (int)GetDiagnosticsCount(_nativeObject);
for (int i = 0; i < dgCnt; i++)
{
//GetDiagnostic is also PInvoke, gets the CXDiagnostic at the given index
var diag_ptr = GetDiagnostic(_nativeObject, (uint)i);
Diagnostics.Add(new Diagnostic(diag_ptr));
}
//up until now, all the calls seem to work
//I get the expected count of diagnostics and none of the other
//PInvoke calls throw exceptions. They use IntPtrs, but none of them
//use structs.
}

因此,正如 MSDN 教程所建议的那样,我创建了一个 C# 类来将 CXString 结构编码到其中,它看起来像这样:

[StructLayout(LayoutKind.Sequential)]
public class CXString
{
public IntPtr data;
public uint private_flags;
}

当代码到达 FormatDiagnostic 调用时,我得到 AccessViolationException。任何可能出错的提示?

编辑:

CXDiagnostic在原始C++代码中是一个指针类型:

typedef void *CXDiagnostic;

最佳答案

我认为在这里编码到 LPStruct 是不合适的,CXString 类需要是结构体。

试试下面的代码:

public class Diagnostic 
{
...
[DllImport("libclang.dll", EntryPoint = "clang_formatDiagnostic")]
private static extern CXString FormatDiagnostic(IntPtr diag, uint options);
...
}

[StructLayout(LayoutKind.Sequential)]
public struct CXString
{
public IntPtr data;
public uint private_flags;
}

此外,您应该注意调用约定(默认情况下为 StdCall,但例如纯 C 使用 Cdecl)和结构字节对齐。

关于c# - 将 C++ 结构编码(marshal)到 C# 类时出现 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10386139/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com