Click here to Skip to main content
15,894,825 members
Articles / Multimedia / GDI+

A complete C# Screensaver that does double-buffering on multiple monitor systems!

Rate me:
Please Sign up or sign in to vote.
4.75/5 (37 votes)
24 Jun 200534 min read 273.2K   1.8K   190  
Example screensaver in source code. Does a mini-preview too!
  • swarmscreensaver_src.zip
    • SwarmScreenSaver
      • CodeCommentReport
        • banner.htm
        • banner.jpg
        • CodeCommentReportError.htm
        • commentreport.css
        • CommonCode
        • darkcorner.jpg
        • gradleft.jpg
        • gradtop.jpg
        • graycorner.jpg
        • Insects
        • minus.jpg
        • plus.jpg
        • Solution_SwarmScreenSaver.HTM
        • SwarmScreenSaver
          • CWP0.HTM
          • CWP10.HTM
          • CWP100.HTM
          • CWP101.HTM
          • CWP102.HTM
          • CWP103.HTM
          • CWP104.HTM
          • CWP105.HTM
          • CWP106.HTM
          • CWP107.HTM
          • CWP108.HTM
          • CWP109.HTM
          • CWP11.HTM
          • CWP110.HTM
          • CWP111.HTM
          • CWP112.HTM
          • CWP113.HTM
          • CWP114.HTM
          • CWP115.HTM
          • CWP116.HTM
          • CWP117.HTM
          • CWP118.HTM
          • CWP119.HTM
          • CWP12.HTM
          • CWP120.HTM
          • CWP121.HTM
          • CWP122.HTM
          • CWP123.HTM
          • CWP124.HTM
          • CWP125.HTM
          • CWP126.HTM
          • CWP127.HTM
          • CWP128.HTM
          • CWP129.HTM
          • CWP13.HTM
          • CWP130.HTM
          • CWP131.HTM
          • CWP132.HTM
          • CWP134.HTM
          • CWP135.HTM
          • CWP136.HTM
          • CWP137.HTM
          • CWP138.HTM
          • CWP139.HTM
          • CWP14.HTM
          • CWP140.HTM
          • CWP141.HTM
          • CWP142.HTM
          • CWP143.HTM
          • CWP144.HTM
          • CWP145.HTM
          • CWP146.HTM
          • CWP147.HTM
          • CWP148.HTM
          • CWP149.HTM
          • CWP15.HTM
          • CWP150.HTM
          • CWP151.HTM
          • CWP152.HTM
          • CWP153.HTM
          • CWP154.HTM
          • CWP155.HTM
          • CWP156.HTM
          • CWP157.HTM
          • CWP158.HTM
          • CWP159.HTM
          • CWP16.HTM
          • CWP160.HTM
          • CWP161.HTM
          • CWP162.HTM
          • CWP163.HTM
          • CWP164.HTM
          • CWP165.HTM
          • CWP166.HTM
          • CWP167.HTM
          • CWP168.HTM
          • CWP169.HTM
          • CWP17.HTM
          • CWP170.HTM
          • CWP171.HTM
          • CWP172.HTM
          • CWP173.HTM
          • CWP174.HTM
          • CWP175.HTM
          • CWP176.HTM
          • CWP177.HTM
          • CWP178.HTM
          • CWP179.HTM
          • CWP18.HTM
          • CWP180.HTM
          • CWP181.HTM
          • CWP182.HTM
          • CWP183.HTM
          • CWP184.HTM
          • CWP185.HTM
          • CWP186.HTM
          • CWP187.HTM
          • CWP188.HTM
          • CWP189.HTM
          • CWP19.HTM
          • CWP190.HTM
          • CWP191.HTM
          • CWP192.HTM
          • CWP2.HTM
          • CWP20.HTM
          • CWP21.HTM
          • CWP22.HTM
          • CWP23.HTM
          • CWP24.HTM
          • CWP25.HTM
          • CWP26.HTM
          • CWP27.HTM
          • CWP28.HTM
          • CWP29.HTM
          • CWP3.HTM
          • CWP31.HTM
          • CWP32.HTM
          • CWP33.HTM
          • CWP34.HTM
          • CWP35.HTM
          • CWP36.HTM
          • CWP38.HTM
          • CWP39.HTM
          • CWP4.HTM
          • CWP40.HTM
          • CWP41.HTM
          • CWP42.HTM
          • CWP43.HTM
          • CWP44.HTM
          • CWP45.HTM
          • CWP46.HTM
          • CWP47.HTM
          • CWP48.HTM
          • CWP49.HTM
          • CWP5.HTM
          • CWP50.HTM
          • CWP51.HTM
          • CWP52.HTM
          • CWP53.HTM
          • CWP54.HTM
          • CWP55.HTM
          • CWP56.HTM
          • CWP57.HTM
          • CWP58.HTM
          • CWP59.HTM
          • CWP6.HTM
          • CWP60.HTM
          • CWP61.HTM
          • CWP62.HTM
          • CWP63.HTM
          • CWP64.HTM
          • CWP65.HTM
          • CWP66.HTM
          • CWP67.HTM
          • CWP68.HTM
          • CWP69.HTM
          • CWP7.HTM
          • CWP70.HTM
          • CWP71.HTM
          • CWP72.HTM
          • CWP73.HTM
          • CWP74.HTM
          • CWP75.HTM
          • CWP76.HTM
          • CWP77.HTM
          • CWP78.HTM
          • CWP79.HTM
          • CWP8.HTM
          • CWP80.HTM
          • CWP81.HTM
          • CWP82.HTM
          • CWP83.HTM
          • CWP84.HTM
          • CWP85.HTM
          • CWP86.HTM
          • CWP88.HTM
          • CWP9.HTM
          • CWP90.HTM
          • CWP91.HTM
          • CWP92.HTM
          • CWP93.HTM
          • CWP94.HTM
          • CWP95.HTM
          • CWP96.HTM
          • CWP97.HTM
          • CWP98.HTM
          • CWP99.HTM
          • SwarmScreenSaver.HTM
        • titletile.jpg
        • vt.js
      • CommonCode
      • Insects
      • SwarmScreenSaver.sln
      • SwarmScreenSaver
