Stupid .NET 1.1 Service Pack 1

Service pack 1 strikes again.

    using System;
    using System.Drawing;
    using System.IO;
    using System.Reflection;
    public class Resources {
        private Resources() {}
        public static Image LoadImageFromResource(string path) {
            Image i = null;
            using ( Stream s = 
                      Assembly.GetExecutingAssembly().GetManifestResourceStream(path) ) {
                if(s != null) i = Image.FromStream(s, true, true);
            }
            return i;
        }
    }
C#

This is part of a general use utility that I frequently use. An odd bug that came out of this is that the overloaded method

Image.FromStream(Stream, Boolean, Boolean);
C#



was added in Service Pack 1 for .net v1.1 BUT NEVER DOCUMENTED!!!. Well, ok that’s not entirely true It is documented… in v2.0 documentation. So if you wrote this in 1.1 sp1 and deployed it to a machine without sp1 you’ll get a method not found exception when trying to load the image from stream using the above overload–non sp1 only has FromStream(Stream, Boolean)

Nothing like being incompatible with the same version of the framework eh?

C# Binary Serialization Oddities

Ok, it’s been a while since I wrote about anything, so sue me!

Today’s topic is an interesting find (at least to me)… When you serialize an object that has events (or a delegate) that have been assigned a value (and that value is outside of the class containing the event or delegate), .NET’s binary serializer will attempt to serialize the entire object who’s function is assigned to it (it’s an interesting thing to think about why they attempt to persist the event association as well). Said more simply, it will attempt to save the class being serialized, as well as all other classes who contain function definitions for those events or delegates.

Take the following example:

namespace SerializationWoes {
    using System;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    class Class1 {
        Class1() {}

        [STAThread]
        static void Main(string[] args) {
            BinaryFormatter bf = new BinaryFormatter(); 
            byte[] bytes;
            BigDeal bd = new BigDeal();
            bd.Something = "blah blah blah";
            using ( MemoryStream ms = new MemoryStream() ) {
                bf.Serialize(ms, bd);
                ms.Seek(0,0);
                bytes = ms.ToArray();
            }
        }
    }

    // serialized object
    [Serializable]
    public class BigDeal {
        string something = "";
        public string Something {
            get { return this.something; }
            set { 
                this.something = value; 
            }
        }
        public BigDeal() {
        }
    }
}
C#

BigDeal serializes perfectly into the memory stream and therefore to the byte array.

Now, let’s throw in an event (and the event handler) with a non-serializable object who contains the definition of that event method handler:

namespace SerializationWoes {
    using System;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    class Class1 {
        [NonSerialized]
        static Class1 c = new Class1();
        Class1() {} 
        private void bd_MyEvent(object sender, EventArgs e) {
            Console.WriteLine("hey some event just happened");

        } 

        [STAThread]
        static void Main(string[] args) {
            BinaryFormatter bf = new BinaryFormatter(); 
            byte[] bytes;
            BigDeal bd = new BigDeal();
            bd.MyEvent += new EventHandler(c.bd_MyEvent);
            bd.Something = "blah blah blah";
            using ( MemoryStream ms = new MemoryStream() ) {
                bf.Serialize(ms, bd);
                ms.Seek(0,0);
                bytes = ms.ToArray();
            }
        }
    }

    // serialized object
    [Serializable]
    public class BigDeal {
        string something = "";
        public event EventHandler MyEvent;
        protected virtual void OnEvent(EventArgs e) {
            if(MyEvent != null) MyEvent(this, e);
        }
        public string Something {
            get { return this.something; }
            set { 
                this.something = value; 
                OnEvent(EventArgs.Empty);
            }
        }
        public BigDeal() {
        }
    }
}
C#

Now, when we run the app, we get the following exception:

Exception message

An unhandled exception of type ‘System.Runtime.Serialization.SerializationException’ occurred in mscorlib.dll

Additional information: The type SerializationWoes.Class1 in Assembly SerializationWoes, Version=1.0.0.39766, Culture=neutral, PublicKeyToken=null is not marked as serializable.

What interests me here is why the binary formatter attempts to persist the event (and the other object, which contains the method for that event) as well.

