Ver Fonte

Initial

Brad Robinson há 8 anos atrás
commit
52e462db51

+ 13 - 0
.gitignore

@@ -0,0 +1,13 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+
+bin
+obj
+build
+Debug
+Release
+TestResults
+.vs
+*.sdf
+*.opendb
+*.opensdf
+*.user

+ 28 - 0
ConFrames.sln

@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConFrames", "ConFrames\ConFrames.csproj", "{64905DDF-9D01-4A63-BD60-A2586008CEE2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample", "Sample\Sample.csproj", "{885C73BB-668F-4CA1-8015-E8393B25C562}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{64905DDF-9D01-4A63-BD60-A2586008CEE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{64905DDF-9D01-4A63-BD60-A2586008CEE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{64905DDF-9D01-4A63-BD60-A2586008CEE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{64905DDF-9D01-4A63-BD60-A2586008CEE2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{885C73BB-668F-4CA1-8015-E8393B25C562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{885C73BB-668F-4CA1-8015-E8393B25C562}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{885C73BB-668F-4CA1-8015-E8393B25C562}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{885C73BB-668F-4CA1-8015-E8393B25C562}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 53 - 0
ConFrames/ConFrames.csproj

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{64905DDF-9D01-4A63-BD60-A2586008CEE2}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ConFrames</RootNamespace>
+    <AssemblyName>ConFrames</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\build\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\build\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="Microsoft.CSharp" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Desktop.cs" />
+    <Compile Include="Interop.cs" />
+    <Compile Include="PaintContext.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Types.cs" />
+    <Compile Include="Window.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 417 - 0
ConFrames/Desktop.cs

@@ -0,0 +1,417 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace ConFrames
+{
+    public class Desktop
+    {
+        public Desktop(int width, int height)
+        {
+            // Save stdout
+            _stdout = Interop.GetStdHandle(Interop.STD_OUTPUT_HANDLE);
+            
+            // Create buffer
+            _buffer = Interop.CreateConsoleScreenBuffer(Interop.GENERIC_READWRITE, (uint)0, IntPtr.Zero, Interop.CONSOLE_TEXTMODE_BUFFER, IntPtr.Zero);
+
+            // Default colors
+            ActiveBorderBackgroundColor = ConsoleColor.Blue;
+            ActiveBorderLineColor = ConsoleColor.White;
+            InactiveBorderLineColor = ConsoleColor.Gray;
+            InactiveBorderBackgroundColor = ConsoleColor.DarkBlue;
+
+            // Default desktop size
+            DesktopSize = new Size(width, height);
+            DesktopColor = ConsoleColor.DarkBlue;
+        }
+
+        // Handle to the screen and stdout buffers
+        IntPtr _stdout;
+        IntPtr _buffer;
+
+        // Desktop size
+        Size _desktopSize;
+        public Size DesktopSize
+        {
+            get { return _desktopSize; }
+            set
+            {
+                try
+                {
+                    // Try to set it
+                    Interop.SetBufferAndScreenSize(_buffer, (short)value.Width, (short)value.Height);
+
+                    // Save it
+                    _desktopSize = value;
+                }
+                catch
+                {
+                    try
+                    {
+                        // try to set it back
+                        Interop.SetBufferAndScreenSize(_buffer, (short)_desktopSize.Width, (short)_desktopSize.Height);
+                    }
+                    catch { }
+                    throw;
+                }
+            }
+        }
+
+        // List of all windows
+        List<Window> _windows = new List<Window>();
+
+        // Register a new window
+        internal void AddWindow(Window window)
+        {
+            if (_windows.IndexOf(window)<0)
+            {
+                _windows.Add(window);
+                InvalidateDesktop();
+            }
+        }
+
+        // Remove a window
+        internal void RemoveWindow(Window window)
+        {
+            _windows.Remove(window);
+            InvalidateDesktop();
+        }
+
+
+        // Colors
+        public ConsoleColor ActiveBorderBackgroundColor
+        {
+            get;
+            set;
+        }
+
+        public ConsoleColor ActiveBorderLineColor
+        {
+            get;
+            set;
+        }
+
+        public ConsoleColor InactiveBorderBackgroundColor
+        {
+            get;
+            set;
+        }
+
+        public ConsoleColor InactiveBorderLineColor
+        {
+            get;
+            set;
+        }
+
+        // Color of area behind all windows
+        ConsoleColor _desktopColor;
+        public ConsoleColor DesktopColor
+        {
+            get
+            {
+                return _desktopColor;
+            }
+            set
+            {
+                _desktopColor = value;
+                InvalidateDesktop();
+            }
+        }
+
+        // Called just before repainting the screen
+        protected virtual void OnWillUpdate()
+        {
+        }
+
+        // Called just after repainting the screen
+        protected virtual void OnDidUpdate()
+        {
+        }
+
+        // Called just before waiting for input
+        protected virtual void OnEnterProcessing()
+        {
+        }
+
+        // Called just after waiting for input
+        protected virtual void OnLeaveProcessing()
+        {
+        }
+
+        // Preview received keys - return true if handled
+        protected virtual bool OnPreviewKey(ConsoleKeyInfo key)
+        {
+            if (PreviewKey != null)
+                return PreviewKey(key);
+            return false;
+        }
+
+        // Handler
+        public Func<ConsoleKeyInfo, bool> PreviewKey;
+
+        // Get/Set the currently active window
+        public Window ActiveWindow
+        {
+            get { return _windows.Count == 0 ? null : _windows[_windows.Count - 1]; }
+            set
+            {
+                var oldActive = ActiveWindow;               
+                int pos = _windows.IndexOf(value);
+                if (pos < _windows.Count-1)
+                {
+                    _windows.RemoveAt(pos);
+                    _windows.Add(value);
+                }
+
+                if (oldActive!=ActiveWindow)
+                {
+                    Invalidate(oldActive);
+                    Invalidate(ActiveWindow);
+                }
+            }
+        }
+
+        // Invalidate flags
+        bool _needRedraw = false;
+        bool _needClear = false;
+
+        public void Invalidate(Window w)
+        {
+            _needRedraw = true;
+        }
+
+        public void InvalidateDesktop()
+        {
+            _needClear = true;
+            _needRedraw = true;
+        }
+
+        // Update 
+        public void Update()
+        {
+            // Quit if we don't need a redraw
+            if (_needRedraw)
+            {
+                // Notify
+                OnWillUpdate();
+
+                // Clear flag
+                _needRedraw = false;
+
+                // Do we need to clear?
+                if (_needClear)
+                {
+                    _needClear = false;
+
+                    // Get screens size
+                    Interop.CONSOLE_SCREEN_BUFFER_INFO info;
+                    Interop.GetConsoleScreenBufferInfo(_buffer, out info);
+
+                    // Create buffer
+                    CharInfo[] buf = new CharInfo[info.dwSize.X * info.dwSize.Y];
+
+                    // Clear buffer
+                    var defAttributes = (ushort)((ushort)0 | ((ushort)_desktopColor << 4));
+                    for (int i = 0; i < buf.Length; ++i)
+                    {
+                        buf[i].Attributes = defAttributes;
+                        buf[i].Char = (char)' ';
+                    }
+
+                    // Copy it
+                    var r = new Interop.SmallRect()
+                    {
+                        Top = (short)0,
+                        Left = (short)0,
+                        Right = (short)info.dwSize.X,
+                        Bottom = (short)info.dwSize.Y,
+                    };
+                    Interop.WriteConsoleOutput(_buffer,
+                            buf,
+                            new Interop.Coord() { X = (short)info.dwSize.X, Y = info.dwSize.Y },
+                            new Interop.Coord() { X = 0, Y = 0 },
+                            ref r);
+                }
+
+
+                // Draw all windows
+                foreach (var w in _windows)
+                {
+                    var buf = w.Draw();
+                    var r = new Interop.SmallRect()
+                    {
+                        Top = (short)w.FrameRectangle.Top,
+                        Left = (short)w.FrameRectangle.Left,
+                        Right = (short)w.FrameRectangle.Right,
+                        Bottom = (short)w.FrameRectangle.Bottom,
+                    };
+                    Interop.WriteConsoleOutput(_buffer,
+                            buf,
+                            new Interop.Coord() { X = (short)w.FrameRectangle.Width, Y = (short)w.FrameRectangle.Height },
+                            new Interop.Coord() { X = 0, Y = 0 },
+                            ref r);
+                }
+
+                // Finished
+                OnDidUpdate();
+            }
+
+            // Reposition cursor according to how the active window wants it
+            var active = ActiveWindow;
+            if (active != null)
+            {
+                if (active.CursorPosition.X >= 0 && active.CursorPosition.Y >= 0 &&
+                    active.CursorPosition.X < active.FrameRectangle.Width - 2 &&
+                    active.CursorPosition.Y < active.FrameRectangle.Height - 2)
+                {
+                    Interop.SetConsoleCursorPosition(_buffer, new Interop.Coord(
+                        (short)(active.FrameRectangle.Left + active.CursorPosition.X + 1),
+                        (short)(active.FrameRectangle.Top + active.CursorPosition.Y + 1)
+                        ));
+                    Interop.SetConsoleCursorVisible(_buffer, active.CursorVisible);
+                }
+                else
+                {
+                    Interop.SetConsoleCursorVisible(_buffer, false);
+                }
+            }
+            else
+            {
+                Interop.SetConsoleCursorVisible(_buffer, false);
+            }
+
+        }
+
+        // Cancel from the process loop
+        bool _continueProcessing = false;
+        public void EndProcessing()
+        {
+            _continueProcessing = false;
+        }
+
+        // Process
+        public void Process()
+        {
+            // Notfiy
+            OnEnterProcessing();
+
+            // Make active
+            ViewMode = ViewMode.Desktop;
+
+            // Process loop
+            _continueProcessing = true;
+            while (_continueProcessing)
+            {
+                // Do any update
+                Update();
+
+                // Bring console to front
+                BringToFront();
+
+                // Read the next key
+                var key = Console.ReadKey(true);
+
+                // Switch windows?
+                if (key.Key == ConsoleKey.Tab)
+                {
+                    if (key.Modifiers == ConsoleModifiers.Control)
+                    {
+                        if (_windows.Any())
+                        {
+                            var top = _windows[_windows.Count - 1];
+                            _windows.RemoveAt(_windows.Count-1);
+                            _windows.Insert(0, top);
+                            _needRedraw = true;
+                        }
+                        continue;
+                    }
+                    if (key.Modifiers == (ConsoleModifiers.Control | ConsoleModifiers.Shift))
+                    {
+                        if (_windows.Any())
+                        {
+                            var top = _windows[0];
+                            _windows.RemoveAt(0);
+                            _windows.Add(top);
+                            _needRedraw = true;
+                        }
+                        continue;
+                    }
+                }
+
+                // Toggle to stdout?
+                if (key.Key == ConsoleKey.F4 && key.Modifiers == 0)
+                {
+                    ViewMode = ViewMode.StdOut;
+                    Console.ReadKey(true);
+                    ViewMode = ViewMode.Desktop;
+                    continue;
+                }
+
+                // Preview key event
+                if (OnPreviewKey(key))
+                    continue;
+
+                // Send key to the active window
+                var aw = ActiveWindow;
+                if (aw!= null)
+                {
+                    aw.OnKey(key);
+                }
+            }
+
+            // Notify
+            OnLeaveProcessing();
+
+            // Finished
+            return;
+        }
+
+        // Bring the console window to foreground
+        IntPtr _oldForegroundWindow;
+        public void BringToFront()
+        {
+            _oldForegroundWindow = Interop.GetActiveWindow();
+            Interop.SetForegroundWindow(Interop.GetConsoleWindow());
+        }
+
+        // Restore the old active foreground window
+        public void RestoreForegroundWindow()
+        {
+            if (_oldForegroundWindow==IntPtr.Zero)
+            {
+                _oldForegroundWindow = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
+            }
+            if (_oldForegroundWindow !=IntPtr.Zero)
+            {
+                Interop.SetForegroundWindow(_oldForegroundWindow);
+                _oldForegroundWindow = IntPtr.Zero;
+            }
+        }
+
+        // Set the view mode (desktop or stdout)
+        ViewMode _viewMode = ViewMode.StdOut;
+        public ViewMode ViewMode
+        {
+            get
+            {
+                return _viewMode;
+            }
+            set
+            {
+                if (_viewMode !=value)
+                {
+                    _viewMode = value;
+                    if (_viewMode==ViewMode.Desktop)
+                    {
+                        Interop.SetConsoleActiveScreenBuffer(_buffer);
+                    }
+                    else
+                    {
+                        Interop.SetConsoleActiveScreenBuffer(_stdout);
+                    }
+                }
+            }
+        }
+    }
+}

+ 192 - 0
ConFrames/Interop.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConFrames
+{
+    public class Interop
+    {
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern IntPtr GetStdHandle(int nStdHandle);
+        public const int STD_OUTPUT_HANDLE = -11;
+        public const int STD_INPUT_HANDLE = -10;
+        public const int STD_ERROR_HANDLE = -12;
+
+        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool WriteConsoleOutput(
+          IntPtr hConsoleOutput,
+          CharInfo[] lpBuffer,
+          Coord dwBufferSize,
+          Coord dwBufferCoord,
+          ref SmallRect lpWriteRegion);
+
+        [DllImport("Kernel32.dll", SetLastError = true)]
+        public static extern IntPtr CreateConsoleScreenBuffer(
+             uint dwDesiredAccess,
+             uint dwShareMode,
+             IntPtr secutiryAttributes,
+             UInt32 flags,
+             IntPtr screenBufferData
+             );
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleScreenBufferSize(IntPtr hConsoleOutput, Coord dwSize);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleActiveScreenBuffer(IntPtr hConsoleOutput);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleCursorPosition(IntPtr hConsoleOutput, Coord dwCursorPosition);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleCursorInfo(IntPtr hConsoleOutput, ref CONSOLE_CURSOR_INFO info);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool GetConsoleCursorInfo(IntPtr hConsoleOutput, out CONSOLE_CURSOR_INFO info);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleWindowInfo(IntPtr hConsoleOutput, bool absolute, ref SmallRect rect);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO info);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern IntPtr GetConsoleWindow();
+
+        [DllImport("user32.dll")]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetForegroundWindow(IntPtr hWnd);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetForegroundWindow();
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetActiveWindow();
+
+        public static bool SetConsoleCursorVisible(IntPtr hConsole, bool visible)
+        {
+            CONSOLE_CURSOR_INFO info;
+            if (!GetConsoleCursorInfo(hConsole, out info))
+                return false;
+            if (info.bVisible != visible)
+            {
+                info.bVisible = visible;
+                return SetConsoleCursorInfo(hConsole, ref info);
+            }
+            return true;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct CONSOLE_CURSOR_INFO
+        {
+            public uint dwSize;
+            public bool bVisible;
+        };
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct CONSOLE_SCREEN_BUFFER_INFO
+        {
+            public Coord dwSize;
+            public Coord dwCursorPosition;
+            public ushort wAttributes;
+            public SmallRect srWindow;
+            public Coord dwMaximumWindowSize;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct CONSOLE_SCREEN_BUFFER_INFOEX
+        {
+            public int cbSize;
+            public Coord dwSize;
+            public Coord dwCursorPosition;
+            public ushort wAttributes;
+            public SmallRect srWindow;
+            public Coord dwMaximumWindowSize;
+            public ushort wPopupAttributes;
+            public bool bFullscreenSupported;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+            public uint[] ColorTable;
+        }
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool GetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX info);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern bool SetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFOEX info);
+
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        public static extern Coord GetLargestConsoleWindowSize(IntPtr hConsoleOutput);
+
+
+        public static void SetBufferAndScreenSize(IntPtr hConsoleOutput, short x, short y)
+        {
+            var largestSize = GetLargestConsoleWindowSize(hConsoleOutput);
+            if (x > largestSize.X || y > largestSize.Y)
+                throw new ArgumentException(string.Format("requested size is too big (max = {0} x {1})", largestSize.X, largestSize.Y));
+
+
+            CONSOLE_SCREEN_BUFFER_INFO bi;
+            if (!GetConsoleScreenBufferInfo(hConsoleOutput, out bi))
+                throw new InvalidOperationException("GetConsoleScreenBufferInfo failed");
+
+            Coord windowSize = new Coord((short)(bi.srWindow.Width + 1), (short)(bi.srWindow.Height + 1));
+
+            if (windowSize.X > x || windowSize.Y > y)
+            {
+                var shrink = new SmallRect();
+                shrink.Right = (short)(x < windowSize.X ? x - 1 : windowSize.X - 1);
+                shrink.Bottom = (short)(y < windowSize.Y ? y - 1 : windowSize.Y - 1);
+
+                if (!SetConsoleWindowInfo(hConsoleOutput, true, ref shrink))
+                    throw new InvalidOperationException("Failed to shrink window");
+            }
+
+            if (!SetConsoleScreenBufferSize(hConsoleOutput, new Coord(x, y)))
+                throw new InvalidOperationException("Failed to resize buffer");
+
+            var info = new SmallRect();
+            info.Right = (short)(x - 1);
+            info.Bottom = (short)(y - 1);
+            if (!SetConsoleWindowInfo(hConsoleOutput, true, ref info))
+                throw new InvalidOperationException("Failed to resize window");
+
+            CONSOLE_SCREEN_BUFFER_INFO cbi;
+            GetConsoleScreenBufferInfo(hConsoleOutput, out cbi);
+        }
+
+        public const uint CONSOLE_TEXTMODE_BUFFER = 0x00000001;
+        public const uint GENERIC_READ = 0x80000000;
+        public const uint GENERIC_WRITE = 0x40000000;
+        public const uint GENERIC_READWRITE = GENERIC_READ | GENERIC_WRITE;
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct Coord
+        {
+            public short X;
+            public short Y;
+
+            public Coord(short X, short Y)
+            {
+                this.X = X;
+                this.Y = Y;
+            }
+        };
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct SmallRect
+        {
+            public short Left;
+            public short Top;
+            public short Right;
+            public short Bottom;
+            public short Width { get { return (short)(Right - Left); } }
+            public short Height { get { return (short)(Bottom - Top); } }
+
+        }
+
+    }
+}

+ 256 - 0
ConFrames/PaintContext.cs

@@ -0,0 +1,256 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConFrames
+{
+    public class PaintContext
+    {
+        public PaintContext(CharInfo[] buf, Size bufSize, Rect drawRect)
+        {
+            _x = 0;
+            _y = 0;
+            _buf = buf;
+            _bufSize = bufSize;
+            _drawRect = drawRect;
+            _clipRect = drawRect;
+            _clipRect.Intersect(new Rect(0, 0, bufSize.Width, bufSize.Height));
+            _baseOffset = _clipRect.Top * bufSize.Width + _clipRect.Left;
+        }
+
+        public PaintContext(PaintContext underlying, Rect drawRect)
+        {
+            _buf = underlying._buf;
+            _bufSize = underlying._bufSize;
+            _drawRect = drawRect;
+            _clipRect = drawRect;
+            _clipRect.Intersect(underlying._clipRect);
+            _clipRect.Left += underlying._clipRect.Left;
+            _clipRect.Top += underlying._clipRect.Top;
+            _clipRect.Intersect(new Rect(0, 0, _bufSize.Width, _bufSize.Height));
+            _baseOffset = _clipRect.Top * _bufSize.Width + _clipRect.Left;
+        }
+
+        CharInfo[] _buf;            // The buffer to draw to
+        Size _bufSize;              // Size of the buffer
+        Rect _drawRect;             // Drawing rectangle
+        Rect _clipRect;             // Clip rectangle
+        int _baseOffset;            // Origin of first character
+        int _x;                     // Current output position
+        int _y;                     // Current output position
+
+        // Left margin for indent text writes
+        public int LeftMargin
+        {
+            get;
+            set;
+        }
+
+        // Whether to word wrap output text or not
+        public bool WordWrap
+        {
+            get;
+            set;
+        }
+
+        // Foreground color
+        ushort _attributes;
+        public ConsoleColor ForegroundColor
+        {
+            get { return (ConsoleColor)(_attributes & 0x0F); }
+            set { _attributes = (ushort)((_attributes & 0xF0) | (ushort)value); }
+        }
+
+        // Background color
+        public ConsoleColor BackgroundColor
+        {
+            get { return (ConsoleColor)((_attributes & 0xF0) >> 4); }
+            set { _attributes = (ushort)((_attributes & 0x0F) | ((ushort)value) << 4); }
+        }
+
+        // Current fore/back color attributes
+        public ushort Attributes
+        {
+            get
+            {
+                return _attributes;
+            }
+            set
+            {
+                _attributes = value;
+            }
+        }
+
+        // Clear to end of line when outputting a carriage return
+        bool _clearLineOnReturn;
+        public bool ClearLineOnReturn
+        {
+            get { return _clearLineOnReturn; }
+            set { _clearLineOnReturn = value; }
+        }
+
+        // Write text at the current position (and update position)
+        public void Write(string str)
+        {
+            for (int i = 0; i < str.Length; i++)
+            {
+                if (str[i] == '\r')
+                {
+                    // Clear to eol
+                    if (_clearLineOnReturn)
+                    {
+                        if (_y>=0 && _y<_clipRect.Height)
+                        {
+                            int pos = _baseOffset + _bufSize.Width * _y + _x;
+                            for (int x = _x; x < _clipRect.Width; x++, pos++)
+                            {
+                                _buf[pos].Char = ' ';
+                                _buf[pos].Attributes = _attributes;
+                            }
+                        }
+                    }
+                    _x = LeftMargin;
+                }
+                else if (str[i] == '\n')
+                {
+                    _y++;
+                }
+                else
+                {
+                    if (_x >= 0 && _y >= 0 && _x < _clipRect.Width && _y < _clipRect.Height)
+                    {
+                        int pos = _baseOffset + _bufSize.Width * _y + _x;
+                        _buf[pos].Char = str[i];
+                        _buf[pos].Attributes = _attributes;
+                    }
+
+                    _x++;
+
+                    if (WordWrap && _x >= _clipRect.Width)
+                    {
+                        _x = LeftMargin;
+                        _y++;
+                    }
+                }
+            }
+        }
+
+        // Write string and a carriage return
+        public void WriteLine(string str="")
+        {
+            Write(str);
+            Write("\r\n");
+        }
+
+        // Write formatted text
+        public void Write(string str, params object[] args)
+        {
+            Write(string.Format(str, args));
+        }
+
+        // Write formatted line
+        public void WriteLine(string str, params object[] args)
+        {
+            WriteLine(string.Format(str, args));
+        }
+
+        // Current position
+        public Point Position
+        {
+            get { return new Point(_x, _y); }
+            set { _x = value.X; _y = value.Y; }
+        }
+
+        // Clear the entire paint context
+        public void Clear()
+        {
+            // Clear buffer
+            for (int y = 0; y<_clipRect.Height; y++)
+            {
+                int pos = _baseOffset + _bufSize.Width * y;
+                for (int x = 0; x < _clipRect.Width; x++, pos++)
+                {
+                    _buf[pos].Attributes = _attributes;
+                    _buf[pos].Char = ' ';
+                }
+            }
+        }
+
+        // Set a specific character
+        public void SetChar(int x, int y, char ch)
+        {
+            if (x >= 0 && x < _clipRect.Width &&
+                y >= 0 && y < _clipRect.Height)
+            {
+                var pos = _baseOffset + _bufSize.Width * y + x;
+                _buf[pos].Char = ch;
+                _buf[pos].Attributes = _attributes;
+            }
+        }
+
+        // Set a character but don't set attributes
+        public void SetCharNoAttr(int x, int y, char ch)
+        {
+            if (x >= 0 && x < _clipRect.Width &&
+                y >= 0 && y < _clipRect.Height)
+            {
+                var pos = _baseOffset + _bufSize.Width * y + x;
+                _buf[pos].Char = ch;
+            }
+        }
+
+        // Set a character with supplied attributes
+        public void SetChar(int x, int y, char ch, ushort attributes)
+        {
+            if (x >= 0 && x < _clipRect.Width &&
+                y >= 0 && y < _clipRect.Height)
+            {
+                var pos = _baseOffset + _bufSize.Width * y + x;
+                _buf[pos].Char = ch;
+                _buf[pos].Attributes = attributes;
+            }
+        }
+
+        // Draw a box
+        public void DrawBox(Rect rect, bool doubleLine)
+        {
+            // Draw the box
+            var offsBottom = (rect.Height - 1) * rect.Width;
+            var offsRight = rect.Width - 1;
+
+            // Work out character set
+            char[] boxDraw;
+            if (doubleLine)
+            {
+                boxDraw = new char[] { '╔', '╗', '╚', '╝', '═', '═', '║', '║' };
+            }
+            else
+            {
+                boxDraw = new char[] { '┌', '┐', '└', '┘', '─', '─', '│', '│' };
+            }
+
+            // Corners
+            SetChar(rect.Left, rect.Top, boxDraw[0]);
+            SetChar(rect.Right - 1, rect.Top, boxDraw[1]);
+            SetChar(rect.Left, rect.Bottom - 1, boxDraw[2]);
+            SetChar(rect.Right - 1, rect.Bottom - 1, boxDraw[3]);
+
+            // Top/bottom
+            for (int i = 1; i < rect.Width - 1; i++)
+            {
+                SetChar(i, rect.Top, boxDraw[4]);
+                SetChar(i, rect.Bottom - 1, boxDraw[5]);
+            }
+
+            // Left/Right
+            for (int i = 1; i < rect.Height - 1; i++)
+            {
+                SetChar(rect.Left, i, boxDraw[6]);
+                SetChar(rect.Right - 1, i, boxDraw[7]);
+            }
+
+        }
+    }
+}

+ 36 - 0
ConFrames/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ConFrames")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ConFrames")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("62b605ab-0e2b-4e0c-ab08-5ecd66414808")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 164 - 0
ConFrames/Types.cs

@@ -0,0 +1,164 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ConFrames
+{
+    // Character info (matches format used by Windows Console API's)
+    [StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Unicode)]
+    public struct CharInfo
+    {
+        public char Char;
+        public ushort Attributes;
+    }
+
+    // Rectangle
+    public struct Rect
+    {
+        public Rect(int left, int top, int width, int height)
+        {
+            Left = left;
+            Top = top;
+            Width = width;
+            Height = height;
+        }
+
+        public int Left;
+        public int Top;
+        public int Width;
+        public int Height;
+
+        public int Right { get { return Left + Width; } }
+        public int Bottom { get { return Top + Height; } }
+        public Size Size { get { return new Size(Width, Height); } }
+
+        public bool IntersectsWith(Rect other)
+        {
+            // Does it intersect
+            if (other.Right < Left)
+                return false;
+            if (other.Left > Right)
+                return false;
+            if (other.Top > Bottom)
+                return false;
+            if (other.Bottom < Top)
+                return false;
+
+            return true;
+        }
+
+        public bool Intersect(Rect rectOther)
+        {
+            if (!IntersectsWith(rectOther))
+            {
+                Width = 0;
+                Height = 0;
+                return false;
+            }
+
+            var right = Right;
+            var bottom = Bottom;
+            Left = Math.Max(Left, rectOther.Left);
+            Width = Math.Min(right, rectOther.Right) - Left;
+            Top = Math.Max(Top, rectOther.Top);
+            Height = Math.Min(bottom, rectOther.Bottom) - Top;
+
+            return true;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+                return false;
+
+            if (!(obj is Rect))
+                return false;
+
+            return this == (Rect)obj;
+        }
+
+        public override int GetHashCode()
+        {
+            return Left.GetHashCode() ^ Top.GetHashCode() ^ Width.GetHashCode() ^ Height.GetHashCode();
+        }
+
+        public static bool operator ==(Rect a, Rect b)
+        {
+            return a.Left == b.Left && a.Top == b.Top && a.Width == b.Width && a.Height == b.Height;
+        }
+
+        public static bool operator !=(Rect a, Rect b)
+        {
+            return !(a == b);
+        }
+    }
+
+    // Point
+    public struct Point
+    {
+        public Point(int x, int y)
+        {
+            X = x;
+            Y = y;
+        }
+        public int X;
+        public int Y;
+    }
+
+    // Size
+    public struct Size
+    {
+        public Size(int width, int height)
+        {
+            Width = width;
+            Height = height;
+        }
+
+        public int Width;
+        public int Height;
+
+
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+                return false;
+
+            if (!(obj is Size))
+                return false;
+
+            return this == (Size)obj;
+        }
+
+        public override int GetHashCode()
+        {
+            return Width.GetHashCode() ^ Height.GetHashCode();
+        }
+
+        public static bool operator ==(Size a, Size b)
+        {
+            return a.Width == b.Width && a.Height == b.Height;
+        }
+
+        public static bool operator !=(Size a, Size b)
+        {
+            return !(a == b);
+        }
+
+    }
+
+    // View mode
+    public enum ViewMode
+    {
+        StdOut,
+        Desktop,
+    }
+
+    // Helper for working with attributes
+    public static class Attribute
+    {
+        public static ushort Make(ConsoleColor foreground, ConsoleColor background)
+        {
+            return (ushort)(((byte)background << 4) | (ushort)foreground);
+        }
+    }
+
+}

+ 256 - 0
ConFrames/Window.cs

@@ -0,0 +1,256 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConFrames
+{
+    public class Window
+    {
+        public Window(string title, Rect frameRectangle)
+        {
+            Title = title;
+            FrameRectangle = frameRectangle;
+
+            _clearAttributes = Attribute.Make(ConsoleColor.White, ConsoleColor.Blue);
+
+            _needsFrameRender = true;
+            _needsClientRender = true;
+        }
+
+        public int CursorX;
+        public int CursorY;
+
+        bool _needsFrameRender;
+        bool _needsClientRender;
+        bool _frameRenderedActive;
+        Rect _frame;
+        Desktop _manager;
+        CharInfo[] _buf;
+
+
+        // Current cursor position when this window is active
+        public Point CursorPosition
+        {
+            get { return new Point(CursorX, CursorY); }
+            set { CursorX = value.X; CursorY = value.Y; }
+        }
+
+        // Show the cursor?
+        public bool CursorVisible
+        {
+            get;
+            set;
+        }
+
+        // Default attributes to clear paint contexts with
+        ushort _clearAttributes;
+        public ushort ClearAttributes
+        {
+            get
+            {
+                return _clearAttributes;
+            }
+            set
+            {
+                _clearAttributes = value;
+            }
+        }
+
+        // Window title
+        string _title;
+        public string Title
+        {
+            get
+            {
+                return _title;
+            }
+            set
+            {
+                _title = value;
+                _needsFrameRender = true;
+                if (_manager != null)
+                    _manager.Invalidate(this);
+            }
+        }
+
+        // Window frame
+        public Rect FrameRectangle
+        {
+            get
+            {
+                return _frame;
+            }
+            set
+            {
+                if (_frame == value)
+                    return;
+
+                // Did it change size?
+                if (_frame.Size != value.Size)
+                {
+                    _needsClientRender = true;
+                    _needsFrameRender = true;
+                    _buf = null;
+                }
+
+                // Store new frame
+                _frame = value;
+
+                // Re-render desktop
+                if (_manager != null)
+                {
+                    _manager.InvalidateDesktop();
+                    _manager.Invalidate(this);
+                }
+            }
+        }
+
+        // Client size
+        public Size ClientSize
+        {
+            get
+            {
+                return new Size(FrameRectangle.Width - 2, FrameRectangle.Height - 2);
+            }
+        }
+
+        // Open the window and add to the desktop manager
+        public void Open(ConFrames.Desktop manager)
+        {
+            if (_manager != null)
+                throw new InvalidOperationException();
+
+            _manager = manager;
+            _manager.AddWindow(this);
+        }
+
+        // Close this window and remove from desktop
+        public void Close()
+        {
+            if (_manager != null)
+            {
+                _manager.RemoveWindow(this);
+                _manager = null;
+            }
+        }
+
+        // Override to paint the context of this window
+        public virtual void OnPaint(PaintContext ctx)
+        {
+        }
+
+        // Override receive key events
+        public virtual bool OnKey(ConsoleKeyInfo key)
+        {
+            return false;
+        }
+
+        // Force this window to repaint
+        public void Invalidate()
+        {
+            _needsClientRender = true;
+            if (_manager != null)
+                _manager.Invalidate(this);
+        }
+
+        // Is this window active?
+        public bool IsActive
+        {
+            get
+            {
+                if (_manager == null)
+                    return false;
+                return _manager.ActiveWindow == this;
+            }
+        }
+
+        // Activate this window
+        public void Activate()
+        {
+            if (_manager == null)
+                return;
+            _manager.ActiveWindow = this;
+        }
+
+
+        // Get a paint context for this window
+        public PaintContext GetPaintContext()
+        {
+            // Create buffer?
+            if (_buf == null)
+            {
+                _buf = new CharInfo[FrameRectangle.Width * FrameRectangle.Height];
+            }
+
+            var ctx = new PaintContext(_buf, FrameRectangle.Size, new Rect(1, 1, FrameRectangle.Width - 2, FrameRectangle.Height - 2));
+            ctx.Attributes = _clearAttributes;
+            _manager.Invalidate(this);
+            return ctx;
+        }
+
+        // Called by manager to draw this window - including frame
+        public virtual CharInfo[] Draw()
+        {
+            // Create buffer?
+            if (_buf == null)
+            {
+                _buf = new CharInfo[FrameRectangle.Width * FrameRectangle.Height];
+                _needsFrameRender = true;
+                _needsClientRender = true;
+            }
+
+            // Create paint context for the frame
+            var px = new PaintContext(_buf, new Size(FrameRectangle.Width, FrameRectangle.Height), new Rect(0, 0, FrameRectangle.Width, FrameRectangle.Height));
+
+            // Paint frame?
+            if (_needsFrameRender || _frameRenderedActive != IsActive)
+            {
+                _frameRenderedActive = IsActive;
+
+                // Draw border
+                if (IsActive)
+                {
+                    px.ForegroundColor = _manager.ActiveBorderLineColor;
+                    px.BackgroundColor = _manager.ActiveBorderBackgroundColor;
+                }
+                else
+                {
+                    px.ForegroundColor = _manager.InactiveBorderLineColor;
+                    px.BackgroundColor = _manager.InactiveBorderBackgroundColor;
+                }
+                px.DrawBox(new Rect(0, 0, FrameRectangle.Width, FrameRectangle.Height), IsActive);
+
+                // Draw title
+                if (!string.IsNullOrEmpty(Title))
+                {
+                    var title = " " + Title + " ";
+                    int titleX = (FrameRectangle.Width - title.Length) / 2;
+                    if (titleX < 2)
+                        titleX = 2;
+
+                    for (int i = 0; i < title.Length && i < FrameRectangle.Width - 4; i++)
+                    {
+                        _buf[titleX + i].Char = title[i];
+                    }
+                }
+            }
+
+            // Paint client area
+            if (_needsClientRender)
+            {
+                var ctx = new PaintContext(_buf, FrameRectangle.Size, new Rect(1, 1, FrameRectangle.Width - 2, FrameRectangle.Height - 2));
+                ctx.Attributes = _clearAttributes;
+                ctx.Clear();
+                OnPaint(ctx);
+            }
+
+            _needsClientRender = false;
+            _needsFrameRender = false;
+
+            return _buf;
+        }
+    }
+
+}

+ 6 - 0
Sample/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
+    </startup>
+</configuration>

+ 80 - 0
Sample/Program.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ConFrames;
+
+namespace Sample
+{
+    class Window1 : Window
+    {
+        public Window1() :base("Window 1", new Rect(0, 0, 100, 20))
+        {
+        }
+
+        public override void OnPaint(PaintContext ctx)
+        {
+            for (int i=0; i<20; i++)
+            {
+                ctx.WriteLine("This is line {0}", i + 1);
+            }
+        }
+    }
+
+    class Window2 : Window
+    {
+        public Window2() : base("Window 2", new Rect(0, 20, 100, 20))
+        {
+            CursorVisible = true;
+            CursorX = 5;
+            CursorY = 1;
+        }
+
+        public override void OnPaint(PaintContext ctx)
+        {
+            ctx.WriteLine("Type something, or use Ctrl+Tab to switch windows");
+            ctx.Write("blah>");
+        }
+
+        public override bool OnKey(ConsoleKeyInfo key)
+        {
+            if (key.KeyChar != 0)
+            {
+                var ctx = GetPaintContext();
+                ctx.SetChar(CursorX++, CursorY, key.KeyChar);
+            }
+            else
+            {
+                switch (key.Key)
+                {
+                    case ConsoleKey.LeftArrow:
+                        if (CursorX > 0)
+                            CursorX--;
+                        break;
+
+                    case ConsoleKey.RightArrow:
+                        if (CursorX < ClientSize.Width)
+                            CursorX++;
+                        break;
+
+                }
+            }
+            return base.OnKey(key);
+        }
+    }
+
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            var desktop = new Desktop(100, 40);
+            var w1 = new Window1();
+            var w2 = new Window2();
+            w1.Open(desktop);
+            w2.Open(desktop);
+
+            desktop.Process();
+        }
+    }
+}

+ 36 - 0
Sample/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Sample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Sample")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("885c73bb-668f-4ca1-8015-e8393b25c562")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 66 - 0
Sample/Sample.csproj

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{885C73BB-668F-4CA1-8015-E8393B25C562}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Sample</RootNamespace>
+    <AssemblyName>Sample</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\ConFrames\ConFrames.csproj">
+      <Project>{64905ddf-9d01-4a63-bd60-a2586008cee2}</Project>
+      <Name>ConFrames</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>