<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-19301474</id><updated>2011-04-21T14:23:36.677-07:00</updated><title type='text'>Chris's Blog</title><subtitle type='html'>This is mostly a place for me to make notes about things I'm working on (C# Programming) but I might sometimes drop other things in here that I find interesting/useful - to me that is.  :-)
I'd be a little suprised if anyone else finds it of much interest, but you never know...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-19301474.post-114408041642262762</id><published>2006-04-03T08:59:00.000-07:00</published><updated>2006-04-03T09:06:56.436-07:00</updated><title type='text'>Shift Space on a Dotnet Datagrid</title><content type='html'>Microsoft have added some fairly dumb (IMO) features to the datagrid.&lt;br /&gt;One of the worst is the one where if the user accidently has the SHIFT key down when they press the SPACE then the whole row is selected, and the user usually finishes up deleting everything they just typed.&lt;br /&gt;The only work-round I have found is this.&lt;br /&gt;&lt;br /&gt;You need to derive your own version of the datagrid:&lt;br /&gt;&lt;br /&gt;public class MyDataGrid:System.Windows.Forms.DataGrid&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;// A couple of setup bits:&lt;br /&gt;const int WM_KEYDOWN = 256;&lt;br /&gt;[DllImport("user32.dll")]&lt;br /&gt;public static extern int GetKeyboardState(ref Byte pbKeyState);&lt;br /&gt;[DllImport("user32.dll")]&lt;br /&gt;public static extern int SetKeyboardState(ref Byte pbKeyState);&lt;br /&gt;&lt;br /&gt;// then override the 'ProcessCmdKey' method:&lt;br /&gt;protected override bool ProcessCmdKey(ref Message msg, Keys keyData)&lt;br /&gt;{&lt;br /&gt; Keys keyCode = ((Keys)msg.WParam.ToInt32()) &amp; Keys.KeyCode;&lt;br /&gt; if(msg.Msg == WM_KEYDOWN &amp;&amp; keyCode == Keys.Space)&lt;br /&gt; {&lt;br /&gt;  if (Control.ModifierKeys == Keys.Shift)&lt;br /&gt;  {&lt;br /&gt;   byte[] keystates = new byte[255];&lt;br /&gt;   GetKeyboardState(ref keystates[0]);&lt;br /&gt;   keystates[16] = 0;&lt;br /&gt;   SetKeyboardState(ref keystates[0]);&lt;br /&gt;   SendKeys.Send(" ");&lt;br /&gt;   return true;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; return base.ProcessCmdKey (ref msg, keyData);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;I don't much like this, seems like a bit of a bodge, but as is a lot to do with the datagrid it seems...&lt;br /&gt;Anyway, it works, and now my user is a happy bunny once more :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-114408041642262762?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/114408041642262762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=114408041642262762' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/114408041642262762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/114408041642262762'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2006/04/shift-space-on-dotnet-datagrid.html' title='Shift Space on a Dotnet Datagrid'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113699161688574905</id><published>2006-01-11T07:00:00.000-08:00</published><updated>2006-01-11T07:04:50.496-08:00</updated><title type='text'>Using Words SpellCheck in C# Application</title><content type='html'>They wanted my Windows Form application to spell check some of the fields.&lt;br /&gt;As I have control over all machines running the system, and I know that they all have MS Word installed, the simplest way is to use the Spell Checker already built into Word.&lt;br /&gt;This was much easier than I thought it would be...&lt;br /&gt;Before you start, you need to add a reference to the COM Object 'Microsoft Word 9.0 Object Library' (I guess it should work for other versions of Word, but this is the only one I've tried it with).&lt;br /&gt;&lt;br /&gt;public string SpellCheck(string textToCheck)&lt;br /&gt;{&lt;br /&gt;  if (textToCheck.Length ==0)&lt;br /&gt;    return; //No point in trying to spell check an empty string!&lt;br /&gt;   string returnText = textToCheck; //Default return text to original text.&lt;br /&gt;   object optional = System.Reflection.Missing.Value;&lt;br /&gt;   object dontSaveChanges = false;&lt;br /&gt;   Word._Document wd;&lt;br /&gt;   /Create a new Word Application Object.&lt;br /&gt;   Word.Application wa = new Word.ApplicationClass();&lt;br /&gt;   Word.ProofreadingErrors spellErrors;&lt;br /&gt;   wa.Visible = false;&lt;br /&gt;   //Create a new Document with the Word Application Object.&lt;br /&gt;   wd = wa.Documents.Add(ref optional,ref optional,ref optional,ref optional);&lt;br /&gt;   //We use the object optional to pass Null as it has to be passed by Reference(ref)&lt;br /&gt;   //Stuff the text to be checked into the new (blank) document.&lt;br /&gt;   wd.Words.First.InsertBefore(textToCheck); &lt;br /&gt;   //Get a list of all the spelling mistakes.&lt;br /&gt;   spellErrors = wd.SpellingErrors;&lt;br /&gt;   //If there ARE some mistakes...&lt;br /&gt;   if (spellErrors.Count &gt; 0)&lt;br /&gt;   {&lt;br /&gt;     //Check the spelling. All the parameters are about which dictionary to use etc. They can be ignored.&lt;br /&gt;     wd.CheckSpelling(ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional,ref optional);&lt;br /&gt;     object first=0; &lt;br /&gt;     object last=wd.Characters.Count -1; &lt;br /&gt;     //Suck the corrected text back out of the Word Document into the string to be returned.&lt;br /&gt;     returnText = wd.Range(ref first, ref last).Text; &lt;br /&gt;     //Have to declare things as objects as they need to be passed by ref.&lt;br /&gt;   }&lt;br /&gt;   else&lt;br /&gt;   {&lt;br /&gt;     MessageBox.Show("No Errors Found");&lt;br /&gt;   }&lt;br /&gt;   wa.Quit(ref dontSaveChanges,ref optional,ref optional);&lt;br /&gt;   //Can't just pass 'false' to this Quit method as it has to be sent by ref. Hence need to delcare an object.&lt;br /&gt;   return returnText;&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113699161688574905?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113699161688574905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113699161688574905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113699161688574905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113699161688574905'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2006/01/using-words-spellcheck-in-c.html' title='Using Words SpellCheck in C# Application'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113654917255920107</id><published>2006-01-06T04:06:00.000-08:00</published><updated>2006-01-06T04:06:12.623-08:00</updated><title type='text'>Altering the behavior of TAB key</title><content type='html'>&lt;a href="http://chrismayers.blogspot.com/"&gt;Chris's Blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is sometimes necessary to alter the way the tab key works on a form (eg tabbing out of a particular textbox may move you to another screen rather than the next control).&lt;br /&gt;&lt;br /&gt;In the form that contains the controls where the altered behavior is required:&lt;br /&gt;&lt;br /&gt;protected override bool ProcessTabKey(bool forward)&lt;br /&gt;{&lt;br /&gt;  if (this.ActiveControl = textBox1) //Assuming textBox1 is where you require the altered effect&lt;br /&gt;  {&lt;br /&gt;    DoDifferentStuff();&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    return base.ProcessTabKey(forward); // carry on as normal&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;the forward parameter is true if you are tabbing forwards through the form (false for Shift-Tab). So you can alter the behavior in one direction only.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113654917255920107?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113654917255920107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113654917255920107' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113654917255920107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113654917255920107'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2006/01/altering-behavior-of-tab-key.html' title='Altering the behavior of TAB key'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113525371165490556</id><published>2005-12-22T04:15:00.000-08:00</published><updated>2005-12-22T04:15:11.710-08:00</updated><title type='text'>System Tray Icons and Balloon Popups</title><content type='html'>Wanted to write a little status application that ran hidden, and only made itself know when somthing happened.&lt;br /&gt;Best way seemed to be an app that ran with a hidden window and an icon that sat in the System Tray.&lt;br /&gt;&lt;br /&gt;Putting somthing in the System Tray is very simple in DotNet, you just instantiate an instance of the 'NotifyIcon' class.&lt;br /&gt;NotifyIcon ni = new NotifyIcon();&lt;br /&gt;&lt;br /&gt;You can set the icon that is displayed with the ni.Icon property. Change the pop-up text associated with it with the ni.Text property. You can also assign a Context menu to it so that you can control program functions via the icon without needing to see the actual app window.&lt;br /&gt;&lt;br /&gt;Next I thought it would be nice if you got a little Balloon Message to draw attention if somthing changed... not so easy. A little research turned up the following code which does make the implementation of this pretty straightforward.&lt;br /&gt;&lt;br /&gt;First you need a few references to the API:&lt;br /&gt;&lt;br /&gt;		[DllImport("shell32.Dll")]&lt;br /&gt;		public static extern System.Int32 Shell_NotifyIcon(NotifyCommand cmd,&lt;br /&gt;			ref NotifyIconData data);&lt;br /&gt;&lt;br /&gt;		[DllImport("Kernel32.Dll")]&lt;br /&gt;		public static extern System.UInt32 GetCurrentThreadId();&lt;br /&gt;&lt;br /&gt;		public delegate System.Int32 EnumThreadWndProc(System.IntPtr hWnd,&lt;br /&gt;			System.UInt32 lParam);&lt;br /&gt;&lt;br /&gt;		[DllImport("user32.Dll")]&lt;br /&gt;		public static extern System.Int32 EnumThreadWindows(System.UInt32&lt;br /&gt;			threadId, EnumThreadWndProc callback, System.UInt32 param);&lt;br /&gt;&lt;br /&gt;		[DllImport("user32.Dll")]&lt;br /&gt;		public static extern System.Int32 GetClassName(System.IntPtr hWnd,&lt;br /&gt;			System.Text.StringBuilder className, System.Int32 maxCount);&lt;br /&gt;&lt;br /&gt;** DllImport belongs to the 'System.Runtime.InteropServices' namespace.&lt;br /&gt;&lt;br /&gt;Then you need to declare a Structure for the NotifyIconData:&lt;br /&gt;&lt;br /&gt;			public struct NotifyIconData&lt;br /&gt;		{&lt;br /&gt;			public System.UInt32 cbSize; // DWORD&lt;br /&gt;			public System.IntPtr hWnd; // HWND&lt;br /&gt;			public System.UInt32 uID; // UINT&lt;br /&gt;			public NotifyFlags uFlags; // UINT&lt;br /&gt;			public System.UInt32 uCallbackMessage; // UINT&lt;br /&gt;			public System.IntPtr hIcon; // HICON&lt;br /&gt;			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]&lt;br /&gt;			public System.String szTip; // char[128]&lt;br /&gt;			public System.UInt32 dwState; // DWORD&lt;br /&gt;			public System.UInt32 dwStateMask; // DWORD&lt;br /&gt;			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]&lt;br /&gt;			public System.String szInfo; // char[256]&lt;br /&gt;			public System.UInt32 uTimeoutOrVersion; // UINT&lt;br /&gt;			[MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]&lt;br /&gt;			public System.String szInfoTitle; // char[64]&lt;br /&gt;			public System.UInt32 dwInfoFlags; // DWORD&lt;br /&gt;		}&lt;br /&gt;&lt;br /&gt;Next a little Method to get the current system version info:&lt;br /&gt;&lt;br /&gt;And finally the actual display balloon method itself:&lt;br /&gt;&lt;br /&gt;		public void ShowBalloon(uint uintIconID, string strTitle, string&lt;br /&gt;			strText, uint uintTimeout)&lt;br /&gt;		{&lt;br /&gt;			try&lt;br /&gt;			{&lt;br /&gt;				bool blnVersionOk = false;&lt;br /&gt;				blnVersionOk = this.GetShell32VersionInfo() &gt;= 5;&lt;br /&gt;				if(blnVersionOk)&lt;br /&gt;				{&lt;br /&gt;					// get the current thread ID&lt;br /&gt;					uint uintThreadId = GetCurrentThreadId();&lt;br /&gt;&lt;br /&gt;					Type objType= ni.GetType();&lt;br /&gt;&lt;br /&gt;					IntPtr intPtrWindow =&lt;br /&gt;						((NativeWindow)objType.GetField("window",System.Reflection.BindingFlags.Instance&lt;br /&gt;						|&lt;br /&gt;						System.Reflection.BindingFlags.NonPublic).GetValue(ni)).Handle;&lt;br /&gt;					int intID&lt;br /&gt;						=(int)objType.GetField("id",System.Reflection.BindingFlags.Instance |&lt;br /&gt;						System.Reflection.BindingFlags.NonPublic).GetValue(ni);&lt;br /&gt;&lt;br /&gt;					// show the balloon&lt;br /&gt;					NotifyIconData objData = new NotifyIconData();&lt;br /&gt;					objData.cbSize =&lt;br /&gt;						(System.UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(NotifyIconData));&lt;br /&gt;					objData.hWnd = intPtrWindow;&lt;br /&gt;					objData.uID = (UInt32)intID;&lt;br /&gt;					objData.uFlags = NotifyFlags.Info;&lt;br /&gt;					//objData.uTimeoutOrVersion =uintTimeout;&lt;br /&gt;					objData.uTimeoutOrVersion =NOTIFYICON_VERSION ;&lt;br /&gt;					objData.szInfo = strText;&lt;br /&gt;					objData.szInfoTitle = strTitle;&lt;br /&gt;					int q=Shell_NotifyIcon(NotifyCommand.SetVersion,ref objData);&lt;br /&gt;					int k=Shell_NotifyIcon(NotifyCommand.Modify, ref objData);&lt;br /&gt;					//MessageBox.Show(q.ToString()+k.ToString());&lt;br /&gt;				}&lt;br /&gt;			}&lt;br /&gt;			catch(Exception objException)&lt;br /&gt;			{&lt;br /&gt;				throw new ApplicationException(objException.Message);&lt;br /&gt;			}&lt;br /&gt;		}&lt;br /&gt;&lt;br /&gt;Then when required, you simply use the ShowBalloon(uint IconId, string BalloonTitle, string BalloonText, unit Timeout)&lt;br /&gt;and the balloon will pop up next to the NotifyIcon.&lt;br /&gt;This is where I found the original code:&lt;br /&gt;http://www.hightechtalks.com/archive/index.php/t-2217576-notify-icon-n-balloon-tip-help-urgent.html&lt;br /&gt;&lt;br /&gt;No guarantees on robustness!! it's not even my code(which is probably a good thing...), but it seems to work, and as it is only a tool running on my own computer, it's good enough for me!&lt;br /&gt;&lt;br /&gt;Cheers! &lt;br /&gt;&lt;br /&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113525371165490556?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113525371165490556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113525371165490556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113525371165490556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113525371165490556'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/system-tray-icons-and-balloon-popups.html' title='System Tray Icons and Balloon Popups'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113510118412776442</id><published>2005-12-20T09:52:00.000-08:00</published><updated>2005-12-20T09:53:04.146-08:00</updated><title type='text'>Using Winzip from the command line</title><content type='html'>Below is some information about the undocumented command line options for using the WinZip program module, winzip32.exe.&lt;br /&gt;&lt;br /&gt;WinZip supports command line options to add and extract from files. Be sure to read the Notes section below for additional important information.&lt;br /&gt;&lt;br /&gt;Adding Files&lt;br /&gt;The command format is:&lt;br /&gt;&lt;br /&gt;winzip32 [-min] action [options] filename[.zip] files&lt;br /&gt;&lt;br /&gt;where:&lt;br /&gt;-min specifies that WinZip should run minimized. If -min is specified, it must be the first command line parameter.&lt;br /&gt;&lt;br /&gt;action&lt;br /&gt;-a for add, -f for freshen, -u for update, and -m for move. You must specify one (and only one) of these actions. The actions correspond to the actions described in the section titled "Add dialog box options" in the online manual.&lt;br /&gt;&lt;br /&gt;options&lt;br /&gt;-r corresponds to the Include subfolders checkbox in the Add dialog and causes WinZip to add files from subfolders. Folder information is stored for files added from subfolders. If you add -p, WinZip will store folder information for all files added, not just for files from subfolders; the folder information will begin with the folder specified on the command line.&lt;br /&gt;&lt;br /&gt;-ex, -en, -ef, -es, and -e0 determine the compression method: eXtra, Normal, Fast, Super fast, and no compression. The default is "Normal". -hs includes hidden and system files. Use -sPassword to specify a case-sensitive password. The password can be enclosed in quotes, for example, -s"Secret Password".&lt;br /&gt;&lt;br /&gt;filename.zip&lt;br /&gt;Specifies the name of the Zip file involved. Be sure to use the full filename (including the folder).&lt;br /&gt;&lt;br /&gt;files&lt;br /&gt;Is a list of one or more files, or the @ character followed by the filename containing a list of files to add, one filename per line. Wildcards (e.g. *.bak) are allowed.&lt;br /&gt;&lt;br /&gt;Extracting Files&lt;br /&gt;The command format is:&lt;br /&gt;&lt;br /&gt;winzip32 -e [options] filename[.zip] folder&lt;br /&gt;where -e is required.&lt;br /&gt;options&lt;br /&gt;-o and -j stand for "Overwrite existing files without prompting" and "Junk pathnames", respectively. Unless -j is specified, folder information is used. Use -sPassword to specify a case-sensitive password. The password can be enclosed in quotes, for example, -s"Secret Password".&lt;br /&gt;&lt;br /&gt;filename.zip&lt;br /&gt;Specifies the name of the Zip file involved. Be sure to specify the full filename (including the folder).&lt;br /&gt;&lt;br /&gt;folder&lt;br /&gt;Is the name of the folder to which the files are extracted. If the folder does not exist it is created.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notes&lt;br /&gt;VERY IMPORTANT: always specify complete filenames, including the full folder name and drive letter, for all file IDs.&lt;br /&gt;&lt;br /&gt;To run WinZip in a minimized inactive icon use the "-min" option. When specified this option must be the first option.&lt;br /&gt;&lt;br /&gt;Only operations involving the built-in zip and unzip are supported.&lt;br /&gt;&lt;br /&gt;Enclose long filenames in quotes.&lt;br /&gt;&lt;br /&gt;When using a list ("@") file, no leading or trailing spaces should appear in file IDs in the list.&lt;br /&gt;&lt;br /&gt;The action and each option must be separated by at least one space.&lt;br /&gt;&lt;br /&gt;WinZip can be used to compress files with cc:Mail . Change the compress= line in the [cc:Mail] section of the appropriate WMAIL.INI files to specify the full path for WinZip followed by "-a %1 @%2". For example, if WinZip is installed in your c:\winzip folder, specify&lt;br /&gt;compress=c:\winzip\winzip.exe -a %1 @%2&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113510118412776442?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113510118412776442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113510118412776442' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113510118412776442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113510118412776442'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/using-winzip-from-command-line.html' title='Using Winzip from the command line'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113464944601110311</id><published>2005-12-15T04:24:00.000-08:00</published><updated>2005-12-15T04:24:06.250-08:00</updated><title type='text'>Syntax Errors in SQL - Check for Reserved Words</title><content type='html'>After spending the best part of an hour trying to workout what was wrong with my query... when trying to update the dataset, I kept getting a 'Syntax Error' message.&lt;br /&gt;Turns out one of the fields in my table was 'Password' which of course is a reserved word... Doh!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113464944601110311?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113464944601110311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113464944601110311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113464944601110311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113464944601110311'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/syntax-errors-in-sql-check-for.html' title='Syntax Errors in SQL - Check for Reserved Words'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113463992431461140</id><published>2005-12-15T01:45:00.000-08:00</published><updated>2005-12-15T01:45:24.943-08:00</updated><title type='text'>Dot Net Encryption</title><content type='html'>Looking for a safer way to store some passwords in the database than just using plain text, I came across this class which makes use to the built in DotNet Cryptography classes. &lt;br /&gt;&lt;br /&gt;using System; &lt;br /&gt;using System.IO; &lt;br /&gt;using System.Security.Cryptography;&lt;br /&gt;&lt;br /&gt;namespace APTS&lt;br /&gt;{&lt;br /&gt;	/// &lt;summary&gt;&lt;br /&gt;	/// Summary description for EncDec.&lt;br /&gt;	/// &lt;/summary&gt;&lt;br /&gt;public class EncDec &lt;br /&gt;{&lt;br /&gt;    // Encrypt a byte array into a byte array using a key and an IV &lt;br /&gt;    public static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV) &lt;br /&gt;    { &lt;br /&gt;        // Create a MemoryStream to accept the encrypted bytes &lt;br /&gt;        MemoryStream ms = new MemoryStream(); &lt;br /&gt;&lt;br /&gt;        // Create a symmetric algorithm. &lt;br /&gt;        // We are going to use Rijndael because it is strong and&lt;br /&gt;        // available on all platforms. &lt;br /&gt;        // You can use other algorithms, to do so substitute the&lt;br /&gt;        // next line with something like &lt;br /&gt;        //      TripleDES alg = TripleDES.Create(); &lt;br /&gt;        Rijndael alg = Rijndael.Create(); &lt;br /&gt;&lt;br /&gt;        // Now set the key and the IV. &lt;br /&gt;        // We need the IV (Initialization Vector) because&lt;br /&gt;        // the algorithm is operating in its default &lt;br /&gt;        // mode called CBC (Cipher Block Chaining).&lt;br /&gt;        // The IV is XORed with the first block (8 byte) &lt;br /&gt;        // of the data before it is encrypted, and then each&lt;br /&gt;        // encrypted block is XORed with the &lt;br /&gt;        // following block of plaintext.&lt;br /&gt;        // This is done to make encryption more secure. &lt;br /&gt;&lt;br /&gt;        // There is also a mode called ECB which does not need an IV,&lt;br /&gt;        // but it is much less secure. &lt;br /&gt;        alg.Key = Key; &lt;br /&gt;        alg.IV = IV; &lt;br /&gt;&lt;br /&gt;        // Create a CryptoStream through which we are going to be&lt;br /&gt;        // pumping our data. &lt;br /&gt;        // CryptoStreamMode.Write means that we are going to be&lt;br /&gt;        // writing data to the stream and the output will be written&lt;br /&gt;        // in the MemoryStream we have provided. &lt;br /&gt;        CryptoStream cs = new CryptoStream(ms, &lt;br /&gt;           alg.CreateEncryptor(), CryptoStreamMode.Write); &lt;br /&gt;&lt;br /&gt;        // Write the data and make it do the encryption &lt;br /&gt;        cs.Write(clearData, 0, clearData.Length); &lt;br /&gt;&lt;br /&gt;        // Close the crypto stream (or do FlushFinalBlock). &lt;br /&gt;        // This will tell it that we have done our encryption and&lt;br /&gt;        // there is no more data coming in, &lt;br /&gt;        // and it is now a good time to apply the padding and&lt;br /&gt;        // finalize the encryption process. &lt;br /&gt;        cs.Close(); &lt;br /&gt;&lt;br /&gt;        // Now get the encrypted data from the MemoryStream.&lt;br /&gt;        // Some people make a mistake of using GetBuffer() here,&lt;br /&gt;        // which is not the right way. &lt;br /&gt;        byte[] encryptedData = ms.ToArray();&lt;br /&gt;&lt;br /&gt;        return encryptedData; &lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;    // Encrypt a string into a string using a password &lt;br /&gt;    //    Uses Encrypt(byte[], byte[], byte[]) &lt;br /&gt;&lt;br /&gt;    public static string Encrypt(string clearText, string Password) &lt;br /&gt;    { &lt;br /&gt;        // First we need to turn the input string into a byte array. &lt;br /&gt;        byte[] clearBytes = &lt;br /&gt;          System.Text.Encoding.Unicode.GetBytes(clearText); &lt;br /&gt;&lt;br /&gt;        // Then, we need to turn the password into Key and IV &lt;br /&gt;        // We are using salt to make it harder to guess our key&lt;br /&gt;        // using a dictionary attack - &lt;br /&gt;        // trying to guess a password by enumerating all possible words. &lt;br /&gt;        PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, &lt;br /&gt;            new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, &lt;br /&gt;            0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); &lt;br /&gt;&lt;br /&gt;        // Now get the key/IV and do the encryption using the&lt;br /&gt;        // function that accepts byte arrays. &lt;br /&gt;        // Using PasswordDeriveBytes object we are first getting&lt;br /&gt;        // 32 bytes for the Key &lt;br /&gt;        // (the default Rijndael key length is 256bit = 32bytes)&lt;br /&gt;        // and then 16 bytes for the IV. &lt;br /&gt;        // IV should always be the block size, which is by default&lt;br /&gt;        // 16 bytes (128 bit) for Rijndael. &lt;br /&gt;        // If you are using DES/TripleDES/RC2 the block size is&lt;br /&gt;        // 8 bytes and so should be the IV size. &lt;br /&gt;        // You can also read KeySize/BlockSize properties off&lt;br /&gt;        // the algorithm to find out the sizes. &lt;br /&gt;        byte[] encryptedData = Encrypt(clearBytes, &lt;br /&gt;                 pdb.GetBytes(32), pdb.GetBytes(16)); &lt;br /&gt;&lt;br /&gt;        // Now we need to turn the resulting byte array into a string. &lt;br /&gt;        // A common mistake would be to use an Encoding class for that.&lt;br /&gt;        //It does not work because not all byte values can be&lt;br /&gt;        // represented by characters. &lt;br /&gt;        // We are going to be using Base64 encoding that is designed&lt;br /&gt;        //exactly for what we are trying to do. &lt;br /&gt;        return Convert.ToBase64String(encryptedData); &lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    // Encrypt bytes into bytes using a password &lt;br /&gt;    //    Uses Encrypt(byte[], byte[], byte[]) &lt;br /&gt;&lt;br /&gt;    public static byte[] Encrypt(byte[] clearData, string Password) &lt;br /&gt;    { &lt;br /&gt;        // We need to turn the password into Key and IV. &lt;br /&gt;        // We are using salt to make it harder to guess our key&lt;br /&gt;        // using a dictionary attack - &lt;br /&gt;        // trying to guess a password by enumerating all possible words. &lt;br /&gt;        PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, &lt;br /&gt;            new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, &lt;br /&gt;            0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); &lt;br /&gt;&lt;br /&gt;        // Now get the key/IV and do the encryption using the function&lt;br /&gt;        // that accepts byte arrays. &lt;br /&gt;        // Using PasswordDeriveBytes object we are first getting&lt;br /&gt;        // 32 bytes for the Key &lt;br /&gt;        // (the default Rijndael key length is 256bit = 32bytes)&lt;br /&gt;        // and then 16 bytes for the IV. &lt;br /&gt;        // IV should always be the block size, which is by default&lt;br /&gt;        // 16 bytes (128 bit) for Rijndael. &lt;br /&gt;        // If you are using DES/TripleDES/RC2 the block size is 8&lt;br /&gt;        // bytes and so should be the IV size. &lt;br /&gt;        // You can also read KeySize/BlockSize properties off the&lt;br /&gt;        // algorithm to find out the sizes. &lt;br /&gt;        return Encrypt(clearData, pdb.GetBytes(32), pdb.GetBytes(16)); &lt;br /&gt;&lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;    // Decrypt a byte array into a byte array using a key and an IV &lt;br /&gt;    public static byte[] Decrypt(byte[] cipherData, &lt;br /&gt;                                byte[] Key, byte[] IV) &lt;br /&gt;    { &lt;br /&gt;        // Create a MemoryStream that is going to accept the&lt;br /&gt;        // decrypted bytes &lt;br /&gt;        MemoryStream ms = new MemoryStream(); &lt;br /&gt;&lt;br /&gt;        // Create a symmetric algorithm. &lt;br /&gt;        // We are going to use Rijndael because it is strong and&lt;br /&gt;        // available on all platforms. &lt;br /&gt;        // You can use other algorithms, to do so substitute the next&lt;br /&gt;        // line with something like &lt;br /&gt;        //     TripleDES alg = TripleDES.Create(); &lt;br /&gt;        Rijndael alg = Rijndael.Create(); &lt;br /&gt;&lt;br /&gt;        // Now set the key and the IV. &lt;br /&gt;        // We need the IV (Initialization Vector) because the algorithm&lt;br /&gt;        // is operating in its default &lt;br /&gt;        // mode called CBC (Cipher Block Chaining). The IV is XORed with&lt;br /&gt;        // the first block (8 byte) &lt;br /&gt;        // of the data after it is decrypted, and then each decrypted&lt;br /&gt;        // block is XORed with the previous &lt;br /&gt;        // cipher block. This is done to make encryption more secure. &lt;br /&gt;        // There is also a mode called ECB which does not need an IV,&lt;br /&gt;        // but it is much less secure. &lt;br /&gt;        alg.Key = Key; &lt;br /&gt;        alg.IV = IV; &lt;br /&gt;&lt;br /&gt;        // Create a CryptoStream through which we are going to be&lt;br /&gt;        // pumping our data. &lt;br /&gt;        // CryptoStreamMode.Write means that we are going to be&lt;br /&gt;        // writing data to the stream &lt;br /&gt;        // and the output will be written in the MemoryStream&lt;br /&gt;        // we have provided. &lt;br /&gt;        CryptoStream cs = new CryptoStream(ms, &lt;br /&gt;            alg.CreateDecryptor(), CryptoStreamMode.Write); &lt;br /&gt;&lt;br /&gt;        // Write the data and make it do the decryption &lt;br /&gt;        cs.Write(cipherData, 0, cipherData.Length); &lt;br /&gt;&lt;br /&gt;        // Close the crypto stream (or do FlushFinalBlock). &lt;br /&gt;        // This will tell it that we have done our decryption&lt;br /&gt;        // and there is no more data coming in, &lt;br /&gt;        // and it is now a good time to remove the padding&lt;br /&gt;        // and finalize the decryption process. &lt;br /&gt;        cs.Close(); &lt;br /&gt;&lt;br /&gt;        // Now get the decrypted data from the MemoryStream. &lt;br /&gt;        // Some people make a mistake of using GetBuffer() here,&lt;br /&gt;        // which is not the right way. &lt;br /&gt;        byte[] decryptedData = ms.ToArray(); &lt;br /&gt;&lt;br /&gt;        return decryptedData; &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Decrypt a string into a string using a password &lt;br /&gt;    //    Uses Decrypt(byte[], byte[], byte[]) &lt;br /&gt;&lt;br /&gt;    public static string Decrypt(string cipherText, string Password) &lt;br /&gt;    { &lt;br /&gt;        // First we need to turn the input string into a byte array. &lt;br /&gt;        // We presume that Base64 encoding was used &lt;br /&gt;        byte[] cipherBytes = Convert.FromBase64String(cipherText); &lt;br /&gt;&lt;br /&gt;        // Then, we need to turn the password into Key and IV &lt;br /&gt;        // We are using salt to make it harder to guess our key&lt;br /&gt;        // using a dictionary attack - &lt;br /&gt;        // trying to guess a password by enumerating all possible words. &lt;br /&gt;        PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, &lt;br /&gt;            new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, &lt;br /&gt;            0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); &lt;br /&gt;&lt;br /&gt;        // Now get the key/IV and do the decryption using&lt;br /&gt;        // the function that accepts byte arrays. &lt;br /&gt;        // Using PasswordDeriveBytes object we are first&lt;br /&gt;        // getting 32 bytes for the Key &lt;br /&gt;        // (the default Rijndael key length is 256bit = 32bytes)&lt;br /&gt;        // and then 16 bytes for the IV. &lt;br /&gt;        // IV should always be the block size, which is by&lt;br /&gt;        // default 16 bytes (128 bit) for Rijndael. &lt;br /&gt;        // If you are using DES/TripleDES/RC2 the block size is&lt;br /&gt;        // 8 bytes and so should be the IV size. &lt;br /&gt;        // You can also read KeySize/BlockSize properties off&lt;br /&gt;        // the algorithm to find out the sizes. &lt;br /&gt;        byte[] decryptedData = Decrypt(cipherBytes, &lt;br /&gt;            pdb.GetBytes(32), pdb.GetBytes(16)); &lt;br /&gt;&lt;br /&gt;        // Now we need to turn the resulting byte array into a string. &lt;br /&gt;        // A common mistake would be to use an Encoding class for that.&lt;br /&gt;        // It does not work &lt;br /&gt;        // because not all byte values can be represented by characters. &lt;br /&gt;        // We are going to be using Base64 encoding that is &lt;br /&gt;        // designed exactly for what we are trying to do. &lt;br /&gt;        return System.Text.Encoding.Unicode.GetString(decryptedData); &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Decrypt bytes into bytes using a password &lt;br /&gt;    //    Uses Decrypt(byte[], byte[], byte[]) &lt;br /&gt;&lt;br /&gt;	public static byte[] Decrypt(byte[] cipherData, string Password) &lt;br /&gt;	{ &lt;br /&gt;		// We need to turn the password into Key and IV. &lt;br /&gt;		// We are using salt to make it harder to guess our key&lt;br /&gt;		// using a dictionary attack - &lt;br /&gt;		// trying to guess a password by enumerating all possible words. &lt;br /&gt;		PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, &lt;br /&gt;			new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, &lt;br /&gt;						   0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76}); &lt;br /&gt;&lt;br /&gt;		// Now get the key/IV and do the Decryption using the &lt;br /&gt;		//function that accepts byte arrays. &lt;br /&gt;		// Using PasswordDeriveBytes object we are first getting&lt;br /&gt;		// 32 bytes for the Key &lt;br /&gt;		// (the default Rijndael key length is 256bit = 32bytes)&lt;br /&gt;		// and then 16 bytes for the IV. &lt;br /&gt;		// IV should always be the block size, which is by default&lt;br /&gt;		// 16 bytes (128 bit) for Rijndael. &lt;br /&gt;		// If you are using DES/TripleDES/RC2 the block size is&lt;br /&gt;		// 8 bytes and so should be the IV size. &lt;br /&gt;&lt;br /&gt;		// You can also read KeySize/BlockSize properties off the&lt;br /&gt;		// algorithm to find out the sizes. &lt;br /&gt;		return Decrypt(cipherData, pdb.GetBytes(32), pdb.GetBytes(16)); &lt;br /&gt;	}&lt;br /&gt; }&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113463992431461140?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113463992431461140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113463992431461140' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113463992431461140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113463992431461140'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/dot-net-encryption.html' title='Dot Net Encryption'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113448207389544306</id><published>2005-12-13T05:54:00.000-08:00</published><updated>2005-12-13T05:54:33.900-08:00</updated><title type='text'>Changing the clock/info bulbs in Vauxhall Astra</title><content type='html'>Came across this while looking for somthing totally different. But I may well need to do this sometime, so might as well remember it...&lt;br /&gt;&lt;br /&gt;To replace your info display bulb just lift out the rubber mat below it and undo the screws. It will now pull forward and out. Two second job,replace both bulbs in it. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113448207389544306?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113448207389544306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113448207389544306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113448207389544306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113448207389544306'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/changing-clockinfo-bulbs-in-vauxhall.html' title='Changing the clock/info bulbs in Vauxhall Astra'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113414320529943653</id><published>2005-12-09T07:18:00.000-08:00</published><updated>2005-12-09T07:48:19.053-08:00</updated><title type='text'>Two State WinForm</title><content type='html'>OK, so I wanted a form that would let you fill in the upper half of the form (say a Booking in ref and some header details) then when TAB or ENTER is pressed in the last field of the header items, switch to the lower half to allow entry of all items in that batch.&lt;br /&gt;&lt;br /&gt;Need:&lt;br /&gt;integer to contain current state of the form (0 or 1 in this case, so could be a bool, but may want a third or more state in the future, so int makes more sense (I think))&lt;br /&gt;&lt;br /&gt;A private property on the form (formState) and a simple Method is used to select the state that is required, then call the Method to make that state 'active':&lt;br /&gt;&lt;br /&gt;private void SetFormState(int newState)&lt;br /&gt;{&lt;br /&gt;if (newState == formState)&lt;br /&gt;return;&lt;br /&gt;if (formState == 0)&lt;br /&gt;formState = 1;&lt;br /&gt;else&lt;br /&gt;formState = 0;&lt;br /&gt;DoFormState();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The main difference between states is which controls on the form are active. This is handled by a simple Switch like this:&lt;br /&gt;&lt;br /&gt;private void DoFormState()&lt;br /&gt;{&lt;br /&gt;switch(formState)&lt;br /&gt;{&lt;br /&gt;case 0:&lt;br /&gt;{&lt;br /&gt;txtBatchId.Enabled = true;&lt;br /&gt;dteBookedDate.Enabled = true;&lt;br /&gt;txtLinePrice.Enabled = false;&lt;br /&gt;txtLinePrice.Text = "";&lt;br /&gt;txtLineQty.Enabled = false;&lt;br /&gt;txtLineQty.Text = "";&lt;br /&gt;txtPartNumber.Enabled = false;&lt;br /&gt;txtPartNumber.Text = "";&lt;br /&gt;cmdAddToBatch.Enabled = false;&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;case 1:&lt;br /&gt;{&lt;br /&gt;txtPartNumber.Enabled = true;&lt;br /&gt;txtLineQty.Enabled = true;&lt;br /&gt;txtLinePrice.Enabled = true;&lt;br /&gt;cmdAddToBatch.Enabled = true;&lt;br /&gt;dteBookedDate.Enabled = false;&lt;br /&gt;txtPartNumber.Enabled = true;&lt;br /&gt;txtBatchId.Enabled = false;&lt;br /&gt;dteBookedDate.Enabled = false;&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;To detect when to switch to the second state, initially, just trapped OnLeave event of BookingInRef textbox, but that isn't really good enough as if you mouse-click out of the box or do a Shift-TAB (most likely going back to change an earlier box in the upper-header screen), you may not want to switch states when you leave the BookingInRef box..&lt;br /&gt;&lt;br /&gt;Next looked at KeyUp/KeyDown events, but no good as TAB key doesn't show up here, or if it does, the Form has already used it to move to the next control on the form.&lt;br /&gt;&lt;br /&gt;Finaly result seemed to be to override ProcessDialogKey event on the form thus:&lt;br /&gt;&lt;br /&gt;protected override bool ProcessDialogKey(Keys keyData)&lt;br /&gt;{&lt;br /&gt;if (keyData == Keys.Tab &amp;&amp; keyData !=Keys.Shift)&lt;br /&gt;{&lt;br /&gt;if (this.ActiveControl.Name == "txtBatchId")&lt;br /&gt;{&lt;br /&gt;SetFormState(1);&lt;br /&gt;return true;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return base.ProcessDialogKey(keyData);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;So if a TAB key is pressed and the SHIFT key is not down and the focus is on the BookingIn reference textbox then we switch the form into the other state. Otherwise we process the DialogKey as normal.&lt;br /&gt;&lt;br /&gt;To catch ENTER which was also required to switch states is far simpler. I caught the KeyDown event in the TextBox thus:&lt;br /&gt; &lt;br /&gt;  private void txtBatchId_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)&lt;br /&gt;  {&lt;br /&gt;   if (e.KeyCode == Keys.Enter)&lt;br /&gt;    SetFormState(1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;Finally to finish off, I caught the ESCAPE key on the form and either moved back to the previous state, or if already in the initial state, leave the form:&lt;br /&gt;&lt;br /&gt;  private void frmBatchCommercial_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)&lt;br /&gt;  {&lt;br /&gt;   if (e.KeyCode == Keys.Escape)&lt;br /&gt;   {&lt;br /&gt;    if (formState == 1)&lt;br /&gt;     SetFormState(0);&lt;br /&gt;    else&lt;br /&gt;     this.Close();&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;NOTE: For that to work, needed to set KeyPreview property of Form to True so that it gets a go at any keys pressed before the controls on the form.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113414320529943653?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113414320529943653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113414320529943653' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113414320529943653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113414320529943653'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/12/two-state-winform.html' title='Two State WinForm'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113292782588537591</id><published>2005-11-25T06:10:00.000-08:00</published><updated>2005-11-25T06:29:13.753-08:00</updated><title type='text'>Mobile Blog</title><content type='html'>Posted an entry from my mobile... This is clever :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113292782588537591?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113292782588537591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113292782588537591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292782588537591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292782588537591'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/11/mobile-blog.html' title='Mobile Blog'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113292699580166509</id><published>2005-11-25T05:56:00.000-08:00</published><updated>2005-11-25T06:00:02.996-08:00</updated><title type='text'>From email</title><content type='html'>Added a post from my email&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113292699580166509?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113292699580166509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113292699580166509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292699580166509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292699580166509'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/11/from-email.html' title='From email'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-19301474.post-113292438890423686</id><published>2005-11-25T05:11:00.000-08:00</published><updated>2005-12-09T07:51:51.416-08:00</updated><title type='text'>Well here we are then</title><content type='html'>This is the first posting in my new Blog. No idea quite what I'm going to put here, but might be a good place to jot this and that from time to time...&lt;br /&gt;At the moment, I intend to use it kind of like a notepad to make a note of stuff I find out.&lt;br /&gt;&lt;br /&gt;Not sure how often I will post stuff here. If it's anything like my diaries when I was younger, probably not very often... ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/19301474-113292438890423686?l=chrismayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chrismayers.blogspot.com/feeds/113292438890423686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=19301474&amp;postID=113292438890423686' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292438890423686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/19301474/posts/default/113292438890423686'/><link rel='alternate' type='text/html' href='http://chrismayers.blogspot.com/2005/11/well-here-we-are-then.html' title='Well here we are then'/><author><name>Chris Mayers</name><uri>http://www.blogger.com/profile/13261051823007548097</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
