C# WinFroms Splash Screen

One fo the first challenges I faced as a C# developer writing windows forms applications was the concept of a splash screen with a progress bar. While in principle it seemed simple, opening a different form in a separate thread and making its controls updatable from the first thread was alien to me.

I decided to (finally) write this post after seeing a lot of requests for help around this subject on various forums. The main thing new developers struggle with when attempting their very first splash screen are delegates.

To start with, either create a blank Windows Forms Application in Visual Studio or follow the steps below in the project you are adding a splash screen to. If you are creating a new project, you will find Form1.cs, which we will leave as is for this tutorial. Imagine that Form1 is going to be the main window of your application.

Now go and add a new Windows Form to your project and call is SplashScreen.cs. Add a Progress Bar control to your new form and resize the form around it. Now change the FormBorderStyle property for the form to None and StartPosition to CenterScreen. I’ve also changed the BAckColor property to red to make it a bit more visible for this tutorial.


Now head into the code view for SplashScreen.cs (right click it in the solution explorer windows and click View Code).

The code for the splash screen is reasonably straight forward if you know how delegates and threads work. Check out the comments for some information on what each section does.

using System;
using System.Threading;
using System.Windows.Forms;

namespace SplashScreenTutorial
public partial class SplashScreen : Form
//The delegates required to invoke methods from a different thread
private delegate void CloseDelegate();
private delegate void UpdateDelegate(string txt);

private SplashScreen _splashInstance;

//The initializer for the SplashScreen Class
public SplashScreen(int max)
progressBar1.Minimum = 0;
progressBar1.Maximum = max;

//Private method used to display the splash creen form.
private void ShowForm(object max)
_splashInstance = new SplashScreen(Convert.ToInt32(max));

//Public method that spawns a new thread and calls the ShowForm() method to lauch the splash screen in the new thread.
public void ShowSplashScreen(int max)
if (_splashInstance != null)
Thread thread = new Thread(ShowForm);
thread.IsBackground = true;

//Public bool to check if the splash screen is ready.
public bool Ready()
return (_splashInstance != null) && (_splashInstance.Created);

//Public method used to update the progress bar progress and text from your main application thread.
public void UpdateProgress(string txt)
_splashInstance.Invoke(new UpdateDelegate(UpdateProgressInternal), txt);


//Public method used to close the splash screen from your main application thread.
public void CloseForm()
_splashInstance.Invoke(new CloseDelegate(CloseFormInternal));

//The private method invoked by the delegate to update the progress bar.
private void UpdateProgressInternal(string txt)
_splashInstance.progressBar1.Text = txt;

//The private method invoked by the delegate to close the splash screen.
private void CloseFormInternal()


Next you need to add a bit of code to your Program.cs file to call the splash screen and update it between each task during your application startup process. Make sure it goes before Application.Run(Form1).

static void Main()

//Instantiate a new instance of SplashScreen
SplashScreen splash = new SplashScreen(4);
//Display the splash screen with a max value for the progress bar

//Wait for the form to be loaded.
while (!splash.Ready())
//Loop to wait for the splash screen to be ready before trying to
update it. We will get a null reference exception if the splash screen isn't ready yet.

//Update the progress bar
splash.UpdateProgress("Loading Step 1");
//Perform action
Thread.Sleep(1000); //Lets pretend this is doing something constructive
//Update the progress bar
splash.UpdateProgress("Loading Step 2");
//Perform action
Thread.Sleep(1000); //Lets pretend this is doing something constructive
//Update the progress bar
splash.UpdateProgress("Loading Step 3");
//Perform action
Thread.Sleep(1000); //Lets pretend this is doing something constructive
//Update the progress bar
splash.UpdateProgress("Loading Step 4");
//Perform action
Thread.Sleep(1000); //Lets pretend this is doing something constructive
//Close the Splash Screen

//Launch your main application form
Application.Run(new Form1());

That’s all there is to it. I’m not going to go into a load of detail about threads and delegates in this post. To be honest it’s mainly because I can’t be bothered because both subjects are tedious and boring.

And for all those who are still reading, the example project is available here for download.

Controlling the Startech VS421HDPIP with C#

As part of a project I have been working on to spec and install a video conferencing solution I purchased a couple of Startech VS421HDPIP units to switch between camera inputs. I chose this unit for a couple of reasons; it has enough inputs for the project, it’s capable of doing picture in picture, it can be controlled via telnet or RS232, our supplier could get it for half the RRP and it’s made by Startech, who’s kit has never left us in an awkward situation.

When I first hooked it up it just worked and the presets that were built-in were decent. Unfortunately it didn’t have presets to support the use cases I required, but I expected that from reading the manual prior to purchasing them. The presets can be changed from the web interface, which is the only downside to this unit… its utter pants. Fortunately it supports some pretty advanced commands via telnet so all is not lost. After playing with the telnet prompt for a while I figured that I could probably write some form of application to change the video output layout from a PC, which would certainly make it more user-friendly. The VC solution is going to be installed in a remote office and anything to make operation easier for the end users is a big plus. This will also allow me to have basically unlimited “presets” to cover more use cases without reconfiguration. Bonus.