using System;
using System.IO;
using System.Runtime.InteropServices; // So API functions can be called.
using Microsoft.Win32;
//using System.Diagnostics; // Uncomment out for debugging.
using System.Drawing;


namespace CommonCode
{
	/// <summary>
	/// Summary description for StructsAndFunctions.cs which is actually a class called CommonFunctions.<br></br>
	/// Actually this is under the CommonCode namespace. This namespace contains structures commonly used and the<br></br>
	/// class CommonFunctions contains functions that are commonly needed, such as various random number related<br></br>
	/// and color adjustment functions. I would have liked to use private for most of these structures but the<br></br>
	/// C# namespace is evil, it does not allow me to make private structure even tho I don't need any but the<br></br>
	/// RECT struct outside the file. Bah!
	/// </summary>

	/// <summary>
	/// Various paint states ....<br></br>
	/// ShuttingDown,<br></br>
	/// PaintError,<br></br>
	/// OtherPaint, Means another process did the paint.<br></br>
	/// NoActivity, Paint not called.<br></br>
	/// OurpaintPending, Paint event invoked but not yet in progress.<br></br>
	/// PaintInProgress, Our drawing code executing.<br></br>
	/// PaintSuccessful.
	/// </summary>
	public struct PaintStates
	{
		public const int 
		ShuttingDown = -4,
		PaintError = -3,
		OtherPaint = -2,
		NoActivity = -1,
		OurPaintPending = 0,
		PaintInProgress = 1,
		PaintSuccessful = 2;
	}
	
	/// <summary>
	/// An instance of this struct is passed GetClientRect API to get the size of the preview window.<br></br>
	/// A struct of ints that contains the location and size info for a screen region.<br></br>
	/// It is passed to GetClientRect API call as a ref variable so the members can be filled in.
	/// </summary>
	public struct RECT
	{
		public int left; 
		public int top; 
		public int right;
		public int bottom;

		public RECT(int l, int t, int r, int b)
		{
			left = l;
			top = t;
			right = r;
			bottom = b;
		}
	}
	/// <summary>
	/// A struct to represent a line via 4 ints. x1, y1 for the starting point and x2, y2 for the ending point.<br></br>
	/// this represents bees and the wasp too.
	/// </summary>
	public struct Segment 
	{
		public int x1; // Starting X and Y point for line
		public int y1;
		public int x2; // Ending X and Y point for line.
		public int y2;
	} 

