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.

SplashForm.jpeg

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)
{
InitializeComponent();
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));
Application.Run(_splashInstance);
}

//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)
return;
Thread thread = new Thread(ShowForm);
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start(max);
}

//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.Value++;
_splashInstance.progressBar1.Text = txt;
}

//The private method invoked by the delegate to close the splash screen.
private void CloseFormInternal()
{
_splashInstance.Close();
}

}
}

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()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

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

//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
splash.CloseForm();

//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.

Installing / Configuring and Administering pfSense as a multi-tenant firewall

I am about to embark on a mission… A mission to provide uncontested but limited Internet connectivity to our tenants. To do this I have decided to deploy pfSense, and I will be documenting each step for both our reference here at work, and in the hope that it will help somebody do something similar in the future.

To start with, we needed a specification of what we need the system to do. Here it is.

  • The firewall must serve multiple tenants (up to 50+)
  • The firewall must give each tenant their own external IP
  • The firewall must prevent each of the tenants from seeing each others’ networks
  • The firewall must allow us to limit the amount of bandwidth each tenant can utilize (otherwise they have free reign of our dual redundant gigabit fibre connections)
  • The firewall must allow us to filter out certain traffic such as p2p
  • The firewall must allow us to set data caps for each tenant
  • The firewall must let us create a DMZ for each tenant if required
  • The firewall must allow us to configure network services for each tenant (DHCP, DNS, etc)
  • The firewall must allow each tenant to have their own VPN connection if required
  • The firewall must allow us to report on bandwidth utilization and data transfer usage on a per-tenant basis

This may seem a tall order for one box, but with pfsense it is absolutely possible providing the hardware is capable of it. for our firewall we are going to re-deploy one of our old servers which was decommissioned during our virtualization project. The server used to be one of our domain controllers and it performed well while it was in service. I believe it will perform well as firewall as well. Its spec is below.

  • IBM x3550 1u Server
  • 2x Dual core Xeon processors
  • 4GB Ram
  • 2 x 76GB SAS disks in a RAID 1 (mirrored) configuration
  • 2x On board Intel Pro/1000 Gigabit NIC’s
  • 1x Dual port Intel Pro/1000 Gigabit NIC
  • N+1 Power supplies

As you can see the server isn’t wanting when it comes to specs for the purpose it will be used for. It was slightly higher speced but parts have since been “pinched” for other projects. If this project goes well then we will be looking to build another similar firewall using our other domain controller of the same spec and cluster them for both resilience and load balancing.

I will be starting this project this afternoon so check back for updates, step-by-step guides and images of the entire process during “Project FireServer”.

Part 1 – The Hardware and Topology ->>>