I need to open a writable file handle in Python and then hand off the file descriptor to a function in a .NET assembly (accessed via pythonnet's clr
module.
Getting from the Python file object to the win32 HANDLE*
is fairly straightforward, as shown in this question:
import clr
from Microsoft.Win32.SafeHandles import SafeFileHandle
from System.IO import FileStream, FileAccess
pyf=open("c:/temp/testing123.txt","w")
fileno=pyf.fileno()
print fileno # 6
handle = msvcrt.get_osfhandle(fileno)
print handle # 1832L
According to MSDN, it should now be possible to construct a standard FileStream
object from either a straight IntPtr
(the handle) or from a SafeFileHandle
wrapper.
FileStream(IntPtr, FileAccess)
FileStream(SafeFileHandle, FileAccess)
The problem is... how can I convince the clr
module to cast handle
as an IntPtr
?
I've tried various versions of the following, but they all give me errors:
FileStream(IntPtr(handle), True)
FileStream(IntPtr(Int64(handle), True)
FileStream(IntPtr(Int32(handle), True)
SafeFileHandle(IntPtr(handle), True)
...
=> TypeError ("value cannot be converted to System.IntPtr")
Any suggestions for how to get this darn file handle into C#?
Got an answer thanks to the good folks on the pythonnet
mailing list.
The key is to use the Overloads
constructor to force-cast the win32 HANDLE
to IntPtr
type.
Here's a complete working example:
import tempfile, msvcrt
import clr, msvcrt
from System.IO import FileStream, FileAccess
from System import IntPtr
with tempfile.NamedTemporaryFile(suffix='.txt', delete=False) as pyf:
fileno=pyf.fileno()
print "fileno", fileno
handle = msvcrt.get_osfhandle(fileno)
print "HANDLE", handle
pyf.write("Python\n")
pyf.flush()
cs_handle = IntPtr.Overloads[long](handle)
cs_fs = FileStream(cs_handle, FileAccess.Write)
cs_fs.Write("CLR\n", 0, 4)
cs_fs.Flush()
print "file should contain a line from Python and a line from CLR: ", pyf.name