0

In the docs for the FileStream class, the Remarks section says:

Use the FileStream class to read from, write to, open, and close files on a file system, and to manipulate other file-related operating system handles, including pipes, standard input, and standard output.

I know that System.IO.Pipes exists for creating, reading, and writing from pipes in Windows, but due to limitations in the project I am currently working on, I don't have access to that package. It seems that FileStreams can interact with pipes, but I can't seem to find any examples of how to do this.

How does one use a FileStream directly to do basic I/O with a named pipe in Windows?

porgull
  • 102
  • 10
  • 1
    You need a pipe handle and to use the FileStream constructor that accepts an File handle. FileStream won’t create or open the pipe for you. So you’ll have to use P/Invoke against the Win32 APIs at least to create or open the pipe. – David Browne - Microsoft Dec 15 '19 at 01:58
  • Ah, I see - that makes sense. With the CreatePipe function, I see it gives you the raw file descriptors, but is there a way to subsequently name the created pipe, such that another process can open it normally, like `\\.\pipe\...`? I apologize if this is a naive question @DavidBrowne-Microsoft – porgull Dec 15 '19 at 02:20
  • oh duh! here we go - https://stackoverflow.com/questions/26561604/create-named-pipe-c-windows - will make up an answer using this. thanks for the tip! – porgull Dec 15 '19 at 02:30

1 Answers1

1
using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Test
{

    class Program
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateNamedPipe(string lpName, uint dwOpenMode,
           uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize,
           uint nDefaultTimeOut, IntPtr lpSecurityAttributes);
        static uint PIPE_ACCESS_DUPLEX = 0x00000003;
        static uint PIPE_ACCESS_INBOUND = 0x00000001;
        static uint PIPE_ACCESS_OUTBOUND = 0x00000002;
        static uint FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000;
        static uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
        static uint FILE_FLAG_OVERLAPPED = 0x40000000;
        static uint WRITE_DAC = 0x00040000;
        static uint WRITE_OWNER = 0x00080000;
        static uint ACCESS_SYSTEM_SECURITY = 0x01000000;
        //One of the following type modes can be specified. The same type mode must be specified for each instance of the pipe.
        static uint PIPE_TYPE_BYTE = 0x00000000;
        static uint PIPE_TYPE_MESSAGE = 0x00000004;
        //One of the following read modes can be specified. Different instances of the same pipe can specify different read modes
        static uint PIPE_READMODE_BYTE = 0x00000000;
        static uint PIPE_READMODE_MESSAGE = 0x00000002;
        //One of the following wait modes can be specified. Different instances of the same pipe can specify different wait modes.
        static uint PIPE_WAIT = 0x00000000;
        static uint PIPE_NOWAIT = 0x00000001;
        //One of the following remote-client modes can be specified. Different instances of the same pipe can specify different remote-client modes.
        static uint PIPE_ACCEPT_REMOTE_CLIENTS = 0x00000000;
        static uint PIPE_REJECT_REMOTE_CLIENTS = 0x00000008;


        static void Main(string[] args)
        {

            Console.WriteLine("Hello World!");
            var name = "test";
            var p = CreateNamedPipe(@"\\.\pipe\" + name, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_WAIT, 255, 0, 4096, 0xffffffff, IntPtr.Zero);
            if (p.ToInt32() == -1)
            {
                throw new Exception("Error creating named pipe " + name + " . Internal error: " + Marshal.GetLastWin32Error().ToString());
            }
            var fs = new FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(p, true), FileAccess.Write);
            fs.Close();
        }
    }
}

This appears to be working just fine. Slightly uglier than I'd hoped, but not impossible. Thanks to @David Browne for pointing me in the right direction.

More complete example: https://www.pinvoke.net/default.aspx/kernel32.createnamedpipe

porgull
  • 102
  • 10