using System; using System.Text; using System.Runtime.InteropServices; using System.Threading; using System.Security; using System.Security.Permissions; using System.Runtime.ConstrainedExecution; using Microsoft.Win32.SafeHandles; using System.ComponentModel; namespace MailSlot { public delegate void MailSlotClientError(string message); class MailSlotClient { public event MailSlotClientError OnError; private SafeMailslotHandle hMailslot; private Encoding encoding; public MailSlotClient() { this.hMailslot = null; encoding = Encoding.Default; } public void Send(string Host, string MailslotName, string message) { if (this.hMailslot != null) { this.hMailslot.Close(); this.hMailslot = null; } try { // Try to open the mailslot with the write access. this.hMailslot = NativeMethod.CreateFile( @"\\" + Host + @"\mailslot\" + MailslotName, // The name of the mailslot FileDesiredAccess.GENERIC_WRITE, // Write access FileShareMode.FILE_SHARE_READ, // Share mode IntPtr.Zero, // Default security attributes FileCreationDisposition.OPEN_EXISTING, // Opens existing mailslot 0, // No other attributes set IntPtr.Zero // No template file ); if (this.hMailslot.IsInvalid) { if (OnError != null) OnError("Unable to open the mailslot."); else throw new Win32Exception(); } else { // Write messages to the mailslot. // Append '\0' at the end of each message considering the native C++ // Mailslot server (CppMailslotServer). WriteMailslot(this.hMailslot, message);// + "\0"); } } catch (Win32Exception ex) { if (OnError != null) OnError("The server throws the error: " + ex.Message); } finally { if (this.hMailslot != null) { this.hMailslot.Close(); this.hMailslot = null; } } } /// /// Encoding property /// public Encoding Encoding { set { this.encoding = value; } get { return this.encoding; } } /// /// Write a message to the specified mailslot /// /// Handle to the mailslot /// The message to be written to the slot private void WriteMailslot(SafeMailslotHandle hMailslot, string message) { int cbMessageBytes = 0; // Message size in bytes int cbBytesWritten = 0; // Number of bytes written to the slot byte[] bMessage = this.encoding.GetBytes(message); cbMessageBytes = bMessage.Length; bool succeeded = NativeMethod.WriteFile( hMailslot, // Handle to the mailslot bMessage, // Message to be written cbMessageBytes, // Number of bytes to write out cbBytesWritten, // Number of bytes written IntPtr.Zero // Not overlapped ); if (!succeeded || cbMessageBytes != cbBytesWritten) { if (OnError != null) OnError("WriteFile failed: " + Marshal.GetLastWin32Error()); } } #region Native API Signatures and Types /// /// Desired Access of File/Device /// [Flags] internal enum FileDesiredAccess : uint { GENERIC_READ = 0x80000000, GENERIC_WRITE = 0x40000000, GENERIC_EXECUTE = 0x20000000, GENERIC_ALL = 0x10000000 } /// /// File share mode /// [Flags] internal enum FileShareMode : uint { Zero = 0x00000000, // No sharing FILE_SHARE_DELETE = 0x00000004, FILE_SHARE_READ = 0x00000001, FILE_SHARE_WRITE = 0x00000002 } /// /// File Creation Disposition /// internal enum FileCreationDisposition : uint { CREATE_NEW = 1, CREATE_ALWAYS = 2, OPEN_EXISTING = 3, OPEN_ALWAYS = 4, TRUNCATE_EXISTING = 5 } /// /// Represents a wrapper class for a mailslot handle. /// [SecurityCritical(SecurityCriticalScope.Everything), HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true), SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internal 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); } } /// /// The class exposes Windows APIs to be used in this code sample. /// [SuppressUnmanagedCodeSecurity] internal class NativeMethod { /// /// Creates or opens a file, directory, physical disk, volume, console /// buffer, tape drive, communications resource, mailslot, or named pipe. /// /// /// The name of the file or device to be created or opened. /// /// /// The requested access to the file or device, which can be summarized /// as read, write, both or neither (zero). /// /// /// The requested sharing mode of the file or device, which can be read, /// write, both, delete, all of these, or none (refer to the following /// table). /// /// /// A SECURITY_ATTRIBUTES object that contains two separate but related /// data members: an optional security descriptor, and a Boolean value /// that determines whether the returned handle can be inherited by /// child processes. /// /// /// An action to take on a file or device that exists or does not exist. /// /// /// The file or device attributes and flags. /// /// Handle to a template file. /// /// If the function succeeds, the return value is an open handle to the /// specified file, device, named pipe, or mail slot. /// If the function fails, the return value is an invalid handle. /// [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); /// /// Writes data to the specified file or input/output (I/O) device. /// /// /// A handle to the file or I/O device (for example, a file, file stream, /// physical disk, volume, console buffer, tape drive, socket, /// communications resource, mailslot, or pipe). /// /// /// A buffer containing the data to be written to the file or device. /// /// /// The number of bytes to be written to the file or device. /// /// /// The number of bytes written when using a synchronous IO. /// /// /// A pointer to an OVERLAPPED structure is required if the file was /// opened with FILE_FLAG_OVERLAPPED. /// /// /// If the function succeeds, the return value is true. If the function /// fails, or is completing asynchronously, the return value is false. /// [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); } #endregion } }