A delegate / event is a function which is used like a variable. It can be assigned to and used just like a variable, so why not save its value as well. It makes sense when you think about it that way (Trust me. We spent far too much time wondering why some random UserControl was trying to be serialized into a custom object we had just written at work–until we realized that its events were being persisted as well). To persist a delegate or event, the framework also has to serialize the object whose function is the value of that event or delegate. Oddly enough, to do this, that object must be marked as [Serializable]. If not the above exception will be thrown every time you attempt to serialize your object containing the event.

There are 2 ways to get around this issue:

  • Make the class who subscribes to the event or delegate [Serializable] (if persisting that event / delegate is critical). This is often not the preferred choice.
  • Break your event out into a delegate / event Property. (as shown below)

The way to implement the latter is as follows. Change the public event to a private delegate, and a public event property. Our sample class changes to look like the following:

    using System.Runtime.CompilerServices;
	
    // serialized object
    [Serializable]
    public class BigDeal {
        string something = "";

        [NonSerialized]
        private EventHandler _myEvent;        
        public event EventHandler MyEvent {
            [MethodImpl(MethodImplOptions.Synchronized)]
            add {
                _myEvent = (EventHandler)Delegate.Combine(_myEvent, value);
            }
            [MethodImpl(MethodImplOptions.Synchronized)]
            remove {
                _myEvent = (EventHandler)Delegate.Remove(_myEvent, value);
            }
        }
        protected virtual void OnEvent(EventArgs e) {
            if(_myEvent != null) _myEvent(this, e);
        }
        public string Something {
            get { return this.something; }
            set { 
                this.something = value; 
                OnEvent(EventArgs.Empty);
            }
        }
        public BigDeal() {
        }
    }
C#

As you can see, we’ve added a using statement for System.Runtime.CompilerServices, which is actually for the MethodImpl attributes placed in the add and remove blocks of the event property.

Next, we created a private delegate, and public event property for the event. We added the necessary Add & Remove blocks for the event property (events use add & remove to keep event’s in sync) and add the MethodImpl attributes which take care of making the appropriate locks when we compile so that only 1 thread can access the event at a time to add and remove event definitions.

Next, we mark our delegate with the [NonSerialized] attribute, so that the serializer doesn’t attempt to serialize the value of our event’s delegate (aka our event handler).

The first suggestion–Marking your event handling class as [Serializable]–only works in a few situations, because we don’t always have code for the base class we’re extending (which also must be marked as serializable).

Here you have the final product which can have non-serializable objects define event handlers for it, and no exception will be thrown.

namespace SerializationWoes {
    using System;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Runtime.Serialization.Formatters.Binary;
    class Class1 {
        [NonSerialized]
        static Class1 c = new Class1();
        Class1() {} 
        private void bd_MyEvent(object sender, EventArgs e) {
            Console.WriteLine("hey some event just happened");
        } 

        [STAThread]
        static void Main(string[] args) {
            BinaryFormatter bf = new BinaryFormatter(); 
            byte[] bytes;
            BigDeal bd = new BigDeal();
            bd.MyEvent += new EventHandler(c.bd_MyEvent);
            bd.Something = "blah blah blah";
            using ( MemoryStream ms = new MemoryStream() ) {
                bf.Serialize(ms, bd);
                ms.Seek(0,0);
                bytes = ms.ToArray();
            }
        }
    }

    // serialized object
    [Serializable]
    public class BigDeal {
        string something = "";
        [NonSerialized]
        private EventHandler _myEvent;        
        public event EventHandler MyEvent {
            [MethodImpl(MethodImplOptions.Synchronized)]
            add {
                _myEvent = (EventHandler)Delegate.Combine(_myEvent, value);
            }
            [MethodImpl(MethodImplOptions.Synchronized)]
            remove {
                _myEvent = (EventHandler)Delegate.Remove(_myEvent, value);
            }
        }
        protected virtual void OnEvent(EventArgs e) {
            if(_myEvent != null) _myEvent(this, e);
        }
        public string Something {
            get { return this.something; }
            set { 
                this.something = value; 
                OnEvent(EventArgs.Empty);
            }
        }
        public BigDeal() {
        }
    }
}
C#

Now hopefully anyone having the same problem we had today at work (who has access to Google), won’t have to spend as long with the problem as we had to (not that an hour or two is much time, just annoying).

