我正在包装一个c dll(我只有.h),并且我被"试图读取或写下受保护的内存"。
信息:
- Windows 7 64位
- dll是64位
- C#App和包装器是64位
导出def:
#if defined(_WIN32) && !defined(__SYMBIAN32__)
#define EXP_API __cdecl
#else
#if !defined(__SYMBIAN32__)
#define EXP_API
#else
#define EXP_API EXPORT_C
#endif
#endif
这是C头结构:
typedef struct bufferstrm bufferstrm_tt;
struct bufferstrm
{
uint32_t (EXP_API * bytes_usage)(bufferstrm_tt *bs);
uint8_t * (EXP_API * get_stuff)(bufferstrm_tt *bs, uint32_t length);
struct implstrm* some_struct;
};
int32_t EXP_API strmParser(struct bufferstrm_tt *bs);
我的C#包装器:
[DllImport("Parser.dll", EntryPoint = "strmParser", CallingConvention = CallingConvention.Cdecl)]
public static extern int strmParser(ref bufferstrm bs);
// Delegates
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint BUFSTRM_bytes_usage(ref bufferstrm bs);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr BUFSTRM_get_stuff(ref bufferstrm bs, uint length);
[StructLayout(LayoutKind.Sequential)]
public struct bufferstrm
{
public BUFSTRM_bytes_usage bytes_usage;
public BUFSTRM_get_stuff get_stuff;
public IntPtr some_struct;
}
[StructLayout(LayoutKind.Sequential)]
public struct implstrm
{
public uint dummy;
}
public static uint test_bytes_usage(ref bufferstrm bs)
{
return 0;
}
public static IntPtr test_get_stuff(ref bufferstrm bs, uint length)
{
return IntPtr.Zero;
}
如果我这样使用它: [尝试读取或写下受保护的内存]
bufferstrm bs = new bufferstrm();
bs.bytes_usage = BUFSTRM_bytes_usage(test_bytes_usage);
bs.get_stuff = BUFSTRM_get_stuff(test_get_stuff);
implstrm testStruct = new implstrm();
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(testStruct)));
Marshal.StructureToPtr(testStruct, ptr, false);
bs.some_struct = ptr;
int hr = strmParser(ref bs);
如果我不设置回调,它只会返回预测的HR值(丢失的内容)。
有人知道我在做什么错?
谢谢!
编辑:
启用"不受管理的代码debuggin",我得到了"访问违规读取位置0xffffffffffffffffffff"。这会告诉你们吗?
您翻译中的明显错误是在bufferstrm
的第三个成员中
struct implstrm* some_struct;
这是一个指向结构的指针。基于名称,该结构提供了流的实际实现。bufferstrm
struct用缓冲层包裹该原始流。至少,这就是名字所暗示的。
现在在C#代码中,您将some_struct
翻译为在线结构,而不是指针。那显然是错误的。应该是:
public struct bufferstrm
{
public BUFSTRM_bytes_usage bytes_usage;
public BUFSTRM_get_stuff get_stuff;
public IntPtr some_struct;
}
您需要使用Marshal.StructureToPtr
来创建此指针。
除此之外,您提供的两个函数被错误地实现似乎是非常合理的。您已经提供了预期功能的任何细节。也许不允许get_stuff
返回零指针。我们无法检查其中任何一个,因为您仅给出了功能的原型,但是省略了函数必须遵守的语义规则的细节。
所以我怀疑您通过的代表不正确。但是,只有知道他们期望做什么的人才能理解如何纠正它们。