	/// <summary>
	/// A structure to represent all the bees in a swarm. segs and old_segs (unused) refer to bee lines at xy start and xy end points.<br></br>
	/// x and y are 2 dimentional int arrays to represent the starting and ending points of bees to be erased or drawn.
	/// </summary>
	public struct SwarmStruct // This struct holds data for all the bees in the swarm.
	{
		public Segment[]	segs;		// bee lines 
		public Segment[]	old_segs;	// old bee lines // I"m nost terribly sure why the programmer kept so many segment copies.
		public int[,] 		x;			// Bee X positions. y[TIME][bee#] Time is a constant of 4. I don't know why four copies are kept. 
		public int[,]		y;			// Bee Y positions. y[TIME][bee#] I imagine it's just to keep them ready for drawing ahead of time as a kind of cache.
		public int[]		xv;			// Bee horizontal velocity 
		public int[]		yv;			// Bee virtical velocity xv[bee#] 
	} // End of swarmstruct class.

	/// <summary>
	/// A class of commonly used functions: Custom random number generators and a random RGB color method.<br></br>
	/// This class needs no constructor.
	/// </summary>
	public class CommonFunctions 
	{
//		[DllImport("gdi32.dll")]
//		private static extern bool Rectangle(
//			IntPtr hdc,
//			int ulCornerX, int ulCornerY,
//			int lrCornerX, int lrCornerY);
//		public bool RectangleApi(IntPtr hdc, int X1, int Y1, int X2, int Y2)
//		{
//			return Rectangle(hdc,X1,Y1, X2, Y2);
//		}

//		public static int RGB(int R,int G,int B)
//		{
//			return (R |(G<<8)|(B<<16));         
//		}
//
//		[DllImport("gdi32.dll")] // -*** CreatePen cr = color. Stupid programmers!
//		private static extern IntPtr CreatePen(int iStyle, int iWidth, int cr);
//
//		[DllImport("gdi32.dll")] // -*** MoveToEx use 0 for just plain MoveTo.
//		private static extern bool MoveToEx(IntPtr hdc, int x, int y, IntPtr pt);
//
//		[DllImport("gdi32.dll")] // -*** LineTo
//		private static extern bool LineTo(IntPtr hdc, int x, int y);		

		// ---------------------------------------------
//		[DllImport("user32.dll")]
//		private static extern IntPtr GetDC(IntPtr hWnd);
//		public IntPtr GetDcApi(IntPtr hWnd)
//		{
//			return GetDC(hWnd);
//		}

//		[DllImport("gdi32.dll")]
//		private static extern IntPtr CreateCompatibleBitmap(IntPtr HDC, int X, int Y);
//		public IntPtr CreateCompatibleBitmapApi(IntPtr HDC, int X, int Y)
//		{
//			return CreateCompatibleBitmap(HDC, X, Y);
//		}

//		[DllImport("gdi32.dll")] // -*** CreateCompatibleDC Used to turn the htBitmap from a graphic to a real memory pointer we need.
//		private static extern IntPtr CreateCompatibleDC(IntPtr HDC);
//		public IntPtr CreateCompatibleDcApi(IntPtr HDC)
//		{
//			return CreateCompatibleDC(HDC);
//		}
		// ----------------------------------------------------------------------------
//		[DllImport("gdi32.dll")] // -*** BitBlt BitBltApi
//		private static extern bool BitBlt(IntPtr HDC, int Top, int Left, 
//			int Width, int Height, IntPtr SourceHDC, 
//			int X, int Y, int ROP);
//		public bool BitBltApi(IntPtr HDC, int Top, int Left, int Width, int Height, IntPtr SourceHDC, int X, int Y)
//		{	
//			// this value for ROP copies the buffer.
//            bool b = BitBlt(HDC, Top, Left, Width, Height, SourceHDC, X, Y, 0x00CC0020); 
//			return b;
//		}
//		// -----------------------------------------------------------------------
//        [DllImport("gdi32.dll")]// -*** SelectObject SelectObjectApi 
//		private static extern IntPtr SelectObject(IntPtr hMemDC, IntPtr hObject);
//		public IntPtr SelectObjectApi(IntPtr hMemDC, IntPtr hObject)
//		{
//			return SelectObject(hMemDC, hObject);
//		}
//		// ----------------------------------------------------
//		[DllImport("gdi32.dll")] // -*** DeleteDC DeleteDcApi
//		private static extern bool DeleteDC(IntPtr hMemDC);
//		public bool DeleteDcApi(IntPtr hMemDC)
//		{
//			return DeleteDC(hMemDC);
//		}
//		// --------------------------------------------------------
//		[DllImport("gdi32.dll")]
//		private static extern bool DeleteObject(IntPtr hpen);
//		public bool DeleteObjectApi(IntPtr hObj)
//		{
//			return DeleteObject(hObj);
//		}
		// --------------------------------------------------------
//		[System.Runtime.InteropServices.DllImport("user32.dll")]
//		private static extern int GetSystemMetrics(int nMetrics);
//		public int GetSystemMetricsApi(int nMetrics)
//		{
//			return GetSystemMetrics(nMetrics);
//		}
		// ---------------------------------------------
//		[DllImport("user32.dll")] 
//		private static extern int MessageBeep(uint n); 
// 
//		public void MessageBeepApi() 
//		{ 
//			MessageBeep(0x0);  
//		} 
 

