[.net] "Error creating window handle."

Started by
3 comments, last by SunTzu 17 years, 1 month ago
I'm starting to play around with some simple C# stuff having been a C++ programmer for a decade or two now. Generally speaking I love it, but I've just run into a bit of a problem with a sample program I got from a magazine. The magazine had some .NET 2.0 stuff in it where I've only got .NET 1.1, but that didn't ought to be an issue, I just need to find another way to do a couple of things. However, when I run the code below (which should create a screensaver-type app, and if you were to rename the compiled .exe to .scr and put it in the Windows folder it would be a screensaver in every sense), after calling through Application.Run (and successfully creating the Form1 object etc.) I get an unhandled System.ComponentModel.Win32Exception, "Error creating window handle." Call stack is as follows: at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp) at System.Windows.Forms.Control.CreateHandle() at System.Windows.Forms.Form.CreateHandle() at System.Windows.Forms.Control.get_Handle() at System.Windows.Forms.Form.SetVisibleCore(Boolean value) at System.Windows.Forms.Control.set_Visible(Boolean value) at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at BasicScreenSaver.Form1.Main(String[] args) ...and the code looks like this (I've pasted the whole lot so you can see what it's doing from start to finish):

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;

// Simple screen saver, using code from Computer Shopper April 07 pp186-189

namespace BasicScreenSaver
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class Form1 : System.Windows.Forms.Form
	{
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.Timer timer1;
		private string[] m_args;

		private Point m_textPos = new Point( 0, 0 );
		private Point m_textVelocity = new Point( 1, 1 );
		private Point m_mousePos;
		private IntPtr m_hwnd;

		// This is all so we can use Windows API calls... but seems an immensely ugly way to do it?
		public struct RECT
		{
			public int Left;
			public int Top;
			public int Right;
			public int Bottom;
		}

		[DllImport("user32.dll")]
			static extern bool GetClientRect( IntPtr hWnd, out RECT lpRect );

		[DllImport("user32.dll", SetLastError = true )]
			static extern int GetWindowLong( IntPtr hWnd, int nIndex );

		const int GWL_style = (-16);
		const int WS_CHILD = 0x40000000;

		[DllImport("user32.dll")]
			static extern IntPtr SetWindowLong( IntPtr hWnd, int nIndex, int dwNewLong );

		[DllImport("user32.dll")]
			static extern IntPtr SetParent( IntPtr hWndChild, IntPtr hwndNewParent );

		const int GWL_HWNDPARENT = (-8);

		[DllImport("user32.dll")]
			static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags );

		static readonly IntPtr HWND_TOP = new IntPtr(0);

		const UInt32 SWP_NOZORDER = 0x0004;
		const UInt32 SWP_NOACTIVATE = 0x0010;
		const UInt32 SWP_SHOWWINDOW = 0x0040;

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.timer1 = new System.Windows.Forms.Timer(this.components);
			// 
			// timer1
			// 
			this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(292, 266);
			this.Name = "Form1";
			this.Text = "Form1";
			this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnMouseEvent);
			this.Load += new System.EventHandler(this.Form1_Load);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnMouseEvent);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main( string[] args ) 
		{
			Application.Run( new Form1( args ) );
		}

		// Parameterized constructor, to receive command line parameters from Main
		public Form1( string[] args )
		{
			InitializeComponent();
			m_args = args;
			this.TopLevel = false;	// Set invisible (can't use Hide or Visible = False)
		}

		private void Form1_Load( object sender, EventArgs e )
		{
			if ( m_args.Length > 0 )
			{
				string arg = m_args[0].ToLower().Trim().Substring( 0, 2 );

				switch ( arg )
				{
					case "/c":
						// TODO configure screen saver
						break;

					case "/s":
						ShowScreenSaver();
						break;

					case "/p":
						if ( m_args.Length > 1 )
						{
							this.TopLevel = false;
							m_hwnd = (IntPtr)Int32.Parse( m_args[1] );
							ShowScreenSaver();
						}
						break;
				}
			}
			else
			{
				ShowScreenSaver();
			}
		}

		void ShowScreenSaver()
		{
			// Are we previewing or running for real?
			if ( this.m_hwnd == IntPtr.Zero )
			{
				//this.DoubleBuffered = true;	// ???
				this.timer1.Interval = 20;
				this.timer1.Enabled = true;

				this.FormBorderstyle = FormBorderstyle.None;
				this.TopLevel = true;
				this.WindowState = FormWindowState.Maximized;
				this.Capture = true;
				Cursor.Hide();
			}
			else
			{
				// This is a child window
				int style = GetWindowLong( this.Handle, GWL_style );
				style = style | WS_CHILD;
				SetWindowLong( this.Handle, GWL_style, style );

				// Its parent is the preview window
				SetParent( this.Handle, m_hwnd );
				SetWindowLong( this.Handle, GWL_HWNDPARENT, (int)m_hwnd );

				// Draw within the parent window
				this.FormBorderstyle = FormBorderstyle.None;
				RECT r = new RECT();
				GetClientRect( m_hwnd, out r );

				SetWindowPos( this.Handle, HWND_TOP, 0, 0, r.Right, r.Bottom, SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW );
			}
		}

		private void timer1_Tick( object sender, EventArgs e )
		{
			Graphics g = this.CreateGraphics();
			RectangleF bounds = this.ClientRectangle;

			//string displayMessage = "Some String";
			int fontSize = (int)bounds.Height / 20;

			FontFamily fontFamily = new FontFamily( "Arial" );
			Font font = new Font( fontFamily, fontSize, Fontstyle.Regular, GraphicsUnit.Pixel );

			// TODO determine text size - not sure how to do this in .NET 1.1

			m_textPos.X += m_textVelocity.X;
			m_textPos.Y += m_textVelocity.Y;

			if ( m_textPos.X > bounds.Width || m_textPos.X <= 0 )	// XXX slightly different
			{
				m_textVelocity.X *= -1;
			}
			
			if ( m_textPos.Y > bounds.Height || m_textPos.Y <= 0 )	// XXX slightly different
			{
				m_textVelocity.Y *= -1;
			}

			// TODO draw the text - not sure how to do this in .NET 1.1
		}

		private void OnMouseEvent( object sender, System.Windows.Forms.MouseEventArgs e )
		{
			if ( !m_mousePos.IsEmpty )
			{
				if ( m_mousePos != new Point( e.X, e.Y ) )
				{
					this.Close();
				}

				if ( e.Clicks > 0 )
				{
					this.Close();
				}
			}

			m_mousePos = new Point( e.X, e.Y );

			// TODO trap keyboard events as well
		}

	}
}

