Avatar of Bryon Czaja
Bryon Czaja
Flag for United States of America asked on

The client connected to another applications mailslot returns access denied when attempting to write.

The problem I am encountering is with the Mailslot write function of the client. The purpose of this is to build a compatible code base in C#, that will be used with older applications built in C++. The C# code client to server works fine, using either separate (local) applications or internal communication. I can also talk to the server spun up in C++ code. So, everything seems to be working...to a point.


But the thing is, I cannot write from the C++ client to the C# server. The code returned is 5, which is access denied. 

This seems to be a security/permission problem with the C# code base. Any thoughts?



https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-


The basic ideas for the mailslot is this:


//Server  - C# 
CreateMailslot(mailBoxPath, 
      1024, 
      2000, 
      IntPtr.Zero);


ReadFile(serverHandle,
     buffer,
     msgSize,
     out numBytesReadm
     Intptr.Zero);


//Client  - C++
CreatFile(mailBoxPath, 
      GENERIC_WRITE, 
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      NULL);


WriteFile(clientHandle,
     mailMsg,
     numBytesToWrite,
     numBytesWritten,
     NULL);

Open in new window

Here is some information on the topic.

* mailslot* Interprocess CommunicationC++C#Windows OS

Avatar of undefined
Last Comment
Bryon Czaja

8/22/2022 - Mon
Bryon Czaja

ASKER
Thanks Gerwin!
ste5an

Without testing: The client can only write to the slot. Thus FILE_SHARE_READ is probably the issue.
Bryon Czaja

ASKER
Hello ste5an,
That is an idea I can try. I will remove the FILE_SHARE_READ attribute and see if that does the job. Thanks for the suggestion.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
Bryon Czaja

ASKER
Ok. it seems that ommitting FILE_SHARE_READ does not correct the problem.
Bryon Czaja

ASKER
Not sure if this would make a difference, but I am running on Windows Server 2019. My thought on this is that this may be a security or permission problem. 
ste5an

Never used that tool, but I would give it a shot: https://ioninja.com/plugins/mailslot-monitor.html
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
Bryon Czaja

ASKER
I tried this out on a Win 10 machine, and it does not exhibit the problem. It really does seem like a permission problem.
Thanks for the tool ste5an. I was able to see it send data from the C# client to the C++ server. However sending from the C++ client to the C# server showed no activity when sending the message. It did validate that the client did connect, so that is a positive!
ste5an

As you have limited the message size, Is it maybe too large?

To test permissions: Do you have a test domain? Then I would run the C# server and C++ client as full domain admin with full access on both machines. When this works, then it is for sure an permission issue.

How do you run your C# server? I would try also a STA console application.
Bryon Czaja

ASKER
Hello ste5an. The messages are about 16 bytes in length. I run the server on the local machine, both the C++ and C# machines, but different paths obviously.

One thing to note is that the mailslot uses a virtual path and 'file'.So the file is just hanging out in memory. I think that the server running the C# code has permissions issue that does not allow the C++ MFC client to access when it goes to write.


https://docs.microsoft.com/en-us/windows/win32/ipc/mailslots

