PInvoke“试图读取或写入受保护的内存”

Posted

技术标签:

【中文标题】PInvoke“试图读取或写入受保护的内存”【英文标题】:PInvoke "Attempted to read or write protected memory" 【发布时间】:2014-03-07 21:47:10 【问题描述】:

我正在包装一个 C DLL(我只有 .h 的)并且我被“试图读取或写入受保护的内存”所困。

信息:

Windows 7 64 位 DLL 是 64 位的 C# 应用程序和包装器是 64 位的

导出定义:

#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 值(缺少东西)。

有人知道我做错了什么吗?

谢谢!

编辑:

启用“非托管代码调试”我得到“访问冲突读取位置 0xffffffffffffffff”。这能告诉你们什么吗?

【问题讨论】:

我的第一直觉(虽然还没有仔细查看代码)是仔细检查所有委托/函数/函数指针上的调用约定匹配。 我已经检查过了,一切都是 CallingConvention.Cdecl,就像 DLL 头文件一样:/ 你确定 C 头文件使用的是 cdecl 吗?来自MSDN:On ARM and x64 processors, __cdecl is accepted and ignored by the compiler. 我们需要有关错误的更多信息,至少需要堆栈跟踪或更多调试信息。似乎本机代码正在尝试取消引用 NULL(由于您的 IntPtr.Zero)。我建议修改您的 test_get_stuff 以改为返回指向某些非托管内存的有效指针(使用 Marshal.AllocHGlobal 分配它,并在 test_bytes_usage 中使用相同的大小。并且不要忘记在您使用后 Marshal.FreeHGlobal完成)。 另外,根据您的编辑(尝试在 0xffffffff... 又名 -1 读取),本机代码可能不安全,因为它使用 (length-1) 来索引最后一个您提供的数据项(长度为 0)。按照我的建议尝试一个非空数组。 【参考方案1】:

你翻译的明显错误是bufferstrm的第三个成员

struct implstrm* some_struct;

这是一个指向结构的指针。根据名称,此结构提供流的实际实现。 bufferstrm 结构用缓冲层包装该原始流。至少,这就是名字所暗示的。

现在在 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 不允许返回空指针。我们无法检查这些,因为您只给出了函数的原型,但省略了函数必须遵守的语义规则的细节。

所以我怀疑您传递的代表不正确。但是只有知道他们应该做什么的人才能理解如何纠正他们。

【讨论】:

大卫 我理解你的沮丧,因为这首先是我的。我不能提供我没有的东西,正如你所看到的,我发布了 de header 代码、export 和 c# 代码。我试过你的方法,可能是成功的第一步,但它仍然返回那个讨厌的异常。 我认为没有文档会很困难。您的问题的解决方案是联系供应商并索取文档。

以上是关于PInvoke“试图读取或写入受保护的内存”的主要内容,如果未能解决你的问题,请参考以下文章

LinQ 试图读取或写入受保护的内存。这通常表明其他内存已损坏

由 urlmon.dll 引起的“试图读取或写入受保护的内存”

VB.NET 访问 - 试图读取或写入受保护的内存

“试图读取或写入受保护的内存。这通常表明其他内存已损坏。”

错误“试图读取或写入受保护的内存。这通常表明其他内存已损坏。”

“试图读取或写入受保护的内存。这通常表明其他内存已损坏。”