/// <summary> /// Override for a form's Window Procedure to handle WM_COPYDATA /// messages sent by other instances of this class. /// </summary> /// <param name="m">The Windows Message information.</param> protected override void WndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_COPYDATA) { COPYDATASTRUCT cds = new COPYDATASTRUCT(); cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT)); if (cds.cbData > 0) { byte[] data = new byte[cds.cbData]; Marshal.Copy(cds.lpData, data, 0, cds.cbData); MemoryStream stream = new MemoryStream(data); BinaryFormatter b = new BinaryFormatter(); CopyDataObjectData cdo = (CopyDataObjectData)b.Deserialize(stream); if (channels.Contains(cdo.Channel)) { DataReceivedEventArgs d = new DataReceivedEventArgs(cdo.Channel, cdo.Data, cdo.Sent); OnDataReceived(d); m.Result = (IntPtr)1; } } } else if (m.Msg == WM_DESTROY) { // WM_DESTROY fires before OnHandleChanged and is // a better place to ensure that we've cleared // everything up. channels.OnHandleChange(); base.OnHandleChange(); } base.WndProc(ref m); }
/// <summary> /// Sends the specified object on this channel to any other /// applications which are listening. The object must have the /// SerializableAttribute set, or must implement ISerializable. /// </summary> /// <param name="obj">The object to send</param> /// <returns>The number of recipients</returns> public int Send(object obj) { int recipients = 0; if (disposed) { throw new InvalidOperationException("Object has been disposed"); } if (recreateChannel) // handle has changed { addChannel(); } CopyDataObjectData cdo = new CopyDataObjectData(obj, channelName); // Try to do a binary serialization on obj. // This will throw and exception if the object to // be passed isn't serializable. BinaryFormatter b = new BinaryFormatter(); MemoryStream stream = new MemoryStream(); b.Serialize(stream, cdo); stream.Flush(); // Now move the data into a pointer so we can send // it using WM_COPYDATA: // Get the length of the data: int dataSize = (int)stream.Length; if (dataSize > 0) { // This isn't very efficient if your data is very large. // First we copy to a byte array, then copy to a CoTask // Mem object... And when we use WM_COPYDATA windows will // make yet another copy! But if you're talking about 4K // or less of data then it doesn't really matter. byte[] data = new byte[dataSize]; stream.Seek(0, SeekOrigin.Begin); stream.Read(data, 0, dataSize); IntPtr ptrData = Marshal.AllocCoTaskMem(dataSize); Marshal.Copy(data, 0, ptrData, dataSize); // Enumerate all windows which have the // channel name, send the data to each one EnumWindows ew = new EnumWindows(); ew.GetWindows(); // Send the data to each window identified on // the channel: foreach (EnumWindowsItem window in ew.Items) { if (!window.Handle.Equals(this.owner.Handle)) { if (GetProp(window.Handle, this.channelName) != 0) { COPYDATASTRUCT cds = new COPYDATASTRUCT(); cds.cbData = dataSize; cds.dwData = IntPtr.Zero; cds.lpData = ptrData; int res = SendMessage(window.Handle, WM_COPYDATA, (int)owner.Handle, ref cds); recipients += (Marshal.GetLastWin32Error() == 0 ? 1 : 0); } } } // Clear up the data: Marshal.FreeCoTaskMem(ptrData); } stream.Close(); return(recipients); }