		/// Declares an API call to determine if a window is visible.
		/// /summary>
		/// param name="hWnd"> Handle to the window being checked for visibility.</param>
		/// returns> Returns true if the window is visible, false if not.</returns>
		[DllImport("user32.DLL",EntryPoint="IsWindowVisible")]
		private static extern bool IsWindowVisible(IntPtr hWnd);

		/// <summary>
		/// Declare an external API function call. A wrapper function calls this.
		/// </summary>
		/// <param name="hWnd"> Handle to the window being addressed.</param>
		/// <param name="rect"> Struct containing Size and Location to be filled with the client area size and loc.</param>
		/// <returns> true is success, otherwise false.</returns>
		[DllImport("user32.dll")]
		private static extern bool GetClientRect(IntPtr hWnd, ref RECT rect);

		/// <summary>
		/// Wrapper to call the IsWindowVisible api call.
		/// </summary>
		/// <param name="hWnd">Handle to the Desktop Properties window.</param>
		/// <returns></returns>
		public bool IsWindowVisibleApi(IntPtr hWnd)
		{
			return IsWindowVisible(hWnd);
		}
		/// <summary>
		/// Wrapper to call GetClientRect API functions in user32.dll to get size of the client area of a window.
		/// </summary>
		/// <param name="hWnd"> This is a handle to the desktop properties dialog box</param>
		/// <param name="rect"> This is an instance of a RECT struct to be filled with the location & size of the client area.
		/// </param>
		/// <returns>true if successful, false if uncuccessful</returns>
		public bool GetClientRectApi(IntPtr hWnd, ref RECT rect)
		{
			return GetClientRect(hWnd, ref rect);
		}

//		public void CopyMemoryGraphicToScreen(Graphics screenGr, Graphics memGr, Rectangle rct)
//		{
//			IntPtr hdc = screenGr.GetHdc();
//			IntPtr memHdc = memGr.GetHdc(); 
//			IntPtr hMemdc = CreateCompatibleDC(memHdc);
//			BitBltApi(hdc, rct.Top, rct.Left, rct.Width, rct.Height,hMemdc,rct.X,rct.Y);
//			screenGr.ReleaseHdc(hdc);
//			DeleteDcApi(hMemdc);
//			memGr.ReleaseHdc(memHdc);
//		}
		/// <summary>
		/// A private instance of a random number generator for use by all functions in this class.
		/// </summary>
		private Random RandIntGenerator = new Random(); // Create an instance of a random number generator.
		/// <summary>
		/// Returns a non-negative integer between 0 and 32767 inclusive.
		/// </summary>
		/// <returns>a int positive random number between 0 and 32767 inclusive.</returns>
		public int rand() 
		{
			return RandIntGenerator.Next(32768); // Used 32767 Because it returns 0 to Parameter - 1;
		} 

