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
}
}