"An investment in knowledge always pays the best interest."
Benjamin Franklin
Introduction
In this article, I would like to discuss problems the Splash \ Login Forms creating. I often stumble on the questions of the novice programmers about the Splash \ Login Forms on the forums. In my opinion, the answers on these questions often don't give a comprehensive information. So I decided to write the article. It fully describes these problems and solutions.
At first, I would like to discuss a question - What causes these problems to arise? In my opinion it is connected with an insufficient information or a fuzzy concept about the Windows architecture and Windows processes when we start executing program in the Windows systems. Here's the main problem. So let's resolve it. I am not going to retell a big good books about Windows, there is no point. I only want to let you have the opportunity to know about the creation of the instance program in Windows. That will give you an understanding of how to create the Splash \ Login Forms.
What is a Process?
First, we'll discuss a definition of "process in Windows". The Process - it is a copy of the executable program, and it consists of two components:
- An object of the kernel, through which the operating system manages the process. It keeps the
static
information about the process. - An address space that contains executable code and data of the process.
The process itself does nothing, i.e., it is inert. To make it do something, it should have at least one thread. The thread is responsible for the execution of code in the address space of the process. Therefore, when the process is starting, the operating system automatically creates the main thread, which in turn can generate other threads. In addition, if we want our application to respond to the mouse moving, the button clicking, and so on, we have to create a message loop in the thread. So we have some structure: process - thread - a message loop. If we want to close the program, we need to close the main message loop. It happens when you close the main form or doing method Application.Exit()
, as well as the method ExitThread()
in the main thread.
How Do I Do It?
All discussed above, Visual Studio creates automatically, when we choose to create a project template with Windows Forms Application. Armed with this knowledge, take a look at the code, which we all certainly have repeatedly seen:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
When you call a method Application.Run (new Form1 ())
, we create a new thread that creates a message loop, and an object of class Form
and shows it. Let us carefully consider this method. This method is overloaded, and may have the following options:
Run()
Run(ApplicationContext)
Run(Form)
(For additional information, see this link.)
We are not interested in the first overloaded method in the context of this article, unless, of course, you decide to create something in the unsafe code, the third method we have already discussed. But the second is what we will be particularly interesting in. This creates the object class ApplicationContext
, which is responsible for creating the thread and the standard cycle of message. Now everything is pretty simple - we must create a descendant class LoginTestContext
of class ApplicationContext
, which we will create a logic with application forms:
public class LoginTestContext: ApplicationContext
{
private frmLogIn fLogin;
private frmMain fMain;
public LoginTestContext()
{
CreateSplashForm();
CreateLoginForm();
}
}
(For additional information, see this link.)
And our entry point into the application will look as follows:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LoginTestContext());
}
Creating the Splash Form
That's it! The Splash form is displayed when we need it and at the time that we need. Here, in place of slumber thread, you can do something really necessary, such as loading any resources, while showing progress bar or some other kind of information.
private static void CreateSplashForm()
{
Form fSplash = new Form();
fSplash.BackgroundImage = System.Drawing.Image.FromFile(@"backg.bmp");
fSplash.BackgroundImageLayout = ImageLayout.Center;
fSplash.FormBorderStyle = FormBorderStyle.None;
fSplash.StartPosition = FormStartPosition.CenterScreen;
fSplash.TopMost = true;
fSplash.TransparencyKey = System.Drawing.Color.White;
fSplash.Width = (int)fSplash.BackgroundImage.PhysicalDimension.Width;
fSplash.Height = (int)fSplash.BackgroundImage.PhysicalDimension.Height;
fSplash.Show();
System.Threading.Thread.Sleep(2000);
fSplash.Close();
}
Creating the Login Form
Now we'll discuss the problem of the Login form establishing. The Login form follows after the Splash form. The Login form in any case should be closed. When it is closing itself, we must determine whether the login is made in the application:
private void CreateLoginForm()
{
fLogin = new frmLogIn();
fLogin.Closed += new EventHandler(fLogin_Closed);
fLogin.TopMost = true;
fLogin.Show();
}
void fLogin_Closed( object sender, EventArgs e )
{
if (LWork.LoginWork.Login)
{
fMain = new frmMain();
this.MainForm = fMain;
fMain.Show();
}
else
{
ExitThread();
}
}
The registration process is implemented in a static
class LoginWork
.
public static void DoLogin( string NikName, string Password )
{
if (IsExistNikName(NikName))
{
if (_user.Password == HashString(Password))
{
_Logged = true;
}
}
else
_Logged = false;
}
The search function of the user name in the list IsExistNikName (string name)
is implemented using lambda expression UserData => UserData.Nikname == NikName
. In this case, the explanation the entity lambda expressions is too simple. For more information about the lambda expression, see this link.
private static bool IsExistNikName( string NikName )
{
if (_UserDataList.Count == 0)
{
return false;
}
_user = _UserDataList.FirstOrDefault(UserData => UserData.Nikname == NikName);
if (String.IsNullOrEmpty(_user.Nikname))
{
return false;
}
return true;
}
For security, the user's password is hashed using the function:
public static string HashString( string s )
{
byte[] data = Encoding.Default.GetBytes(s);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(data);
StringBuilder sb = new StringBuilder();
foreach (byte item in result)
{
sb.Append(item.ToString("X"));
}
return sb.ToString();
}
The processes of saving, load the data registered users are implemented using XML Serialization and UserData
structure. The data is stored locally in the XML file:
[Serializable]
public struct UserData
{
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
private string _Nikname;
public string Nikname
{
get { return _Nikname; }
set { _Nikname = value; }
}
private string _Password;
public string Password
{
get { return _Password; }
set { _Password = value; }
}
}
Conclusion
That is all I wanted to tell you on this topic. I hope I succeeded in revealing the topic of this article fully. The implementation of the classes registration form and Login form, I think, will not cause any difficulty in understanding, but if you have any questions please write, I'll answer everyone.
Good coding!
History
- Initial release: 31 August, 2010
- Changed the code version: 3 September, 2010