├── .gitignore ├── LICENSE ├── README.md ├── RemoteView.sln ├── RemoteView ├── App.config ├── Configuration.cs ├── NativeMethods.cs ├── PageHandlers │ ├── AbstractPageHandler.cs │ ├── HomePageHandler.cs │ ├── IconPageHandler.cs │ ├── InfoPageHandler.cs │ ├── JavascriptPageHandler.cs │ ├── LeftClickPageHandler.cs │ ├── MouseMovePageHandler.cs │ ├── NotFoundPageHandler.cs │ ├── RightClickPageHandler.cs │ └── ScreenPageHandler.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── RemoteView.csproj ├── Server.cs └── app.manifest ├── StaticAnalysis.fxcop └── TODO.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Remote Viewer - Desktop sharing software 2 | Copyright (C) 2013 Joao Vilaca 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RemoteView 2 | ========== 3 | 4 | Desktop sharing HTTP server. 5 | 6 | No need for a dedicated client, any modern browser will do. 7 | 8 | Licensed as GPL. See license file or . 9 | 10 | 11 | Running the Server Application 12 | ============================== 13 | 14 | Syntax: RemoteView [Port to listen] [Options] 15 | 16 | Example: RemoteView 6060 -b 17 | 18 | Options: 19 | 20 | -ip : Bind ip; 21 | 22 | -b : Don't show banner message; 23 | 24 | -m : Allow multiple instances; 25 | 26 | -h : Help (This screen); 27 | 28 | 29 | Requirements 30 | ============ 31 | 32 | Server has been tested in both Windows XP 32 bits and Windows 7 64 bits. DotNet Framework 2.0 or better needed. 33 | 34 | Client has been tested with Chrome on the same Windows configurations as above but "should" work in any browser/OS combination. 35 | 36 | 37 | Project Status 38 | ============== 39 | 40 | This application is already somewhat functional but a few features and code quality assurance are still needed. 41 | 42 | See [TODO file](https://github.com/vilaca/RemoteView/blob/master/TODO.md) for more info. 43 | 44 | 45 | Contributors Wanted 46 | =================== 47 | 48 | If you find this project interesting or that in any wait it could be useful for you and want to contribute please do. 49 | 50 | The following roles are needed and open for contributors: 51 | 52 | - C# developer; 53 | - Beta tester; 54 | - Code reviewer. 55 | 56 | See [TODO file](https://github.com/vilaca/RemoteView/blob/master/TODO.md) for more info on pending tasks. 57 | 58 | 59 | How does the Application work ? 60 | =============================== 61 | 62 | This Application is basically an embedded HTTP server that generates a simple HTML5 page with an image. That image is a representation of the current Screen Device of the Server. 63 | 64 | The user sees the remote computer Desktop as a webpage on the browser. Clicks on the browser are sent to the remote computer. 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /RemoteView.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteView", "RemoteView\RemoteView.csproj", "{5DA6855A-DDE4-4F77-BB8D-BC3D39412005}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {5DA6855A-DDE4-4F77-BB8D-BC3D39412005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {5DA6855A-DDE4-4F77-BB8D-BC3D39412005}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {5DA6855A-DDE4-4F77-BB8D-BC3D39412005}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {5DA6855A-DDE4-4F77-BB8D-BC3D39412005}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /RemoteView/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /RemoteView/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Globalization; 4 | 5 | namespace RemoteView 6 | { 7 | class Configuration 8 | { 9 | /// 10 | /// Allow multiple instances of process 11 | /// 12 | public bool AllowMultiple { get; private set; } 13 | 14 | /// 15 | /// Display banner 16 | /// 17 | public bool Banner { get; private set; } 18 | 19 | /// 20 | /// Display help 21 | /// 22 | public bool Help { get; private set; } 23 | 24 | /// 25 | /// Port where to listen 26 | /// 27 | public int Port { get; private set; } 28 | 29 | /// 30 | /// Gets the ip address. 31 | /// 32 | /// The ip address. 33 | public string IpAddress { get; private set; } 34 | 35 | /// 36 | /// Private c'tor with default values for object instances 37 | /// Use factory method instead of instatiating c'tor 38 | /// 39 | private Configuration() 40 | { 41 | this.AllowMultiple = false; 42 | this.Banner = true; 43 | this.Help = false; 44 | this.Port = 6060; 45 | this.IpAddress = "*"; 46 | } 47 | 48 | public static Configuration create(string[] parameters) 49 | { 50 | Configuration conf = new Configuration(); 51 | 52 | // use default configuration if no parameters exist 53 | 54 | if (parameters.Length == 0) 55 | return conf; 56 | 57 | // cycle throught command line using enumerator on parameters array 58 | 59 | IEnumerator enumerator = parameters.GetEnumerator(); 60 | enumerator.MoveNext(); 61 | 62 | string parameter = (string)enumerator.Current; 63 | 64 | // parse if first parameter is a valid integer and use it as a port number for listener 65 | 66 | int port; 67 | bool hasPortParameter = int.TryParse(parameter, out port); 68 | 69 | if (hasPortParameter) 70 | { 71 | conf.Port = port; 72 | 73 | // continue parsing parameters (if they exist) 74 | if (!enumerator.MoveNext()) 75 | return conf; 76 | parameter = (string)enumerator.Current; 77 | } 78 | 79 | do 80 | { 81 | if (parameter.Equals("-m")) 82 | { 83 | conf.AllowMultiple = true; 84 | } 85 | else if (parameter.Equals("-b")) 86 | { 87 | conf.Banner = false; 88 | } 89 | else if (parameter.Equals("-h")) 90 | { 91 | conf.Help = true; 92 | } 93 | else if (parameter.Equals("-ip")) 94 | { 95 | enumerator.MoveNext(); 96 | conf.IpAddress = (string)enumerator.Current; 97 | } 98 | else 99 | { 100 | throw new ArgumentException(string.Format("Error: {0} is an invalid command line parameter.", parameter)); 101 | } 102 | 103 | parameter = (string)enumerator.Current; 104 | } while (enumerator.MoveNext()); 105 | 106 | return conf; 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /RemoteView/NativeMethods.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Net; 4 | using System.Runtime.InteropServices; 5 | using System.Windows.Forms; 6 | 7 | namespace RemoteView 8 | { 9 | 10 | /// 11 | /// This class is heavily based on source code presented as an answer at 12 | /// http://stackoverflow.com/questions/8021954/sendinput-doesnt-perform-click-mouse-button-unless-i-move-cursor 13 | /// 14 | class NativeMethods 15 | { 16 | /// 17 | /// Don't allow instatiation of this class 18 | /// 19 | private NativeMethods() 20 | { 21 | } 22 | 23 | enum SystemMetric 24 | { 25 | SM_CXSCREEN = 0, 26 | SM_CYSCREEN = 1, 27 | } 28 | 29 | [DllImport("user32.dll")] 30 | static extern int GetSystemMetrics(SystemMetric smIndex); 31 | 32 | [DllImport("user32.dll", SetLastError = true)] 33 | static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); 34 | 35 | [StructLayout(LayoutKind.Sequential)] 36 | public struct HARDWAREINPUT 37 | { 38 | public int uMsg; 39 | public short wParamL; 40 | public short wParamH; 41 | } 42 | 43 | [StructLayout(LayoutKind.Sequential)] 44 | public struct KEYBDINPUT 45 | { 46 | public ushort wVk; 47 | public ushort wScan; 48 | public uint dwFlags; 49 | public uint time; 50 | public IntPtr dwExtraInfo; 51 | } 52 | 53 | [StructLayout(LayoutKind.Explicit)] 54 | public struct MouseKeybdhardwareInputUnion 55 | { 56 | [FieldOffset(0)] 57 | public MouseInputData mi; 58 | 59 | [FieldOffset(0)] 60 | public KEYBDINPUT ki; 61 | 62 | [FieldOffset(0)] 63 | public HARDWAREINPUT hi; 64 | } 65 | 66 | [StructLayout(LayoutKind.Sequential)] 67 | public struct INPUT 68 | { 69 | public SendInputEventType type; 70 | public MouseKeybdhardwareInputUnion mkhi; 71 | } 72 | 73 | [Flags] 74 | public enum MouseEventFlags : uint 75 | { 76 | MOUSEEVENTF_MOVE = 0x0001, 77 | MOUSEEVENTF_LEFTDOWN = 0x0002, 78 | MOUSEEVENTF_LEFTUP = 0x0004, 79 | MOUSEEVENTF_RIGHTDOWN = 0x0008, 80 | MOUSEEVENTF_RIGHTUP = 0x0010, 81 | MOUSEEVENTF_MIDDLEDOWN = 0x0020, 82 | MOUSEEVENTF_MIDDLEUP = 0x0040, 83 | MOUSEEVENTF_XDOWN = 0x0080, 84 | MOUSEEVENTF_XUP = 0x0100, 85 | MOUSEEVENTF_WHEEL = 0x0800, 86 | MOUSEEVENTF_VIRTUALDESK = 0x4000, 87 | MOUSEEVENTF_ABSOLUTE = 0x8000 88 | } 89 | 90 | public enum SendInputEventType : int 91 | { 92 | InputMouse, 93 | InputKeyboard, 94 | InputHardware 95 | } 96 | 97 | public struct MouseInputData 98 | { 99 | public int dx; 100 | public int dy; 101 | public uint mouseData; 102 | public MouseEventFlags dwFlags; 103 | public uint time; 104 | public IntPtr dwExtraInfo; 105 | } 106 | 107 | public static int CalculateAbsoluteCoordinateX(int x) 108 | { 109 | return (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN); 110 | } 111 | 112 | public static int CalculateAbsoluteCoordinateY(int y) 113 | { 114 | return (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN); 115 | } 116 | 117 | public static void LeftMouseButton(MouseEventFlags mouseEventFlags, int x, int y) 118 | { 119 | INPUT mouseInput = new INPUT(); 120 | mouseInput.type = SendInputEventType.InputMouse; 121 | mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); 122 | mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); 123 | mouseInput.mkhi.mi.mouseData = 0; 124 | 125 | mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE | MouseEventFlags.MOUSEEVENTF_ABSOLUTE; 126 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 127 | 128 | mouseInput.mkhi.mi.dwFlags = mouseEventFlags; 129 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 130 | } 131 | 132 | public static void ClickRightMouseButton(int x, int y) 133 | { 134 | INPUT mouseInput = new INPUT(); 135 | mouseInput.type = SendInputEventType.InputMouse; 136 | mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); 137 | mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); 138 | mouseInput.mkhi.mi.mouseData = 0; 139 | 140 | mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE | MouseEventFlags.MOUSEEVENTF_ABSOLUTE; 141 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 142 | 143 | mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN; 144 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 145 | 146 | mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP; 147 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 148 | } 149 | 150 | public static void MoveMouse(int x, int y) 151 | { 152 | INPUT mouseInput = new INPUT(); 153 | mouseInput.type = SendInputEventType.InputMouse; 154 | mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x); 155 | mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y); 156 | mouseInput.mkhi.mi.mouseData = 0; 157 | 158 | mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE | MouseEventFlags.MOUSEEVENTF_ABSOLUTE; 159 | SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT())); 160 | 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/AbstractPageHandler.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Globalization; 4 | using System.Net; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace RemoteView.PageHandlers 9 | { 10 | /// 11 | /// base class for all the request handlers 12 | /// 13 | abstract class AbstractPageHandler 14 | { 15 | /// 16 | /// 17 | /// 18 | /// response to be sent to client 19 | /// tokenized request URI 20 | /// response body 21 | public abstract byte[] HandleRequest(HttpListenerResponse response, String[] uri); 22 | 23 | /// 24 | /// Parse from tokenized URI the selected Screen Device. 25 | /// Default to 0 if parameter not present or error 26 | /// 27 | /// tokenized URI 28 | /// system screens 29 | /// selected screen or default(0) 30 | internal static int GetRequestedScreenDevice(String[] uri, Screen[] screens) 31 | { 32 | int screen = 0; 33 | if (uri.Length > 2) 34 | { 35 | try 36 | { 37 | screen = Convert.ToInt16(uri[2], CultureInfo.InvariantCulture); 38 | } 39 | catch { } 40 | 41 | if (screen < 0 || screen >= screens.Length) 42 | { 43 | screen = 0; 44 | } 45 | } 46 | return screen; 47 | } 48 | 49 | /// 50 | /// boilerplate HTML wraping for all the response streams 51 | /// 52 | /// 53 | /// 54 | internal static byte[] BuildHTML(string content) 55 | { 56 | return Encoding.UTF8.GetBytes("" + Environment.NewLine + 57 | "Remote View" + Environment.NewLine + 58 | "" + Environment.NewLine + 59 | content + 60 | "" + Environment.NewLine + 61 | "" + Environment.NewLine); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/HomePageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Windows.Forms; 4 | 5 | namespace RemoteView.PageHandlers 6 | { 7 | // This class is responsable for generating all the HTML and javascript the the application homepage 8 | 9 | class HomePageHandler : AbstractPageHandler 10 | { 11 | // screen devices list 12 | private Screen[] screens = Screen.AllScreens; 13 | 14 | /// 15 | /// Generate the HTML and javascript needed for this the homepage 16 | /// 17 | /// not used 18 | /// raw URI tokenized by '/' 19 | /// HTML page + javascript 20 | public override byte[] HandleRequest(HttpListenerResponse response, String[] uri) 21 | { 22 | 23 | // list amount of screen devices 24 | 25 | string staticPage = "

