319 lines
9.9 KiB
C#
319 lines
9.9 KiB
C#
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<MemoryChunk> buffers = new Queue<MemoryChunk>();
|
|
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<IAddin, IAddinMetadata> Addin;
|
|
|
|
public Channel(RDPClient client, Lazy<IAddin, IAddinMetadata> 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<MenuItem>().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<MenuItem>().ToArray());
|
|
Client.MainForm.mnuAddinsContext.MenuItems.Add(parentmenu);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|