		/// <summary>
		/// Returns an Int that seems to be in the range of approximately -(v/2)+1 to (v/2)-1 
		/// </summary>
		/// <param name="v"></param>
		/// <returns>an Int that seems to be in the range of approximately -(v/2)+1 to (v/2)-1.</returns>
		public int RAND(int v)
		{
			return ((RandIntGenerator.Next(32768)%(v))-((v)/2)); // WE use 32768 because we want this to work with a random in between 0 to 32767 inclusive.
		}
		// ----------------------------------------------------
		/// <summary>
		/// Returns an integer in the range of MinVal to MaxVal inclusive.
		/// </summary>
		/// <param name="MinVal"></param>
		/// <param name="MaxVal"></param>
		/// <returns>A random int between MinVal and MaxVal inclusive</returns>
		public int randInRange(int MinVal, int MaxVal)
		{
			return RandIntGenerator.Next(MinVal,MaxVal+1);
		}
		// ----------------------------------------------------
		// This does not seem to yield accurate results, but very close. 
		/// <summary>
		/// Convert an HSB to RGB color. Thanks to George Shepherd's site..
		/// http://www.syncfusion.com/FAQ/WindowsForms/FAQ_c85c.aspx#q982q
		/// </summary>
		/// <param name="h"></param>
		/// <param name="s"></param>
		/// <param name="v"></param>
		/// <param name="r"></param>
		/// <param name="g"></param>
		/// <param name="b"></param>
		private void ConvertHSBToRGB(float h, float s, float v, out float r, out float g, out float b) 
		{ 
			if (s == 0f) 
 			{ 
 			// if s = 0 then h is undefined 
 				r = v; 
 				g = v; 
 				b = v; 
 			} 
 			else 
 			{ 
 				float hue = (float)h; 
 				if (h == 360.0f) 
 				{ 
 					hue = 0.0f; 
 				} 
 				hue /= 60.0f; 
 				int i = (int)Math.Floor((double)hue); 
 				float f = hue - i; 
 				float p = v * (1.0f - s); 
 				float q = v * (1.0f - (s * f)); 
 				float t = v * (1.0f - (s * (1 - f))); 
 				switch(i) 
 				{ 
 					case 0: r = v; g = t; b = p; break; 
 					case 1: r = q; g = v; b = p; break; 
 					case 2: r = p; g = v; b = t; break; 
 					case 3: r = p; g = q; b = v; break; 
 					case 4: r = t; g = p; b = v; break; 
 					case 5: r = v; g = p; b = q; break; 
 					default: r = 0.0f; g = 0.0f; b = 0.0f; break; 
				} 
			} 
		} 
		// ----------------------------------------------------
		/// 
		/// Adjusts the specified Fore Color's brightness based on the specified back color and preferred contrast. <br>
		/// Thanks to George Shepherd's site..<br>
		/// http://www.syncfusion.com/FAQ/WindowsForms/FAQ_c85c.aspx#q982q<br>
		/// The fore Color to adjust. <br>
		/// The back Color for reference.<br> 
		/// Preferred contrast level. <br>
		/// This method checks if the current contrast in brightness between the 2 colors is <br>
		/// less than the specified contrast level. If so, it brightens or darkens the fore color appropriately. 
		/// 
	public void AdjustForeColorBrightnessForBackColor(ref Color foreColor, Color backColor, float prefContrastLevel) 
 	{ 
		float fBrightness = foreColor.GetBrightness(); 
 		float bBrightness = backColor.GetBrightness(); 
 		float curContrast = fBrightness - bBrightness; 
 		float delta = prefContrastLevel - (float)Math.Abs(curContrast); 
		if((float)Math.Abs(curContrast) < prefContrastLevel) 
		{ 
			if(bBrightness < 0.5f) 
			{ 
				fBrightness = bBrightness + prefContrastLevel; 
				if(fBrightness > 1.0f) 
					fBrightness = 1.0f; 
			} 
			else 
			{ 
				fBrightness = bBrightness - prefContrastLevel; 
				if(fBrightness < 0.0f) 
					fBrightness = 0.0f; 
			} 
			float newr, newg, newb; 
			ConvertHSBToRGB(foreColor.GetHue(), foreColor.GetSaturation(), fBrightness, out newr, out newg, out newb); 
			foreColor = Color.FromArgb(foreColor.A, (int)Math.Floor(newr * 255f), (int)Math.Floor(newg * 255f), (int)Math.Floor(newb * 255f)); 
		}
	} 
 
		// <summary>
		// Fills a ref byte array with random numbers 0 to 255 inclusive per element. 
		// </summary>
		// <param name="rgb">R for Red, G for Green, B for Blue. The higher the number, the more intense the color.</param>
//		public void RandRGB(byte[] rgb) // No longer in use.
//		{
//			RandIntGenerator.NextBytes(rgb);
//			rgb[0] |= 64;
//			rgb[1] |= 64;
//			rgb[2] |= 64;
//		}
		// ------------------------------------------- End methods. ----------------------------------------------

	} // Class End
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Hello, I have been a professional hairpuller aka programmer for a large company during the last nine years. The acquiring company is closing down the california office so I'll be out of work at the end of June at the latest. I program in a variety of laguages, C#, C++, C, Visual Basic, SQl Server among others. I live north of Sacramento in Paradise CA. I've been programming since the early 1980 and people accuse me of going bald. I'm not going bald, my hair is just migrating south and into my ears.

I am a firm believer that the most widely used programming language is #$@$@$%#$%^ but folks tend to object to the unusual synatax where each word has a colorful meaning and sentences are limited to three words max, while the punching bag flys back and forth so fast it heats up from friction like a meteorite through the air.

In short, I'm nuts, but I'm good at what I do.

Programming is like beating my head against a brick wall, it hurts so bad I can't stand it, but when I stop beating my head against the wall (Solve the problem), it feels so good I gotta do it again!

Comments and Discussions