Friday, March 16, 2012

Check If CD was inserted

In this post I want to explain, based upon the method from the previous post, how to spot, when a CD Rom is inserted.

As described in the previous post therefor we again use the WM_DEVICECHANGE event and the enumeration System.IO.DriveInfo.GetDrives().
During the check we now just have to determine whether the devices are of the type DriveType.CDRom and contain a readable CD, which is indicated by IsReady. In the WndProc() function the current value of the variable is compared to the previous and thus determined, whether the user inserted a CD (for multiple CD drives, the code has to be changed accordingly):

        const int WM_DEVICECHANGE = 0x219;
        bool CDInserted;

        private void CheckCD()
        {
            foreach (System.IO.DriveInfo d in System.IO.DriveInfo.GetDrives())
            {
                if (d.DriveType == System.IO.DriveType.CDRom && d.IsReady)
                    CDInserted = true;
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_DEVICECHANGE)
            {
                bool OldCD = CDInserted;
                CheckCD();
                if (!OldCD && CDInserted)
                    MessageBox.Show("CD inserted.");
            }

            base.WndProc(ref m);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            CheckCD();
        }

Thursday, March 15, 2012

Check if Removable Devices (like USB Flash Drives) Are Connected Or Disconnected

In the previous post, upon which this post is based, I explained, how to recognize with C#, if the hardware settings of the computer have changed.
This most now focusses on the topic of finding out, if removable mediums, like USB flash drives, got plugged in or plugged off.

Therefor we use the previously introduced event WM_DEVICECHANGE as a notification, when devices are connected or disconnected.
Then we use the enumeration System.IO.DriveInfo.GetDrives(), which contains all drives of the computer, all internal harddrives but also the external flashdrives. Of these devices we now determine the type (DriveType), if this is DriveType.Removable, the currently examined device is a flash drive.
In the function we count the number of these devices and by calculating the difference, we can determine, whether a USB flash drive was connected or disconnected.

I think, the corresponding should be self explaining:

        private void Form1_Load(object sender, EventArgs e)
        {
            CheckDrives();
        }

        int USBCount;

        private void CheckDrives()
        {
            USBCount = 0;
            foreach (System.IO.DriveInfo d in System.IO.DriveInfo.GetDrives())
            {
                if (d.DriveType == System.IO.DriveType.Removable)
                    USBCount++;
            }
        }

        const int WM_DEVICECHANGE = 0x219;
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_DEVICECHANGE)
            {
                int OldUSBCount = USBCount;
                CheckDrives();
                if (USBCount > OldUSBCount)
                    MessageBox.Show("USB flash drive connected.");
                if (USBCount < OldUSBCount)
                    MessageBox.Show("USB flash drive disconnected.");
            }

            base.WndProc(ref m);
        }

Diagnose Connection of Devices / Removable Mediums

In the previous post I explained basics about the function WndProc().
In this post I now want to show, how to use this function to find out, if device settings have changed, for example if new hardware like mouses, USB sticks or a CD were plugged in / inserted.
If such a setting changes, the operating system sends our C# application the message WM_DEVICECHANGE (hexadecimal the value 219).

The following code produces a message, if above is the case:

const int WM_DEVICECHANGE = 0x219;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_DEVICECHANGE)
        MessageBox.Show("Device settings changed.");
    base.WndProc(ref m);
}

In the next posts I show, how to recognize, if a USB flash drive is plugged in or a CD inserted.

Wednesday, March 14, 2012

Overwriting WndProc()

The operating system Windows works event oriented, meaning programs do not ask continously for the state of certain system variables or something else, but they are informed themselves by events (messages) about changes.

In this post I want to show, how to overwrite the function, which receives the messages send from the operating system to the C# application, and thus is able to manipulate the data processing.

The function responsible for this is called WndProc() and is part of every form class. While the application is running, Windows sends continously meesages to the application, WndProc() receives them. Windows notifies our program about practically everything  which could be interesting for it, starting from the movement of the mouse cursor over the activation of another application to the click on the exit button on the form. In general all actions, which the user undertakes on the form, are registered by Windows, processes and then send back to the application for processing. The case, that the user clicks "X" for quitting our C# aplication, provokes the following action chain: Windows recognizes a mouse click in the area of our application, sends the event to the application, which then determines then via the position that "X" was clicked and exits itself.