I decided that the application should probably allow control of the PTZ cameras too to encompass the entire VC solution in one control panel, so a simple “driver” style API would be the best bet for controlling each component. The driver for the Startech VS421HDPIP only took two hours to write, including an application to test the class, and is incredibly simple to use. It is available to download at the end of this post. Here’s an example of how to use it.

//create a new instance of the VS421HDPIP class.
VS421HDPIP Conn = new VS421HDPIP();

//set the unit IP address and port
Conn.Ip = IPAddress.Parse(“”;
Conn.Port = 23;

//open the connection to the unit.

//execute commands. See list of commands in the accompanying blog post.
Conn.PowerOn();  //Power on the unit from standby
Conn.Recall(VS421HDPIP.WindowState.Fav1);  //Recall the Fav.1 Preset
Conn.SetImagePosition(VS421HDPIP.InputChannel.Input2, 1420, 790); //Sets the possition of channel 2.

//always close the connection when done. The unit only allows one session at a time and not closing a session will result in you having to reboot the unit or waiting for the session timeout on the unit before opening a new connection.

Unfortunately the telnet prompt doesn’t let you retrieve information. Maybe this is something Startech will add to future models but it is what it is.


The commands I implemented are basically identical to the commands listed in the manual for the VS421HDPIP. I won’t go over available parameters for each here. The parameters are similar to those listed in the manual as well so I’m sure they’d be easy to figure out with intellisense.

  • PowerOn() – Power on the unit from standby.
  • PowerOff() – Place the unit in standby.
  • SetOutResolution(Resolution res) – Sets the output resolution.
  • OsdDisable() – Disable the On Screen Display.
  • OsdEnable() – Enable the On Screen Display.
  • OsdHOffset(int offset) – Sets the horizontal offset of the OSD.
  • OsdVOffset(int offset) – Sets the verticle offset of the OSD.
  • OsdTimeout(int timeout) – Sets the timeout of the OSD.
  • OsdGain(int gain) – Sets the gain of the OSD.
  • SetBrightness(InputChannel chan, int level) – Sets the brightness level of an input.
  • SetContrast(InputChannel chan, int level) – Sets the contrast level of an input.
  • SetSaturation(InputChannel chan, int level) – Sets the saturation level of an input.
  • SetHue(InputChannel chan, int level) – Set the hue level of an input.
  • Mute() – Mutes the audio output of the unit.
  • Unmute() – Unmutes the audio output of the unit.
  • SetImageSize(InputChannel chan, int h, int v) – Sets the size of a channel.
  • SetImagePosition(InputChannel chan, int h, int v) – Sets the position of a channel.
  • ChannelImageOn(InputChannel chan) – Turns a channel on.
  • ChannelImageOff(InputChannel chan) – Turns a channel off.
  • ChannelPriority(InputChannel chan, int priority) – Sets a channel’s priority.
  • SetChannelLabel(InputChannel chan, string label) – Sets a channel’s label.
  • StoreCurrentConfiguration(Favorite loc) – Stores current settings to a preset.
  • MirrorOn() – Makes the unit mirror it’s output (rear projection).
  • MirrorOff() – Disables the output mirror feature.
  • SetOutputRotation(Rotation value) – Rotate unit output (ceiling hung projector).
  • SetFadeDuration(Fadetime time) – Sets fadetime between windows.
  • SendTelnetCommand(string command) – Send a telnet command to the unit.


I have provided the driver I wrote in case it is useful to anybody. I do so with absolutely no warranty or support and you use it at your own risk.

Compiled DLL
Visual Studio Project Files

Writing a Book: Characters

A few months ago I started writing my first ever book. So far the experience has been both enjoyable and exciting, but one element of book writing is harder for me than the rest: Keeping track of characters. I have problems remembering stuff and fictional stuff is even harder to remember, which is why I’m a terrible liar.

To help keep track of characters as the book progresses I came up with a “template” character profile. The template contains the information on a single character, which I copy to a separate note in the MacOS notes app for each character and password protect to save them from prying eyes. So far this system has worked well for me, but I imagine it would fall on its face if I wasn’t continuously updating each note as the book progresses.

I thought I would share the template I use to profile each character in case anybody else finds it useful. So here it is.

  • Name – An obvious one really…
  • Age – Again pretty obvious
  • Description – A description of a character is helpful, for example, homeless man or police officer.
  • Aliases – Characters aren’t always known by their full name. Bill instead of William for example.
  • Physical Appearance – I find it helpful to help visualisation of the characters I’m writing about to jot down what they look like. Hair style and colour, height, eye colour, build, etc.
  • Skills – Handy for reminding me of which character might be able to pick a lock, or cook beans.
  • Relationships – The relationships a character has to other characters is a valuable piece of information to know, even if the relationship isn’t mentioned once in the book. Knowing that two brothers had the same upbringing might help build in common traits.
  • Book Appearances – A list of chapters that the character appears in within the book is helpful for referencing back to previous chapters.
  • Book Mentions – I list of chapters that a character is mentioned in but doesn’t appear in.

As always, I’m always happy to take advice on ways to improve my work, so if any authors out there have any tips on managing characters consistently throughout a book they’d be greatly appreciated.

ShoreTel LLDP Followup

A while ago I wrote a post about the experience I had setting up LLDP on Cisco switches with ShoreTel phones. Since then I have learned a trick or two and though I’d give a little update.

In the post I mentioned changing the configuration files for the phones on the ShoreTel server in order to correctly set the language and country, thus making the dial tone etc sound correct to end users. Unfortunately, this approach is broken. While it works to start with, we found that ShoreTel overwrites the configuration files periodically and removes the custom settings enter, which is a pain un the UK when the default country for ShoreTel is USA.

To get around this, there are some other configuration files which I was made aware of by our ShoreTel partner. Fortunately though ShoreTel provide some custom configuration files for each phone which are included in the main configuration file. The table below shows which custom configuration file you need for each model of phone.


So within the c:\inetpub\ftproot\sevgcustom.txt file for the IP 230g phones we use, all we have to do is add the following to the file.

# Please consult Shoreline support before editing or deleting this file

Include “Country_7.txt”
Include “Language_4.txt”

And done. If you reboot a phone, you will see it downloads the sevgcustom.txt file from the server and the language and country settings are all correct.

Don’t forget to change the configuration files for any other model phones you have!

tado – An Honest 1 Year Review.

A little over a year ago I was excited to receive my new tado smart thermostat. When it dropped on the doorstep I couldn’t wait to get it installed and it was actually up and running in less than half an hour before I had to go to work. The instructions provided were tailored to my setup based on the boiler and existing thermostat and were easy to follow, although an “expert” mode would have been nice as I’m familiar with central heating wiring to start with. The included extras were a big plus though, including everythin one might need for the installation. 

Configuration of schedules isn’t as simple as I had imagined it would be. Having to add new sections which tweaked the sections either side of them, which made the process quite tedeous. The only real positive was the fact you only need to spend the time once when first setting up the tado. 

Location based control using the family’s phones worked suprisingly well and was pretty accurate. Not having to worry about turning the heating off before leaving the house was very convenient and having the house warm when we returned improves the whole coming home in the dark after work depression. It also worked well for when the kids return from school before me and the wife, not having to worry about teaching the kids how the heating system works was great.

The thermostat itself is pretty vanilla looking which I suppose makes its integration into your room decor pretty pain free. Unfortunately though, the thermostat isn’t particularly user friendly or responsive. I seemed to find myself standing in front of the thermostat far longer than I used to with the old thermostat, just to turn the temperature up a degree or two. 

Unfortunately the experience continued to decline from there. Tado promised apple HomeKit integration “soon” which was one of the selling points for me personally. There was also talk of an Apple Watch app too, which could have been excused if HomeKit integration was available. After a year of “2nd quarter” then “third quarter” and so on as a release date though I pretty much gave up on HomeKit integration. Then I received an email claiming it would be available within a month and to contact support to arrange a replacement tado bridge to enable it. Then the release was delayed again. Then again. I wish I was exaggerating. It’s even more insulting that they have managed to release radiator valves in the same time frame.

Then came the fabled savings touted on tado’s website. According to their website a house the same age and same size as mine should see over €1,000 saving. I knew this was far fetched, but I wasn’t prepared to see the actual savings I made on gas over the period of 12months. £33. Again, I wish I was exaggerating but unfortunately not. This means my tado cost me £110 in the first year. Nothing like what was implied on tado’s website. 

Last week I received an email from tado reminding me that my next annual subscription was due, which is upwards of £100. After contacting tado to voice my concerns and receiving no reply other than automated “we’re sorry it’s taking so long” messages I was fed up with tado’s customer service. I then emailed them again to tell them to cancel my subscription and send a box to return my tado. I’m yet to receive a response three weeks later. 

While I like the idea of smart thermostats and understand the concept of energy efficiency using technology, tado isn’t a product I would endorse. Don’t get me wrong, it has worked reliably since the day I got it, but the lies, broken promises and lack of customer service to back their technology leaves me disappointed at best. Since central heating is imperative to the comfort and health of my family, tado is now back in it’s box waiting to be collected and there is a nest on my wall in it’s place. At the end of the day, the nest was only £30 more to buy outright than the next annual tado subscription, so it was a no brainier really. Plus it looks way cooler. And it’s easier to use. And the schedule is far superior.