using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using System.Drawing; using Win32.WtsApi32; using System.Threading; using System.ComponentModel; using RDPAddins.Common; namespace RDPAddins { internal class Channel: IChannel, IUI { uint openChannel = 0; ChannelOpenEventDelegate channelOpenEventDelegate; ManualResetEvent write = new ManualResetEvent(true); internal object tooltipconext = null; Queue buffers = new Queue(); object readlock = new object(); public event EventHandler Connected; public event EventHandler Disconnected; public event EventHandler Terminated; public event DataArrivedHandler DataArrived; public event BalloonTipClickedHandler BalloonTipClicked; public Lazy Addin; public Channel(RDPClient client, Lazy addin) { Client = client; Addin = addin; Addin.Value.Initialize(this); ChannelDef = new ChannelDef(){name = Metadata.ChannelName, options = Metadata.ChannelOptions }; channelOpenEventDelegate = new ChannelOpenEventDelegate(VirtualChannelOpenEvent); } internal ChannelDef ChannelDef; public IChannel Parent { get { return this; } } public bool Visible { get { if (Page != null) return TabCtrl.TabPages.Contains(Page); return false; } set { if (Page != null) { if (value) { if (!TabCtrl.TabPages.Contains(Page)) TabCtrl.TabPages.Add(Page); } else { if (TabCtrl.TabPages.Contains(Page)) TabCtrl.TabPages.Remove(Page); } } } } private void VirtualChannelOpenEvent(uint openHandle, ChannelEvents openEvent, byte[] data, uint dataLength, uint totalLength, ChannelFlags dataFlags) { switch (openEvent) { case ChannelEvents.DataRecived: int flag = (int)(dataFlags & ChannelFlags.Only); WriteCore(data, dataLength); OnDataArrived(dataLength, totalLength, (DataParts)flag); break; case ChannelEvents.WriteComplete: write.Set(); break; } } void WriteCore(byte[] data, uint count) { var mem = AllocateMemoryChunk(count); Buffer.BlockCopy(data, 0, mem.Buffer, 0, (int)count); lock (readlock) { buffers.Enqueue(mem); AvailableDataLength += count; } } public void Write(byte[] data, int offset, int count) { byte[] buff = data; if (offset != 0) { buff = new byte[count]; Buffer.BlockCopy(data, offset, buff, 0, count); } write.Reset(); ChannelReturnCodes ret = Client.EntryPoint.VirtualChannelWrite(openChannel, buff, (uint)count, IntPtr.Zero); write.WaitOne(); } public int Read(byte[] buffer, int offset, int count) { if (AvailableDataLength > 0) { int toread = 0; lock (readlock) { if (buffers.Count != 0) { var buf = buffers.Peek(); toread = buf.Buffer.Length - buf.Offset; int off = buf.Offset; if (count >= toread) buffers.Dequeue(); else { toread = count; buf.Offset += toread; } Buffer.BlockCopy(buf.Buffer, off, buffer, offset, toread); AvailableDataLength -= (uint)toread; } return toread; } } return 0; } TabPage Page = null; TabControl TabCtrl = null; RDPClient Client = null; public uint AvailableDataLength { get; private set; } internal ChannelReturnCodes ConnectedInternal(IntPtr Handle) { ChannelReturnCodes ret = Client.EntryPoint.VirtualChannelOpen(Handle, ref openChannel, Addin.Metadata.ChannelName, channelOpenEventDelegate); if (ret == ChannelReturnCodes.Ok) OnConnected(this, new EventArgs()); return ret; } internal void DisconnectedInternal() { openChannel = 0; OnDisconnected(this, new EventArgs()); if (Stream != null) { Stream.Dispose(); Stream = null; } } protected virtual void OnConnected(object sender, EventArgs e) { if (Connected != null) DoOnUIThread(() => Connected(sender, e)); } protected virtual void OnDisconnected(object sender, EventArgs e) { if (Disconnected != null) DoOnUIThread(() => Disconnected(sender, e)); } protected virtual void OnTerminated(object sender, EventArgs e) { if (Terminated != null) DoOnUIThread(() => Terminated(sender, e)); } internal void TerminatedInternal() { OnTerminated(this, new EventArgs()); } protected virtual void OnInitialized(object sender, EventArgs e) { if (Initialized != null) DoOnUIThread(() => Initialized(sender, e)); } internal void InitializedInternal() { OnInitialized(this, new EventArgs()); } public void ShowControl() { if (Page != null) { Client.MainForm.Visible = true; Client.MainForm.Tab.SelectTab(Page); } } public void DoOnUIThread(Action action) { if (Client.MainForm.InvokeRequired) Client.MainForm.Invoke(action); else action(); } public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon, object context) { tooltipconext = context; Client.MainForm.ShowToolTip(timeout, tipTitle, tipText, tipIcon, this); } protected virtual void OnDataArrived(uint dataLength, uint totalLength, DataParts dataFlags) { if (DataArrived != null) DoOnUIThread(() => DataArrived(dataLength, totalLength, dataFlags)); } internal protected virtual void OnBalloonTipClicked(object sender, EventArgs e) { if (BalloonTipClicked != null) DoOnUIThread(() => BalloonTipClicked(this, tooltipconext)); } private MemoryChunk AllocateMemoryChunk(uint newSize) { MemoryChunk chunk = new MemoryChunk(newSize); return chunk; } ChannelStream Stream = null; private class MemoryChunk { internal byte[] Buffer; internal int Offset = 0; internal MemoryChunk(uint bufferSize) { Buffer = new byte[bufferSize]; Offset = 0; } } public event EventHandler Initialized; public Stream GetStream() { Stream = Stream ?? new ChannelStream(this); return Stream; } public IAddinMetadata Metadata { get { return Addin.Metadata; } } public IUI UI { get { return this; } } public event ControlCreatingHandler ControlCreating; public event MenuCreatingHandler MenuCreating; public event MenuCreatingHandler TrayMenuCreating; public event IconCreatingHandler IconCreating; internal void CreateUI() { if (ControlCreating != null) { var control = ControlCreating(this); if (control != null) { Page = new TabPage(Metadata.AddinName); TabCtrl = Page.Parent as TabControl; control.Dock = DockStyle.Fill; Page.Controls.Add(control); Client.MainForm.Tab.TabPages.Add(Page); Image icon = null; if (IconCreating != null) icon = IconCreating(this); Page.ImageIndex = Client.MainForm.AddImage(icon); } } if (MenuCreating != null) { var menu = MenuCreating(this); if (menu != null) { var parentmenu = new MenuItem(Metadata.AddinName); parentmenu.MenuItems.AddRange(menu.MenuItems.Cast().ToArray()); Client.MainForm.MenuAddins.MenuItems.Add(parentmenu); } } if (TrayMenuCreating != null) { var menu = TrayMenuCreating(this); if (menu != null) { var parentmenu = new MenuItem(Metadata.AddinName); parentmenu.MenuItems.AddRange(menu.MenuItems.Cast().ToArray()); Client.MainForm.mnuAddinsContext.MenuItems.Add(parentmenu); } } } } }