将对象转换为void*,再将其转换回来?

6
我正在尝试编写一个包装器,用于包装一个期望函数指针和任意用户数据(void*)的C函数。我已经通过使用委托处理了函数指针,但我无法想出如何将object转换为void*
我可以将其变成ref object,因为它的行为类似于指针,但是当我尝试这样做时,我会收到异常,如下所示:

An invalid VARIANT was detected during a conversion from an unmanaged VARIANT to a managed object. Passing invalid VARIANTs to the CLR can cause unexpected exceptions, corruption or data loss.

这个“解决方案”可能适合我,但我认为必须有一种方法可以将任意数据传递给C DLL,以便稍后可以将其传回?

我个人认为,最好使用一个指向fixed块的结构体指针... - Marc Gravell
@NoIdeaForName:C DLL 可以轻松地使用 IntPtr,但当它返回时,我该如何将其转换回 object 呢?(还有,如何将一个对象“强制转换”为 IntPtr?) - mpen
像这样吗,@Mark?-http://msdn.microsoft.com/en-us/library/9a8d37fb.aspx - No Idea For Name
@MarcGravell:所以我应该禁止传递任意对象吗?我想那可能可行。目前我没有明确需要对象,只是试图使API尽可能友好。 "fixed" 一词确实引发了另一个问题,但我将单独提出。 - mpen
@NoIdeaForName:这只是将IntPtr转换为int的操作... - mpen
2个回答

2

个人建议在这里使用struct,它更适用于您正在尝试做的事情(而且如果需要,您可以调整内部布局)。例如,使用struct Foo和引用类型上的字段foo:

unsafe void Bar()
{   
    fixed (Foo* ptr = &foo) // here foo is a field on a reference-type
    {
        void* v = ptr; // if you want void*
        IntPtr i = new IntPtr(ptr); // if you want IntPtr
        // use v or i here...
    }
}

注意:如果foo是一个局部变量,那么它在堆栈上,甚至不需要进行fixed操作。
unsafe void Bar()
{
    Foo foo = new Foo();
    Foo* ptr = &foo; // here foo is a local variable

    void* v = ptr; // if you want void*
    IntPtr i = new IntPtr(ptr); // if you want IntPtr
    // use v or i here...
}

1
关于第二个比特的问题——如果foo在堆栈上,那么在函数结束时它不会被弹出堆栈,这样会导致C DLL有一个悬空指针吗? - mpen

2
如果我没记错的话,您需要使用Pointer.BoxPointer.UnBox方法。这些方法可以帮助将非托管指针进行装箱和拆箱。请参考msdn上的Pointer.BoxPointer.UnBox

如果我理解正确的话,这听起来是相反的。Box 需要一个“提供的未托管内存指针”。C DLL 没有向我提供 void*,我需要生成一个传递给它。而且我相当确定,除非 object 先被装箱,否则 Unbox 将失败。 - mpen
你想传递的 userdata 的实际类型是什么? - Sriram Sakthivel
@SriramSakthivel: object。当回调被调用时,它是用户想要传回给自己的任何东西。可以是任何东西。 - mpen
它将是值类型还是? - Sriram Sakthivel
@SriramSakthivel:不一定。如果必须的话,我想我可以将其限制为值类型,但是C API接受任何类型,我希望使我的包装器尽可能灵活。 - mpen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接