Advertisement
Guest User

Untitled

a guest
Dec 21st, 2011
2,466
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.60 KB | None | 0 0
  1. using System;
  2. using System.IO.Pipes;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Threading;
  6.  
  7. namespace ConsoleApplication
  8. {
  9.     class Program
  10.     {
  11.         /// <summary>
  12.         /// Performs some asyncronous action given a stream and returning a stream.
  13.         /// </summary>
  14.         /// <param name="inputStream">Represents the native HANDLE of an AnonymousPipeServerStream.</param>
  15.         /// <param name="outputStream">A native pointer which can be used with an AnonymousPipeClientStream.</param>
  16.         [DllImport("foo.dll")]
  17.         private extern static void Bar(IntPtr source, IntPtr destination);
  18.  
  19.         static void Main(string[] args)
  20.         {
  21.             // This is a sample showing how you might use the class:
  22.             string sourceFile = @"c:\list.txt";
  23.             string destinationFile = @"c:\list_out.txt";
  24.  
  25.             using (Stream source = File.OpenRead(sourceFile))
  26.             {
  27.                 using (Stream destination = File.Open(destinationFile, FileMode.OpenOrCreate))
  28.                 {
  29.                     NativeStreamInOutWrapper.Execute(new NativeStreamInOutWrapper.NativeStreamInOutMethod(Bar), source, destination);
  30.                 }
  31.             }
  32.         }
  33.  
  34.         /* SAMPLE NATIVE C CODE:
  35.  
  36. #include <stdio.h>
  37. #include <stdbool.h>
  38. #include <string.h>
  39. #include <unistd.h>
  40. #include <Windows.h>
  41. #include <io.h>
  42. #include <fcntl.h>
  43.  
  44. #define DLLEXPORT __declspec(dllexport) __cdecl
  45.  
  46. extern void DLLEXPORT Bar(HANDLE source, HANDLE destination)
  47. {
  48.     // Open the source stream (for reading):
  49.     int sourceFD = _open_osfhandle((intptr_t)source, _O_RDONLY);
  50.     FILE * sourceStream = _fdopen(sourceFD, "r");
  51.  
  52.     // Open the destination stream (for writing):
  53.     int destinationFD = _open_osfhandle((intptr_t)destination, _O_APPEND);
  54.     FILE * destinationStream = _fdopen(destinationFD, "w");
  55.    
  56.     // SAMPLE CODE:
  57.     // Here you would call your real method which takes (FILE *, FILE *)
  58.     int val = 0;
  59.     while (0 < (val = getc(sourceStream)))
  60.     {  
  61.         // Write the input into the output
  62.         // followed by the "-" character:
  63.         putc(val, destinationStream);
  64.         putc('-', destinationStream);
  65.        
  66.         // Continuously flush:
  67.         fflush(destinationStream);
  68.     }
  69.    
  70.     // Write the null terminator to the output stream:
  71.     putc(0, destinationStream);
  72.        
  73.     // Flush any buffered data into the output stream:
  74.     fflush(destinationStream);
  75.    
  76.     // Close the source and destination streams:
  77.     fclose(sourceStream);
  78.     fclose(destinationStream);
  79. }
  80.          
  81.          */
  82.  
  83.         /// <summary>
  84.         /// This class allows you to work with native methods
  85.         /// which need to use FILE * s to read input and write
  86.         /// output to. From within the native methods you could,
  87.         /// for example, use this to get the native application
  88.         /// to take STDIN from a stream and STDOUT to a stream.
  89.         /// </summary>
  90.         public static class NativeStreamInOutWrapper
  91.         {
  92.             public delegate void NativeStreamInOutMethod(IntPtr source, IntPtr destination);
  93.  
  94.             /// <summary>
  95.             /// Executes a native method which takes two HANDLE parameters
  96.             /// to anonymous pipes and streams the data from the source stream
  97.             /// into the source pipe and from the destination pipe to the destination
  98.             /// stream.
  99.             /// </summary>
  100.             /// <param name="method">The method to call.</param>
  101.             /// <param name="source">The source data stream.</param>
  102.             /// <param name="destination">The destination data stream.</param>
  103.             public static void Execute(NativeStreamInOutMethod method, Stream source, Stream destination)
  104.             {
  105.                 Execute(method, source, destination, 1, 30000, true);
  106.             }
  107.  
  108.             /// <summary>
  109.             /// Executes a native method which takes two HANDLE parameters
  110.             /// to anonymous pipes and streams the data from the source stream
  111.             /// into the source pipe and from the destination pipe to the destination
  112.             /// stream.
  113.             /// </summary>
  114.             /// <param name="method">The method to call.</param>
  115.             /// <param name="source">The source data stream.</param>
  116.             /// <param name="destination">The destination data stream.</param>
  117.             /// <param name="bufferSize">The buffer size to use.</param>
  118.             /// <param name="timeout">The timeout in milliseconds before the operation is aborted.</param>
  119.             /// <param name="continuousFlush">Whether the stream is flushed after every write of the buffer.</param>
  120.             public static void Execute(NativeStreamInOutMethod method, Stream source, Stream destination,
  121.                                         int bufferSize, int timeout, bool constantFlush)
  122.             {
  123.                 //  source --> sourcePipe |Native| destinationPipe --> destination
  124.  
  125.                 // Construct the anonymous pipes we'll need to stream data to/from
  126.                 // the native method:
  127.                 using (AnonymousPipeServerStream sourcePipe = new AnonymousPipeServerStream(
  128.                                         PipeDirection.Out, HandleInheritability.Inheritable))
  129.                 {
  130.                     using (AnonymousPipeServerStream destinationPipe = new AnonymousPipeServerStream(
  131.                                         PipeDirection.In, HandleInheritability.Inheritable))
  132.                     {
  133.                         // This mutex waits for the native process to complete:
  134.                         // << NOTE: The native process should block until it recieves
  135.                         //          the null terminator on the source stream. >>
  136.                         ManualResetEvent processComplete = new ManualResetEvent(false);
  137.  
  138.                         // This mutex waits for us to finish pumping the destination stream:
  139.                         ManualResetEvent dumpComplete = new ManualResetEvent(false);
  140.  
  141.                         // This thread will pump the source stream into the sourcePipe:
  142.                         Thread sourcePump = new Thread(new ParameterizedThreadStart(PumpSourceBuffer));
  143.                         sourcePump.Start(new PumpSourceStartArguments()
  144.                         {
  145.                             source = source,
  146.                             sourcePipe = sourcePipe,
  147.                             bufferSize = bufferSize,
  148.                             mutex = processComplete,
  149.                             constantFlush = constantFlush
  150.                         });
  151.  
  152.                         // This thread will pump the destinationPipe into the destination:
  153.                         Thread destinationPump = new Thread(new ParameterizedThreadStart(PumpDestinationBuffer));
  154.                         destinationPump.Start(new PumpDestinationStartArguments()
  155.                         {
  156.                             destination = destination,
  157.                             destinationPipe = destinationPipe,
  158.                             bufferSize = bufferSize,
  159.                             mutex = dumpComplete,
  160.                             constantFlush = constantFlush
  161.                         });
  162.  
  163.                         // This is the native method which will process data from
  164.                         // the sourcePipe and dump data into the destinationPipe:
  165.                         Thread t = new Thread(new ParameterizedThreadStart(Process));
  166.                         t.Start(new ProcessStartArguments()
  167.                         {
  168.                             sourcePipe = sourcePipe,
  169.                             destinationPipe = destinationPipe,
  170.                             nativeMethod = method,
  171.                             mutex = processComplete
  172.                         });
  173.  
  174.                         processComplete.WaitOne();
  175.                         dumpComplete.WaitOne();
  176.                     }
  177.                 }
  178.             }
  179.  
  180.             #region Native Method Call
  181.  
  182.             private class ProcessStartArguments
  183.             {
  184.                 public AnonymousPipeServerStream sourcePipe;
  185.                 public AnonymousPipeServerStream destinationPipe;
  186.                 public ManualResetEvent mutex;
  187.                 public NativeStreamInOutMethod nativeMethod;
  188.             }
  189.  
  190.             private static void Process(Object o)
  191.             {
  192.                 ProcessStartArguments args = (ProcessStartArguments)o;
  193.  
  194.                 // Call out to the operation, passing the outPipe handle,
  195.                 // and getting back the handle we'll use for the inPipe:
  196.                 args.nativeMethod(args.sourcePipe.ClientSafePipeHandle.DangerousGetHandle(),
  197.                                   args.destinationPipe.ClientSafePipeHandle.DangerousGetHandle());
  198.  
  199.                 args.sourcePipe.DisposeLocalCopyOfClientHandle();
  200.                 args.destinationPipe.DisposeLocalCopyOfClientHandle();
  201.  
  202.                 // Let everyone know we've finished with the native
  203.                 // method call:
  204.                 args.mutex.Set();
  205.             }
  206.  
  207.             #endregion
  208.  
  209.             #region Destination Pump
  210.  
  211.             private class PumpDestinationStartArguments
  212.             {
  213.                 public Stream destination;
  214.                 public AnonymousPipeServerStream destinationPipe;
  215.                 public ManualResetEvent mutex;
  216.                 public int bufferSize;
  217.                 public bool constantFlush;
  218.             }
  219.  
  220.             private static void PumpDestinationBuffer(Object o)
  221.             {
  222.                 PumpDestinationStartArguments args = (PumpDestinationStartArguments)o;
  223.  
  224.                 byte[] buffer = new byte[args.bufferSize];
  225.                 int len = 0;
  226.                 while (0 != (len = args.destinationPipe.Read(buffer, 0, args.bufferSize)))
  227.                 {
  228.                     args.destination.Write(buffer, 0, len);
  229.                     if (args.constantFlush) args.destination.Flush();
  230.                    
  231.                     // Wait for the null terminator:
  232.                     if (buffer[len - 1] == 0) break;
  233.                 }
  234.  
  235.                 // Flush any buffered data into the pipe:
  236.                 args.destination.Flush();
  237.  
  238.                 // Let everyone know we've finished processing the
  239.                 // data from the stream:
  240.                 args.mutex.Set();
  241.             }
  242.  
  243.             #endregion
  244.  
  245.             #region Source Pump
  246.  
  247.             private class PumpSourceStartArguments
  248.             {
  249.                 public Stream source;
  250.                 public AnonymousPipeServerStream sourcePipe;
  251.                 public ManualResetEvent mutex;
  252.                 public int bufferSize;
  253.                 public bool constantFlush;
  254.             }
  255.  
  256.             private static void PumpSourceBuffer(Object o)
  257.             {
  258.                 PumpSourceStartArguments args = (PumpSourceStartArguments)o;
  259.  
  260.                 int len = 0;
  261.                 byte[] buffer = new byte[args.bufferSize];
  262.                 while (0 != (len = args.source.Read(buffer, 0, args.bufferSize)))
  263.                 {
  264.                     args.sourcePipe.Write(buffer, 0, len);
  265.                     if (args.constantFlush) args.sourcePipe.Flush();
  266.                 }
  267.                
  268.                 // Write the null terminator:
  269.                 args.sourcePipe.WriteByte(0);
  270.  
  271.                 // Flush any buffered data into the pipe:
  272.                 args.sourcePipe.Flush();
  273.                
  274.                 // Wait for the reciever to take all of our data.
  275.                 args.sourcePipe.WaitForPipeDrain();
  276.  
  277.                 // Wait for the native process to complete:
  278.                 args.mutex.WaitOne();
  279.             }
  280.  
  281.             #endregion
  282.  
  283.         }
  284.     }
  285. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement