2017-08-24 51 views
1

我需要将System.IntPtr传递给.NET函数(Python with pythonnet)。这个指针应该指向在cffi中创建的结构体。如何将指向Python cffi结构的指针转换为System.IntPtr(.NET)?

我发现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()相结合,我很确定有更好的解决方案。

+0

这是在我的例子中,P2,不能正常工作。还是为你做? – Joe

+0

我发现这个:IntPtr只是一个.NET类型的void *。它本身并不意味着任何意义。即使它的名字听起来像“指向int的指针”,它也没有与它关联,它与C/C++中的void *等价。 – Joe

+0

在cffi文档中也发现了这一点:要将指针转换为int类型,请将其转换为由C定义的intptr_t或uintptr_t,以使其足够大到足够大的整数类型。但是像'p = IntPtr(int(ffi.cast(“intptr_t”,...)))'也不起作用。 – Joe

回答

1

的解决方案是使用的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))) 

Overloads方法如前所述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只是一个.NET类型的void *。

  • C#语言中非托管指针的等价物是IntPtr。您可以自由地转换指针与来自演员。没有指针类型是 与它相关联,即使它的名字听起来像“指向int” 它是相当于C/C++中的void *。 (5)抱怨int/long' value cannot be converted to System.IntPtr。它似乎是试图转换或者其他东西而不是调用构造函数。(发现here)CLR对象

  • 方法有一个“_ 重载 _”,很快将有利于IPY兼容重载,属性,可以用于此目的的被废弃。 (发现here

+0

您的第二个链接已损坏 – denfromufa

+0

谢谢,链接已修复。 – Joe

1
+0

这是我的例子中的p2,不起作用。还是为你做? – Joe

+0

对,对不起。进一步看,它似乎代码'ffi.new(“float3 *”)'实际上已经返回一个指针。你确定你不能使用变量cfloat3作为指针吗? – lancew

+0

like'p4 = IntPtr(cfloat3)'? – Joe

3

没有为CFFI内Python.Net或反之亦然没有直接的支持,所以你需要从一个库转换指针为整数并将该整数重新导入到其他库中。

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

+0

我已经试过了,看到我的问题的评论。但IntPtr仍然抱怨。即使我从pythonnet中导入了System.Int64或System.Int32数据类型,并将已铸造的整数提供给那里,然后将Int64/32提供给IntPtr。目前没有此处的代码。我明天可以粘贴它。 – Joe

相关问题