All About The @T Sign (C# Verbatim Identifier)

Bad form. Bad style. People will hate you. But, its totally legal.

I think I read this back in the language specification, or maybe a college professor said it, but I had forgotten about it until I read it on someone else’s blog.

namespace Test {
    using System;
    public class Test { 
        static void Foo(string @namespace) {
            bool @true = @namespace == "hello";
            if(@true) Console.WriteLine(@namespace);
        }
    }
    
    [STAThread]
    static void Main(string[] args) {
        Test.Foo("hello"); // prints out "hello"
        Test.Foo("world"); // prints nothing
    }
}
C#

Odd eh?

If you’re ever have a sudden urge to use a reserved word, and just *HAVE* to have the word “true” as a variable name, @true will work.

Now… if you ever use that in public, you may be bludgeoned to death by co-workers.

its called a “verbatim” identifier, and should only be used in tandem with a goto statement for maximum annoyance.

C# 2 Language Specification

I’ve been reading over the new beta 2 C# specification lately. Good Read: Download it here

Cant wait until its production ready!

A Simple Line Control

Some time ago, I was working on a clone of Solitaire (the one that comes with windows), and I needed a line control (for… surprise surprise… the about box) like the one shown in its about window:

Example Line Control
Example Line Control

after a brisk 2 seconds I came up with the following class:

/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  Line Control                                      */
/*  by: Steve Whitley                                 */
/*  © 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/

namespace NullFX.Controls {
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    [Designer(typeof(Line.LineDesigner))]
    public class Line : Control {
        internal class LineDesigner : ControlDesigner {
            public override SelectionRules SelectionRules {
                get {
                    return SelectionRules.LeftSizeable |
                        SelectionRules.RightSizeable |
                        SelectionRules.Visible |
                        SelectionRules.Moveable;
                }
            }

        }
        private FlatStyle _flatStyle;
        private Pen _systemPen;
        private Container components = null;
        [Category("Appearance"), 
        Description(
        "Determines the display of the control" +
        "when the users move the mouse over the control" +
        "and click")]
        public FlatStyle FlatStyle {
            get{return _flatStyle;}
            set{
                _flatStyle = value;
                Invalidate();
            }
        }
        public Line() {
            _flatStyle = FlatStyle.Standard;
            _systemPen = 
                  new Pen(SystemColors.ControlDark, 2);
            SetStyle(ControlStyles.AllPaintingInWmPaint |
                ControlStyles.DoubleBuffer|
                ControlStyles.ResizeRedraw|
                ControlStyles.UserPaint, true);
        }		 
        protected override void Dispose( bool disposing ) {
            if( disposing ) {
                if( components != null ) {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }
        protected override Size DefaultSize {
            get {
                return new System.Drawing.Size(120, 2);
            }
        } 
        protected override void OnPaint(PaintEventArgs pe) {
            switch(_flatStyle) { 
                case FlatStyle.Flat:
                case FlatStyle.Popup:
                case FlatStyle.Standard: {
                    pe.Graphics.FillRectangle(
                       SystemBrushes.ControlLightLight, 
                       0, 0, Width, 2);
                    pe.Graphics.FillRectangle(
                       SystemBrushes.ControlDark, 
                       0, 0, Width - 1, Height / 2); 
                }break;
                case System.Windows.Forms.FlatStyle.System: {
                    pe.Graphics.DrawLine(_systemPen, 
                                             0, 1, Width, 1);
                }break;
                default:
                    goto case FlatStyle.Standard; 
            }
        }
    }
}
C#

Now to talk over a few points in this very simple control.

There were 2 requirements I had for the control:

  1. It had to have an inherent size when I dragged it onto the canvass
  2. it had to keep its aspect ratio (meaning I couldn’t make it look inconsistent)

I was able to accomplish this using a class designer, and by overriding the DefaultSize property of the control. I could have gotten much more fancy with the control, but since I was going to be the only one using it (well… that was the plan anyway :D), I kept it super simple.

protected override Size DefaultSize {
    get {
        return new System.Drawing.Size(120, 2);
    }
}
C#

This allows the control to default to this size. Anytime the control needs its base size, it uses the DefaultSize property. My first iteration of this control actually set the size property in the InitializeComponent method, but after reading up on it, using the DefaultSize property and specifying its size is the better solution.

The next thing was to keep its aspect ratio. This is achieved by providing my control with a designer. There are lots of articles out there on how to implement a designer, so I’ll leave that for another topic, and just discuss what I used in the designer to accomplish this.
There is a property in the ControlDesigner called SelectionRules. This tells the control host at design time, how it can be used. Here’s our designer class. It’s actually an inner class of the Line control.

internal class LineDesigner : ControlDesigner {
	public override SelectionRules SelectionRules {
		get {
			return SelectionRules.LeftSizeable |
				SelectionRules.RightSizeable |
				SelectionRules.Visible |
				SelectionRules.Moveable;
		}
	}
}
C#

Notice we’re only overriding the SelectionRules property. It returns a bit flag value of which types of selection are possible in the designer. I didn’t want the control to be sized up or down, so I left those selection rules out. I did want it to be able to be sized right or left, and movable (and obviously visible), so these are the rules I return.

Other than this, all we need is to draw the line. This is achieved by overriding the OnPaint function in the control. I have provided functionality (however ugly it may be) for flat style, but for simplicity, I’ll speak to the normal line.
The line in the about box has a highlight line and a shadow line. In our OnPaint method, I draw both lines using Control.Dark and Control.LightLight colors (this is so these colors can match whatever theme is being used).

case FlatStyle.Standard: {
	pe.Graphics.FillRectangle( SystemBrushes.ControlLightLight, 0, 0, Width, 2 );
	pe.Graphics.FillRectangle( SystemBrushes.ControlDark, 0, 0, Width - 1, Height / 2 );
}break;
C#

Anyway, this is my simple line control.

Download the Binary Here.

Obtaining Key State info in .NET (A C# GetKeyState implementation)

Sometimes it’s usefull to know the current state of a given key. The platform SDK provides this functionality however .NET (at least v1.1) doesn’t provide access to it.

GetKeyState allows a developer to get information such as whether or not the given key is currently being pressed down, or if the key has a toggled state, whether or not it is currently being toggled.

The following utility is a .NET complement to the GetKeyState platform SDK function. I’ve created a struct which has 3 properties: Key, IsPressed, and IsToggled. These properties are set when GetKeyState is invoked. The return value of this GetKeyState is this struct, to give easy access to the data provided. As MSDN documentation states, the return value of this function is a number who’s high bit denotes whether or not the key is being pressed, and the low bit denotes whether or not the key is currently toggled. The “Key” property is simply being passed through. Another thing to take notice of, is that the platform sdk uses the virtual key VK_<XX> definition for keys. These have been mapped into .NET’s System.Windows.Forms.Keys enumeration, so that the value of the given Keys.<key> has the same value as the VK_<key> winuser.h definition.

Anyway, here’s the sample:

/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  GetKeyState Utility                               */
/*  by: Steve Whitley                                 */
/*  © 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/

namespace NullFX.Win32 {
    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    public class KeyboardInfo {
        private KeyboardInfo() {}
        [DllImport("user32")]
        private static extern short GetKeyState(int vKey);
        public static KeyStateInfo GetKeyState(Keys key) {
            short keyState = GetKeyState((int)key);
            byte[] bits = BitConverter.GetBytes(keyState);
            bool toggled = bits[0] > 0, pressed = bits[1] > 0;
            return new KeyStateInfo(key, pressed, toggled);
        }
    }


    public struct KeyStateInfo {
        Keys _key;
        bool _isPressed,
            _isToggled;
        public KeyStateInfo(Keys key, 
                        bool ispressed, 
                        bool istoggled) {
            _key = key;
            _isPressed = ispressed;
            _isToggled = istoggled;
        }
        public static KeyStateInfo Default {
            get { 
                return new KeyStateInfo(Keys.None, 
                                            false, 
                                            false);
            }
        }
        public Keys Key {
            get{return _key;}
        }
        public bool IsPressed {
            get{return _isPressed;}
        }
        public bool IsToggled {
            get{return _isToggled;}
        }
    }
}
C#

Usage:

KeyStateInfo capsLock = KeyboardInfo.GetKeyState(Keys.CapsLock);
if(capsLock.IsToggled) MessageBox.Show("Caps Lock is On");
C#

A CRC32 Implementation in C#

The other day I was looking for a simple CRC32 library…

I couldn’t find one (that suited my needs) so I wrote a quick and dirty implementation.

here it is:

namespace NullFX.Security {
    using System;
    public class Crc32 {
        uint[] table;

        public uint ComputeChecksum(byte[] bytes) {
            uint crc = 0xffffffff;
            for(int i = 0; i < bytes.Length; ++i) {
                byte index = (byte)(((crc) & 0xff) ^ bytes[i]);
                crc = (uint)((crc >> 8) ^ table[index]);
            }
            return ~crc;
        }

        public byte[] ComputeChecksumBytes(byte[] bytes) {
            return BitConverter.GetBytes(ComputeChecksum(bytes));
        }

        public Crc32() {
            uint poly = 0xedb88320;
            table = new uint[256];
            uint temp = 0;
            for(uint i = 0; i < table.Length; ++i) {
                temp = i;
                for(int j = 8; j > 0; --j) {
                    if((temp & 1) == 1) {
                        temp = (uint)((temp >> 1) ^ poly);
                    }else {
                        temp >>= 1;
                    }
                }
                table[i] = temp;
            }
        }
    }
}
C#

Its admittedly small, and hardly anyone uses CRC32 for security purposes (at least I hope not), but it is a decent checksum generator for small non-critical items.

I needed a 32 bit sized number generator–I was implementing my own object.GetHashCode() and wanted to get an int hashcode for my own objects–and this seemed like a decent way to do it.

If you need for this code to be CLS compliant, you can change the method signature’s return type from uint to long and it will operate the same (the uint crc value will be implicitly converted from uint to long)

Links to the other C# CRC implementations CRC16-CCITT, CRC16-CCITT Kermit, CRC16, and CRC8

I’ve consolidated all of these into a single library on GitHub here: NullFX.CRC.

I’m also very into Swift at the moment and have created Swift versions of these same classes and released a Swift PM version of this library here as well Swift NullfxCrc Package

Numeric Text Box: A Number Only Text Box Control in C#

Here’s my numeric only text control. I’ll admit there’s not much too it, and there are masked edit controls, but for those who dare…

/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  NumericTextBox Library                            */
/*  by: Steve Whitley                                 */
/*  © 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/

namespace NullFX.Controls {
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Forms;

    public class NumericTextBox : TextBox {
        static NumberFormatInfo CurrentNumberFormat = 
               CultureInfo.CurrentCulture.NumberFormat;
        const int WM_KEYDOWN = 0x0100,
                  WM_PASTE = 0x0302;

        public decimal Value {
            set { Text = value.ToString ( ); }
            get {
                decimal.TryParse ( Text, out decimal tmpValue );
                return tmpValue;
            }
        }

        public override bool PreProcessMessage ( ref Message msg ) {
            if ( msg.Msg == WM_KEYDOWN ) {
                Keys keys = ( Keys ) msg.WParam.ToInt32 ( );
                bool isPaste = keys == Keys.V && ModifierKeys == Keys.Control;
                bool isNumeric = IsNumeric ( keys );
                bool isKeyValid = IsKeyValid ( keys );
                if ( isNumeric | isKeyValid ) {
                    return false;
                } else if ( isPaste ) {
                    IDataObject obj = Clipboard.GetDataObject ( );
                    string input = ( string ) obj.GetData ( typeof ( string ) );
                    if ( !IsInputOrTextNumeric ( input ) ) {
                        return true;
                    }
                    return false;
                } else {
                    return true;
                }
            } else {
                return base.PreProcessMessage ( ref msg );
            }
        }

        protected override void WndProc ( ref Message m ) {
            if ( m.Msg == WM_PASTE ) {
                IDataObject obj = Clipboard.GetDataObject ( );
                string input = ( string ) obj.GetData ( typeof ( string ) );
                if ( !IsInputOrTextNumeric ( input ) ) {
                    m.Result = ( IntPtr ) 0;
                    return;
                }

            }
            base.WndProc ( ref m );
        }

        private bool IsNumeric ( Keys key ) {
            return ( ( key >= Keys.D0 && key <= Keys.D9 ) ||
                   ( key >= Keys.NumPad0 && key <= Keys.NumPad9 ) ) &&
                   ModifierKeys != Keys.Shift;
        }

        private bool IsKeyValid ( Keys key ) {
            bool ctrl = key == Keys.Control;
            bool ctrlZ = key == Keys.Z && ModifierKeys == Keys.Control,
                 ctrlX = key == Keys.X && ModifierKeys == Keys.Control,
                 ctrlC = key == Keys.C && ModifierKeys == Keys.Control,
                 ctrlV = key == Keys.V && ModifierKeys == Keys.Control,
                 homeEnd = key == Keys.Home | key == Keys.End,
                 del = key == Keys.Delete,
                 bksp = key == Keys.Back,
                 arrows = ( key == Keys.Up ) | ( key == Keys.Down ) | 
                          ( key == Keys.Left ) | ( key == Keys.Right );
            bool standardTests = ctrl | del | bksp | arrows | homeEnd | 
                                 ctrlC | ctrlX | ctrlV | ctrlZ;
            bool containsTokenChar = false;
            if ( !standardTests ) {
                string token = VKtoChar ( key );
                containsTokenChar = validTokens.ContainsKey ( token );
                if ( token != CurrentNumberFormat.CurrencyGroupSeparator && 
                    Text.Contains ( token ) ) {
                    containsTokenChar = false;
                }
                if ( !IsInputOrTextNumeric ( token ) ) {
                    containsTokenChar = false;
                }
            }
            return standardTests | containsTokenChar;
        }

        private bool IsInputOrTextNumeric ( string tokenOrInput ) {
            string tmp = Text;
            string inserted = tmp.Insert ( SelectionStart, tokenOrInput );
            if ( !decimal.TryParse ( inserted, out decimal result ) ) {
                return false;
            }
            return true;
        }

        private static string VKtoChar ( Keys key ) {
            StringBuilder sb = new StringBuilder ( 256 );
            byte[] keystate = new byte[256];
            if ( GetKeyboardState ( keystate ) ) {
                uint scanCode = MapVirtualKey ( ( uint ) key, 2 );
                int res = ToUnicode ( ( uint ) key, scanCode, keystate, sb, 256, 2 );
            }
            return sb.ToString ( );
        }

        static Dictionary<string, string> validTokens = 
                                      new Dictionary<string, string> ( );

        static NumericTextBox ( ) {
            validTokens.Add ( CurrentNumberFormat.NegativeSign, "" );
            validTokens.Add ( CurrentNumberFormat.NumberDecimalSeparator, "" );
            validTokens.Add ( CurrentNumberFormat.CurrencyGroupSeparator, "" );
        }

        [DllImport ( "user32.dll", SetLastError = true )]
        private static extern bool GetKeyboardState ( byte[] receivingBuffer );

        [DllImport ( "user32.dll", SetLastError = true )]
        private static extern int ToUnicode ( uint virtualKey, uint scanCode, 
            byte[] keyState, [Out, MarshalAs ( UnmanagedType.LPWStr, SizeConst = 256 )]  
            StringBuilder buffer, int bufferSize, uint flags );
        [DllImport ( "user32.dll" )]
        private static extern uint MapVirtualKey ( uint keyCode, uint mapType );
    }
}
C#

What this does, is watch the Windows Message Queue for incoming messages (specifically WM_KEYDOWN and WM_PASTE). If a key has been pressed, it will look to see if the key is actually a number. It also looks to see if a paste command has been sent. if a key has been pressed and it is a numeric key (there are a few more keys for convenience sake) or the paste operation has been invoked (the contents of the paste operation are checked to make sure that anything that gets pasted is a number, else it fails to paste in the data) and its contents are numeric, allows that data to be pasted into the textbox.

Since originally posting this control on my older website, I’ve made some minor updates, checking the key pressed against its text character, checking to see if the resulting value will parse as a decimal and adding a few more keystroke character checks in there.

For Clarity sake, PreProcessMessage is invoked before the Message is sent into the message queue. If the control handles this message, it returns true, and the message ends there. If it returns false, it will send the Message into the message pump for further processing. WndProc is similar to WindowProc in win32, and one can filter messages sent here like they used to in standard windows programming. In this sample, we’re peeking at the KEYDOWN message, in the PreProcessMessage function. Commands are not sent through here, but are passed in WndProc, where we can listen, and handle this Message ourselves (because we need to check the contents of the clip board for numeric data).

If PreProcessMessage‘s Message contains numeric or one of our allowed keys, it returns false which forces the base TextBox to handle the instruction like normal, if not it returns true meaning we’ve handled it and it doesn’t get passed into the base TextBox control and nothing flows to the textbox. If WndProc receives a numeric only string in the clip board, then it sends the message to the base TextBox

base.WndProc(ref m);

if the clipboard contains alpha or other data, it sets the LResult to 0, and returns without passing the message to the base TextBox effectively saying we’ve handled the message, and there’s no need to process it any further.

ScrollableRichTextBox

The standard RichTextBox’s “Auto-Scroll” functionality is so obscure, that most rarely ever find out how to use it. This class appends text and gives the option for the user to scroll to the bottom of the textbox.

/******************************************************/
/*          NULLFX FREE SOFTWARE LICENSE              */
/******************************************************/
/*  ScrollableRichTextBox Library                     */
/*  by: Steve Whitley                                 */
/*  © 2005 NullFX Software                            */
/*                                                    */
/* NULLFX SOFTWARE DISCLAIMS ALL WARRANTIES,          */
/* RESPONSIBILITIES, AND LIABILITIES ASSOCIATED WITH  */
/* USE OF THIS CODE IN ANY WAY, SHAPE, OR FORM        */
/* REGARDLESS HOW IMPLICIT, EXPLICIT, OR OBSCURE IT   */
/* IS. IF THERE IS ANYTHING QUESTIONABLE WITH REGARDS */
/* TO THIS SOFTWARE BREAKING AND YOU GAIN A LOSS OF   */
/* ANY NATURE, WE ARE NOT THE RESPONSIBLE PARTY. USE  */
/* OF THIS SOFTWARE CREATES ACCEPTANCE OF THESE TERMS */
/*                                                    */
/* USE OF THIS CODE MUST RETAIN ALL COPYRIGHT NOTICES */
/* AND LICENSES (MEANING THIS TEXT).                  */
/*                                                    */
/******************************************************/

namespace NullFX.Controls {
    using System;
    using System.Windows.Forms;
    /// <summary>
    /// This components adds a much lacking function
    /// "Scroll to the end" which is missing
    /// from the original rich text box.
    /// </summary>
    public class ScrollableRichTextBox : RichTextBox {
        // constants for the message sending
        const int WM_VSCROLL = 0x0115;
        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_SETFOCUS = 0x0007;
        const int WM_KILLFOCUS = 0x0008;
        readonly IntPtr SB_ENDSCROLL = (IntPtr)8;
        readonly IntPtr SB_BOTTOM = (IntPtr)7;
        // flag we use to determine if we can scroll
        bool _scrollable = true;
        private delegate void AppendTextDelegate(string text, bool scrollToEnd);
        public void AppendText(string text, bool scrollToEnd) {
            if(InvokeRequired) {
                Invoke(new AppendTextDelegate(AppendText), 
                           new object[] {text, scrollToEnd});
            }else {
                decimal length = base.Text.Length + text.Length;
                if(length >= base.MaxLength) base.Clear();
                base.Text += text;
                if(_scrollable && scrollToEnd) {
                    if(IntPtr.Zero != base.Handle) {
                        base.SelectionStart = base.Text.Length;
                        Message m = Message.Create(
                            base.Handle, 
                            WM_VSCROLL, 
                            SB_BOTTOM, IntPtr.Zero);
                        base.WndProc(ref m);
                    }
                }
            }

        }

        protected override void WndProc(ref Message m) {
            // if we're in a scroll set the scrolling flag 
            // to false & skip theauto scroll
            if((m.Msg == WM_LBUTTONDOWN) 
                || m.Msg == WM_VSCROLL 
                && m.WParam != SB_BOTTOM) {
                _scrollable = false;
            }

            // if we are done scrolling, set the falg to true & do the scrolling
            if(m.Msg == WM_VSCROLL && m.WParam == SB_ENDSCROLL) {
                _scrollable = true;
            }
            // HACK: this keeps the user from setting the cursor in the textbox
            //  because that causes problems if they do
            if(m.Msg == WM_SETFOCUS && base.ReadOnly) m.Msg = WM_KILLFOCUS;

            base.WndProc (ref m);
        }
    }
}
C#

There used to be a threading problem which would throw an unhandled exception every now and then, but due to an article recently published on msdn blogs this has been fixed, and the change is reflected above.