「
GDD Blog: [.NET]MailSlot(その2)」で掲載しましたMailSlot操作クラスですが、ReadFileで受信待機をします。そのため、
- 何かしら情報を受信しないと終わらない
- すべての受信が終わるまで、受信メッセージを取得する方法が無い
という問題がありました。そこで
- 待機ループし、終了フラグを監視する
- イベントを発行する機構を実装する
- IDisposableをインプリメント
することにしました。
以下、メールスロットを送受信するクラスです。
public class MailSlot : IDisposable
{
#region Win32 API宣言
[DllImport("kernel32.dll")]
static extern SafeFileHandle CreateMailslot(
string lpName,
uint nMaxMessageSize,
uint lReadTimeout,
IntPtr lpSecurityAttributes);
[DllImport("kernel32.dll")]
static extern bool GetMailslotInfo(
SafeFileHandle hMailslot,
ref uint lpMaxMessageSize,
ref uint lpNextSize,
ref uint lpMessageCount,
ref uint lpReadTimeout);
[DllImport("kernel32.dll")]
static extern bool SetMailslotInfo(
SafeFileHandle hMailslot,
uint lReadTimeout);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(SafeFileHandle hMailslot);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
DesiredAccess dwDesiredAccess,
ShareMode dwShareMode,
int lpSecurityAttributes,
CreationDisposition dwCreationDisposition,
FlagsAndAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
#endregion
#region 列挙体
private enum DesiredAccess : uint
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000
}
private enum ShareMode : uint
{
FILE_SHARE_READ = 0x00000001,
FILE_SHARE_WRITE = 0x00000002,
FILE_SHARE_DELETE = 0x00000004
}
private enum CreationDisposition : uint
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
private enum FlagsAndAttributes : uint
{
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
FILE_ATTRIBUTE_HIDDEN = 0x00000002,
FILE_ATTRIBUTE_NORMAL = 0x00000080,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTRIBUTE_OFFLINE = 0x00001000,
FILE_ATTRIBUTE_READONLY = 0x00000001,
FILE_ATTRIBUTE_SYSTEM = 0x00000004,
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
}
private enum MailSlotStatus : uint
{
MAILSLOT_NO_MESSAGE = 0xffffffff,
}
#endregion
public delegate void ReceiveEventHandler(object sender, ReceiveEventArgs e);
public event ReceiveEventHandler receive;
private SafeFileHandle slotHandle = null;
public SafeFileHandle SlotHandle
{
get { return slotHandle; }
set { slotHandle = value; }
}
private bool receiveLoop = true;
public bool ReceiveLoop
{
get { return receiveLoop; }
set { receiveLoop = value; }
}
public MailSlot()
{
}
public void Open(string slotName, uint maxMessageSize, uint readTimeout)
{
SlotHandle = CreateMailslot(slotName, maxMessageSize, readTimeout, (IntPtr)0);
}
public void Close()
{
lock (this)
{
if (SlotHandle != null)
{
CloseHandle(SlotHandle);
SlotHandle = null;
}
}
}
public void ReadMailSlot()
{
try
{
while (ReceiveLoop)
{
uint msgMaxCnt = 1;
uint nextSize = 0;
uint msgCnt = 0;
uint timeout = 0;
if (!GetMailslotInfo(SlotHandle, ref msgMaxCnt, ref nextSize, ref msgCnt, ref timeout))
{
System.Diagnostics.Debug.WriteLine("GetMailslotInfo失敗!!");
continue;
}
if (msgCnt > 0 && nextSize != (uint)MailSlotStatus.MAILSLOT_NO_MESSAGE)
{
FileStream fs = new FileStream(SlotHandle, FileAccess.Read);
byte[] buf = new byte[msgMaxCnt];
int len = fs.Read(buf, 0, buf.Length);
ReceiveEventArgs e = new ReceiveEventArgs(Encoding.UTF8.GetString(buf, 0, len));
OnReceive(e);
if (e.ReceiveEnd)
{
ReceiveLoop = false;
}
}
else
{
Thread.Sleep(500);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
protected virtual void OnReceive(ReceiveEventArgs e)
{
if (receive != null)
{
receive(this, e);
}
}
#region IDisposable メンバ
public void Dispose()
{
Close();
}
#endregion
public static void WriteMailSlot(string slot, string message)
{
try
{
SafeFileHandle fileHandle = CreateFile(slot,
DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE,
ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
0,
CreationDisposition.OPEN_EXISTING,
FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL,
(IntPtr)0);
using (FileStream fs = new FileStream(fileHandle, FileAccess.Write))
{
byte[] msg = Encoding.UTF8.GetBytes(message);
fs.Write(msg, 0, msg.Length);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
throw ex;
}
}
}
以下、受信イベントオブジェクトクラスです。
public class ReceiveEventArgs : EventArgs
{
private string message;
public string Message
{
get { return message; }
}
private bool receiveEnd = false;
public bool ReceiveEnd
{
get { return receiveEnd; }
set { receiveEnd = value; }
}
public ReceiveEventArgs(string msg)
{
message = msg;
}
}
使うほうはこんな感じ。
private void btnMLReceive2_Click(object sender, EventArgs e)
{
using (MailSlot slot = new MailSlot())
{
slot.receive += new MailSlot.ReceiveEventHandler(slot_receive2);
slot.Open(txtMQPath.Text, 512, 0xffff);
slot.ReadMailSlot();
slot.Close();
}
}
private void slot_receive2(object sender, ReceiveEventArgs e)
{
txtMQRecieve.AppendText(e.Message);
txtMQRecieve.AppendText(Environment.NewLine);
if (e.Message == "TERMINATE")
{
e.ReceiveEnd = true;
}
}