📄 conn.cs
字号:
internal void Run(ViewOpts viewOpts)
{
this.viewOpts = viewOpts;
Run();
}
internal void Run(ConnOpts opts)
{
this.opts = opts;
Run();
}
internal void Run()
{
try
{
// Get connection details from the user.
if(opts == null)
GetConnDetails();
// Establish a network (not VNC) connection with the connection manager.
EstNetworkConn();
// Make a connection to the server.
if(opts.ConnMode == ConnMode.Active)
Connect();
else
Listen();
// Negotiate the protocol version with the server.
NegoProtoVer();
// Authenticate the user.
Auth();
// Send client initialization message.
SendCliInit();
// Read server initialization message.
ReadServInit();
SetPixelFormat();
SetEncodings();
// Create a display locally.
CreateDisp();
// Logically speaking I should send this AFTER sending a refresh request with the
// default width and height. But for some strange reason it does not work on the
// emulator (real devices work fine). I have to send this before the first refresh
// request.
// In addition, a refresh request must be sent here. If we wait until a resize frame
// buffer message, we will wait forever.
if(opts.ViewOpts.ServScaling != ServScaling.Default)
SendSetScale((byte)opts.ViewOpts.ServScaling);
// Ask the server to send us the entire screen.
SendUpdReq(0, 0, frameBufWidth, frameBufHeight, false);
termBgThread = false;
(new Thread(new ThreadStart(Start))).Start();
App.AddConn(this);
}
catch(IOException)
{
CleanUp();
MessageBox.Show(App.GetStr("Unable to communicate with the server!"),
App.GetStr("Error"),
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
catch(QuietEx)
{
CleanUp();
}
catch(WarnEx ex)
{
CleanUp();
MessageBox.Show(ex.Message,
App.GetStr("Error"),
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
}
}
private void SendUpdReq(UInt16 x, UInt16 y, UInt16 width, UInt16 height, bool incremental)
{
byte[] msg = RfbProtoUtil.GetFrameBufUpdReqMsg(x, y, width, height, incremental);
WriteBytes(msg, RfbCliMsgType.FrameBufUpdReq);
}
internal void SendSetScale(byte scale)
{
byte[] msg = RfbProtoUtil.GetSetScaleMsg(scale);
WriteBytes(msg, RfbCliMsgType.SetScale);
}
private Color GetColorFromData(byte[] data, UInt32 offset)
{
return GetColorFromPixel(RfbProtoUtil.GetPixelFromData(data, offset, bytesPp));
}
private Color GetColorFromPixel(UInt32 pixel)
{
int red = (int)((pixel >> redShift) & redMax) * 255 / redMax;
int green = (int)((pixel >> greenShift) & greenMax) * 255 / greenMax;
int blue = (int)((pixel >> blueShift) & blueMax) * 255 / blueMax;
return Color.FromArgb(red, green, blue);
}
private void ReadRawRect(Rectangle rect)
{
byte[] rectBytes = ReadBytes(rect.Width * rect.Height * bytesPp);
view.LockFrameBuf();
try
{
// TODO: Anything faster?
int curPos = 0;
for(int i = 0; i < rect.Height; i++)
{
for(int j = 0; j < rect.Width; j++)
{
view[(UInt16)(rect.X + j), (UInt16)(rect.Y + i)] = GetColorFromData(rectBytes, (UInt32)curPos);
curPos += bytesPp;
}
}
}
catch(OverflowException)
{
// Swallow this exception. For some strange reason UltraVNC sends X and Y > 65K.
}
catch(ArgumentException)
{
// Swallow this exception. For some strange reason UltraVNC sends invalid values.
}
view.UnlockFrameBuf();
}
private void ReadCopyRect(Rectangle rect)
{
byte[] rectBytes = ReadBytes(RfbSize.CopyRect);
CopyRectMsg srcRect = new CopyRectMsg(rectBytes);
view.LockFrameBuf();
view.CopyRect(rect, srcRect.X, srcRect.Y);
view.UnlockFrameBuf();
}
private void FillRreRect(Rectangle rect, Color bgColor, RreSubRectMsg[] subRects)
{
view.LockFrameBuf();
view.FillRect(rect, bgColor);
for(int i = 0; i < subRects.Length; i++)
{
Rectangle subRect = new Rectangle();
subRect.X = rect.X + subRects[i].X;
subRect.Y = rect.Y + subRects[i].Y;
subRect.Width = subRects[i].Width;
subRect.Height = subRects[i].Height;
view.FillRect(subRect, GetColorFromPixel(subRects[i].Pixel));
}
view.UnlockFrameBuf();
}
private void ReadRreRectCore(Rectangle rect, bool isCompact)
{
UInt32 numSubRects = ReadUInt32();
byte[] data = ReadBytes(bytesPp);
Color bgColor = GetColorFromData(data, 0);
int subRectSize = bytesPp;
if(isCompact)
subRectSize += RfbSize.CoRreSubRect;
else
subRectSize += RfbSize.RreSubRect;
RreSubRectMsg[] subRects = new RreSubRectMsg[numSubRects];
for(int i = 0; i < numSubRects; i++)
{
byte[] rectBytes = ReadBytes(subRectSize);
subRects[i] = new RreSubRectMsg(rectBytes, bytesPp, isCompact);
}
FillRreRect(rect, bgColor, subRects);
}
private void ReadRreRect(Rectangle rect)
{
ReadRreRectCore(rect, false);
}
private void ReadCoRreRect(Rectangle rect)
{
ReadRreRectCore(rect, true);
}
private void ReadHexRect(Rectangle rect)
{
Color bgColor = App.Black;
UInt32 fgPixel = 0;
Rectangle tile = new Rectangle();
for(tile.Y = rect.Y; tile.Y < rect.Bottom; tile.Y += 16)
{
for(tile.X = rect.X; tile.X < rect.Right; tile.X += 16)
{
tile.Width = 16;
tile.Height = 16;
tile.Width = Math.Min(tile.Right, rect.Right) - tile.Left;
tile.Height = Math.Min(tile.Bottom, rect.Bottom) - tile.Top;
RfbHexSubEncoding encoding = (RfbHexSubEncoding)ReadByte();
if((encoding & RfbHexSubEncoding.Raw) != 0)
{
ReadRawRect(tile);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(tile);
continue;
}
byte[] data;
if((encoding & RfbHexSubEncoding.BgSpec) != 0)
{
data = ReadBytes(bytesPp);
bgColor = GetColorFromData(data, 0);
}
if((encoding & RfbHexSubEncoding.FgSpec) != 0)
{
data = ReadBytes(bytesPp);
fgPixel = RfbProtoUtil.GetPixelFromData(data, 0, bytesPp);
}
byte numSubRects = 0;
if((encoding & RfbHexSubEncoding.AnySubRects) != 0)
numSubRects = ReadByte();
bool subRectsColored = ((encoding & RfbHexSubEncoding.SubRectsColored) != 0);
int subRectSize = RfbSize.HexSubRect;
subRectSize += subRectsColored? (int)bytesPp : 0;
RreSubRectMsg[] subRects = new RreSubRectMsg[numSubRects];
byte[] rectBytes = ReadBytes(subRectSize * numSubRects);
for(int i = 0; i < numSubRects; i++)
subRects[i] = new HexSubRectMsg(rectBytes, (UInt32)(i * subRectSize), bytesPp, subRectsColored, fgPixel);
FillRreRect(tile, bgColor, subRects);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(tile);
}
}
}
internal void SendUpdReq(bool incremental)
{
if(IsFmtChgPending)
{
IsFmtChgPending = false;
SetPixelFormat();
SendUpdReq(0, 0, frameBufWidth, frameBufHeight, false);
}
else
SendUpdReq(0, 0, frameBufWidth, frameBufHeight, incremental);
}
private void ReadScrnUpd()
{
byte[] msg = ReadBytes(RfbSize.FrameBufUpd - 1);
UInt16 numRects = RfbProtoUtil.GetNumRectsFromFrameBufUpdMsg(msg);
for(int i = 0; i < numRects; i++)
{
msg = ReadBytes(RfbSize.FrameBufUpdRectHdr);
FrameBufUpdRectMsgHdr frameBufUpdRectHdr = new FrameBufUpdRectMsgHdr(msg);
Rectangle rect = new Rectangle(frameBufUpdRectHdr.X, frameBufUpdRectHdr.Y, frameBufUpdRectHdr.Width, frameBufUpdRectHdr.Height);
if(frameBufUpdRectHdr.Encoding == RfbEncoding.NewFBSize)
{
frameBufWidth = (UInt16)rect.Width;
frameBufHeight = (UInt16)rect.Height;
if(!termBgThread)
view.NewFrameBuf(frameBufWidth, frameBufHeight);
break;
}
switch(frameBufUpdRectHdr.Encoding)
{
case RfbEncoding.Raw:
ReadRawRect(rect);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(rect);
break;
case RfbEncoding.CopyRect:
ReadCopyRect(rect);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(rect);
break;
case RfbEncoding.Rre:
ReadRreRect(rect);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(rect);
break;
case RfbEncoding.CoRre:
ReadCoRreRect(rect);
if(opts.ViewOpts.ScrnUpdAlgo == ScrnUpdAlgo.Asap)
view.InvalidateRect(rect);
break;
case RfbEncoding.Hex:
ReadHexRect(rect);
break;
default:
throw new WarnEx(App.GetStr("Server is using unknown encoding!"));
}
}
if(opts.ViewOpts.ScrnUpdAlgo != ScrnUpdAlgo.Asap)
view.Invalidate();
// Do this in the UI thread so we always send data in one thread.
view.SendUpdReq();
}
private void ReadServCutTxt()
{
// .NET CF does not have built-in support for the clipboard.
// We ignore this message at the moment.
byte[] msg = ReadBytes(RfbSize.ServCutTxt - 1);
UInt32 len = RfbProtoUtil.GetLenFromServCutTxtMsg(msg);
string txt = ReadAsciiStr((int)len);
}
private void ReadResizeFrameBuf()
{
byte[] msg = ReadBytes(RfbSize.ResizeFrameBuf - 1);
ResizeFrameBufMsg resizeFrameBufMsg = new ResizeFrameBufMsg(msg);
frameBufWidth = resizeFrameBufMsg.Width;
frameBufHeight = resizeFrameBufMsg.Height;
// This call actually involves an Invoke, so we need to check termBgThread to make
// sure that it does not hang.
// TODO: Time to reorg the codebase...
if(!termBgThread)
view.ResizeFrameBuf(frameBufWidth, frameBufHeight);
}
/// <summary>
/// This is the entry point of the background thread that handles
/// server messages.
/// </summary>
private void Start()
{
// This is a background thread so the priority should be lower.
Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
try
{
while(!termBgThread)
{
// Yield to other threads so this thread does not dominate.
Thread.Sleep(App.Delta);
// Avoid the blocking ReadByte() if we have nothing to read.
if(!stream.DataAvailable)
continue;
RfbServMsgType msgType = (RfbServMsgType)ReadByte();
switch(msgType)
{
case RfbServMsgType.FrameBufUpd:
ReadScrnUpd();
break;
case RfbServMsgType.SetColorMapEntries:
throw new WarnEx(App.GetStr("The server is sending SetColorMapEntries!"));
case RfbServMsgType.Bell:
break;
case RfbServMsgType.ServCutTxt:
ReadServCutTxt();
break;
case RfbServMsgType.ResizeFrameBuf:
ReadResizeFrameBuf();
break;
default:
throw new WarnEx(App.GetStr("The server is sending unknown message!"));
}
}
}
catch(SocketException)
{
MessageBox.Show(App.GetStr("Unable to communicate with the server!"),
App.GetStr("Error"),
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
// If termBgThread is true then view has been closed.
// Don't Invoke or this thread will hang due to a .NET CF bug.
// Technically speaking there is a slight chance that the view closes before Invoke
// but after checking termBgThread, so this is not bullet proof.
if(!termBgThread)
view.Invoke(closeHdr);
}
catch(IOException)
{
MessageBox.Show(App.GetStr("Unable to communicate with the server!"),
App.GetStr("Error"),
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
if(!termBgThread)
view.Invoke(closeHdr);
}
catch(QuietEx)
{
if(!termBgThread)
view.Invoke(closeHdr);
}
catch(WarnEx ex)
{
MessageBox.Show(ex.Message,
App.GetStr("Error"),
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
if(!termBgThread)
view.Invoke(closeHdr);
}
finally
{
CleanUp();
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -