通过引用传递结构导致 AccessViolationException
我的又一个 P/Invoke 问题!我有这个 C 函数:
int _ei_x_new(ei_x_buff* x);
本质上,它初始化一个新的缓冲区结构。在 C# 中,我有这样的:
[DllImport(EIDLL, EntryPoint = "_ei_x_new")]
public static extern int ei_x_new(out ei_x_buff x);
ei_x_buff
非常简单:
typedef struct ei_x_buff_TAG {
char* buff;
int buffsz;
int index;
} ei_x_buff;
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ei_x_buff {
[MarshalAsAttribute(UnmanagedType.LPStr)]
public string buff;
public int buffsz;
public int index;
}
但是当我这样做时:
ei_x_buff buffer;
Ei.ei_x_new(out buffer);
我得到一个 AccessViolationException:
尝试读取或写入受保护的内存。这通常表明其他内存已损坏。
我需要分配一些内存什么的吗?这是一段非常简单的代码,我看不出它有任何明显的问题。
编辑: _ei_x_new
的本机代码:
// In my wrapper library
DLL_EXPORT int _ei_x_new(ei_x_buff* x) {
return ei_x_new(x);
}
// In external library being wrapped
int ei_x_extra = 100;
int ei_x_new(ei_x_buff* x)
{
x->buff = malloc(ei_x_extra);
x->buffsz = ei_x_extra;
x->index = 0;
return x->buff != NULL ? 0 : -1;
}
Yet another one of my P/Invoke questions! I have this C function:
int _ei_x_new(ei_x_buff* x);
Essentially, it initializes a new buffer struct. In C#, I have this:
[DllImport(EIDLL, EntryPoint = "_ei_x_new")]
public static extern int ei_x_new(out ei_x_buff x);
ei_x_buff
is pretty simple:
typedef struct ei_x_buff_TAG {
char* buff;
int buffsz;
int index;
} ei_x_buff;
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ei_x_buff {
[MarshalAsAttribute(UnmanagedType.LPStr)]
public string buff;
public int buffsz;
public int index;
}
But when I do this:
ei_x_buff buffer;
Ei.ei_x_new(out buffer);
I get an AccessViolationException:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Do I need to alloc some memory or something? It's such a simple piece of code that I can't see any glaring problems with it.
EDIT: Native code for _ei_x_new
:
// In my wrapper library
DLL_EXPORT int _ei_x_new(ei_x_buff* x) {
return ei_x_new(x);
}
// In external library being wrapped
int ei_x_extra = 100;
int ei_x_new(ei_x_buff* x)
{
x->buff = malloc(ei_x_extra);
x->buffsz = ei_x_extra;
x->index = 0;
return x->buff != NULL ? 0 : -1;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有几件事
EDIT
只是为了消除一种可能性,将 buff 成员切换为不带属性的 IntPtr 类型。如果这不会导致崩溃,那么可能是字符串类型的编组问题。
Couple of things
EDIT
Just to eliminate one possibility, switch the buff member to be typed IntPtr with no attributes. If that doesn't cause a crash then it's likely a marshalling issue with the string type.
您是否已使用 修复将缓冲区标记为固定在内存中 语句:
示例:
Do yo have mark the buffer as pinned in memory using the fixed statement:
example:
我认为如果你只是在 C 端正确初始化缓冲区,它也适用于字符串。请记住,缓冲区 malloc 返回可能包含垃圾,因此您应该添加类似
if (x->buff) x->buff[0] = '\0'; 的
内容。您可能需要仔细检查的另一件事是您在本机端和托管端使用相同的调用约定。除非您在 DllImport 属性中指定其他内容,否则 CLR 假定为 _stdcall。
I think it will work with string too, if you just initialisze the buffer properly on the C side. Keep in mind that the buffer malloc returns may contain garbage, so you should add something like
if (x->buff) x->buff[0] = '\0';
Another thing you may want to double check is that you're using the same calling convention on the native and managed side. The CLR assumes _stdcall unless you specify something else in the DllImport attribute.