"; 26 | for (int i = 0; i < screens.Length; i++) 27 | { 28 | staticPage += "| Screen:" + i + ""; 29 | } 30 | staticPage += "

"; 31 | 32 | // display current screen on image 33 | // if no parameter for screen, default to 0 34 | int screen = GetRequestedScreenDevice(uri, screens); 35 | staticPage += ""; 36 | 37 | // script for handling clicks/dblclicks/contextclicks 38 | staticPage += ""; 39 | 40 | // closing body and html tags 41 | 42 | return BuildHTML(staticPage); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /RemoteView/PageHandlers/IconPageHandler.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Drawing; 3 | using System.IO; 4 | using System.Net; 5 | using System.Windows.Forms; 6 | 7 | namespace RemoteView.PageHandlers 8 | { 9 | class IconPageHandler : AbstractPageHandler 10 | { 11 | /// 12 | /// cached copy of favicon 13 | /// 14 | byte[] buffer; 15 | 16 | /// 17 | /// c'tor, creates chached copy of favicon 18 | /// 19 | public IconPageHandler() 20 | { 21 | using (MemoryStream icon = new MemoryStream()) 22 | { 23 | Icon bitmap = Icon.ExtractAssociatedIcon(Application.ExecutablePath); 24 | bitmap.Save(icon); 25 | buffer = icon.GetBuffer(); 26 | } 27 | } 28 | 29 | /// 30 | /// not much to do here, just return the cached favicon 31 | /// 32 | /// 33 | /// 34 | /// 35 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 36 | { 37 | return buffer; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/InfoPageHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Windows.Forms; 3 | 4 | namespace RemoteView.PageHandlers 5 | { 6 | class InfoPageHandler : AbstractPageHandler 7 | { 8 | private Screen[] screens = Screen.AllScreens; 9 | 10 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 11 | { 12 | string page = "

