首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于非托管互操作的C#对象指针

用于非托管互操作的C#对象指针
EN

Stack Overflow用户
提问于 2015-06-28 17:34:42
回答 2查看 416关注 0票数 1

我目前正在为PhysFS库编写一个包装器,在托管对象的编组方面遇到了一些麻烦。例如,enumerateFilesCallback方法,它以一个函数指针和一个用户定义的指针作为参数。如何将托管对象传递给此方法?这就是我目前正在做的事情:

代码语言:javascript
复制
// This is the delegate signature
public delegate void EnumFilesCallback(IntPtr data, string origdir, string fname);

// This is the method signature
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void PHYSFS_enumerateFilesCallback(string dir, EnumFilesCallback c, IntPtr d);

最后,这就是我要将任意对象传递给方法的目的:

代码语言:javascript
复制
// I use the unsafe keyword because the whole Interop class is declared so.
// This code was taken from https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle(VS.71).aspx
public static void EnumerateFilesCallback(string dir, EnumFilesCallback c, object data)
{
  unsafe
  {
    GCHandle objHandle = GCHandle.Alloc(data);
    Interop.PHYSFS_enumerateFilesCallback(dir, c, (IntPtr)objHandle);
    objHandle.Free();
  }
}

当我运行这段代码时:

代码语言:javascript
复制
static void Enum(IntPtr d, string origdir, string fname )
{
  System.Runtime.InteropServices.GCHandle handle = (System.Runtime.InteropServices.GCHandle)d;
  TestClass c = (TestClass)handle.Target;
  Console.WriteLine("{0} {1}", origdir, fname);
}

static void Main(string[] args)
{
  PhysFS.Init("");
  PhysFS.Mount("D:\\", "/hello", true);

  TestClass x = new TestClass() { a = 3, b = 4 }; // This can be any gibberish object

  PhysFS.EnumerateFilesCallback("/hello/", Enum, x);
}

委托会被合法数据调用4次,第五次包含垃圾数据,然后抛出一个AccessViolationException (我怀疑这是因为对象在调用委托之间得到了GCed )。有人能弄清楚这件事吗?

更新:更改挂载目录可以消除垃圾数据,但异常仍然会抛出,而且在所有数据都可以使用之前仍然会抛出异常。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-26 19:06:54

感谢每一个投入他们的时间试图提供答案的人!我终于找到了问题的根源并解决了它!

问题是..。我有点惭愧..。电话会议。所有的PInvoked方法都被声明为cdecl,而我忘记了将委托声明为cdecl,所以它造成了不平衡的堆栈和混乱等等。

票数 0
EN

Stack Overflow用户

发布于 2015-08-06 15:42:06

您是否尝试过创建回调并将其存储为类静态字段?

代码语言:javascript
复制
private static EnumFilesCallback callback = new EnumFilesCallback(Enum);

在你的主要方法中:

代码语言:javascript
复制
PhysFS.EnumerateFilesCallback("/hello/", callback, x);

这可能会避免GC收集包含委托对象的局部变量。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31102706

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档