The solution to this is to use the Overloads
method of 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)))
as mentioned here and here.
Here is a working example:
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)))
Some further info on what is happening above (found here and there):
C#'s IntPtr maps exactly to C/C++'s intptr_t.
intptr_t integer type capable of holding a pointer
To cast a pointer to an int, cast it to intptr_t or uintptr_t, which are defined by C to be large enough integer types. cffi doc with examples
IntPtr is just a .NET type for void*.
The equivalent of an unmanaged pointer in the C# language is IntPtr. You can freely convert a pointer back and forth with a cast. No pointer type is
associated with it even though its name sounds like "pointer to int",
it is the equivalent of void* in C/C++.
IntPtr(5) complains that int/long' value cannot be converted to System.IntPtr
. It seems like it is trying to cast or something instead of calling the constructor. (found here)
Methods of CLR objects have an '_ overloads _', which will soon be deprecated in favor of iPy compatible Overloads, attribute that can be used for this purpose. (found here)