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

时间:2014-03-07 21:47:10

标签: c# c++ c pinvoke

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

的信息:

  • Windows 7 64位
  • DLL是64位
  • C#App和Wrapper是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值(缺少的东西)。

任何人都知道我做错了什么?

谢谢!

编辑:

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

1 个答案:

答案 0 :(得分:3)

翻译中的明显错误是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不允许返回空指针。由于您只提供了函数的原型,但忽略了函数必须遵守的语义规则的细节,因此我们无法检查其中任何一个。

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