Form load:
    public partial class Form1 : Form
    {
        private  string serverPath = "Server";
        private MailslotServer server;

        public Form1()
        {
            InitializeComponent();

            try
            {
                server = new MailslotServer(serverPath);
                textBox2.Text = @"//.mailslot/" + serverPath;
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Open in new window


Server code:

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Runtime.ConstrainedExecution;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;

[SuppressUnmanagedCodeSecurity]
public static class Mailslot
{
    public const int MailslotNoMessage = -1;

    [Flags]
    public enum FileDesiredAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000
    }

    [Flags]
    public enum FileShareMode : uint
    {
        Zero = 0x00000000,
        FileShareDelete = 0x00000004,
        FileShareRead = 0x00000001,
        FileShareWrite = 0x00000002
    }

    public enum FileCreationDisposition : uint
    {
        CreateNew = 1,
        CreateAlways = 2,
        OpenExisting = 3,
        OpenAlways = 4,
        TruncateExisting = 5
    }

    [SecurityCritical(SecurityCriticalScope.Everything)]
    [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
    [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
    public sealed class SafeMailslotHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeMailslotHandle() : base(true) { }
        public SafeMailslotHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
        {
            base.SetHandle(preexistingHandle);
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(base.handle);
        }
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateMailslot(string mailslotName,
                                                uint nMaxMessageSize, int lReadTimeout,
                                                IntPtr securityAttributes);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetMailslotInfo(SafeMailslotHandle hMailslot,
                                                IntPtr lpMaxMessageSize,
                                                out int lpNextSize, out int lpMessageCount,
                                                IntPtr lpReadTimeout);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool ReadFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToRead,
                                        out int numBytesRead,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool WriteFile(SafeMailslotHandle handle,
                                        byte[] bytes, int numBytesToWrite,
                                        out int numBytesWritten,
                                        IntPtr overlapped);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern SafeMailslotHandle CreateFile(string fileName,
                                        FileDesiredAccess desiredAccess,
                                        FileShareMode shareMode,
                                        IntPtr securityAttributes,
                                        FileCreationDisposition creationDisposition,
                                        int flagsAndAttributes, IntPtr hTemplateFile);
}

public class MailslotServer : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;

    public MailslotServer(string name)
    {
        _handle = Mailslot.CreateMailslot(@"\\.\mailslot\" + name, 0, 0, IntPtr.Zero);
        if (_handle.IsInvalid) throw new Win32Exception();
    }

    public string GetNextMessage()
    {
        int messageBytes;
        int bytesRead;
        int messages;

        if (!Mailslot.GetMailslotInfo(_handle, IntPtr.Zero, out messageBytes,
                     out messages, IntPtr.Zero)) throw new Win32Exception();

        if (messageBytes == Mailslot.MailslotNoMessage) return null;

        var bBuffer = new byte[messageBytes];

        if (!Mailslot.ReadFile(_handle, bBuffer, messageBytes, out bytesRead,
             IntPtr.Zero) || bytesRead == 0) throw new Win32Exception();

        return Encoding.Unicode.GetString(bBuffer);
    }

    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }
}

public class MailslotClient : IDisposable
{
    private Mailslot.SafeMailslotHandle _handle;
    private readonly string _name;
    private readonly string _machine;

    public MailslotClient(string name) : this(name, ".") { }
    public MailslotClient(string name, string machine)
    {
        _name = name;
        _machine = machine;
    }

    public void SendMessage(string msg)
    {
        if (_handle == null) CreateHandle();

        int bytesWritten;

        byte[] bMessage = Encoding.Unicode.GetBytes(msg);

        bool succeeded = Mailslot.WriteFile(_handle, bMessage,
             bMessage.Length, out bytesWritten, IntPtr.Zero);

        if (!succeeded || bMessage.Length != bytesWritten)
        {
            if (_handle != null) _handle.Close();
            _handle = null;

            throw new Win32Exception();
        }
    }
    public void Dispose()
    {
        if (_handle != null)
        {
            _handle.Close();
            _handle = null;
        }
    }

    private void CreateHandle()
    {
        _handle = Mailslot.CreateFile(
            @"\\" + _machine + @"\mailslot\" + _name,
            Mailslot.FileDesiredAccess.GenericWrite,
            Mailslot.FileShareMode.FileShareRead,
            IntPtr.Zero,
            Mailslot.FileCreationDisposition.OpenExisting,
            0,
            IntPtr.Zero);

        if (_handle.IsInvalid) throw new Win32Exception();

    }
}

Open in new window

Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
ASKER CERTIFIED SOLUTION
ste5an

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
Bryon Czaja

ASKER
Hello ste5an,
That was the problem. I cannot believe that was it. Now, I can communicate between applications, and verified it with the old code base.
Thank you for the help!