Click here to Skip to main content
15,883,606 members
Articles / Programming Languages / C#

Net Spy: Your Network Spy

Rate me:
Please Sign up or sign in to vote.
4.31/5 (63 votes)
16 Feb 2008CPOL4 min read 203.9K   6.4K   188  
This is a Windows based tool to continuously monitor your shared folders in a network and generate a log for different folders.
// C# TaskbarNotifier Class v1.0
// by John O'Byrne - 02 december 2002
// 01 april 2003 : Small fix in the OnMouseUp handler
// 11 january 2003 : Patrick Vanden Driessche <pvdd@devbrains.be> added a few enhancements
//           Small Enhancements/Bugfix
//           Small bugfix: When Content text measures larger than the corresponding ContentRectangle
//                         the focus rectangle was not correctly drawn. This has been solved.
//           Added KeepVisibleOnMouseOver
//           Added ReShowOnMouseOver
//           Added If the Title or Content are too long to fit in the corresponding Rectangles,
//                 the text is truncateed and the ellipses are appended (StringTrimming).

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CustomUIControls
{
	/// <summary>
	/// TaskbarNotifier allows to display MSN style/Skinned instant messaging popups
	/// </summary>
	public class TaskbarNotifier : System.Windows.Forms.Form
	{
		#region TaskbarNotifier Protected Members
		protected Bitmap BackgroundBitmap = null;
		protected Bitmap CloseBitmap = null;
		protected Point CloseBitmapLocation;
		protected Size CloseBitmapSize;
		protected Rectangle RealTitleRectangle;
		protected Rectangle RealContentRectangle;
		protected Rectangle WorkAreaRectangle;
		protected Timer timer = new Timer();
		protected TaskbarStates taskbarState = TaskbarStates.hidden;
		protected string titleText;
		protected string contentText;
		protected Color normalTitleColor = Color.FromArgb(255,0,0);
		protected Color hoverTitleColor = Color.FromArgb(255,0,0);
		protected Color normalContentColor = Color.FromArgb(0,0,0);
		protected Color hoverContentColor = Color.FromArgb(0,0,0x66);
		protected Font normalTitleFont = new Font("Arial",12,FontStyle.Regular,GraphicsUnit.Pixel);
		protected Font hoverTitleFont = new Font("Arial",12,FontStyle.Bold,GraphicsUnit.Pixel);
		protected Font normalContentFont = new Font("Arial",11,FontStyle.Regular,GraphicsUnit.Pixel);
		protected Font hoverContentFont = new Font("Arial",11,FontStyle.Regular,GraphicsUnit.Pixel);
		protected int nShowEvents;
		protected int nHideEvents;
		protected int nVisibleEvents;
		protected int nIncrementShow;
		protected int nIncrementHide;
		protected bool bIsMouseOverPopup = false;
		protected bool bIsMouseOverClose = false;
		protected bool bIsMouseOverContent = false;
		protected bool bIsMouseOverTitle = false;
		protected bool bIsMouseDown = false;
		protected bool bKeepVisibleOnMouseOver = true;			// Added Rev 002
		protected bool bReShowOnMouseOver = false;				// Added Rev 002
		#endregion
						
		#region TaskbarNotifier Public Members
		public Rectangle TitleRectangle;
		public Rectangle ContentRectangle;
		public bool TitleClickable = false;
		public bool ContentClickable = true;
		public bool CloseClickable = true;
		public bool EnableSelectionRectangle = true;
		public event EventHandler CloseClick = null;
		public event EventHandler TitleClick = null;
		public event EventHandler ContentClick = null;
		#endregion
	
		#region TaskbarNotifier Enums
		/// <summary>
		/// List of the different popup animation status
		/// </summary>
		public enum TaskbarStates
		{
			hidden = 0,
			appearing = 1,
			visible = 2,
			disappearing = 3
		}
		#endregion

		#region TaskbarNotifier Constructor
		/// <summary>
		/// The Constructor for TaskbarNotifier
		/// </summary>
		public TaskbarNotifier()
		{
			// Window Style
			FormBorderStyle = FormBorderStyle.None;
			WindowState = FormWindowState.Minimized;
			base.Show();
			base.Hide();
			WindowState = FormWindowState.Normal;
			ShowInTaskbar = false;
			TopMost = true;
			MaximizeBox = false;
			MinimizeBox = false;
			ControlBox = false;
			
			timer.Enabled = true;
			timer.Tick += new EventHandler(OnTimer);
		}
		#endregion

		#region TaskbarNotifier Properties
		/// <summary>
		/// Get the current TaskbarState (hidden, showing, visible, hiding)
		/// </summary>
		public TaskbarStates TaskbarState
		{
			get
			{
				return taskbarState;
			}
		}

		/// <summary>
		/// Get/Set the popup Title Text
		/// </summary>
		public string TitleText
		{
			get
			{
				return titleText;
			}
			set
			{
				titleText=value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the popup Content Text
		/// </summary>
		public string ContentText
		{
			get
			{
				return contentText;
			}
			set
			{
				contentText=value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Normal Title Color
		/// </summary>
		public Color NormalTitleColor
		{
			get
			{
				return normalTitleColor;
			}
			set
			{
				normalTitleColor = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Hover Title Color
		/// </summary>
		public Color HoverTitleColor
		{
			get
			{
				return hoverTitleColor;
			}
			set
			{
				hoverTitleColor = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Normal Content Color
		/// </summary>
		public Color NormalContentColor
		{
			get
			{
				return normalContentColor;
			}
			set
			{
				normalContentColor = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Hover Content Color
		/// </summary>
		public Color HoverContentColor
		{
			get
			{
				return hoverContentColor;
			}
			set
			{
				hoverContentColor = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Normal Title Font
		/// </summary>
		public Font NormalTitleFont
		{
			get
			{
				return normalTitleFont;
			}
			set
			{
				normalTitleFont = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Hover Title Font
		/// </summary>
		public Font HoverTitleFont
		{
			get
			{
				return hoverTitleFont;
			}
			set
			{
				hoverTitleFont = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Normal Content Font
		/// </summary>
		public Font NormalContentFont
		{
			get
			{
				return normalContentFont;
			}
			set
			{
				normalContentFont = value;
				Refresh();
			}
		}

		/// <summary>
		/// Get/Set the Hover Content Font
		/// </summary>
		public Font HoverContentFont
		{
			get
			{
				return hoverContentFont;
			}
			set
			{
				hoverContentFont = value;
				Refresh();
			}
		}

		/// <summary>
		/// Indicates if the popup should remain visible when the mouse pointer is over it.
		/// Added Rev 002
		/// </summary>
		public bool KeepVisibleOnMousOver
		{
			get
			{
				return bKeepVisibleOnMouseOver;
			}
			set
			{
				bKeepVisibleOnMouseOver=value;
			}
		}

		/// <summary>
		/// Indicates if the popup should appear again when mouse moves over it while it's disappearing.
		/// Added Rev 002
		/// </summary>
		public bool ReShowOnMouseOver
		{
			get
			{
				return bReShowOnMouseOver;
			}
			set
			{
				bReShowOnMouseOver=value;
			}
		}

		#endregion

		#region TaskbarNotifier Public Methods
		[DllImport("user32.dll")]
		private static extern Boolean ShowWindow(IntPtr hWnd,Int32 nCmdShow);
		/// <summary>
		/// Displays the popup for a certain amount of time
		/// </summary>
		/// <param name="strTitle">The string which will be shown as the title of the popup</param>
		/// <param name="strContent">The string which will be shown as the content of the popup</param>
		/// <param name="nTimeToShow">Duration of the showing animation (in milliseconds)</param>
		/// <param name="nTimeToStay">Duration of the visible state before collapsing (in milliseconds)</param>
		/// <param name="nTimeToHide">Duration of the hiding animation (in milliseconds)</param>
		/// <returns>Nothing</returns>
		public void Show(string strTitle, string strContent, int nTimeToShow, int nTimeToStay, int nTimeToHide)
		{
			WorkAreaRectangle = Screen.GetWorkingArea(WorkAreaRectangle);
			titleText = strTitle;
			contentText = strContent;
			nVisibleEvents = nTimeToStay;
			CalculateMouseRectangles();

			// We calculate the pixel increment and the timer value for the showing animation
			int nEvents;
			if (nTimeToShow > 10)
			{
				nEvents = Math.Min((nTimeToShow / 10), BackgroundBitmap.Height);
				nShowEvents = nTimeToShow / nEvents;
				nIncrementShow = BackgroundBitmap.Height / nEvents;
			}
			else
			{
				nShowEvents = 10;
				nIncrementShow = BackgroundBitmap.Height;
			}

			// We calculate the pixel increment and the timer value for the hiding animation
			if( nTimeToHide > 10)
			{
				nEvents = Math.Min((nTimeToHide / 10), BackgroundBitmap.Height);
				nHideEvents = nTimeToHide / nEvents;
				nIncrementHide = BackgroundBitmap.Height / nEvents;
			}
			else
			{
				nHideEvents = 10;
				nIncrementHide = BackgroundBitmap.Height;
			}

			switch (taskbarState)
			{
				case TaskbarStates.hidden:
					taskbarState = TaskbarStates.appearing;
					SetBounds(WorkAreaRectangle.Right-BackgroundBitmap.Width-17, WorkAreaRectangle.Bottom-1, BackgroundBitmap.Width, 0);
					timer.Interval = nShowEvents;
					timer.Start();
					// We Show the popup without stealing focus
					ShowWindow(this.Handle, 4);
					break;

				case TaskbarStates.appearing:
					Refresh();
					break;

				case TaskbarStates.visible:
					timer.Stop();
					timer.Interval = nVisibleEvents;
					timer.Start();
					Refresh();
					break;

				case TaskbarStates.disappearing:
					timer.Stop();
					taskbarState = TaskbarStates.visible;
					SetBounds(WorkAreaRectangle.Right-BackgroundBitmap.Width-17, WorkAreaRectangle.Bottom-BackgroundBitmap.Height-1, BackgroundBitmap.Width, BackgroundBitmap.Height);
					timer.Interval = nVisibleEvents;
					timer.Start();
					Refresh();
					break;
			}
		}

		/// <summary>
		/// Hides the popup
		/// </summary>
		/// <returns>Nothing</returns>
		public new void Hide()
		{
			if (taskbarState != TaskbarStates.hidden)
			{
				timer.Stop();
				taskbarState = TaskbarStates.hidden;
				base.Hide();
			}
		}

		/// <summary>
		/// Sets the background bitmap and its transparency color
		/// </summary>
		/// <param name="strFilename">Path of the Background Bitmap on the disk</param>
		/// <param name="transparencyColor">Color of the Bitmap which won't be visible</param>
		/// <returns>Nothing</returns>
		public void SetBackgroundBitmap(string strFilename, Color transparencyColor)
		{
			BackgroundBitmap = new Bitmap(strFilename);
			Width = BackgroundBitmap.Width;
			Height = BackgroundBitmap.Height;
			Region = BitmapToRegion(BackgroundBitmap, transparencyColor);
		}

		/// <summary>
		/// Sets the background bitmap and its transparency color
		/// </summary>
		/// <param name="image">Image/Bitmap object which represents the Background Bitmap</param>
		/// <param name="transparencyColor">Color of the Bitmap which won't be visible</param>
		/// <returns>Nothing</returns>
		public void SetBackgroundBitmap(Image image, Color transparencyColor)
		{
			BackgroundBitmap = new Bitmap(image);
			Width = BackgroundBitmap.Width;
			Height = BackgroundBitmap.Height;
			Region = BitmapToRegion(BackgroundBitmap, transparencyColor);
		}

		/// <summary>
		/// Sets the 3-State Close Button bitmap, its transparency color and its coordinates
		/// </summary>
		/// <param name="strFilename">Path of the 3-state Close button Bitmap on the disk (width must a multiple of 3)</param>
		/// <param name="transparencyColor">Color of the Bitmap which won't be visible</param>
		/// <param name="position">Location of the close button on the popup</param>
		/// <returns>Nothing</returns>
		public void SetCloseBitmap(string strFilename, Color transparencyColor, Point position)
		{
			CloseBitmap = new Bitmap(strFilename);
			CloseBitmap.MakeTransparent(transparencyColor);
			CloseBitmapSize = new Size(CloseBitmap.Width/3, CloseBitmap.Height);
			CloseBitmapLocation = position;
		}

		/// <summary>
		/// Sets the 3-State Close Button bitmap, its transparency color and its coordinates
		/// </summary>
		/// <param name="image">Image/Bitmap object which represents the 3-state Close button Bitmap (width must be a multiple of 3)</param>
		/// <param name="transparencyColor">Color of the Bitmap which won't be visible</param>
		/// /// <param name="position">Location of the close button on the popup</param>
		/// <returns>Nothing</returns>
		public void SetCloseBitmap(Image image, Color transparencyColor, Point position)
		{
			CloseBitmap = new Bitmap(image);
			CloseBitmap.MakeTransparent(transparencyColor);
			CloseBitmapSize = new Size(CloseBitmap.Width/3, CloseBitmap.Height);
			CloseBitmapLocation = position;
		}
		#endregion

		#region TaskbarNotifier Protected Methods
		protected void DrawCloseButton(Graphics grfx)
		{
			if (CloseBitmap != null)
			{	
				Rectangle rectDest = new Rectangle(CloseBitmapLocation, CloseBitmapSize);
				Rectangle rectSrc;

				if (bIsMouseOverClose)
				{
					if (bIsMouseDown)
						rectSrc = new Rectangle(new Point(CloseBitmapSize.Width*2, 0), CloseBitmapSize);
					else
						rectSrc = new Rectangle(new Point(CloseBitmapSize.Width, 0), CloseBitmapSize);
				}		
				else
					rectSrc = new Rectangle(new Point(0, 0), CloseBitmapSize);
					

				grfx.DrawImage(CloseBitmap, rectDest, rectSrc, GraphicsUnit.Pixel);
			}
		}

		protected void DrawText(Graphics grfx)
		{
			if (titleText != null && titleText.Length != 0)
			{
				StringFormat sf = new StringFormat();
				sf.Alignment = StringAlignment.Near;
				sf.LineAlignment = StringAlignment.Center;
				sf.FormatFlags = StringFormatFlags.NoWrap;
				sf.Trimming = StringTrimming.EllipsisCharacter;				// Added Rev 002
				if (bIsMouseOverTitle)
					grfx.DrawString(titleText, hoverTitleFont, new SolidBrush(hoverTitleColor), TitleRectangle, sf);
				else
					grfx.DrawString(titleText, normalTitleFont, new SolidBrush(normalTitleColor), TitleRectangle, sf);
			}

			if (contentText != null && contentText.Length != 0)
			{
				StringFormat sf = new StringFormat();
				sf.Alignment = StringAlignment.Center;
				sf.LineAlignment = StringAlignment.Center;
				sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
				sf.Trimming = StringTrimming.Word;							// Added Rev 002
				
				if (bIsMouseOverContent)
				{
					grfx.DrawString(contentText, hoverContentFont, new SolidBrush(hoverContentColor), ContentRectangle, sf);
					if (EnableSelectionRectangle)
						ControlPaint.DrawBorder3D(grfx, RealContentRectangle, Border3DStyle.Etched, Border3DSide.Top | Border3DSide.Bottom | Border3DSide.Left | Border3DSide.Right);
					
				}
				else
					grfx.DrawString(contentText, normalContentFont, new SolidBrush(normalContentColor), ContentRectangle, sf);
			}
		}

		protected void CalculateMouseRectangles()
		{
			Graphics grfx = CreateGraphics();
			StringFormat sf = new StringFormat();
			sf.Alignment = StringAlignment.Center;
			sf.LineAlignment = StringAlignment.Center;
			sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
			SizeF sizefTitle = grfx.MeasureString(titleText, hoverTitleFont, TitleRectangle.Width, sf);
			SizeF sizefContent = grfx.MeasureString(contentText, hoverContentFont, ContentRectangle.Width, sf);
			grfx.Dispose();

			// Added Rev 002
	        //We should check if the title size really fits inside the pre-defined title rectangle
			if (sizefTitle.Height > TitleRectangle.Height)
			{
				RealTitleRectangle = new Rectangle(TitleRectangle.Left, TitleRectangle.Top, TitleRectangle.Width , TitleRectangle.Height );
			} 
			else
			{
				RealTitleRectangle = new Rectangle(TitleRectangle.Left, TitleRectangle.Top, (int)sizefTitle.Width, (int)sizefTitle.Height);
			}
			RealTitleRectangle.Inflate(0,2);

			// Added Rev 002
			//We should check if the Content size really fits inside the pre-defined Content rectangle
			if (sizefContent.Height > ContentRectangle.Height)
			{
				RealContentRectangle = new Rectangle((ContentRectangle.Width-(int)sizefContent.Width)/2+ContentRectangle.Left, ContentRectangle.Top, (int)sizefContent.Width, ContentRectangle.Height );
			}
			else
			{
				RealContentRectangle = new Rectangle((ContentRectangle.Width-(int)sizefContent.Width)/2+ContentRectangle.Left, (ContentRectangle.Height-(int)sizefContent.Height)/2+ContentRectangle.Top, (int)sizefContent.Width, (int)sizefContent.Height);
			}
			RealContentRectangle.Inflate(0,2);
		}

		protected Region BitmapToRegion(Bitmap bitmap, Color transparencyColor)
		{
			if (bitmap == null)
				throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");

			int height = bitmap.Height;
			int width = bitmap.Width;

			GraphicsPath path = new GraphicsPath();

			for (int j=0; j<height; j++ )
				for (int i=0; i<width; i++)
				{
					if (bitmap.GetPixel(i, j) == transparencyColor)
						continue;

					int x0 = i;

					while ((i < width) && (bitmap.GetPixel(i, j) != transparencyColor))
						i++;

					path.AddRectangle(new Rectangle(x0, j, i-x0, 1));
				}

			Region region = new Region(path);
			path.Dispose();
			return region;
		}
		#endregion

		#region TaskbarNotifier Events Overrides
		protected void OnTimer(Object obj, EventArgs ea)
		{
			switch (taskbarState)
			{
				case TaskbarStates.appearing:
					if (Height < BackgroundBitmap.Height)
						SetBounds(Left, Top-nIncrementShow ,Width, Height + nIncrementShow);
					else
					{
						timer.Stop();
						Height = BackgroundBitmap.Height;
						timer.Interval = nVisibleEvents;
						taskbarState = TaskbarStates.visible;
						timer.Start();
					}
					break;

				case TaskbarStates.visible:
					timer.Stop();
					timer.Interval = nHideEvents;
					// Added Rev 002
					if ((bKeepVisibleOnMouseOver && !bIsMouseOverPopup ) || (!bKeepVisibleOnMouseOver))
					{
						taskbarState = TaskbarStates.disappearing;
					} 
					//taskbarState = TaskbarStates.disappearing;		// Rev 002
					timer.Start();
					break;

				case TaskbarStates.disappearing:
					// Added Rev 002
					if (bReShowOnMouseOver && bIsMouseOverPopup) 
					{
						taskbarState = TaskbarStates.appearing;
					} 
					else 
					{
						if (Top < WorkAreaRectangle.Bottom)
							SetBounds(Left, Top + nIncrementHide, Width, Height - nIncrementHide);
						else
							Hide();
					}
					break;
			}
			
		}

		protected override void OnMouseEnter(EventArgs ea)
		{
			base.OnMouseEnter(ea);
			bIsMouseOverPopup = true;
			Refresh();
		}

		protected override void OnMouseLeave(EventArgs ea)
		{
			base.OnMouseLeave(ea);
			bIsMouseOverPopup = false;
			bIsMouseOverClose = false;
			bIsMouseOverTitle = false;
			bIsMouseOverContent = false;
			Refresh();
		}

		protected override void OnMouseMove(MouseEventArgs mea)
		{
			base.OnMouseMove(mea);

			bool bContentModified = false;
			
			if ( (mea.X > CloseBitmapLocation.X) && (mea.X < CloseBitmapLocation.X + CloseBitmapSize.Width) && (mea.Y > CloseBitmapLocation.Y) && (mea.Y < CloseBitmapLocation.Y + CloseBitmapSize.Height) && CloseClickable )
			{
				if (!bIsMouseOverClose)
				{
					bIsMouseOverClose = true;
					bIsMouseOverTitle = false;
					bIsMouseOverContent = false;
					Cursor = Cursors.Hand;
					bContentModified = true;
				}
			}
			else if (RealContentRectangle.Contains(new Point(mea.X, mea.Y)) && ContentClickable)
			{
				if (!bIsMouseOverContent)
				{
					bIsMouseOverClose = false;
					bIsMouseOverTitle = false;
					bIsMouseOverContent = true;
					Cursor = Cursors.Hand;
					bContentModified = true;
				}
			}
			else if (RealTitleRectangle.Contains(new Point(mea.X, mea.Y)) && TitleClickable)
			{
				if (!bIsMouseOverTitle)
				{
					bIsMouseOverClose = false;
					bIsMouseOverTitle = true;
					bIsMouseOverContent = false;
					Cursor = Cursors.Hand;
					bContentModified = true;
				}
			}
			else
			{
				if (bIsMouseOverClose || bIsMouseOverTitle || bIsMouseOverContent)
					bContentModified = true;

				bIsMouseOverClose = false;
				bIsMouseOverTitle = false;
				bIsMouseOverContent = false;
				Cursor = Cursors.Default;
			}

			if (bContentModified)
				Refresh();
		}

		protected override void OnMouseDown(MouseEventArgs mea)
		{
			base.OnMouseDown(mea);
			bIsMouseDown = true;
			
			if (bIsMouseOverClose)
				Refresh();
		}

		protected override void OnMouseUp(MouseEventArgs mea)
		{
			base.OnMouseUp(mea);
			bIsMouseDown = false;

			if (bIsMouseOverClose)
			{
				Hide();
							
				if (CloseClick != null)
					CloseClick(this, new EventArgs());
			}
			else if (bIsMouseOverTitle)
			{
				if (TitleClick != null)
					TitleClick(this, new EventArgs());
			}
			else if (bIsMouseOverContent)
			{
				if (ContentClick != null)
					ContentClick(this, new EventArgs());
			}
		}

		protected override void OnPaintBackground(PaintEventArgs pea)
		{
			Graphics grfx = pea.Graphics;
			grfx.PageUnit = GraphicsUnit.Pixel;
			
			Graphics offScreenGraphics;
			Bitmap offscreenBitmap;
			
			offscreenBitmap = new Bitmap(BackgroundBitmap.Width, BackgroundBitmap.Height);
			offScreenGraphics = Graphics.FromImage(offscreenBitmap);
			
			if (BackgroundBitmap != null)
			{
				offScreenGraphics.DrawImage(BackgroundBitmap, 0, 0, BackgroundBitmap.Width, BackgroundBitmap.Height);
			}
			
			DrawCloseButton(offScreenGraphics);
			DrawText(offScreenGraphics);

			grfx.DrawImage(offscreenBitmap, 0, 0);
		}
		#endregion

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // TaskbarNotifier
            // 
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Name = "TaskbarNotifier";
            this.Load += new System.EventHandler(this.TaskbarNotifier_Load);
            this.ResumeLayout(false);

        }

        private void TaskbarNotifier_Load(object sender, EventArgs e)
        {

        }
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
India India
.NET Consultant | Former Microsoft MVP - ASP.NET | CodeProject MVP, Mentor, Insiders| Technology Evangelist | Author | Speaker | Geek | Blogger | Husband

Blog : http://abhijitjana.net
Web Site : http://dailydotnettips.com
Twitter : @AbhijitJana
My Kinect Book : Kinect for Windows SDK Programming Guide

Comments and Discussions