Opening pipe connection to a file descriptor in C#
Asked Answered
D

2

5

I have a legacy app where it reads message from a client program from file descriptor 3. This is an external app so I cannot change this. The client is written in C#. How can we open a connection to a specific file descriptor in C#? Can we use something like AnonymousPipeClientStream()? But how do we specify the file descriptor to connect to?

Duax answered 29/10, 2008 at 4:49 Comment(0)
S
5

Unfortunately, you won't be able to do that without P/Invoking to the native Windows API first.

First, you will need to open your file descriptor with a native P/Invoke call. This is done by the OpenFileById WINAPI function. Here's how to use it on MSDN, here's an other link explaining it in detail on the MSDN forums, and here's some help (pinvoke.net) on how to construct your P/Invoke call.

Once you got the file handle, you need to wrap it in a SafeFileHandle, this time in safe, managed C#:

// nativeHandle is the WINAPI handle you have acquired with the P/Invoke call
SafeFileHandle safeHandle = new SafeFileHandle(nativeHandle, true);

Now you can open the file stream directly:

Stream stream = new FileStream(safeHandle, FileAccess.ReadWrite);

And from this point you can use it as any other file or stream in C#. Don't forget to dispose your objects once you're done.

Subadar answered 29/1, 2009 at 22:27 Comment(1)
Are these file ids the same as the C runtime file descriptors? Also, OpenByFileId is only supported on Vista or later.Reduplication
F
2

I was able to solve the same issue by using _get_osfhandle. Example:

using System;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;

class Comm : IDisposable
{
    [DllImport("MSVCRT.DLL", CallingConvention = CallingConvention.Cdecl)]
    extern static IntPtr _get_osfhandle(int fd);

    public readonly Stream Stream;

    public Comm(int fd)
    {
        var handle = _get_osfhandle(fd);
        if (handle == IntPtr.Zero || handle == (IntPtr)(-1) || handle == (IntPtr)(-2))
        {
            throw new ApplicationException("invalid handle");
        }

        var fileHandle = new SafeFileHandle(handle, true);
        Stream = new FileStream(fileHandle, FileAccess.ReadWrite);
    }

    public void Dispose()
    {
        Stream.Dispose();
    }       
}
Furnace answered 19/4, 2017 at 11:36 Comment(3)
Hey Tim, I'm trying to use your code trying to generate a handle for FD3, and _get_osfhandle returns -1, Rings a bell?Scythe
@hardkoded: It doesn't, no. I would suggest using SetLastError = True on the DllImport to see what the underlying error is.Furnace
_get_osfhandle is part of the Universal CRT, not the Windows API. It doesn't set the calling thread's last error code. Asking the CLR to preserve it for you will have it preserve a meaningless value.Artina

© 2022 - 2024 — McMap. All rights reserved.