如何将指向Python cffi结构的指针强制转换为System.IntPtr(.NET)?

时间:2017-08-24 11:30:52

标签: python .net python.net python-cffi

我需要将System.IntPtr传递给.NET函数(Python和pythonnet)。该指针应该引用在cffi中创建的结构。

我找到this

from CLR.System import IntPtr, Int32
i = Int32(32)
p = IntPtr.op_Explicit(i)

这是我到目前为止所尝试的

import clr
from cffi import FFI

ffi = FFI()

custom_t = '''
            typedef struct
            {
                float x;
                 float y;
                 float z;

            } float3;
            '''

ffi.cdef(custom_t)

cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)

from System import IntPtr

p = IntPtr.op_Explicit(id(cfloat3)) #works, sort of...
print(p)

#I would rather see something like
p2 = IntPtr.op_Explicit(ffi.addressof(cfloat3).value)
p3 = IntPtr(ffi.cast("float3*", cfloat3))
p4 = IntPtr(ffi.cast("void3*", cfloat3))

#type(_), ffi.typeof(_), ffi.typeof(_).kind, ffi.addressof()

但我不确定使用IntPtr.op_Explicit是否是最佳解决方案。与id()结合使用看起来有点像解决方法,我很确定有更好的解决方案。

3 个答案:

答案 0 :(得分:3)

Python.Net中没有对CFFI的直接支持,反之亦然,因此您需要将指针从一个库转换为整数并将该整数重新导入到另一个库中。

来自CFFI,intaddr = ffi.cast("intptr_t", p)会给你一个整数。然后你可以做IntPtr(intaddr)

答案 1 :(得分:1)

答案 2 :(得分:1)

解决方法是使用Overloads

IntPtr方法
from System import IntPtr, Int32, Int64
my_ptr = ffi.cast("intptr_t", my_c_struct)
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))

如上所述herehere

这是一个有效的例子:

import clr
from cffi import FFI

ffi = FFI()

custom_t = '''
            typedef struct
            {
                float x;
                 float y;
                 float z;

            } float3;
            '''

ffi.cdef(custom_t)

cfloat3 = ffi.new("float3 *")
cfloat3.x = 1.0
cfloat3.y = 2.0
cfloat3.z = 3.0
print(cfloat3)

from System import IntPtr, Int32, Int64

my_ptr = ffi.cast("intptr_t", cfloat3)
print(my_ptr)
print(ffi.typeof(my_ptr))
print(ffi.typeof(my_ptr).kind)
print(ffi.typeof(my_ptr).cname)
print(int(my_ptr))
print('hex', hex(int(my_ptr)))

#you don't need to cast to System.Int64 first, also works without:

#with casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](int(my_ptr))
print(cs_handle)

#without casting the Python int to System.Int64
cs_handle = IntPtr.Overloads[Int64](Int64(int(my_ptr)))
print(cs_handle)

# using this workaround mentioned in the question also works
p = IntPtr.op_Explicit(int(my_ptr)) #works, sort of...
print('op_Explicit', p)

#careful: do not use the id() of the C structure, it is different and incorrect
print(cfloat3)
print(ffi.addressof(cfloat3[0]))
print('id(cfloat3)', id(cfloat3), hex(id(cfloat3)))

关于上面发生的事情的一些进一步信息(在这里和那里找到):

  
      
  • C#的IntPtr完全映射到C / C ++< intptr_t。

  •   
  • intptr_t能够持有指针的整数类型

  •   
  • 要将指针强制转换为int,请将其强制转换为intptr_t或uintptr_t,它们由C定义为足够大的整数类型。 cffi doc with examples

  •   
  • IntPtr只是void *的.NET类型。

  •   
  • C#语言中非托管指针的等价物是IntPtr。您可以使用强制转换来自由地来回转换指针。没有指针类型   与它相关联,即使它的名字听起来像"指向int"的指针,   它相当于C / C ++中的void *。

  •   
  • IntPtr(5)抱怨int/long' value cannot be converted to System.IntPtr。似乎它正在尝试强制转换或者某些东西而不是调用构造函数。 (找到here

  •   
  • CLR对象的方法有一个' _ 重载 _',很快就会弃用,以支持iPy兼容的Overloads,可用于此目的的属性。 (找到here

  •