Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I stream data from a managed assembly to a native library and back again?

How can I stream data (text) from a managed assembly to a native library and stream data (text) back to the managed assembly?

Specifically, I want to expose a System.IO.Stream of some sort on the .NET side, and (most importantly) a FILE * on the native side.

The signature of the native method should be:

FILE * foo(FILE * bar);

The signature of a wrapper around the native p/invoke call should be:

CustomStream foo(CustomStream bar);

I do not want to use callback methods on the native side (one for getting more data and one for setting more data). I want to use a FILE * on the native side - and all of the associated methods which operate upon it such as fprintf.

I do not want any disk I/O. This needs to be an in-memory operation.

I have complete control over both the managed assembly and the native library.

The solution must work with .NET 2.0

I'm willing to create any sort of managed or unmanaged shim layer required to pull this off.

The "obvious" solution is to use STDIN and STDOUT and launch a child process - however I don't want a separate process. Also, my attempts to redirect the STDIN and STDOUT streams of a native library which isn't a console application on Windows have failed somewhat spectacularly (and with much head-banging).

Based on this question: Redirect stdout+stderr on a C# Windows service I attempted to modify the approach to (at least) solve the "response" stream half of my problem - but without a FileStream (since I want something more analogous to a MemoryStream). However, FileStream is the only stream type which exposes a suitable low-level stream handle.

Otherwise, I'm pretty well stuck and am currently thinking I'll need to dive deeper and come up with my own hand-rolled native<->managed stream implementation but don't really know where to start.


Solution

Finally!

I've posted a complete sample project here:

http://pastebin.com/jcjHdnwz

This is for .NET 3.5 and uses the AnonymousPipeServerStream - but with a little bit of reflector-ing, it's easy enough to duplicate the inner workings of the AnonymousPipeServerStream in .NET 2.0.

Thanks for your help shf301 for pointing me to the native pipe API, which got me looking into the Microsoft docs for a better understanding of what's going on, and for pointing out I needed to use the _open_osfhandle method to get the FILE * reference.

like image 718
Steve Avatar asked Dec 18 '11 21:12

Steve


1 Answers

You should be able to do this using a AnonymousPipeStream in .NET 3.5 or higher. That exposes a handle, via the SafePipeHandle property that you can pass to SetStdHandle.

For .NET 2.0 you may have to P/Invoke to the unmanaged pipe API.

like image 182
shf301 Avatar answered Oct 02 '22 20:10

shf301