That much to the theory, now to the practical realization: As already mentioned WndProc() is already a function of the Form class, so we have to overwrite it, which can be done with the key word override.
If we enter in the .Net development studio the first characters of the signature protected override void WndProc(ref Message m), C# automatically completes this to

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);
}

The added line expresses, that after the call of your function, the original function is called.
If you delete this line, the application cannot even start, since all incoming events "end" in our function and are not processed further.

To get an intuition of which and how many events are received, you could for example add a ListBox to the form and add the following line to the function:
listBox1.Items.Add(m.ToString());

Obviously, this post was kept pretty abstract, but I hope to show you soon some interesting applications, which can be realized based upon the knowledge from this post.

(Edit: In the next post I show, how to use this function to determine whether hardware settings have changed. With this for example can be checked, whether a USB flash drive was pluggin in or a CD inserted.)

Monday, March 5, 2012

Intercept Termination of a Console Applications

Sometimes an application is terminated during the execution of a critical action - for example by the user.
If you want to finish this action or use a different code to exit, in Windows Forms Applications simply the events FormClosed and FormClosing can be used.
In console applications they are not avaible. To be still able to react to the unexpected ending of the application, we use the function SetConsoleCtrlHandler().
With this we can register a function at the application, which is called when the program quits.
SetConsoleCtrlHandler() expects 2 arguments, the first is the delegate to the function which is to be used, the second a Boolean value which determines, if the handler is to be added or deleted.
The function, which is called when exiting, expects an enumeration is parameter, which specifies the event which causes the termination, and has always to return false.
In the code we first create a delegate of the desired signature:
private delegate bool EventHandler(CtrlType e)

Then we create a variable of the previously defined type:
static EventHandler ConsoleCloseHandler
.
This we assign now our function we want to use and register this at the application:
ConsoleCloseHandler += new EventHandler(Console_Closed);
SetConsoleCtrlHandler(ConsoleCloseHandler, true);

In the function Console_Closed() the reason of quitting is saved in the argument, this can be determined and used.
The enumeration used by me contains 4 events: The quitting via the key combination Ctrl + C, the quitting by clicking "X", the quitting because the user loggs off and the quitting because of shutting down.
I hope the following source code explains this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        enum CtrlType
        {
            CTRL_C_EVENT = 0,
            CTRL_CLOSE_EVENT = 2,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT = 6
        }

        private delegate bool EventHandler(CtrlType e);
        static EventHandler ConsoleCloseHandler;

        static void Main(string[] args)
        {
            ConsoleCloseHandler += new EventHandler(Console_Closed);
            SetConsoleCtrlHandler(ConsoleCloseHandler, true);

            while (true)
            {
                // infinite loop
            }
        }

        private static bool Console_Closed(CtrlType e)
        {
            switch (e)
            {
                case CtrlType.CTRL_C_EVENT:
                    Console.WriteLine("Ctrl + C");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_LOGOFF_EVENT:
                    Console.WriteLine("Log Off");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_SHUTDOWN_EVENT:
                    Console.WriteLine("Shutdown");
                    Console.ReadLine();
                    break;
                case CtrlType.CTRL_CLOSE_EVENT:
                    Console.WriteLine("Close");
                    Console.ReadLine();
                    break;
                default:
                    Console.WriteLine("other");
                    Console.ReadLine();
                    break;
            }

            return true;
        }
    }
}

Friday, March 2, 2012

Restart Windows Forms and Console Applications

In this post I quickly want to show, how to restart C# applications.
For Windows Forms Applications one command suffices:
Application.Restart();

But what actually is behind it, or if someone wants to "personalize" this process, is the following:
The current application is restarted as an pown process and the old instance is closed, which leads us to this manual code for Windows Forms Applications:

// create new process
System.Diagnostics.Process NewInstance = new System.Diagnostics.Process();
// link it to the application
NewInstance.StartInfo.FileName = Application.ExecutablePath;
// start new instance
NewInstance.Start();
// quit current instance
Application.Exit();

This method is especially interesting for console applications, since they do not provide the command Application.Restart().
The above code also works for them, just one line has to be adapted, since of course Application.ExecutablePath is also not avaible:
NewInstance.StartInfo.FileName = System.Threading.Thread.GetDomain().BaseDirectory + System.Threading.Thread.GetDomain().FriendlyName; (on this way we determine via the class Threading application path and application name)