322 lines
12 KiB
C#
322 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Yaulw.Win32
|
|
{
|
|
/// <remarks>
|
|
/// Quick and Easy Atom Window Messages Communication between windows of different
|
|
/// Processes.
|
|
/// </remarks>
|
|
public class AtomMessenger : IDisposable
|
|
{
|
|
#region Private Members
|
|
private const string _AtomMsgIDFormat = "AtomMsgID-[{0}]";
|
|
private string _AtomMsgStr = "";
|
|
private uint _AtomMsg = 0;
|
|
private bool _disposed = false;
|
|
|
|
// For Posted Atom Messages
|
|
private const int MAGIC_NUMBER_POSTED_ATOM_KEYS = 7;
|
|
private List<uint> _postedAtomKeys = new List<uint>();
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
/// <summary>
|
|
/// Create an Atom Messaging Component with a Unique Identifier.
|
|
/// The same Identifier should be used by all applications that want to pass
|
|
/// Messages back and forth.
|
|
/// ~You need to dispose of this Object only if you plan on using PostAtomMessage()
|
|
/// </summary>
|
|
/// <param name="UniqueWindowMessageIdentifier">An identifier for the Messaging</param>
|
|
public AtomMessenger(Guid UniqueWindowMessageIdentifier)
|
|
{
|
|
if (UniqueWindowMessageIdentifier == null)
|
|
throw new ArgumentNullException();
|
|
|
|
// Register the Unique Window Message
|
|
_AtomMsgStr = String.Format(_AtomMsgIDFormat, UniqueWindowMessageIdentifier);
|
|
_AtomMsg = User32.RegisterWindowMessage(_AtomMsgStr);
|
|
if (_AtomMsg == 0)
|
|
throw new Exception("RegisterWindowMessage Failed");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finalizer
|
|
/// </summary>
|
|
~AtomMessenger()
|
|
{
|
|
Dispose(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Atom Message Construction Helpers
|
|
|
|
/// <summary>
|
|
/// Retrieve ';' seperated values from an Atom Message
|
|
/// </summary>
|
|
/// <param name="AtomMessage">an atom message that contains multiple args</param>
|
|
/// <returns>multiple args</returns>
|
|
public string[] RetrieveMultipleValuesFromAtomMessage(string AtomMessage)
|
|
{
|
|
if (!String.IsNullOrEmpty(AtomMessage))
|
|
return AtomMessage.Split(';');
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create ';' seperated Atom message from multiple values
|
|
/// </summary>
|
|
/// <returns>an Atom Message containing multiple args</returns>
|
|
public string SetMultipleValueInAtomMessage(params object[] args)
|
|
{
|
|
if (args != null)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
foreach (object a in args)
|
|
{
|
|
sb.Append(a.ToString());
|
|
sb.Append(";");
|
|
}
|
|
|
|
// Remove Trailing ";"
|
|
sb = sb.Remove(sb.Length - 1, 1);
|
|
return sb.ToString();
|
|
}
|
|
return String.Empty;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Atom Message Identify / Retrieval
|
|
|
|
/// <summary>
|
|
/// Use this to check if the passed in Message is an Atom Message.
|
|
/// The identifier of the Message must match the Message registered with the UniqueIdentifier
|
|
/// </summary>
|
|
/// <param name="m">a Windows.Forms Message</param>
|
|
/// <returns>true if the Messages matches the one created by the UniqueIdentifier</returns>
|
|
public bool IsAtomMessage(ref Message m)
|
|
{
|
|
return (m.Msg == _AtomMsg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the values passed in by an Atom Message
|
|
/// </summary>
|
|
/// <param name="m">a Windows.Forms Message</param>
|
|
/// <param name="AtomMessage">the Message Retrieved from the Atom</param>
|
|
/// <param name="hWndSrc">the source window who send it, if valid</param>
|
|
public void GetAtomMessageValues(ref Message m, out string AtomMessage, out IntPtr hWndSrc)
|
|
{
|
|
AtomMessage = String.Empty;
|
|
hWndSrc = IntPtr.Zero;
|
|
|
|
// Check to make sure this is an Atom Message
|
|
if (!IsAtomMessage(ref m))
|
|
return;
|
|
|
|
// Source is passed to us by wParam
|
|
if(m.WParam != IntPtr.Zero && User32.IsWindow(m.WParam))
|
|
hWndSrc = m.WParam;
|
|
|
|
// Now retrieve the Atom Message
|
|
StringBuilder sb = new StringBuilder( 254 );
|
|
uint AtomKey = (uint) m.LParam;
|
|
uint slen = Kernel32.GlobalGetAtomName(AtomKey, sb, 254);
|
|
if (slen == 0)
|
|
return;
|
|
|
|
// Write out Retrieved Message
|
|
AtomMessage = sb.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the values passed in by an Atom Message
|
|
/// </summary>
|
|
/// <param name="m">a Windows.Forms Message</param>
|
|
/// <param name="AtomMessage">the Message with multiple values retrieved from the Atom</param>
|
|
/// <param name="hWndSrc">the source window who send it, if valid</param>
|
|
public void GetAtomMessageValues(ref Message m, out string[] AtomMessage, out IntPtr hWndSrc)
|
|
{
|
|
AtomMessage = null;
|
|
hWndSrc = IntPtr.Zero;
|
|
|
|
// Check to make sure this is an Atom Message
|
|
if (!IsAtomMessage(ref m))
|
|
return;
|
|
|
|
// Source is passed to us by wParam
|
|
if (m.WParam != IntPtr.Zero && User32.IsWindow(m.WParam))
|
|
hWndSrc = m.WParam;
|
|
|
|
// Now retrieve the Atom Message
|
|
StringBuilder sb = new StringBuilder(254);
|
|
uint AtomKey = (uint)m.LParam;
|
|
uint slen = Kernel32.GlobalGetAtomName(AtomKey, sb, 254);
|
|
if (slen == 0)
|
|
return;
|
|
|
|
// Write out Retrieved Message
|
|
AtomMessage = RetrieveMultipleValuesFromAtomMessage(sb.ToString());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Send/Post Atom Message
|
|
|
|
/// <summary>
|
|
/// Sends an Atom Message To the Specified Window or All Windows
|
|
/// </summary>
|
|
/// <param name="hWndSrc">Sender Windows (Nice to have), in case Receiver Needs it</param>
|
|
/// <param name="hWndDst">Can be IntPtr.Zero to BroadCast the Message, otherwise specify window to send to</param>
|
|
/// <param name="AtomMessage">The Message to Send * Can not be longer than 254 chars *</param>
|
|
public void SendAtomMessage(IntPtr hWndSrc, IntPtr hWndDst, string AtomMessage)
|
|
{
|
|
// Is Broadcast?
|
|
bool bBroadcast = (hWndDst==IntPtr.Zero);
|
|
|
|
// Check to make sure Atom Message is proper
|
|
if(String.IsNullOrEmpty(AtomMessage) || AtomMessage.Length > 254)
|
|
throw new ArgumentException("AtomMessage Invalid");
|
|
|
|
// Register Atom
|
|
uint AtomKey = Kernel32.GlobalAddAtom(AtomMessage);
|
|
if (AtomKey == 0)
|
|
throw new Exception("GlobalAddAtom Failed");
|
|
|
|
// Send the Message
|
|
if(bBroadcast)
|
|
User32.SendMessage(Definitions.HWND_BROADCAST, (int)_AtomMsg, hWndSrc, (IntPtr)AtomKey);
|
|
else
|
|
User32.SendMessage(hWndDst, (int)_AtomMsg, hWndSrc, (IntPtr)AtomKey);
|
|
|
|
// We are done with the Atom
|
|
Kernel32.GlobalDeleteAtom(AtomKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends an Atom Message To the Specified Window or All Windows
|
|
/// </summary>
|
|
/// <param name="hWndSrc">Sender Windows (Nice to have), in case Receiver Needs it</param>
|
|
/// <param name="hWndDst">Can be IntPtr.Zero to BroadCast the Message, otherwise specify window to send to</param>
|
|
/// <param name="AtomMessage">The Message to Send that has multiple values * Total string can not be longer than 254 chars *</param>
|
|
public void SendAtomMessage(IntPtr hWndSrc, IntPtr hWndDst, string[] AtomMessage)
|
|
{
|
|
SendAtomMessage(hWndSrc, hWndDst, SetMultipleValueInAtomMessage(AtomMessage));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Post an Atom Message To the Specified Window or All Windows
|
|
/// </summary>
|
|
/// <param name="hWndSrc">Sender Windows (Nice to have), in case Receiver Needs it</param>
|
|
/// <param name="hWndDst">Can be IntPtr.Zero to BroadCast the Message, otherwise specify window to send to</param>
|
|
/// <param name="AtomMessage">The Message to Send * Can not be longer than 254 chars *</param>
|
|
public void PostAtomMessage(IntPtr hWndSrc, IntPtr hWndDst, string AtomMessage)
|
|
{
|
|
// Is Broadcast?
|
|
bool bBroadcast = (hWndDst == IntPtr.Zero);
|
|
|
|
// Check to make sure Atom Message is proper
|
|
if (String.IsNullOrEmpty(AtomMessage) || AtomMessage.Length > 254)
|
|
throw new ArgumentException("AtomMessage Invalid");
|
|
|
|
// Register a new Atom
|
|
uint nAtomKey = Kernel32.GlobalAddAtom(AtomMessage);
|
|
if (nAtomKey == 0)
|
|
throw new Exception("GlobalAddAtom Failed");
|
|
|
|
// Send the Message
|
|
if (bBroadcast)
|
|
User32.PostMessage(Definitions.HWND_BROADCAST, (int)_AtomMsg, hWndSrc, (IntPtr)nAtomKey);
|
|
else
|
|
User32.PostMessage(hWndDst, (int)_AtomMsg, hWndSrc, (IntPtr)nAtomKey);
|
|
|
|
// Imp! Atom still must get Deleted, that is why we add it to DS
|
|
AddPostedAtomKey(nAtomKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Post an Atom Message To the Specified Window or All Windows
|
|
/// </summary>
|
|
/// <param name="hWndSrc">Sender Windows (Nice to have), in case Receiver Needs it</param>
|
|
/// <param name="hWndDst">Can be IntPtr.Zero to BroadCast the Message, otherwise specify window to send to</param>
|
|
/// <param name="AtomMessage">The Message to Send that has multiple values * Can not be longer than 254 chars *</param>
|
|
public void PostAtomMessage(IntPtr hWndSrc, IntPtr hWndDst, string[] AtomMessage)
|
|
{
|
|
PostAtomMessage(hWndSrc, hWndDst, SetMultipleValueInAtomMessage(AtomMessage));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Posted Atom Keys handling
|
|
|
|
/// <summary>
|
|
/// Adds the Specified Posted Atom Key to the Posted Atoms DS.
|
|
/// Clears the DS, if MAGIC_NUMBER_POSTED_ATOM_KEY has been reached.
|
|
/// </summary>
|
|
/// <param name="nKey">a unique AtomKey</param>
|
|
private void AddPostedAtomKey(uint nKey)
|
|
{
|
|
if (_postedAtomKeys.Count >= MAGIC_NUMBER_POSTED_ATOM_KEYS)
|
|
DeleteAllPostedAtomKeys();
|
|
|
|
_postedAtomKeys.Add(nKey);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes all posted Atoms and Clears the PostedAtoms DS
|
|
/// </summary>
|
|
private void DeleteAllPostedAtomKeys()
|
|
{
|
|
foreach (uint Key in _postedAtomKeys)
|
|
Kernel32.GlobalDeleteAtom(Key);
|
|
|
|
_postedAtomKeys.Clear();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
/// <summary>
|
|
/// Dispose Posted Atom Strings
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
|
|
// Use SupressFinalize in case a subclass
|
|
// of this type implements a finalizer
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispose Posted Atom Strings
|
|
/// </summary>
|
|
/// <param name="disposing">true, if called from within</param>
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (_postedAtomKeys.Count != 0)
|
|
DeleteAllPostedAtomKeys();
|
|
}
|
|
|
|
// Indicate that the instance has been disposed.
|
|
_postedAtomKeys = null;
|
|
_disposed = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|