Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.IO.Pipes;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Threading;
- namespace ConsoleApplication
- {
- class Program
- {
- /// <summary>
- /// Performs some asyncronous action given a stream and returning a stream.
- /// </summary>
- /// <param name="inputStream">Represents the native HANDLE of an AnonymousPipeServerStream.</param>
- /// <param name="outputStream">A native pointer which can be used with an AnonymousPipeClientStream.</param>
- [DllImport("foo.dll")]
- private extern static void Bar(IntPtr source, IntPtr destination);
- static void Main(string[] args)
- {
- // This is a sample showing how you might use the class:
- string sourceFile = @"c:\list.txt";
- string destinationFile = @"c:\list_out.txt";
- using (Stream source = File.OpenRead(sourceFile))
- {
- using (Stream destination = File.Open(destinationFile, FileMode.OpenOrCreate))
- {
- NativeStreamInOutWrapper.Execute(new NativeStreamInOutWrapper.NativeStreamInOutMethod(Bar), source, destination);
- }
- }
- }
- /* SAMPLE NATIVE C CODE:
- #include <stdio.h>
- #include <stdbool.h>
- #include <string.h>
- #include <unistd.h>
- #include <Windows.h>
- #include <io.h>
- #include <fcntl.h>
- #define DLLEXPORT __declspec(dllexport) __cdecl
- extern void DLLEXPORT Bar(HANDLE source, HANDLE destination)
- {
- // Open the source stream (for reading):
- int sourceFD = _open_osfhandle((intptr_t)source, _O_RDONLY);
- FILE * sourceStream = _fdopen(sourceFD, "r");
- // Open the destination stream (for writing):
- int destinationFD = _open_osfhandle((intptr_t)destination, _O_APPEND);
- FILE * destinationStream = _fdopen(destinationFD, "w");
- // SAMPLE CODE:
- // Here you would call your real method which takes (FILE *, FILE *)
- int val = 0;
- while (0 < (val = getc(sourceStream)))
- {
- // Write the input into the output
- // followed by the "-" character:
- putc(val, destinationStream);
- putc('-', destinationStream);
- // Continuously flush:
- fflush(destinationStream);
- }
- // Write the null terminator to the output stream:
- putc(0, destinationStream);
- // Flush any buffered data into the output stream:
- fflush(destinationStream);
- // Close the source and destination streams:
- fclose(sourceStream);
- fclose(destinationStream);
- }
- */
- /// <summary>
- /// This class allows you to work with native methods
- /// which need to use FILE * s to read input and write
- /// output to. From within the native methods you could,
- /// for example, use this to get the native application
- /// to take STDIN from a stream and STDOUT to a stream.
- /// </summary>
- public static class NativeStreamInOutWrapper
- {
- public delegate void NativeStreamInOutMethod(IntPtr source, IntPtr destination);
- /// <summary>
- /// Executes a native method which takes two HANDLE parameters
- /// to anonymous pipes and streams the data from the source stream
- /// into the source pipe and from the destination pipe to the destination
- /// stream.
- /// </summary>
- /// <param name="method">The method to call.</param>
- /// <param name="source">The source data stream.</param>
- /// <param name="destination">The destination data stream.</param>
- public static void Execute(NativeStreamInOutMethod method, Stream source, Stream destination)
- {
- Execute(method, source, destination, 1, 30000, true);
- }
- /// <summary>
- /// Executes a native method which takes two HANDLE parameters
- /// to anonymous pipes and streams the data from the source stream
- /// into the source pipe and from the destination pipe to the destination
- /// stream.
- /// </summary>
- /// <param name="method">The method to call.</param>
- /// <param name="source">The source data stream.</param>
- /// <param name="destination">The destination data stream.</param>
- /// <param name="bufferSize">The buffer size to use.</param>
- /// <param name="timeout">The timeout in milliseconds before the operation is aborted.</param>
- /// <param name="continuousFlush">Whether the stream is flushed after every write of the buffer.</param>
- public static void Execute(NativeStreamInOutMethod method, Stream source, Stream destination,
- int bufferSize, int timeout, bool constantFlush)
- {
- // source --> sourcePipe |Native| destinationPipe --> destination
- // Construct the anonymous pipes we'll need to stream data to/from
- // the native method:
- using (AnonymousPipeServerStream sourcePipe = new AnonymousPipeServerStream(
- PipeDirection.Out, HandleInheritability.Inheritable))
- {
- using (AnonymousPipeServerStream destinationPipe = new AnonymousPipeServerStream(
- PipeDirection.In, HandleInheritability.Inheritable))
- {
- // This mutex waits for the native process to complete:
- // << NOTE: The native process should block until it recieves
- // the null terminator on the source stream. >>
- ManualResetEvent processComplete = new ManualResetEvent(false);
- // This mutex waits for us to finish pumping the destination stream:
- ManualResetEvent dumpComplete = new ManualResetEvent(false);
- // This thread will pump the source stream into the sourcePipe:
- Thread sourcePump = new Thread(new ParameterizedThreadStart(PumpSourceBuffer));
- sourcePump.Start(new PumpSourceStartArguments()
- {
- source = source,
- sourcePipe = sourcePipe,
- bufferSize = bufferSize,
- mutex = processComplete,
- constantFlush = constantFlush
- });
- // This thread will pump the destinationPipe into the destination:
- Thread destinationPump = new Thread(new ParameterizedThreadStart(PumpDestinationBuffer));
- destinationPump.Start(new PumpDestinationStartArguments()
- {
- destination = destination,
- destinationPipe = destinationPipe,
- bufferSize = bufferSize,
- mutex = dumpComplete,
- constantFlush = constantFlush
- });
- // This is the native method which will process data from
- // the sourcePipe and dump data into the destinationPipe:
- Thread t = new Thread(new ParameterizedThreadStart(Process));
- t.Start(new ProcessStartArguments()
- {
- sourcePipe = sourcePipe,
- destinationPipe = destinationPipe,
- nativeMethod = method,
- mutex = processComplete
- });
- processComplete.WaitOne();
- dumpComplete.WaitOne();
- }
- }
- }
- #region Native Method Call
- private class ProcessStartArguments
- {
- public AnonymousPipeServerStream sourcePipe;
- public AnonymousPipeServerStream destinationPipe;
- public ManualResetEvent mutex;
- public NativeStreamInOutMethod nativeMethod;
- }
- private static void Process(Object o)
- {
- ProcessStartArguments args = (ProcessStartArguments)o;
- // Call out to the operation, passing the outPipe handle,
- // and getting back the handle we'll use for the inPipe:
- args.nativeMethod(args.sourcePipe.ClientSafePipeHandle.DangerousGetHandle(),
- args.destinationPipe.ClientSafePipeHandle.DangerousGetHandle());
- args.sourcePipe.DisposeLocalCopyOfClientHandle();
- args.destinationPipe.DisposeLocalCopyOfClientHandle();
- // Let everyone know we've finished with the native
- // method call:
- args.mutex.Set();
- }
- #endregion
- #region Destination Pump
- private class PumpDestinationStartArguments
- {
- public Stream destination;
- public AnonymousPipeServerStream destinationPipe;
- public ManualResetEvent mutex;
- public int bufferSize;
- public bool constantFlush;
- }
- private static void PumpDestinationBuffer(Object o)
- {
- PumpDestinationStartArguments args = (PumpDestinationStartArguments)o;
- byte[] buffer = new byte[args.bufferSize];
- int len = 0;
- while (0 != (len = args.destinationPipe.Read(buffer, 0, args.bufferSize)))
- {
- args.destination.Write(buffer, 0, len);
- if (args.constantFlush) args.destination.Flush();
- // Wait for the null terminator:
- if (buffer[len - 1] == 0) break;
- }
- // Flush any buffered data into the pipe:
- args.destination.Flush();
- // Let everyone know we've finished processing the
- // data from the stream:
- args.mutex.Set();
- }
- #endregion
- #region Source Pump
- private class PumpSourceStartArguments
- {
- public Stream source;
- public AnonymousPipeServerStream sourcePipe;
- public ManualResetEvent mutex;
- public int bufferSize;
- public bool constantFlush;
- }
- private static void PumpSourceBuffer(Object o)
- {
- PumpSourceStartArguments args = (PumpSourceStartArguments)o;
- int len = 0;
- byte[] buffer = new byte[args.bufferSize];
- while (0 != (len = args.source.Read(buffer, 0, args.bufferSize)))
- {
- args.sourcePipe.Write(buffer, 0, len);
- if (args.constantFlush) args.sourcePipe.Flush();
- }
- // Write the null terminator:
- args.sourcePipe.WriteByte(0);
- // Flush any buffered data into the pipe:
- args.sourcePipe.Flush();
- // Wait for the reciever to take all of our data.
- args.sourcePipe.WaitForPipeDrain();
- // Wait for the native process to complete:
- args.mutex.WaitOne();
- }
- #endregion
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement