¿Cómo lanzar un puntero a una estructura de Python para System.IntPtr (.NET)?

Necesito pasar un System.IntPtr a una función .NET (Python con pythonnet). Este puntero debe referirse a una estructura creada en cffi.

Encontré esto :

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

Esto es lo que he intentado hasta ahora.

 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() 

Pero no estoy seguro de que usar IntPtr.op_Explicit sea ​​la mejor solución. Parece un poco como una solución en combinación con id() y estoy bastante seguro de que hay una mejor solución.

No hay soporte directo para CFFI dentro de Python.Net o viceversa, por lo que debe convertir el puntero de una biblioteca a un entero y volver a importar ese entero en la otra biblioteca.

Desde CFFI, intaddr = ffi.cast("intptr_t", p) le dará un número entero. Entonces probablemente puedas hacer IntPtr(intaddr) .

FFI tiene una función de dirección incorporada:

http://cffi.readthedocs.io/en/latest/ref.html#ffi-addressof

La solución a esto es usar el método de Overloads de 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))) 

como se menciona aquí y aquí .

Aquí hay un ejemplo de trabajo:

 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))) 

Un poco más de información sobre lo que está pasando arriba (se encuentra aquí y allá)

  • El IntPtr de C # se asigna exactamente al intptr_t de C / C ++.

  • Intptr_t tipo entero capaz de contener un puntero

  • Para convertir un puntero en un int, conviértalo en intptr_t o uintptr_t, que C define como tipos de enteros suficientemente grandes. cffi doc con ejemplos

  • IntPtr es solo un tipo .NET para void *.

  • El equivalente de un puntero no administrado en el lenguaje C # es IntPtr. Puede convertir libremente un puntero de ida y vuelta con un molde. No se le asocia ningún tipo de puntero, aunque su nombre suene como “puntero a int”, es el equivalente de void * en C / C ++.

  • IntPtr (5) se queja de que el valor int/long' value cannot be converted to System.IntPtr . Parece que está tratando de lanzar o algo en lugar de llamar al constructor. (encontrado aquí )

  • Los métodos de los objetos CLR tienen un ‘_ sobrecargas _’, que pronto quedará obsoleto en favor de las sobrecargas compatibles con iPy, atributo que puede usarse para este propósito. (encontrado aquí )