<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>C# &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/category/programming/c/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Mon, 28 Dec 2020 20:16:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Visual C#: GUI front-end for OpenSSH in Windows</title>
		<link>https://blog.andreev.it/2019/03/149-visual-c-gui-front-end-for-openssh-in-windows/</link>
					<comments>https://blog.andreev.it/2019/03/149-visual-c-gui-front-end-for-openssh-in-windows/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 04 Mar 2019 19:48:10 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[front-end]]></category>
		<category><![CDATA[OpenSSH]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4573</guid>

					<description><![CDATA[As of late 2018, Windows 10 and Windows 2019 come up with OpenSSH installed.&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>As of late 2018, Windows 10 and Windows 2019 come up with OpenSSH installed. I had to use OpenSSH in some of the scripts at work, but managing the connections became difficult. So, I created a small .NET program that manages SSH connections. It&#8217;s a very simple SSH GUI front-end for OpenSSH. It&#8217;s not meant to be a replacement for putty or any other SSH terminal programs.<br />
In case you get an error that your PEM certificate is wide open, change the permissions on that file. Do this from a command prompt, not from a Power Shell prompt.</p>
<pre class="brush: bash; title: ; notranslate">
set key=&quot;c:\folder\mykey.pem&quot;
cmd /c icacls %key% /c /t /inheritance:d
cmd /c icacls %key% /c /t /grant %username%:F
cmd /c icacls %key%  /c /t /remove Administrator BUILTIN\Administrators BUILTIN Everyone System Users &quot;Authenticated Users&quot;
cmd /c icacls %key%
</pre>
<p>Here is the <a href="https://github.com/klimenta/pusshy" rel="noopener noreferrer" target="_blank">link</a> to the GitHub repo.<br />
Here is a screenshot.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P126-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P126-01.png" alt="" width="699" height="160" class="aligncenter size-full wp-image-8461" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P126-01.png 699w, https://blog.andreev.it/wp-content/uploads/2019/03/P126-01-300x69.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P126-01-585x134.png 585w" sizes="(max-width: 699px) 100vw, 699px" /></a><br />
Here is the C# source. Click + to expand. </p>
<pre class="brush: csharp; collapse: true; light: false; title: ; toolbar: true; notranslate">
using System;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;

namespace pusshy
{
    public partial class frmpusshy : Form
    {
        //It holds the name of the header column when a cell is right-clicked
        //Used for hiding columns
        string strColumnHeader; 
        //When a user hits enter, the next selected cell is on the right, not the bottom one
        //It allows horizontal scrolling when typing, not vertical
        protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
        {
            int intColumn = gridHosts.CurrentCell.ColumnIndex;
            int intRow = gridHosts.CurrentCell.RowIndex;
            if (keyData == Keys.Enter)
            {
                if (intColumn == gridHosts.Columns.Count - 1)
                {
                    gridHosts.Rows.Add();
                    gridHosts.CurrentCell = gridHosts&#x5B;0, intRow + 1];
                }
                else
                {
                    gridHosts.CurrentCell = gridHosts&#x5B;intColumn + 1, intRow];
                }
                return true;
            }
            else
                return base.ProcessCmdKey(ref msg, keyData);
        }

        public frmpusshy()
        {
            InitializeComponent();
        }

        private void frmpusshy_FormClosed(object sender, FormClosedEventArgs e)
        {
            //Save the current size and position of the window
            //Used to remember these settings when the program is started next time
            Properties.Settings.Default&#x5B;&quot;Location&quot;] = this.Location;
            Properties.Settings.Default&#x5B;&quot;Size&quot;] = this.Size;
            Properties.Settings.Default.Save();
            //The local app data folder where settings and the data will be saved
            var strLocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            //The data is in pusshy.csv file under C:\Users\&lt;username&gt;\AppData\Local\pusshy
            var strFileName = strLocalAppData + &quot;/pusshy/&quot; + &quot;pusshy.csv&quot;;
            string strCellValue;
            //Open the file for saving
            StreamWriter csvFileWriter = new StreamWriter(strFileName, false);
            int intColumnCount = gridHosts.ColumnCount - 1;
            int intColCount = gridHosts.Columns.Count;
            //Iterate through the grid and save
            foreach (DataGridViewRow dataRowObject in gridHosts.Rows)
            {
                if (!dataRowObject.IsNewRow)
                {
                    string strDataFromGrid = &quot;&quot;;                    
                    for (int i = 0; i &lt;= intColumnCount; i++)
                    {
                        try
                        {
                            strCellValue = dataRowObject.Cells&#x5B;i].Value.ToString();
                        }
                        //If the cell has no value, replace it with blank string instead of null
                        catch (System.NullReferenceException exception)
                        {
                            strCellValue = &quot;&quot;;
                        }
                        //Create a comma separated line
                        if (i != 0)
                        {
                            strDataFromGrid = strDataFromGrid + ',' + strCellValue;
                        }
                        else
                        {
                            strDataFromGrid = strCellValue;
                        }
                    }
                    csvFileWriter.WriteLine(strDataFromGrid);
                }
            }
            csvFileWriter.Flush();
            csvFileWriter.Close();
        }
        //Tag the whole row if there is a password in the password column (column=2). Used to hide password cells
        private void gridHosts_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {            
            if (gridHosts.CurrentRow.Tag != null &amp;&amp; gridHosts.CurrentCell.ColumnIndex == 2)
            {
                e.Control.Text = gridHosts.CurrentRow.Tag.ToString();
            }
        }
        //Replace the text in the password cell (column=2) with dots
        private void gridHosts_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 2 &amp;&amp; e.Value != null)
            {                
                gridHosts.Rows&#x5B;e.RowIndex].Tag = e.Value;
                e.Value = new String('\u25CF', e.Value.ToString().Length);
            }
        }
        //Right-click on row header or column header
        private void gridHosts_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                var hit = gridHosts.HitTest(e.X, e.Y);
                var intCurrentColumnIndex = hit.ColumnIndex;
                //If the user right-clicks the column header display this menu
                if ((hit.Type == DataGridViewHitTestType.ColumnHeader))
                {
                    strColumnHeader = gridHosts.Columns&#x5B;intCurrentColumnIndex].HeaderText;
                    menuRightColumnClick.Show(MousePosition);
                }
                //If the user right-clicks the column header display this menu
                if ((hit.Type == DataGridViewHitTestType.RowHeader))
                {
                    menuRightRowClick.Show(MousePosition);
                }
            }
        }
        //Hide the column that was selected
        private void hideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            gridHosts.Columns&#x5B;strColumnHeader].Visible = false;
        }       
        //Delete a row
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in gridHosts.SelectedRows)
            {
                try
                {
                    gridHosts.Rows.Remove(row);
                }
                //Can't delete the bottom row. Catch the exception
                catch (InvalidOperationException exception)
                {
                    return;
                }
            }
        }

        private void frmpusshy_Load(object sender, EventArgs e)
        {
            //The local app data folder where settings and the data will be saved
            var strLocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            //The data is in pusshy.csv file under C:\Users\&lt;username&gt;\AppData\Local\pusshy
            var strFileName = strLocalAppData + &quot;/pusshy/&quot; + &quot;pusshy.csv&quot;;
            if (!File.Exists(strFileName))
            {
                return;
            }   
            //Clear the grid and load the pusshy.csv file
            gridHosts.Rows.Clear();
            StreamReader fileReader = new StreamReader(strFileName, false);
            int i = 0;
            while (fileReader.Peek() != -1)
            {
                var fileRow = fileReader.ReadLine();
                var fileDataField = fileRow.Split(',');
                gridHosts.Rows.Add(fileDataField);
                //var rd = fileDataField&#x5B;2];                
                i++;
            }
            fileReader.Dispose();
            fileReader.Close();
            //Change the size and the position of the application on load
            //With the settings that were saved last time the app was used
            this.Location = Properties.Settings.Default.Location;
            this.Size = Properties.Settings.Default.Size;
        }
        //When the user chooses Show All, all hidden columns will become visible
        private void showAllToolStripMenuItem_Click(object sender, EventArgs e)
        {            
            foreach (DataGridViewColumn column in gridHosts.Columns)
            {
                string strHeaderCaptionText = column.HeaderText;
                gridHosts.Columns&#x5B;strHeaderCaptionText].Visible = true;
            }                    
        }
        //When the user double-clicks a cell, launch the terminal
        private void gridHosts_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            string strCommand = &quot;&quot;;
            int intRowIndex = gridHosts.CurrentCell.RowIndex;  
            //Get all values from the row
            string strHost = gridHosts.Rows&#x5B;intRowIndex].Cells&#x5B;0].Value.ToString();
            string strLogin = gridHosts.Rows&#x5B;intRowIndex].Cells&#x5B;1].Value.ToString();
            string strPwd = gridHosts.Rows&#x5B;intRowIndex].Cells&#x5B;2].Value.ToString();
            string strCert = gridHosts.Rows&#x5B;intRowIndex].Cells&#x5B;3].Value.ToString();
            //If the password cell is empty, start the terminal with certificate
            if (strPwd == &quot;&quot;)
            {
                strCommand = &quot;\&quot;C:/windows/sysnative/OpenSSH/ssh.exe\&quot; -l &quot; + strLogin + &quot; &quot; + &quot;-i &quot; + strCert + &quot; &quot; + strHost;
            } else
            //Or without password
            {
                strCommand = &quot;\&quot;C:/windows/sysnative/OpenSSH/ssh.exe\&quot; -l &quot; + strLogin + &quot; &quot; + strHost;
            }
            Process.Start(&quot;powershell.exe&quot;, strCommand);            
        }
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/03/149-visual-c-gui-front-end-for-openssh-in-windows/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: CmdDepot &#8211; small clipboard utility</title>
		<link>https://blog.andreev.it/2019/01/144-visual-c-cmddepot-small-clipboard-utility/</link>
					<comments>https://blog.andreev.it/2019/01/144-visual-c-cmddepot-small-clipboard-utility/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 26 Jan 2019 13:24:17 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4354</guid>

					<description><![CDATA[While I was playing with docker, I needed some 10-15 commands executed repeatedly. At&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>While I was playing with docker, I needed some 10-15 commands executed repeatedly. At first, I was using the cursor up to search through the history, but at point there were so menu of them that I got lost. In bash, you can also use the command history and then execute the command from it if you know the line number by putting ! as a prefix, e.g. !20, but that didn&#8217;t work too. So, I&#8217;ve opened a notepad on a side and pasted my most used commands in a separate line. This worked better, but then while I was selecting and copying the lines, I would make mistakes and copy the line with a part of the next line or with the line feed character, so it executed immediately when pasted. I needed a small text edit where each line can be copied to the clipboard with a click of a button and can stay on top of the other windows. In addition, I needed many of these, so I needed something to spawn a new instance from the program itself. So, I made this utility that looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/01/P121-01.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/01/P121-01.png" alt="" width="300" height="81" class="aligncenter size-full wp-image-8405" /></a><br />
The program&#8217;s caption bar has been minimized so the program doesn&#8217;t take much real estate on the screen. The green bar on top is used to move the window. The buttons have captions to quickly display the function. Form left to right, button C copies from the text box to the clipboard, button P paste the text from clipboard into the text box, N means a new window &#8211; the program will start another instance of itself, the T button is a toggle &#8211; to stay on top of the other windows or not (if you have one monitor, this is very useful), and the last two buttons are minimize and exit. On the right bottom size there is a grip to resize the instance. This is how I use my program.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/01/P121-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/01/P121-02.png" alt="" width="497" height="365" class="aligncenter size-full wp-image-8406" srcset="https://blog.andreev.it/wp-content/uploads/2019/01/P121-02.png 497w, https://blog.andreev.it/wp-content/uploads/2019/01/P121-02-300x220.png 300w" sizes="(max-width: 497px) 100vw, 497px" /></a><br />
Anytime I need something, I just click on the C button and then right-click-Paste in my shell. No need to search through the history of your bash.<br />
The source and the exe are at github.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/cmddepot.git
</pre>
<p>The EXE is under cmddepot\CmdDepot\bin\Release folder.<br />
The main source. Click to expand.</p>
<pre class="brush: bash; collapse: true; light: false; title: ; toolbar: true; notranslate">
using System;
using System.Drawing;
using System.Windows.Forms;

namespace CmdDepot
{
    public partial class CmdDepot : Form
    {
        public CmdDepot()
        {
            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;
            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.ResizeRedraw, true);
        }
        private const int cGrip = 16;      // Grip size
        private const int cCaption = 5;   // Caption bar height;

        protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
            ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
            rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
            e.Graphics.FillRectangle(Brushes.Chartreuse, rc);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x84)
            {  // Trap WM_NCHITTEST
                Point pos = new Point(m.LParam.ToInt32());
                pos = this.PointToClient(pos);
                if (pos.Y &lt; cCaption)
                {
                    m.Result = (IntPtr)2;  // HTCAPTION
                    return;
                }
                if (pos.X &gt;= this.ClientSize.Width - cGrip &amp;&amp; pos.Y &gt;= this.ClientSize.Height - cGrip)
                {
                    m.Result = (IntPtr)17; // HTBOTTOMRIGHT
                    return;
                }
            }
            base.WndProc(ref m);
        }
    
        private void btnClose_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Application.Exit();
        }

        private void btnMinimize_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void btnPaste_Click(object sender, EventArgs e)
        {
            tbCmd.Paste();
        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(tbCmd.Text);
        }

        private void btnNew_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
        }

        private void btnStayOnTop_Click(object sender, EventArgs e)
        {
            this.TopMost = !this.TopMost;
            if (this.TopMost) {
                btnStayOnTop.BackColor = Color.Tomato;
            } else
            {
                btnStayOnTop.BackColor = btnCopy.BackColor;
            }            
        }
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/01/144-visual-c-cmddepot-small-clipboard-utility/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: Screenshot Grabber &#8211; Take screenshots automatically</title>
		<link>https://blog.andreev.it/2018/04/127-c-screenshot-grabber-take-screenshots-automatically/</link>
					<comments>https://blog.andreev.it/2018/04/127-c-screenshot-grabber-take-screenshots-automatically/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 21 Apr 2018 23:48:16 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=3819</guid>

					<description><![CDATA[I needed a tool that takes screenshots at a regular interval. No bells and&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I needed a tool that takes screenshots at a regular interval. No bells and whistles, just simple tool where you can specify at what interval you can take the screesnhots, the destination folder and the monitor (if you have more than one). It looks like this. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2018/04/P104-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/04/P104-01.png" alt="" width="303" height="237" class="aligncenter size-full wp-image-8219" /></a><br />
Click <strong>Start </strong>when you are ready and the tool will minimize itself. When you are done, double-click the icon in the tray or right-click on it and choose <strong>Open </strong>where you can <strong>Stop </strong>the screesnhot grabbing. </p>
<p>Here is the source for your review but you&#8217;ll need the whole C# solution in order to work. Get it (git clone) from <a href="https://github.com/klimenta/SSG" rel="noopener noreferrer" target="_blank">github</a>. You&#8217;ll need .NET 3.5. Here is the <a href="https://blog.andreev.it/wp-content/uploads/2018/04/SSG.7z">EXE</a>. </p>
<pre class="brush: cpp; collapse: true; light: false; title: ; toolbar: true; notranslate">
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;

namespace SSG
{
    public partial class Form1 : Form
    {

        //Get all available monitors
        Screen&#x5B;] scrScreens = Screen.AllScreens;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnFolderBrowser_Click(object sender, EventArgs e)
        {
            //Shows up the browse dialog for the destination files
            DialogResult drResult = fbdBrowserDialog.ShowDialog();
            if (drResult == DialogResult.OK)
            {
                tbFolder.Text = fbdBrowserDialog.SelectedPath;
            }

        }

        private void btnRecord_Click(object sender, EventArgs e)
        {
            //Check if valid interval
            int intInterval = 1000;
            if (!(Int32.TryParse(tbInterval.Text, out intInterval)))
            {
                MessageBox.Show(&quot;Not a valid interval.&quot;, &quot;SSG&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (intInterval &lt; 1)
            {
                MessageBox.Show(&quot;Not a valid interval.&quot;, &quot;SSG&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            timTimer.Interval = intInterval * 1000;
            //Check if folder exists
            if (!(Directory.Exists(tbFolder.Text)))
            {
                MessageBox.Show(&quot;The folder does not exist.&quot;, &quot;SSG&quot;, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (timTimer.Enabled)
            {
                timTimer.Enabled = false;
                btnRecord.Image = Properties.Resources.StartWithoutDebug_16x;
                return;
            }
            timTimer.Enabled = true;
            this.WindowState = FormWindowState.Minimized;
            btnRecord.Image = Properties.Resources.Stop_16x;            
        }

        private void timTimer_Tick(object sender, EventArgs e)
        {
            //Get the screenshots as JPG files
            Rectangle bounds = scrScreens&#x5B;cbMonitor.SelectedIndex].Bounds;
            using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(bounds.Left, bounds.Top, 0, 0, bounds.Size);
                }
                string strDateTime = DateTime.Now.ToString(&quot;yyyyMMddHHmmss&quot;);
                bitmap.Save(tbFolder.Text + &quot;\\&quot; + strDateTime + &quot;.jpg&quot;, ImageFormat.Jpeg);
            }

        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            //Minimize to tray
            if (this.WindowState == FormWindowState.Minimized)
            {
                Hide();
                niTrayIcon.Visible = true;
                if (timTimer.Enabled)
                {
                    niTrayIcon.Text = &quot;SSG - Recording&quot;;
                }
                else
                {
                    niTrayIcon.Text = &quot;SSG - Idle&quot;;
                }
            }
        }

        private void niTrayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
            this.WindowState = FormWindowState.Normal;
            niTrayIcon.Visible = false;
        }

        private void tsmiExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void tsmiOpen_Click(object sender, EventArgs e)
        {
            Show();
            this.WindowState = FormWindowState.Normal;
            niTrayIcon.Visible = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Adds the number of monitors in a combox box
            int intMonitors = scrScreens.Length;
            int intCounter = 0;
            while (intCounter &lt; intMonitors)
            {
                cbMonitor.Items.Add((intCounter + 1).ToString());
                intCounter++;
            }
            cbMonitor.SelectedIndex = 0;
        }
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2018/04/127-c-screenshot-grabber-take-screenshots-automatically/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: listen &#8211; utility for checking TCP sockets</title>
		<link>https://blog.andreev.it/2016/12/102-visual-c-listen-utility-checking-tcp-sockets/</link>
					<comments>https://blog.andreev.it/2016/12/102-visual-c-listen-utility-checking-tcp-sockets/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 10 Dec 2016 22:33:11 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[port listener]]></category>
		<category><![CDATA[tcp]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2964</guid>

					<description><![CDATA[I needed an utility that acts as a TCP server on a random port&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I needed an utility that acts as a TCP server on a random port and if a client telnets to that port, the server will have to return something to that client. There are probably a tons of utilities like this, ranging from PowerShell scripts to nc (netcat), but I&#8217;ve decided to make one in Visual C# 2015 using .NET 3.5.<br />
My utility is based on this <a href="https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.110).aspx" target="_blank" rel="noopener noreferrer">MSDN </a>article with slight modifications.<br />
So, launch the utility with the port in mind, e.g. <strong>listen -p 25000</strong> and the program will wait for someone to connect to that port. Once you do telnet <server_ip> 25000, you&#8217;ll be greeted with a banned from the utility. Type any key and you&#8217;ll get a response with the upper version of that key. Type q and it will terminate the session. The utility is useful to check TCP ports across networks. If you try to run the utility on a port that&#8217;s already in use, e.g. port 80 on a web server, the utility will throw an exception. Also, if you try to listen on port 443 and then go to https://server_ip, the utility will also throw an exception. Nevertheless, this means you have a connection.<br />
So, here is the source and <a href="https://github.com/klimenta/listen" target="_blank" rel="noopener noreferrer">link </a>to github repo.<br />
An image of listen in action.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/12/P081-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/12/P081-01.png" alt="" width="621" height="383" class="aligncenter size-full wp-image-7626" srcset="https://blog.andreev.it/wp-content/uploads/2016/12/P081-01.png 621w, https://blog.andreev.it/wp-content/uploads/2016/12/P081-01-300x185.png 300w, https://blog.andreev.it/wp-content/uploads/2016/12/P081-01-585x361.png 585w" sizes="(max-width: 621px) 100vw, 621px" /></a></p>
<pre class="brush: cpp; title: ; notranslate">
using System;
using System.Net;
using System.Net.Sockets;

namespace listen
{
    class Program
    {
        static void usage()
        {
            Console.WriteLine(new string('=', 42));
            Console.WriteLine(&quot;listen v1.0, Kliment Andreev 2016&quot;);
            Console.WriteLine(&quot;Usage: listen -p &lt;port&gt;&quot;);
            Console.WriteLine(&quot;Opens a TCP socket on a given port&quot;);
            Console.WriteLine(&quot;CTRL + C to exit or type q from the client&quot;);
            Console.WriteLine(new string('=', 42));
        }

        static void Main(string&#x5B;] args)
        {
            if ((args.Length == 0) || (args.Length != 2))
            {
                usage();
                return;
            }

            if (args&#x5B;0]!=&quot;-p&quot;)
            {
                Console.WriteLine(&quot;Unknown switch {0}&quot;, args&#x5B;0]);
                usage();
                return;
            }

            int intTemp;
            bool bisNumeric = int.TryParse(args&#x5B;1], out intTemp);
            if (!bisNumeric)
            {
                usage();
                return;
            }
           
            TcpListener server = null;
            try
            {
                // Set the TcpListener on port intTemp.
                Int32 intPort = intTemp;
                IPAddress localAddr = IPAddress.Parse(&quot;0.0.0.0&quot;);
                // TcpListener server = new TcpListener(port);
                server = new TcpListener(localAddr, intPort);
                // Start listening for client requests.
                server.Start();
                // Buffer for reading data
                Byte&#x5B;] bytes = new Byte&#x5B;4096];
                
                String data = null;
                // Enter the listening loop.
                while (true)
                {
                    usage();
                    Console.WriteLine(&quot;I am listening on {0}... &quot;, intPort);
                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine(&quot;=====&gt; Connected to {0}&quot;, client.Client.RemoteEndPoint);
                    data = null;
                    // Get a stream object for reading and writing
                    NetworkStream stream = client.GetStream();
                    byte&#x5B;] banner = System.Text.Encoding.ASCII.GetBytes(
                        &quot;listen v1.0, Kliment Andreev 2016\r\nType q to exit\r\n&quot; 
                        + &quot;Connected to &quot; + client.Client.LocalEndPoint + &quot;\r\n&quot;);
                    stream.Write(banner, 0, banner.Length);
                    int intLoop;
                    // Loop to receive all the data sent by the client.
                    while ((intLoop = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Translate data bytes to a ASCII string.
                        data = System.Text.Encoding.ASCII.GetString(bytes, 0, intLoop);
                        Console.WriteLine(&quot;Received: {0} from {1}&quot;, data, client.Client.RemoteEndPoint);
                        // Process the data sent by the client.
                        data = data.ToUpper();
                        if (data == &quot;Q&quot;) return;
                        byte&#x5B;] msg = System.Text.Encoding.ASCII.GetBytes(data);
                        // Send back a response.                        
                        stream.Write(msg, 0, msg.Length);                        
                        Console.WriteLine(&quot;Sent: {0} to {1}&quot;, data, client.Client.RemoteEndPoint);
                    }

                    // Shutdown and end connection
                    client.Close();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(&quot;SocketException: {0}&quot;, e);
            }
            finally
            {
                // Stop listening for new clients.
                //server.Stop();
            }
        }
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/12/102-visual-c-listen-utility-checking-tcp-sockets/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: KRSS &#8211; mini RSS feed tracker</title>
		<link>https://blog.andreev.it/2016/10/97-visual-c-krss-mini-rss-feed-tracker/</link>
					<comments>https://blog.andreev.it/2016/10/97-visual-c-krss-mini-rss-feed-tracker/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 17 Oct 2016 16:13:26 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[RSS reader]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2808</guid>

					<description><![CDATA[I made a small RSS feed tracker that monitors up to 5 RSS feeds&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I made a small RSS feed tracker that monitors up to 5 RSS feeds and displays the changes in combo boxes. The program looks like this. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/10/P076-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/10/P076-01.png" alt="" width="490" height="204" class="aligncenter size-full wp-image-7571" srcset="https://blog.andreev.it/wp-content/uploads/2016/10/P076-01.png 490w, https://blog.andreev.it/wp-content/uploads/2016/10/P076-01-300x125.png 300w" sizes="(max-width: 490px) 100vw, 490px" /></a><br />
If you want to read the full article, select it from the drop down box and click on it. If you just want to see all of the available articles, click on the down arrow. Anytime you click on the article, it will open your default browser. For any other articles, a new tab will be opened. </p>
<p>The program can be minimized in the tray (double-click to bring it back). Every minute the program will check for any changes and if there are any, they will be displayed as a balloon tip.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/10/P076-02.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/10/P076-02.jpg" alt="" width="408" height="107" class="aligncenter size-full wp-image-7572" srcset="https://blog.andreev.it/wp-content/uploads/2016/10/P076-02.jpg 408w, https://blog.andreev.it/wp-content/uploads/2016/10/P076-02-300x79.jpg 300w" sizes="(max-width: 408px) 100vw, 408px" /></a></p>
<p>Under Windows 10, it looks like this.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/10/P076-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/10/P076-03.png" alt="" width="367" height="173" class="aligncenter size-full wp-image-7573" srcset="https://blog.andreev.it/wp-content/uploads/2016/10/P076-03.png 367w, https://blog.andreev.it/wp-content/uploads/2016/10/P076-03-300x141.png 300w" sizes="(max-width: 367px) 100vw, 367px" /></a><br />
By default, the following 5 RSS sites are monitored. </p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
https://blog.andreev.it/?feed=rss2
http://feeds.bbci.co.uk/news/world/rss.xml
http://feeds.feedburner.com/neowin-main
http://feeds.gawker.com/lifehacker/full.xml
http://feeds.mashable.com/Mashable
</pre>
<p>If you want to check other feeds, click on the button in the lower right corner and when the settings window pops up, enter your RSS URLs and click OK.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/10/P076-04.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/10/P076-04.jpg" alt="" width="491" height="295" class="aligncenter size-full wp-image-7574" srcset="https://blog.andreev.it/wp-content/uploads/2016/10/P076-04.jpg 491w, https://blog.andreev.it/wp-content/uploads/2016/10/P076-04-300x180.jpg 300w" sizes="(max-width: 491px) 100vw, 491px" /></a><br />
If there are any issues with the feeds, you can delete the whole KRSS folder that&#8217;s under:</p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
C:\Users\%username%\AppData\Local
</pre>
<p>The C# code can be found at https://github.com/klimenta/KRSS and you can download the EXE from there as well (https://github.com/klimenta/KRSS/tree/master/KRSS/bin/Release/KRSS.exe)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/10/97-visual-c-krss-mini-rss-feed-tracker/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: Weather Gadget &#8211; WUnderK</title>
		<link>https://blog.andreev.it/2016/04/89-visual-c-weather-gadget-wunderk/</link>
					<comments>https://blog.andreev.it/2016/04/89-visual-c-weather-gadget-wunderk/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Thu, 21 Apr 2016 16:07:04 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Visual C#]]></category>
		<category><![CDATA[weather gadget]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2568</guid>

					<description><![CDATA[Wunderground and free API keys NOTE: Wunderground discontinued the use of free API keys&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">Wunderground and free API keys</span> </strong></p>
<p style="text-align:left;"><center>NOTE: Wunderground discontinued the use of free API keys so this solution won&#8217;t work anymore. There are some other sites that offer free API keys and weather services but the program will require some heavy modification in order to work.<a href="http://paul-barford.blogspot.com/"></center> </a></p>
</div>
<p>I miss the onscreen weather gadget that was included in Windows 7, but not in Windows 10, so I made a similar application. It gets the current weather and the forecast from the Weather Underground web site. Initially I tried to use OpenWeatherMap and its API but the temperatures were off for an hour or two, meaning the current temperature that I got from the API call was the actual temperature 1-2 hours ago.<br />
Both Weather Underground and OpenWeatherMap offer free API calls and you need to register in order to get an API key. Using that key, you can retrieve the weather. No key &#8211; no weather forecast.</p>
<p>So, first go to WU web <a href="https://www.wunderground.com/weather/api/" target="_blank" rel="noopener noreferrer">site</a>, register and get a key.<br />
If you want to get the source, make sure that you have JSON from Netwtonsoft in your project reference. See their web <a href="http://www.newtonsoft.com/json" target="_blank" rel="noopener noreferrer">page </a>for install.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/WUnderK
</pre>
<p>If you want the EXE, you&#8217;ll have to install it because the EXE comes with the Json.dll.<br />
Download it from <a href="https://blog.andreev.it/wp-content/uploads/2016/04/WUnderKInstaller.7z" target="_blank" rel="noopener noreferrer">here</a>. </p>
<p>NOTE: The WU API returns JSON which can be parsed and validated on <a href="https://jsonformatter.curiousconcept.com/" target="_blank" rel="noopener noreferrer">this </a>web site for accuracy. The output was deserialized directly to C# classes and the conversion was possible because of <a href="http://json2csharp.com/" target="_blank" rel="noopener noreferrer">this </a>site. </p>
<p>This is how the gadget (app) looks like expanded with the details and forecast panes. You can hide them if you want, so only the temperature and the city is shown.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/04/P068-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P068-01.png" alt="" width="662" height="278" class="aligncenter size-full wp-image-7482" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P068-01.png 662w, https://blog.andreev.it/wp-content/uploads/2016/04/P068-01-300x126.png 300w, https://blog.andreev.it/wp-content/uploads/2016/04/P068-01-585x246.png 585w" sizes="(max-width: 662px) 100vw, 662px" /></a><br />
This is the options screen.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/04/P068-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P068-02.png" alt="" width="494" height="376" class="aligncenter size-full wp-image-7483" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P068-02.png 494w, https://blog.andreev.it/wp-content/uploads/2016/04/P068-02-300x228.png 300w" sizes="(max-width: 494px) 100vw, 494px" /></a><br />
And this is how it looks like on the screen.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/04/P068-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P068-03.png" alt="" width="625" height="537" class="aligncenter size-full wp-image-7484" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P068-03.png 625w, https://blog.andreev.it/wp-content/uploads/2016/04/P068-03-300x258.png 300w, https://blog.andreev.it/wp-content/uploads/2016/04/P068-03-585x503.png 585w" sizes="(max-width: 625px) 100vw, 625px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/04/89-visual-c-weather-gadget-wunderk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: 5ball &#8211; game</title>
		<link>https://blog.andreev.it/2016/04/88-visual-c-5ball-game/</link>
					<comments>https://blog.andreev.it/2016/04/88-visual-c-5ball-game/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 11 Apr 2016 14:03:27 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2556</guid>

					<description><![CDATA[This is an old game that I made about 15 years ago. The original&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>This is an old game that I made about 15 years ago. The original game can be found on my old web <a href="http://www.futurebit.com/" target="_blank" rel="noopener noreferrer">site</a>. Look for <a href="http://www.futurebit.com/kling2001.htm" target="_blank" rel="noopener noreferrer">Kling! 2.001</a> and <a href="http://www.futurebit.com/kling.htm" target="_blank" rel="noopener noreferrer">Kling</a>!</p>
<p>Lately, when I played with C#, I decided to remake it. The original games were written in Delphi (Pascal).<br />
You can get the source from GitHub.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/5ball
</pre>
<p>The goal is to match 5 or more balls in any direction. Once you do that, they&#8217;ll disappear. But, every move you make, three more random balls are dropped on the grid. </p>
<p>You can get the <a href="https://blog.andreev.it/wp-content/uploads/2016/04/5ball.zip" target="_blank" rel="noopener noreferrer">EXE </a>from here.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/04/P067-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P067-01.png" alt="" width="549" height="597" class="aligncenter size-full wp-image-7479" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P067-01.png 549w, https://blog.andreev.it/wp-content/uploads/2016/04/P067-01-276x300.png 276w" sizes="(max-width: 549px) 100vw, 549px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/04/88-visual-c-5ball-game/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: CPU monitoring gadget</title>
		<link>https://blog.andreev.it/2016/04/86-visual-c-cpu-monitoring-gadget/</link>
					<comments>https://blog.andreev.it/2016/04/86-visual-c-cpu-monitoring-gadget/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 01 Apr 2016 22:57:54 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[CPU monitoring]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2520</guid>

					<description><![CDATA[Windows 7 came with gadgets, small tools that sit on your desktop and do&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Windows 7 came with gadgets, small tools that sit on your desktop and do something. I used CPU/Memory gadget and the Weather gadget. Windows 8 and Windows 10, discontinued the gadgets, but there are <a href="http://www.intowindows.com/desktop-gadgets-for-windows-10/" target="_blank" rel="noopener noreferrer">some</a> <a href="http://win7gadgets.com/blog/how-install-desktop-gadgets-windows-10/" target="_blank" rel="noopener noreferrer">ways </a>of how to install them back under Win 10. </p>
<p>I made a small tool in Visual C# (Community edition 2015) that does pretty much the same. It monitors the CPU usage and draws a graph. You can choose the background, transparency, threshold colors, etc&#8230; See the options screenshot below.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/04/P065-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P065-01.png" alt="" width="320" height="292" class="aligncenter size-full wp-image-7474" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P065-01.png 320w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-01-300x274.png 300w" sizes="(max-width: 320px) 100vw, 320px" /></a><br />
You can get the source here.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/CPU-Gadget
</pre>
<p>If you get an exception while trying to compile or execute the program, it means your counters in registry are messed up.<br />
This is the error that you might get.</p>
<pre class="brush: bash; title: ; notranslate">
InvalidOperationException: Cannot load Counter Name data because an invalid index '' was read from the registry.
</pre>
<p>Open the command prompt (Run as Administrator) and execute these commands depending on your OS (32/64) bit.</p>
<pre class="brush: bash; title: ; notranslate">
C:\windows\system32&gt; lodctr /r
</pre>
<p>or </p>
<pre class="brush: bash; title: ; notranslate">
C:\windows\SysWOW64&gt; lodctr /r
</pre>
<p>You should get this back if everything is OK.</p>
<pre class="brush: plain; title: ; notranslate">
Info: Successfully rebuilt performance counter setting from system backup store
</pre>
<p>If you get this, you are doing it for 32 bit OS instead of 64 bit OS and vice versa.</p>
<pre class="brush: plain; title: ; notranslate">
Error: Unable to rebuild performance counter setting from system backup store, error code is 2
</pre>
<p>This is how the gadget looks like on the desktop (click for larger image).<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/04/P065-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/04/P065-02.png" alt="" width="1280" height="800" class="aligncenter size-full wp-image-7475" srcset="https://blog.andreev.it/wp-content/uploads/2016/04/P065-02.png 1280w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-02-300x188.png 300w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-02-1024x640.png 1024w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-02-768x480.png 768w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-02-1170x731.png 1170w, https://blog.andreev.it/wp-content/uploads/2016/04/P065-02-585x366.png 585w" sizes="(max-width: 1280px) 100vw, 1280px" /></a><br />
UPDATE 4/12/2016<br />
================</p>
<p>Based on this source, I made slight modifications for another gadget that monitors the available RAM usage.<br />
You can get the code here.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/CPU-Gadget
</pre>
<p>Or get both executables from <a href="https://blog.andreev.it/wp-content/uploads/2016/04/CPU-Gadget.7z" target="_blank" rel="noopener noreferrer">here (CPU Gadget)</a> and <a href="https://blog.andreev.it/wp-content/uploads/2016/04/RAM-Gadget.7z" target="_blank" rel="noopener noreferrer">here (RAM Gadget)</a>. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/04/86-visual-c-cpu-monitoring-gadget/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C# : Create Outlook VSTO plugin</title>
		<link>https://blog.andreev.it/2016/03/85-visual-c-create-outlook-vsto-plugin/</link>
					<comments>https://blog.andreev.it/2016/03/85-visual-c-create-outlook-vsto-plugin/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 18 Mar 2016 14:38:41 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Outlook]]></category>
		<category><![CDATA[plug-in]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2501</guid>

					<description><![CDATA[I used Visual C# and MS Office Development Tools to create a VSTO plugin&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I used Visual C# and MS Office Development Tools to create a VSTO plugin for Outlook. Anytime you receive an email that have the words &#8220;please advise&#8221;, &#8220;please assist&#8221; or &#8220;kindly&#8221;, you&#8217;ll see a red banner in the email.</p>
<p>As Urban Dictionary says, please advise is &#8220;<em>an extremely stuffy phrase used by business executives to close emails when they don&#8217;t understand how to ask a real question. It basically means Please use your imagination to figure out what the f* I need to know to make a decision on this item without making me look like an idiot in front of all the people I CCed&#8221;</em></p>
<pre class="brush: plain; title: ; notranslate">
Dear Luke,

I recently got a call from Alex in LA telling me that we're out of blinkity blank in California so the blippity blue isn't working. 
What-the-f* we're losing 15k a day what-the-f* save me please.

Please Advise, 
John
</pre>
<p>So&#8230;. Go to Visual Studio, choose a new Project and select Outlook. I did mine for Outlook 2010, but it should be very similar for 2013 and 2016.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/03/P064-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/03/P064-01.png" alt="" width="955" height="660" class="aligncenter size-full wp-image-7469" srcset="https://blog.andreev.it/wp-content/uploads/2016/03/P064-01.png 955w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-01-300x207.png 300w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-01-768x531.png 768w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-01-585x404.png 585w" sizes="(max-width: 955px) 100vw, 955px" /></a><br />
Once you have the template, update the methods, so it looks like the source below. Change the list of words if you like (line 29), then compile and run and the add-in will be automatically added to Outlook. If you want to distribute it, it&#8217;s a bit more complicated, but check this <a href="https://msdn.microsoft.com/en-us/library/cc442767.aspx" target="_blank" rel="noopener noreferrer">page</a> or this <a href="https://blogs.msdn.microsoft.com/emeamsgdev/2013/11/21/outlook-deploying-an-outlook-2013-add-in-using-installshield-le/" target="_blank" rel="noopener noreferrer">page</a>. </p>
<p>If everything is OK, next time you receive an e-mail it will look like this.<a href="https://blog.andreev.it/wp-content/uploads/2016/03/P064-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/03/P064-02.png" alt="" width="1057" height="324" class="aligncenter size-full wp-image-7470" srcset="https://blog.andreev.it/wp-content/uploads/2016/03/P064-02.png 1057w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-02-300x92.png 300w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-02-1024x314.png 1024w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-02-768x235.png 768w, https://blog.andreev.it/wp-content/uploads/2016/03/P064-02-585x179.png 585w" sizes="(max-width: 1057px) 100vw, 1057px" /></a></p>
<pre class="brush: cpp; title: ; notranslate">
using System.Collections.Generic;
using System.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace PleaseAdvise
{
    public partial class ThisAddIn
    {

        Outlook.NameSpace outlookNameSpace;
        Outlook.MAPIFolder inbox;
        Outlook.Items items;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            outlookNameSpace = this.Application.GetNamespace(&quot;MAPI&quot;);
            inbox = outlookNameSpace.GetDefaultFolder(
                    Microsoft.Office.Interop.Outlook.
                    OlDefaultFolders.olFolderInbox);

            items = inbox.Items;
            items.ItemAdd +=
                new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
  
        }

        void items_ItemAdd(object Item)
        {            
            List&lt;string&gt; lstKeyWords = new List&lt;string&gt;(new string&#x5B;] { &quot;PLEASE ADVISE&quot;, &quot;PLEASE ASSIST&quot;, &quot;KINDLY&quot; });
            Outlook.MailItem mail = (Outlook.MailItem)Item;
            if (Item != null)
            {
                bool bSubject = lstKeyWords.Any(mail.Subject.ToUpper().Contains);
                bool bBody = lstKeyWords.Any(mail.Body.ToUpper().Contains);
              
                if ((mail.MessageClass == &quot;IPM.Note&quot;) &amp;&amp; (bSubject || bBody))
                {
                    mail.FlagIcon = Outlook.OlFlagIcon.olRedFlagIcon;
                }
            }
        }
    
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            // Note: Outlook no longer raises this event. If you have code that 
            //    must run when Outlook shuts down, see http://go.microsoft.com/fwlink/?LinkId=506785
        }

        #region VSTO generated code

        /// &lt;summary&gt;
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// &lt;/summary&gt;
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/03/85-visual-c-create-outlook-vsto-plugin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Visual C#: TCP/ICMP monitoring program &#8211; kmon</title>
		<link>https://blog.andreev.it/2016/03/84-visual-c-simple-tcpicmp-monitoring-program-kmon/</link>
					<comments>https://blog.andreev.it/2016/03/84-visual-c-simple-tcpicmp-monitoring-program-kmon/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Thu, 17 Mar 2016 18:05:51 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Visual C#]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2497</guid>

					<description><![CDATA[I needed some small program that will work in the background and do basic&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I needed some small program that will work in the background and do basic PING checks. Then I&#8217;ve decided to expand the scope and include TCP port checks, so I made this small program in Visual C#. You can get the program from GitHub.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://www.github.com/klimenta/kmon
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/03/P063-01.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/03/P063-01.jpg" alt="" width="508" height="375" class="aligncenter size-full wp-image-7465" srcset="https://blog.andreev.it/wp-content/uploads/2016/03/P063-01.jpg 508w, https://blog.andreev.it/wp-content/uploads/2016/03/P063-01-300x221.jpg 300w" sizes="(max-width: 508px) 100vw, 508px" /></a><br />
As you can see from the screenshot, the top left buttons are used to <strong>add/remove a server</strong>. Each server can have maximum of <strong>6 ports that can be monitored</strong> plus <strong>ping (ICMP)</strong>. When you click on the <strong>red/green button</strong>, it enables or disables the monitoring. The <strong>time interval</strong> of 5 seconds (default) means that the program will do its checks for 5 seconds and then stop for 5 seconds. The more servers you have, the more your time interval should be. Do about 1-2 seconds per server for internal servers and 3-4 seconds for external (internet facing) servers. The <strong>timeout value</strong> of 100 ms means that when checking TCP ports, the program will wait for 100 ms before giving up. If your services are slow in response, increase this value. </p>
<p>There are also three buttons (SA, CLR and CPY). When clicked, they <strong>Select All</strong> the text from the text box, <strong>Clear</strong> the text and/or <strong>Copy </strong>it to the clipboard. </p>
<pre class="brush: cpp; collapse: true; light: false; title: ; toolbar: true; notranslate">
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.ComponentModel;
using System.Drawing;
using System.Text;

namespace kmon
{

    public partial class frmMain : Form
    {
        //All checks are running as background processes, otherwise the GUI would be very unresponsive
        private BackgroundWorker bw = new BackgroundWorker();
        //Ping average in ms
        double dPingTimeAverage;
        //Holds the status of each TCP port (open/closed)
        bool bCheckOpenTCPPort;
        //kmon can monitor up to 6 ports. You can probably go with more
        const int iNumberOfPorts = 6;
        //A list of Text Boxes for the ports
        List&lt;TextBox&gt; tbPort = new List&lt;TextBox&gt;();
        //Temp variable/counter
        public int intCounter = 0;
        //Default timeout for ping or port checks before kmon gives up
        int intTimeout = 100; //Default = 100 ms
        //Time interval for all checks. kmon will do it's job for 5 secs then pause for 5 secs
        int intTimeInterval = 5000; //Default 5 sec

        //Checks if the TCP port is open or closed
        public static bool CheckOpenTCPPort(string host, int port, int intTimeout)
        {
            bool bOpenPort = false;
            try
            {            
                TcpClient tcpClient = new TcpClient();
                tcpClient.ReceiveTimeout = intTimeout;
                tcpClient.SendTimeout = intTimeout;
                var AsyncResult = tcpClient.BeginConnect(host, port, null, null);
                var waitHandle = AsyncResult.AsyncWaitHandle;
                try
                {
                    if (!AsyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(intTimeout), false))
                {
                        // wait handle didn't came back in time
                        tcpClient.Close();
                    }
                    else
                    {
                        // The result was positiv
                        bOpenPort = tcpClient.Connected;
                    }
                    // ensure the ending-call
                    tcpClient.EndConnect(AsyncResult);
                }
                finally
                {
                    // Ensure to close the wait handle.
                    waitHandle.Close();
                }
            }
            catch
            {
            }
            return bOpenPort;
        }

        //Returns the ping time average. If the return value is negative 1 (-1), it means the host is not reachable.
        //It doesn't necessarily means it's down. It means, ICMP protocolo can not be established between kmon and the end host.
        public static double PingTimeAverage(string host, int timeout)
        {
            Ping pingSender = new Ping();
            PingOptions options = new PingOptions();
            options.DontFragment = true;
            string data = &quot;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&quot;;
            byte&#x5B;] buffer = Encoding.ASCII.GetBytes(data);
            //int timeout = 
            PingReply reply = pingSender.Send(host, timeout, buffer, options);
            if (reply.Status == IPStatus.Success)
            {
                return reply.RoundtripTime;
            }
            else
            { return -1.0; }
        }

        //A class for each monitored server
        public class Server
        {
            //Server name
            public string strServerName { get; set; }
            //Ping monitoring (y/n)
            public bool bPing { get; set; }
            //TCP Ports
            public List&lt;int&gt; lstPorts = new List&lt;int&gt;();
        }

        //Initialize a list of server objects
        List&lt;Server&gt; srvServer = new List&lt;Server&gt;();
        //Toggle for monitoring/not monitoring button
        private bool bMonitor = false;
        
        public frmMain()
        {
            InitializeComponent();
            btnMonitor.BackColor = System.Drawing.Color.Red;
            btnMonitor.Text = &quot;Not Monitoring&quot;;
            
            for (int i = 0; i &lt; iNumberOfPorts; i++)
            {
                TextBox newTextBox = new TextBox();
                tbPort.Add(newTextBox);
                tbPort&#x5B;i].Width = 45;
                tbPort&#x5B;i].Height = 20;
                                
                tbPort&#x5B;i].TabIndex = i + 10;
                tbPort&#x5B;i].Text = &quot;0&quot;;
                tbPort&#x5B;i].Name = &quot;tbPort&quot; + i.ToString();
                tbPort&#x5B;i].Tag= i;
                tbPort&#x5B;i].TextChanged += new EventHandler(tbPort_TextChanged);
                this.Controls.Add(newTextBox);
            }
            tbPort&#x5B;0].Top = 45; tbPort&#x5B;1].Top = 45; tbPort&#x5B;2].Top = 45;
            tbPort&#x5B;3].Top = 75; tbPort&#x5B;4].Top = 75; tbPort&#x5B;5].Top = 75;
            tbPort&#x5B;0].Left = 221; tbPort&#x5B;3].Left = 221;
            tbPort&#x5B;1].Left = 335; tbPort&#x5B;4].Left = 335;
            tbPort&#x5B;2].Left = 449; tbPort&#x5B;5].Left = 449;


            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);            
        }

        //Event when you change the port to be monitored
        protected void tbPort_TextChanged(object sender, EventArgs e)
        {
            int intPort;
            int intCheck = lbServers.SelectedIndices.Count;
            
            if (lbServers.SelectedIndex == -1)
            {
                MessageBox.Show(&quot;You have to select a server on the left side&quot;, &quot;Error&quot;);
                return;
            }
            try
            {                
                intPort = Convert.ToInt32((sender as TextBox).Text.Trim());
                if (intPort &gt; 65535) intPort = 65535;           
            }
            catch (Exception)
            {
                (sender as TextBox).Text = &quot;0&quot;;
                return;
            }
            srvServer&#x5B;lbServers.SelectedIndex].lstPorts&#x5B;Convert.ToInt32((sender as TextBox).Tag)] = intPort;            
        }

        //Add server to be monitored
        private void btnAdd_Click(object sender, EventArgs e)
        {
            frmAddServer frm2 = new frmAddServer();
            frm2.ShowDialog();
            //Prevent duplicates
            if (frmAddServer.strServerName == null || frmAddServer.strServerName == &quot;&quot;) return;
            if (!lbServers.Items.Contains(frmAddServer.strServerName))
            {
                lbServers.Items.Add(frmAddServer.strServerName);
                srvServer.Add(new Server { strServerName = frmAddServer.strServerName, bPing = false, lstPorts = new List&lt;int&gt;(iNumberOfPorts) { 0, 0, 0, 0, 0, 0 } });                
            }
            else
            {
                MessageBox.Show(&quot;Duplicate entry. Please re-enter.&quot;, &quot;kmon&quot;);
            }            
        }

        //Remove server from being monitored
        private void btnRemove_Click(object sender, EventArgs e)
        {
            for (int intCounter = lbServers.SelectedIndices.Count - 1; intCounter &gt;= 0; intCounter--)
            {
                int intIndex = lbServers.SelectedIndices&#x5B;intCounter];
                lbServers.Items.RemoveAt(intIndex);
                srvServer.RemoveAt(intIndex);
            }
        }

        //Toggle button monitor/not monitor
        private void btnMonitor_Click(object sender, EventArgs e)
        {            
            if (bMonitor)
            {
                bMonitor = false;
                btnMonitor.BackColor = Color.Red;
                btnMonitor.Text = &quot;Not Monitoring&quot;;               
                if (bw.WorkerSupportsCancellation == true)
                {
                    bw.CancelAsync();
                }
            }
            else
            {
                bMonitor = true;
                btnMonitor.BackColor = Color.Green;
                btnMonitor.Text = &quot;Monitoring&quot;;               
                if (bw.IsBusy != true)
                {
                    bw.RunWorkerAsync();
                }
            }
        }

        //Event when you change the time interval
        private void tbInterval_TextChanged(object sender, EventArgs e)
        {
            try
            {
                intTimeInterval = Convert.ToInt32(tbInterval.Text.Trim()) * 1000;                
            }
            catch (Exception)
            {
                tbInterval.Text = &quot;5&quot;;
            }
        }

        //Event when you select the server from the list of servers
        private void lbServers_SelectedIndexChanged(object sender, EventArgs e)
        {            
            try
            {               
                for (int i = 0; i &lt; iNumberOfPorts; i++)
                {
                    tbPort&#x5B;i].Text = srvServer&#x5B;lbServers.SelectedIndex].lstPorts&#x5B;i].ToString();
                }                    
                cbPing.Checked = srvServer&#x5B;lbServers.SelectedIndex].bPing;
            }
            catch (Exception)
            { }            
        }

        //Check mark event ping/not ping
        private void cbPing_CheckedChanged(object sender, EventArgs e)
        {
            int intCheck = lbServers.SelectedIndices.Count;
            if (lbServers.SelectedIndex == -1)
            {
                MessageBox.Show(&quot;You have to select a server on the left side&quot;, &quot;Error&quot;);
                return;
            }
            srvServer&#x5B;lbServers.SelectedIndex].bPing = cbPing.Checked;       
        }

        //Background process init/cancel
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            while ( true )
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {                    
                    System.Threading.Thread.Sleep(intTimeInterval); //Time interval between each thread
                    worker.ReportProgress(0);
                }
            }
        }

        //Append log
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if ((e.Cancelled == true))
            {                
                rtbLog.AppendText(DateTime.Now + &quot; &quot;, Color.Blue);                
                rtbLog.AppendText(&quot;NOT MONITORING!&quot; + Environment.NewLine, Color.Red);
            }

            else if (!(e.Error == null))
            {
                rtbLog.AppendText(DateTime.Now + &quot; &quot;, Color.Blue);
                rtbLog.AppendText(&quot;Error: &quot; + e.Error.Message, Color.Red);
            }

            else
            {
                rtbLog.AppendText(DateTime.Now + &quot; &quot;, Color.Blue);
                rtbLog.AppendText(&quot;Done!&quot;, Color.Green);
            }
        }

        //Main process for ping/check TCP ports
        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Color cColor;
            for (int j = 0; j &lt; srvServer.Count; j++)
            {
                if (srvServer&#x5B;j].bPing) {
                    dPingTimeAverage = PingTimeAverage(srvServer&#x5B;j].strServerName, intTimeout);
                    rtbLog.AppendText(DateTime.Now + &quot; &quot;, Color.Blue);
                    if (dPingTimeAverage == -1)
                    {
                        cColor = Color.Red;
                    }
                    else
                    {
                        cColor = Color.Green;
                    }
                    string strPingTimeAverage = dPingTimeAverage.ToString();
                    if (strPingTimeAverage == &quot;-1&quot;)
                    {
                        strPingTimeAverage = &quot;NOT REACHABLE &quot;;
                    }
                    rtbLog.AppendText(srvServer&#x5B;j].strServerName + &quot; &quot; + strPingTimeAverage + &quot;ms reply time &quot; + Environment.NewLine, cColor);
                }
                int i = 0;
                while (srvServer&#x5B;j].lstPorts&#x5B;i] != 0) {
                    bCheckOpenTCPPort = CheckOpenTCPPort(srvServer&#x5B;j].strServerName, srvServer&#x5B;j].lstPorts&#x5B;i], intTimeout);
                    rtbLog.AppendText(DateTime.Now + &quot; &quot;, Color.Blue);
                    if (bCheckOpenTCPPort)
                    {
                        cColor = Color.Green;
                    }
                    else
                    {
                        cColor = Color.Red;
                    }
                    string strPort;
                    if (bCheckOpenTCPPort)
                    {
                        strPort = &quot; opened&quot;;
                    }
                    else {
                        strPort = &quot; CLOSED&quot;;
                    }
                    rtbLog.AppendText(srvServer&#x5B;j].strServerName + &quot; has port &quot; + srvServer&#x5B;j].lstPorts&#x5B;i].ToString() + strPort + Environment.NewLine, cColor);
                    i++;
                }
            }
        }

        //Select all in the log
        private void btnSelectAll_Click(object sender, EventArgs e)
        {
            rtbLog.SelectAll();
        }

        //Clear the log
        private void btnClearLog_Click(object sender, EventArgs e)
        {
            rtbLog.Clear();
        }

        //Copy the log to clipboard
        private void btnCopy_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(rtbLog.SelectedRtf, TextDataFormat.Rtf);
        }

        //Event when you change the timeout setting
        private void tbTimeout_TextChanged(object sender, EventArgs e)
        {
            try
            {
                intTimeout = Convert.ToInt32(tbTimeout.Text.Trim());
            }
            catch (Exception)
            {
                tbTimeout.Text = &quot;100&quot;;
            }            
        }

        //Hide the window when minimized
        private void frmMain_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState)
                Hide();
        }

        //Retore the view when the icon is clicked in the tray
        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

        //Restore the icon when &quot;restore&quot; option is chosen from the menu
        private void restoreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

        //Try to close the program when &quot;exit&quot; option is chosen from the menu
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        //Ask for confirmation before the program closes
        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show(&quot;Are you sure you want to close?&quot;, &quot;kmon&quot;, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                e.Cancel = true;
            }
        }
    }
}

//Class to Extend AppendText for RichTextBox control to include the color value
public static class RichTextBoxExtensions
{
    public static void AppendText(this RichTextBox box, string text, Color color)
    {
        box.SelectionStart = box.TextLength;
        box.SelectionLength = 0;
        box.SelectionColor = color;
        box.AppendText(text);
        box.SelectionColor = box.ForeColor;
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/03/84-visual-c-simple-tcpicmp-monitoring-program-kmon/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