Desktop Viewer - Desktop sharing Application

"; 13 | 14 | for (int i = 0; i < screens.Length; i++) 15 | { 16 | page += "

Screen " + i + ": '" + screens[i].DeviceName + "', Width:" + screens[i].Bounds.Width + ", Height:" + screens[i].Bounds.Height + "

"; 17 | } 18 | 19 | return BuildHTML(page); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/JavascriptPageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | 6 | namespace RemoteView.PageHandlers 7 | { 8 | class JavascriptPageHandler : AbstractPageHandler 9 | { 10 | // screen devices list 11 | private Screen[] screens = Screen.AllScreens; 12 | 13 | /// 14 | /// All client side scripting is here. Tasks include detecting clicks, mouse moves and updating screen image 15 | /// 16 | /// 17 | /// 18 | /// 19 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 20 | { 21 | int screen = GetRequestedScreenDevice(uri, screens); 22 | 23 | response.ContentType = "application/javascript"; 24 | 25 | return Encoding.UTF8.GetBytes( 26 | 27 | "var http = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject(\"Microsoft.XMLHTTP\");" + Environment.NewLine + 28 | 29 | // cache last mouse down event 30 | "var mousedownEvt = null;" + Environment.NewLine + 31 | 32 | // cache mouse move event 33 | "var mouseMoveEvt = null;" + Environment.NewLine + 34 | 35 | // listeners for mouse actions 36 | "image.addEventListener('contextmenu', function(e){ rightclick(e); });" + Environment.NewLine + 37 | "image.addEventListener('mousedown', function(e){ mouseDown(e); });" + Environment.NewLine + 38 | "image.addEventListener('mouseup', function(e){ mouseUp(e); });" + Environment.NewLine + 39 | "image.addEventListener('load', setReloadTimeout );" + Environment.NewLine + 40 | "image.addEventListener('mousemove', function(e){ mouseMove(e); } );" + Environment.NewLine + 41 | 42 | // interval to ask server for a new screen image 43 | "setInterval('imageLoader();', 5555);" + Environment.NewLine + 44 | 45 | // interval for mouse move update 46 | "setInterval('mouseMoveUpdate();', 333);" + Environment.NewLine + 47 | 48 | // reload image 49 | "function mouseMoveUpdate () {" + Environment.NewLine + 50 | 51 | "if (mouseMoveEvt === null) return;" + Environment.NewLine + 52 | 53 | // update mouse position 54 | "e = mouseMoveEvt" + Environment.NewLine + 55 | "px = e.offsetX ? e.offsetX :e.pageX-document.getElementById(\"image\").offsetLeft;" + Environment.NewLine + 56 | "py = e.offsetY ? e.offsetY :e.pageY-document.getElementById(\"image\").offsetTop;" + Environment.NewLine + 57 | 58 | "mouseMoveEvt = null;" + Environment.NewLine + 59 | 60 | "var request = '/mousemove/" + screen + "/' + py + '/' + px;" + Environment.NewLine + 61 | "http.open('GET', request, true);" + Environment.NewLine + 62 | "http.send();" + Environment.NewLine + 63 | 64 | "}" + Environment.NewLine + 65 | 66 | "function setReloadTimeout () {" + Environment.NewLine + 67 | // interval to ask server for a new screen image 68 | "setTimeout('imageLoader();', 1000);" + Environment.NewLine + 69 | "}" + Environment.NewLine + 70 | 71 | // reload image 72 | "function imageLoader () {" + Environment.NewLine + 73 | " var newImageUrl = '/screen/" + screen + "/' + new Date() / 1;" + Environment.NewLine + 74 | " document.getElementById(\"image\").src = newImageUrl; " + Environment.NewLine + 75 | "}" + Environment.NewLine + 76 | 77 | "function cancelUiEvts (e) {" + Environment.NewLine + 78 | "e.stopPropagation();" + Environment.NewLine + 79 | "e.preventDefault();" + Environment.NewLine + 80 | "}" + Environment.NewLine + 81 | 82 | "function mouseDown (e) {" + Environment.NewLine + 83 | "cancelUiEvts(e);" + Environment.NewLine + 84 | "mousedownEvt = e;" + Environment.NewLine + 85 | "}" + Environment.NewLine + 86 | 87 | "function mouseUp (e) {" + Environment.NewLine + 88 | "cancelUiEvts(e);" + Environment.NewLine + 89 | 90 | "dx = mousedownEvt.offsetX ? mousedownEvt.offsetX :mousedownEvt.pageX-document.getElementById(\"image\").offsetLeft;" + Environment.NewLine + 91 | "dy = mousedownEvt.offsetY ? mousedownEvt.offsetY :mousedownEvt.pageY-document.getElementById(\"image\").offsetTop;" + Environment.NewLine + 92 | 93 | "ux = e.offsetX ? e.offsetX :e.pageX-document.getElementById(\"image\").offsetLeft;" + Environment.NewLine + 94 | "uy = e.offsetY ? e.offsetY :e.pageY-document.getElementById(\"image\").offsetTop;" + Environment.NewLine + 95 | 96 | "var request = '/leftclick/" + screen + "/' + dy + '/' + dx + '/' + uy + '/' + ux;" + Environment.NewLine + 97 | "http.open('GET', request, true);" + Environment.NewLine + 98 | "http.send();" + Environment.NewLine + 99 | 100 | "mousedownEvt = null;" + Environment.NewLine + 101 | 102 | "}" + Environment.NewLine + 103 | 104 | "function rightclick(e) { " + Environment.NewLine + 105 | 106 | "cancelUiEvts(e);" + Environment.NewLine + 107 | 108 | "px = e.offsetX ? e.offsetX :e.pageX-document.getElementById(\"image\").offsetLeft;" + Environment.NewLine + 109 | "py = e.offsetY ? e.offsetY :e.pageY-document.getElementById(\"image\").offsetTop;" + Environment.NewLine + 110 | "var request = '/rightclick/" + screen + "/' + py + '/' + px;" + Environment.NewLine + 111 | "http.open('GET', request, true);" + Environment.NewLine + 112 | "http.send();" + Environment.NewLine + 113 | 114 | "}" + Environment.NewLine + 115 | 116 | "function mouseMove(e) { " + Environment.NewLine + 117 | 118 | "mouseMoveEvt = e;" + Environment.NewLine + 119 | 120 | "}"); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/LeftClickPageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Net; 4 | using System.Windows.Forms; 5 | 6 | namespace RemoteView.PageHandlers 7 | { 8 | class LeftClickPageHandler : AbstractPageHandler 9 | { 10 | // screen devices list 11 | private Screen[] screens = Screen.AllScreens; 12 | 13 | /// 14 | /// handle left clicks from client 15 | /// 16 | /// 17 | /// 18 | /// 19 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 20 | { 21 | // must have 5 tokens 22 | if (uri.Length != 7) 23 | { 24 | response.StatusCode = 400; 25 | return BuildHTML("Error..."); 26 | } 27 | 28 | int screen = GetRequestedScreenDevice(uri, screens); 29 | 30 | bool error = handleMouseDown(uri, screen); 31 | if (error) 32 | { 33 | // parameter error 34 | response.StatusCode = 400; 35 | return BuildHTML("Error..."); 36 | } 37 | 38 | error = handleMouseUp(uri, screen); 39 | if (error) 40 | { 41 | // parameter error 42 | response.StatusCode = 400; 43 | return BuildHTML("Error..."); 44 | } 45 | 46 | return BuildHTML("Updating..."); 47 | } 48 | 49 | private bool handleMouseDown(string[] uri, int screen) 50 | { 51 | int x, y; 52 | try 53 | { 54 | y = Convert.ToInt16(uri[3], CultureInfo.InvariantCulture); 55 | x = Convert.ToInt16(uri[4], CultureInfo.InvariantCulture); 56 | } 57 | catch 58 | { 59 | return true; 60 | } 61 | 62 | // check bounds 63 | Screen device = screens[screen]; 64 | if (x < 0 || x >= device.Bounds.Width || y < 0 || y >= device.Bounds.Height) 65 | { 66 | return true; 67 | } 68 | 69 | 70 | // adapt to real screen bounds 71 | 72 | x = device.Bounds.X + x; 73 | y = device.Bounds.X + y; 74 | 75 | NativeMethods.LeftMouseButton(NativeMethods.MouseEventFlags.MOUSEEVENTF_LEFTDOWN, x, y); 76 | 77 | return false; 78 | } 79 | 80 | private bool handleMouseUp(string[] uri, int screen) 81 | { 82 | int x, y; 83 | try 84 | { 85 | y = Convert.ToInt16(uri[5], CultureInfo.InvariantCulture); 86 | x = Convert.ToInt16(uri[6], CultureInfo.InvariantCulture); 87 | } 88 | catch 89 | { 90 | return true; 91 | } 92 | 93 | // check bounds 94 | Screen device = screens[screen]; 95 | if (x < 0 || x >= device.Bounds.Width || y < 0 || y >= device.Bounds.Height) 96 | { 97 | return true; 98 | } 99 | 100 | // adapt to real screen bounds 101 | 102 | x = device.Bounds.X + x; 103 | y = device.Bounds.X + y; 104 | 105 | NativeMethods.LeftMouseButton(NativeMethods.MouseEventFlags.MOUSEEVENTF_LEFTUP, x, y); 106 | 107 | return false; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /RemoteView/PageHandlers/MouseMovePageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Net; 4 | using System.Windows.Forms; 5 | 6 | namespace RemoteView.PageHandlers 7 | { 8 | class MouseMovePageHandler: AbstractPageHandler 9 | { 10 | // screen devices list 11 | private Screen[] screens = Screen.AllScreens; 12 | 13 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 14 | { 15 | // must have 5 tokens 16 | if (uri.Length != 5) 17 | { 18 | response.StatusCode = 400; 19 | return BuildHTML("Error..."); 20 | } 21 | 22 | int x, y; 23 | try 24 | { 25 | y = Convert.ToInt16(uri[3], CultureInfo.InvariantCulture); 26 | x = Convert.ToInt16(uri[4], CultureInfo.InvariantCulture); 27 | } 28 | catch 29 | { 30 | // parameter error 31 | response.StatusCode = 400; 32 | return BuildHTML("Error..."); 33 | } 34 | 35 | int screen = GetRequestedScreenDevice(uri, screens); 36 | 37 | // check bounds 38 | Screen device = screens[screen]; 39 | if (x < 0 || x >= device.Bounds.Width || y < 0 || y >= device.Bounds.Height) 40 | { 41 | response.StatusCode = 400; 42 | return BuildHTML("Error..."); 43 | } 44 | 45 | // adapt to real screen bounds 46 | 47 | x = device.Bounds.X + x; 48 | y = device.Bounds.X + y; 49 | 50 | NativeMethods.MoveMouse(x, y); 51 | 52 | return BuildHTML("Updating..."); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/NotFoundPageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace RemoteView.PageHandlers 5 | { 6 | class NotFoundPageHandler : AbstractPageHandler 7 | { 8 | /// 9 | /// 404 error page, used when client requests and unexisting resource 10 | /// 11 | /// 12 | /// 13 | /// 14 | public override byte[] HandleRequest(HttpListenerResponse response, String[] uri) 15 | { 16 | response.StatusCode = 404; 17 | return BuildHTML("Page not found!"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/RightClickPageHandler.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Globalization; 4 | using System.Net; 5 | using System.Windows.Forms; 6 | 7 | namespace RemoteView.PageHandlers 8 | { 9 | class RightClickPageHandler: AbstractPageHandler 10 | { 11 | // screen devices list 12 | private Screen[] screens = Screen.AllScreens; 13 | 14 | /// 15 | /// Act upon right clicks received from client. 16 | /// 17 | /// server response 18 | /// tokenized URI 19 | /// 20 | public override byte[] HandleRequest(HttpListenerResponse response, string[] uri) 21 | { 22 | // must have 5 tokens 23 | if (uri.Length != 5) 24 | { 25 | response.StatusCode = 400; 26 | return BuildHTML("Error..."); 27 | } 28 | 29 | int x, y; 30 | try 31 | { 32 | y = Convert.ToInt16(uri[3], CultureInfo.InvariantCulture); 33 | x = Convert.ToInt16(uri[4], CultureInfo.InvariantCulture); 34 | } 35 | catch 36 | { 37 | // parameter error 38 | response.StatusCode = 400; 39 | return BuildHTML("Error..."); 40 | } 41 | 42 | int screen = GetRequestedScreenDevice(uri, screens); 43 | 44 | // check bounds 45 | Screen device = screens[screen]; 46 | if (x < 0 || x >= device.Bounds.Width || y < 0 || y >= device.Bounds.Height) 47 | { 48 | response.StatusCode = 400; 49 | return BuildHTML("Error..."); 50 | } 51 | 52 | // adapt to real screen bounds 53 | 54 | x = device.Bounds.X + x; 55 | y = device.Bounds.X + y; 56 | 57 | NativeMethods.ClickRightMouseButton(x,y); 58 | 59 | return BuildHTML("Updating..."); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /RemoteView/PageHandlers/ScreenPageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Net; 7 | using System.Windows.Forms; 8 | 9 | namespace RemoteView.PageHandlers 10 | { 11 | sealed class ScreenPageHandler : AbstractPageHandler, IDisposable 12 | { 13 | private volatile byte[][] caches = new byte[Screen.AllScreens.Length][]; 14 | private volatile int lastScreenRequested = 0; 15 | private Screen[] screens = Screen.AllScreens; 16 | private System.Timers.Timer timer; 17 | 18 | /// 19 | /// C'tor init cache for all screens 20 | /// 21 | public ScreenPageHandler() 22 | { 23 | for (int i = 0; i < caches.Length; i++) 24 | { 25 | caches[i] = SerializeScreenImage(i); 26 | } 27 | 28 | timer = new System.Timers.Timer(1000); 29 | timer.Elapsed += reloadCache; 30 | timer.Enabled = true; 31 | } 32 | 33 | /// 34 | /// reload image for last requested screen 35 | /// 36 | /// 37 | /// 38 | private void reloadCache(object sender, System.Timers.ElapsedEventArgs e) 39 | { 40 | int toReload = lastScreenRequested; 41 | #if DEBUG 42 | Stopwatch perfCounter = new Stopwatch(); 43 | perfCounter.Start(); 44 | #endif 45 | caches[toReload] = SerializeScreenImage(toReload); 46 | #if DEBUG 47 | perfCounter.Stop(); 48 | Console.WriteLine("Time elapsed: {0}", perfCounter.Elapsed); 49 | #endif 50 | } 51 | 52 | /// 53 | /// Get a copy of the requested device screen image from cache 54 | /// 55 | /// 56 | /// 57 | /// 58 | public override byte[] HandleRequest(HttpListenerResponse response, String[] uri) 59 | { 60 | int requested = GetRequestedScreenDevice(uri, screens); 61 | lastScreenRequested = requested; 62 | response.Headers.Set("Content-Type", "image/png"); 63 | return caches[requested]; 64 | } 65 | 66 | /// 67 | /// Serizalize a screen 68 | /// 69 | /// screen to serialize 70 | /// 71 | private byte[] SerializeScreenImage(int requested) 72 | { 73 | Screen screen = screens[requested]; 74 | using (MemoryStream ms = new MemoryStream()) 75 | { 76 | Bitmap bmp = new Bitmap(screen.Bounds.Width, screen.Bounds.Height); 77 | Graphics.FromImage(bmp).CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size); 78 | bmp.Save(ms, ImageFormat.Png); 79 | return ms.GetBuffer(); 80 | } 81 | } 82 | 83 | public void Dispose() 84 | { 85 | timer.Dispose(); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /RemoteView/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Threading; 5 | using System.Windows.Forms; 6 | 7 | namespace RemoteView 8 | { 9 | class Program 10 | { 11 | static Mutex mutex = new Mutex(true, "-RemoteView-Mutex-"); 12 | 13 | private static string ApplicationName 14 | { 15 | get 16 | { 17 | return Path.GetFileNameWithoutExtension(Application.ExecutablePath); 18 | } 19 | } 20 | 21 | /// 22 | /// Main method. Needs STAThreadAttribute as this App references System.Windows.Forms 23 | /// 24 | /// 25 | [STAThreadAttribute] 26 | static void Main(string[] args) 27 | { 28 | 29 | // get configuration from command line parameters 30 | 31 | Configuration conf; 32 | try 33 | { 34 | conf = Configuration.create(args); 35 | } 36 | catch (Exception e) 37 | { 38 | Console.WriteLine(e.Message); 39 | return; 40 | } 41 | 42 | if (conf.Banner) 43 | { 44 | ShowBanner(); 45 | } 46 | 47 | if (conf.Help) 48 | { 49 | ShowHelpMessage(); 50 | return; 51 | } 52 | 53 | // make sure only one instance is online 54 | 55 | if (!conf.AllowMultiple && !InstanceIsUnique()) 56 | { 57 | Console.WriteLine("Only one instance of process allowed. User -m for muliple instances."); 58 | return; 59 | } 60 | 61 | // check if http listener is supported 62 | 63 | if (!HttpListener.IsSupported) 64 | { 65 | Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class."); 66 | return; 67 | } 68 | 69 | // run server 70 | RunServer(conf); 71 | } 72 | 73 | /// 74 | /// Find out if there are one or more instances of this program running 75 | /// 76 | /// n processes 77 | private static bool InstanceIsUnique() 78 | { 79 | if (mutex.WaitOne(TimeSpan.Zero, true)) 80 | { 81 | mutex.ReleaseMutex(); 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | /// 88 | /// Run server 89 | /// 90 | /// server configuration 91 | private static void RunServer(Configuration conf) 92 | { 93 | using (Server server = new Server().Start(conf.IpAddress, conf.Port)) 94 | { 95 | if (!server.IsRunning()) 96 | { 97 | Console.WriteLine("Could not start server... Exiting."); 98 | return; 99 | } 100 | 101 | Console.WriteLine("Server running press [c] to stop"); 102 | while (server.IsRunning() && Console.ReadKey(true).Key != ConsoleKey.C) 103 | ; 104 | server.Stop(); 105 | } 106 | } 107 | 108 | private static void ShowBanner() 109 | { 110 | Console.WriteLine(Application.ProductName + " - Desktop sharing server"); 111 | Console.WriteLine("Copyright (c) Joao Vilaca, 2013, Email: jvilaca@gmail.com"); 112 | Console.WriteLine(); 113 | } 114 | 115 | private static void ShowHelpMessage() 116 | { 117 | Console.WriteLine("Syntax: " + ApplicationName + " [Port to listen] [Options]"); 118 | Console.WriteLine("Example: " + ApplicationName + " 6060 -b"); 119 | Console.WriteLine("Options: -ip :\tBind ip;"); 120 | Console.WriteLine(" -b :\tDon't show banner message;"); 121 | Console.WriteLine(" -m :\tAllow multiple instances;"); 122 | Console.WriteLine(" -h :\tHelp (This screen);"); 123 | // Console.WriteLine("\t-i :\tInstall as Windows service"); 124 | // Console.WriteLine("\t-u :\tUninstall as Windows service"); 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /RemoteView/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RemoteView")] 9 | [assembly: AssemblyDescription("Desktop sharing application")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("vilaca")] 12 | [assembly: AssemblyProduct("RemoteView")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("174a106e-c84f-4f49-9068-4491370921ac")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /RemoteView/RemoteView.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5DA6855A-DDE4-4F77-BB8D-BC3D39412005} 8 | Exe 9 | Properties 10 | RemoteView 11 | RemoteView 12 | v2.0 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | app.manifest 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Designer 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /RemoteView/Server.cs: -------------------------------------------------------------------------------- 1 | using RemoteView.PageHandlers; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Net; 6 | using System.Threading; 7 | 8 | namespace RemoteView 9 | { 10 | sealed class Server : IDisposable 11 | { 12 | /// 13 | /// Keep list of all resources to be invoked according to received HTTP requests 14 | /// 15 | private Dictionary decoder = new Dictionary(); 16 | /// 17 | /// HTTP listener for server 18 | /// 19 | private HttpListener listener = new HttpListener(); 20 | 21 | /// 22 | /// Constructor 23 | /// 24 | public Server() 25 | { 26 | 27 | // Homepage 28 | decoder.Add("", new HomePageHandler()); 29 | decoder.Add("home", new HomePageHandler()); 30 | 31 | // javascript page handles client side clicks and screen image updates 32 | decoder.Add("script", new JavascriptPageHandler()); 33 | 34 | // information about the system 35 | decoder.Add("info", new InfoPageHandler()); 36 | 37 | // this pages process clicks into server side windows events 38 | decoder.Add("leftclick", new LeftClickPageHandler()); 39 | decoder.Add("rightclick", new RightClickPageHandler()); 40 | decoder.Add("mousemove", new MouseMovePageHandler()); 41 | 42 | // image of choosen device as a png 43 | decoder.Add("screen", new ScreenPageHandler()); 44 | 45 | // image of choosen device as a png 46 | decoder.Add("favicon.ico", new IconPageHandler()); 47 | 48 | // 404 error page 49 | decoder.Add("404", new NotFoundPageHandler()); 50 | } 51 | 52 | /// 53 | /// Start server 54 | /// 55 | /// port to listen to 56 | public Server Start(string address, int port) 57 | { 58 | try 59 | { 60 | Console.WriteLine("Starting server at {0}:{1}", address, port); 61 | listener.Prefixes.Add("http://" + address + ":" + port + "/"); 62 | listener.IgnoreWriteExceptions = true; 63 | listener.Start(); 64 | 65 | new Thread(Start).Start(); 66 | } 67 | catch 68 | { 69 | Console.WriteLine("Could not listen on port: {0}.", port); 70 | } 71 | 72 | return this; 73 | } 74 | 75 | /// 76 | /// This where the server runs 77 | /// 78 | private void Start() 79 | { 80 | do 81 | { 82 | HttpListenerResponse response = null; 83 | Stream output = null; 84 | try 85 | { 86 | // Note: The GetContext method blocks while waiting for a request. 87 | HttpListenerContext context = listener.GetContext(); 88 | 89 | #if DEBUG 90 | Console.WriteLine (context.Request.RawUrl); 91 | #endif 92 | 93 | String[] uri = context.Request.RawUrl.Split('/'); 94 | 95 | AbstractPageHandler page; 96 | bool found = decoder.TryGetValue(uri[1], out page); 97 | if (!found) 98 | { 99 | // if page not found display 404 page 100 | page = decoder["404"]; 101 | } 102 | 103 | response = context.Response; 104 | 105 | byte[] buffer = page.HandleRequest(response, uri); 106 | 107 | // Get a response stream and write the response to it. 108 | response.ContentLength64 = buffer.Length; 109 | output = response.OutputStream; 110 | output.Write(buffer, 0, buffer.Length); 111 | 112 | } 113 | catch (Exception e) 114 | { 115 | if (listener.IsListening) 116 | Console.WriteLine(e.Message); 117 | } 118 | finally 119 | { 120 | if (response != null) 121 | { 122 | try 123 | { 124 | if (output != null) 125 | output.Close(); 126 | } 127 | catch 128 | { 129 | } 130 | response.Close(); 131 | } 132 | } 133 | } while (listener.IsListening); 134 | } 135 | 136 | /// 137 | /// Stop server 138 | /// 139 | public void Stop() 140 | { 141 | this.listener.Stop(); 142 | } 143 | 144 | /// 145 | /// is server running? 146 | /// 147 | /// 148 | public bool IsRunning() 149 | { 150 | return listener.IsListening; 151 | } 152 | 153 | public void Dispose() 154 | { 155 | if (listener != null) 156 | listener.Close(); 157 | 158 | // some page handlers might need to be disposed 159 | 160 | foreach (AbstractPageHandler page in decoder.Values) 161 | { 162 | if (page is IDisposable) 163 | { 164 | ((IDisposable)page).Dispose(); 165 | } 166 | } 167 | } 168 | } 169 | } -------------------------------------------------------------------------------- /RemoteView/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /StaticAnalysis.fxcop: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | True 5 | $(FxCopDir)\Xml\FxCopReport.xsl 6 | 7 | 8 | 9 | 10 | 11 | True 12 | True 13 | True 14 | 10 15 | 1 16 | 17 | False 18 | 19 | False 20 | 120 21 | False 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 'RemoteView.exe' 51 | 52 | 53 | 54 | 55 | 'Program.Main(string[])' 56 | 'RemoteView.exe' 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 'string.Format(string, object)' 70 | 'Configuration.create(string[])' 71 | 'string.Format(IFormatProvider, string, params object[])' 72 | 'CultureInfo.CurrentCulture' 73 | 'CultureInfo.InvariantCulture' 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 'NativeMethods.ClickRightMouseButton(int, int)' 87 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 88 | 89 | 90 | 'NativeMethods.ClickRightMouseButton(int, int)' 91 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 92 | 93 | 94 | 'NativeMethods.ClickRightMouseButton(int, int)' 95 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 'NativeMethods.LeftMouseButton(NativeMethods.MouseEventFlags, int, int)' 105 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 106 | 107 | 108 | 'NativeMethods.LeftMouseButton(NativeMethods.MouseEventFlags, int, int)' 109 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 'NativeMethods.MoveMouse(int, int)' 119 | 'NativeMethods.SendInput(uint, ref NativeMethods.INPUT, int)' 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 'NativeMethods.MouseKeybdhardwareInputUnion.hi' 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 'NativeMethods.MouseKeybdhardwareInputUnion.ki' 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 'page' 155 | 'IDisposable' 156 | 'Server.Dispose()' 157 | castclass 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 'Server.Start()' 167 | 'Exception' 168 | 169 | 170 | 'Server.Start()' 171 | 'object' 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 'Server.Start(int)' 181 | 'object' 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 'AbstractPageHandler.GetRequestedScreenDevice(string[], Screen[])' 199 | 'object' 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 'LeftClickPageHandler.handleMouseDown(string[], int)' 213 | 'object' 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 'LeftClickPageHandler.handleMouseUp(string[], int)' 223 | 'object' 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 'MouseMovePageHandler.HandleRequest(HttpListenerResponse, string[])' 237 | 'object' 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 'RightClickPageHandler.HandleRequest(HttpListenerResponse, string[])' 251 | 'object' 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | Sign {0} with a strong name key. 268 | 269 | 270 | It appears that field {0} is never used or is only ever assigned to. Use this field or remove it. 271 | 272 | 273 | {0}, a variable, is cast to type {1} multiple times in method {2}. Cache the result of the 'as' operator or direct cast in order to eliminate the redundant {3} instruction. 274 | 275 | 276 | Modify {0} to catch a more specific exception than {1} or rethrow the exception. 277 | 278 | 279 | {0} calls {1} but does not use the HRESULT or error code that the method returns. This could lead to unexpected behavior in error conditions or low-resource situations. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method. 280 | 281 | 282 | Mark the entry point method {0} in assembly {1} with an STAThreadAttribute. 283 | 284 | 285 | Because the behavior of {0} could vary based on the current user's locale settings, replace this call in {1} with a call to {2}. If the result of {2} will be displayed to the user, specify {3} as the 'IFormatProvider' parameter. Otherwise, if the result will be stored and accessed by software, such as when it is persisted to disk or to a database, specify {4}. 286 | 287 | 288 | 289 | 290 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | TODOS 2 | ========== 3 | 4 | [ENH] - Enhancement / [BUG] - defect 5 | 6 | 7 | * [BUG] If image loading fails, last loaded image should not be replaced by empty container; 8 | 9 | * [BUG] Can't drag icons on remote desktop Server; 10 | 11 | * [ENH] Text Input from Client to Server; 12 | 13 | * [ENH] Smart refresh rate - throttle the serialization of screen images depending on client request speed; 14 | 15 | * [ENH] CSS - Improve layout using; 16 | 17 | * [ENH] Improve screen serialization on Server; 18 | 19 | * [ENH] Change mouse cursor on client according to remote Server mouse pointer; 20 | 21 | * [ENH] Resize image on Client/Server; 22 | 23 | * [ENH] User authentication; 24 | 25 | * [ENH] Unit tests; 26 | 27 | * [ENH] Control panel for server settings - update speed, image quality (GIF/PNG/?) etc. 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------