My question is, why am I getting that exception? Still being a C# newbie I haven't the faintest idea why it shouldn't be able to create the window (especially as I'm pretty confident I copied it accurately enough from the magazine).
Advertisement
I just copied the code into my C# 2005 program and compiled it ... looks like some of the code needed altering but that could be due to my having .Net 2.0 and not 1.1 installed.

The only code change I needed to do was FormBorderstyle which had a lower case s and Fontstyle which was similarly affected.

One thing to note though is that once it ran I couldn't quit out of it with Escape or Alt F4. I had to bring up Task Manager and delete the program from there.

So, either the FormBorderstyle was passing the building stage but not the debug stage or some of the code is only available in 2.0 but in that instance you shouldn't have been able to compile it.

What you could do of course is load up the ScreenSaverKit Project wizard and see how that is coded and compare with the one you have.
Thanks, that's good data, at least I know there's no fundamental flaw with it. (You never know with code from magazines). That should give me a couple more things to look at.

You should have been able to exit it just by moving or clicking the mouse... but you'd probably have noticed that, and it's interesting even Alt+F4 didn't kill it...
If you want to use .NET 2.0 you can always download the Express Editions. They run fine side-by-side with 1.1 and even with Visual Studio 2005.

Former Microsoft XNA and Xbox MVP | Check out my blog for random ramblings on game development

Thanks, but VS 2005 is on the shopping list anyway, immediately after a new car, so I'll just wait a couple of weeks...

Incidentally having reviewed the code, I'm not sure where the lower-case s's in FormBorderstyle and Fontstyle came from, as they were upper case in the file I'd copied and pasted the code from... freaky!

Also, once when running it did, very briefly, display a form covering the entire screen (as expected), but then immediately bombed out with the unhandled exception anyway. So something very odd is going on there.

Comparing with the screen saver kit is the next step.

This topic is closed to new replies.

Advertisement