Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Scary Halloween Application

Build an application that will drip animated blood down your victim's computer screen for a scary Halloween treat!
ASPSOFT, Inc.

Difficulty: Easy
Time Required: Less than 1 hour
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: None
Download: Download
 

Introduction

If you're anything like me, and I hope for your friends' and family's sake you're not, you believe that annoying others is amazingly entertaining. If that's the case, then this article is for you.

We are going to build an application that you will copy to a friend's PC that will, at a specified date and time, cause the computer to appear to start dripping blood down the screen and, after a few seconds, switch to a full-screen image of something terrifying while playing a screaming sound effect. This should sufficiently scare your victim for Halloween (hear the built-in scary sound).

The Form

We will be creating a full-screen, always-on-top, transparent form that will overlay the entire screen. This will be our display surface for the dripping blood.

The form can be created as described by modifying the following properties:

BackColor – Fuchsia

FormBorderStyle – None

DoubleBuffered – True

Text - <empty string>

WindowState – Maximized

ShowInTaskbar – False

TransparencyKey – Fuchsia

TopMost - True

This will create our full-screen, transparent form with no visible name, no icon in the task bar, no border that will remain on top of all other windows. With this in place, we can draw whatever we want to on to the form and it will be displayed over whatever happens to be on the screen. A nice bonus to this is that even though the form is maximized, because it is transparent, mouse and keyboard events will pass through to the visible active forms below. The user's PC should act as though nothing is happening!

The Blood

I created a class named BloodDrop to represent the on-screen blood droplets flowing down the screen. When a droplet is instantiated, it loads its frames of animation from a series of images saved as resources in the application. Each image is located in a directory named images in the project, and its Build Action property is set to Embedded Resource.

With the images set as resources, we can load the images in the BloodDrop constructor as follows:

Visual Basic

Public Sub New()
    ' load each animation frame from the app's resources and add it to our frame list
    For Each file As String In _files
        Dim img As Image = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("HalloweenVB." + file))
        _frames.Add(img)
    Next

    ' set our first frame
    _image = _frames(0)
End Sub

Visual C#

public BloodDrop()
{
    // load each animation frame from the app's resources and add it to our frame list
    foreach(string file in _files)
    {
        Image img = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.images." + file));
        _frames.Add(img);
    }

    // set our first frame
    _image = _frames[0];
}

The FromStream method of the Image object allows loading of an image file from an application's embedded resource list. To get access to the stream for a specific resource, the name of the resource needs to be known, which is the fully qualified name of the file. In the case of the C# project, the resources are named Halloween.images.<filename>. The VB project's resources are named HalloweenVB.<filename>. Though the images are stored in a directory named images in both projects, only the C# version includes the directory name as part of the fully qualified name.

In either case, each file is loaded and stored in a List of Image objects.

Drawing

In creating this application, I decided to stay entirely within the framework so deployment would be as simple as copying a single executable to your victim's machine. Therefore, I decided to use standard GDI+ calls for drawing, instead of Managed DirectX or some other method.

At first, I experimented with making each blood droplet a PictureBox control and moving the control down the screen, but that was not quick enough for smooth animation. I next tried using a timer and drawing to the screen directly inside the Tick event, however this too was too jerky. Finally, I set the Tick event to simply invalidate the screen, causing the OnPaint event to fire. I found that performing screen updates inside this method with the DoubleBuffered property set to True allowed for the smoothest animation.

When the blood is set to be drawn, a timer is started that ticks every 100 milliseconds. This timer simply calls the Invalidate method of the current form object. When invalidated, the form calls its OnPaint handler, which we override.

Inside the OnPaint handler, we create a new BloodDrop object and assign a random horizontal position and vertical velocity to it. This provides for an interesting display as the blood drips down. The newly created BloodDrop is then added to a List of BloodDrop types. Finally, the full list of blood drops is enumerated, animated, and drawn.

Visual Basic

' create a new blood drop
Dim drop As BloodDrop = New BloodDrop()

' set it to a random location on the screen
drop.Location = New Point(_random.Next(SystemInformation.PrimaryMonitorSize.Width), 0)

' set it's velocity to a random number
drop.Velocity = _random.Next(40) + 20

' add it to our drawing list
_dropList.Add(drop)

' enumerate the drawing list
For Each bd As BloodDrop In _dropList
    ' animate and then draw the drop            
    bd.Animate()
    bd.Draw(g)
Next
 

Visual C#

// create a new blood drop
BloodDrop drop = new BloodDrop();

// set it to a random location on the screen
drop.Location = new Point(_random.Next(SystemInformation.PrimaryMonitorSize.Width), 0);

// set it's velocity to a random number
drop.Velocity = _random.Next(40) + 20;

// add it to our drawing list
_dropList.Add(drop);

// enumerate the drawing list
foreach(BloodDrop bd in _dropList)
{    
    // animate and then draw the drop            
    bd.Animate();
    bd.Draw(g);
}

At application startup, an instance of the Random class is created and stored in our _random member variable. The Next method requires a parameter for the maximum value of the random number to be returned. In the case of setting the drop's location, I use the maximum screen width, determined by using the SystemInformation object. In the case of velocity, a maximum value of 40 pixels is requested, and an additional 20 pixels is added on in case a very low number is randomly selected.

Drawing the actual drop is pretty simple. The Draw method of our BloodDrop class looks like the following:

Visual Basic

' draw the drop
Public Sub Draw(ByVal g As Graphics)
    ' if we're in "drop" mode, draw the stream behind it
    If _index >= 4 Then
        g.DrawImage(_frames(4), Me._location.X + 24, 0, _frames(4).Width, Me._location.Y + 10)
    End If

    ' if we're beyond the bottom of the screen, don't bother drawing the drop
    If Me._location.Y < SystemInformation.PrimaryMonitorSize.Height Then
        g.DrawImage(_image, Me._location.X, Me._location.Y, _image.Width, _image.Height)
    End If
End Sub

Visual C#

// draw the drop
public void Draw(Graphics g)
{
    // if we're in "drop" mode, draw the stream behind it
    if(_index >= 4)
        g.DrawImage(_frames[4], this._location.X + 24, 0, _frames[4].Width, this._location.Y + 10);

    // if we're beyond the bottom of the screen, don't bother drawing the drop
    if(this._location.Y < SystemInformation.PrimaryMonitorSize.Height)
        g.DrawImage(_image, this._location.X, this._location.Y, _image.Width, _image.Height);
}

In each case, we use the Graphics object provided to us and use the DrawImage method to draw the correct frame number to the correct position. In order to save some CPU cycles, we first determine whether the drop has passed the lower edge of the screen and, if it is, it is not drawn. The size of the screen can be determined by using the SystemInformation object and using the PrimaryMonitorSize method.

The second part of this method draws the blood trail that follows behind the droplet as it falls. This is done by stretching an image that is 1 pixel tall down the screen to the top of the blood drop graphic.

In my first attempts at drawing the blood in this manner, I found that the DrawImage method, when scaling an image as it is doing here, will anti-alias and blend the image to make it appear less blocky. Unfortunately, this caused a great deal of distortion, making the trail look awful. After some experimenting, I found that setting the following properties of the Graphics object before drawing would allow the image to be stretched without modification.

Visual Basic

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    ...
    ' grab the Graphics object for me app and set some properties for correct drawing
    Dim g As Graphics = e.Graphics
    g.PixelOffsetMode = PixelOffsetMode.Half
    g.InterpolationMode = InterpolationMode.NearestNeighbor
    g.CompositingQuality = CompositingQuality.HighSpeed
    ...
End Sub

 

Visual C#

protected override void OnPaint(PaintEventArgs e)
{
    ...
    // grab the Graphics object for this app and set some properties for correct drawing
    Graphics g = e.Graphics;
    g.PixelOffsetMode = PixelOffsetMode.Half;
    g.InterpolationMode = InterpolationMode.NearestNeighbor;
    g.CompositingQuality = CompositingQuality.HighSpeed;
    ...
}

The Finale

After the blood has dripped down the screen for several seconds (10 in the default case), the animation timer is disabled, the screen is cleared and a scary image is quickly displayed along with a loud screaming sound, which should hopefully scare the person at the keyboard. A running count of the time elapsed is stored in a member variable and is incremented by the timer's Interval value each time our OnPaint method is called.

This is accomplished by creating a PictureBox on the fly and loading an image into the box. This box is then added to the Controls collection of the form and displayed. Additionally, two events are handled that will dismiss the application when a user clicks the mouse or presses a key on the keyboard.

The sound is then loaded from a resource and played using the SoundPlay object. This looks like the following:

Visual Basic

' disable the animation timer 
tmrAnim.Enabled = False

' create a Picturebox
Dim pb As PictureBox = New PictureBox()

' pull in the scary image from our resources
pb.Image = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("HalloweenVB.scary.jpg"))

' set it to fill the screen
pb.SizeMode = PictureBoxSizeMode.Zoom
pb.Width = SystemInformation.PrimaryMonitorSize.Width
pb.Height = SystemInformation.PrimaryMonitorSize.Height
pb.BackColor = Color.Black

' if it gets clicked, or someone presses a key, we want to end the app
AddHandler pb.Click, AddressOf pb_Click
AddHandler Me.KeyDown, AddressOf MainForm_KeyDown

' add the Picturebox to the controls list
Me.Controls.Add(pb)

' play a scary sound
Dim sp As SoundPlayer = New SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("HalloweenVB.scream.wav"))
sp.Play()

 

Visual C#

// disable the animation timer
tmrAnim.Enabled = false;

// create a Picturebox
PictureBox pb = new PictureBox();

// pull in the scary image from our resources
pb.Image = Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.images.scary.jpg"));

// set it to fill the screen
pb.SizeMode = PictureBoxSizeMode.Zoom;
pb.Width = SystemInformation.PrimaryMonitorSize.Width;
pb.Height = SystemInformation.PrimaryMonitorSize.Height;
pb.BackColor = Color.Black;

// if it gets clicked, or someone presses a key, we want to end the app
pb.Click += new EventHandler(pb_Click);
this.KeyDown += new KeyEventHandler(MainForm_KeyDown);

// add the Picturebox to the controls list
this.Controls.Add(pb);

// play a scary sound
SoundPlayer sp = new SoundPlayer(Assembly.GetExecutingAssembly().GetManifestResourceStream("Halloween.scream.wav"));
sp.Play();

As you can see, the sound and image resources are loaded in an identical manner as the frames of animation shown earlier.

The Scheduler

The final piece of the puzzle was to allow a user to select the date and time that the animation would start on the victim's PC. I created a simple configuration dialog box that is displayed the first time the application is run. The dialog allows the person setting up the application to choose the date and time the animation should be fired. This is saved using the Settings object of the project. This way, the user can put the application in the startup group, or create a registry key to load it on startup, so if the PC is rebooted before the desired time is reached, the application will restart and wait for the time to occur.

Settings can be added by right-clicking the project in the Solution Explorer and choosing Properties. Select the Settings tab and a new value can be entered. The one for this application looks like the following:

Now, on application startup, the application's Settings can be checked to determine if the configuration dialog needs to be shown, or just wait for the time specified.

When the application is started, a scheduler timer is created which ticks every minute. The Tick method for this timer looks at the current time, and if it is greater than or equal to the specified time, it will disable the scheduler timer, maximize the hidden window, and start the animation timer, which will automatically start drawing our blood droplets.

Visual Basic

Private Sub tmrScheduler_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrScheduler.Tick
    If DateTime.Now >= My.Settings.Time Then
        ' re-maximize the window
        Me.WindowState = FormWindowState.Maximized

        ' disable me timer
        tmrScheduler.Enabled = False

        ' enable the animation timer
        tmrAnim.Enabled = True
    End If
End Sub

Visual C#

// called once per minute to check whether it's time to run the show
private void tmrScheduler_Tick(object sender, EventArgs e)
{
    // if the current time is greater than the time set by the user
    if(DateTime.Now >= Properties.Settings.Default.Time)
    {
        // re-maximize the window
        this.WindowState = FormWindowState.Maximized;

        // disable this timer
        tmrScheduler.Enabled = false;

        // enable the animation timer
        tmrAnim.Enabled = true;
    }
}

Deployment

As mentioned earlier, one of the main goals of this project was to have an extremely easily deployable application. In order to achieve this, all code was kept inside the framework with no dependencies on things like Managed DirectX. Additionally, all resources used by the application (images and sounds) were setup as embedded resources so they do not need to be deployed separately.

When you are ready to scare your friend, simply copy the Halloween.exe file to his or her PC. )You may want to enlist someone as the “lookout” so you don't get caught while doing so!) Create a shortcut to it in the Startup program group, or set it up to run via the registry using the following key for the logged in user:

  • HKCU\Software\Microsoft\Windows\CurrentVersion\Run

Simply create a new string key with any Name, and a Data value of the path to the executable.

Next, start the application once on their PC to setup the date and time for the show to begin. Once that is done, the application will remain running in the background. If the PC is restarted, and the application is setup to run at startup as described above, it will start silently and remain running, waiting for the date and time specified.

Summary

And there we have it. A very simple application requiring very little code that will elicit quite a reaction from your victim. The code can be very easily modified to include different images, a different sound effect, or even different animation effects. There is plenty of time between now and April Fool's Day to modify the project for even more fun.

Thanks

A special thanks to Joey Buczek for drawing up the blood drop animation, Mark Zaugg for testing on a few machines outside my house, and Michelle Leavitt for making my writing a bit more palatable for the masses.

Bio

Though Brian is a recognized .NET expert with over 6 years experience developing .NET solutions, and over 9 years of professional experience architecting and developing solutions using Microsoft technologies and platforms, he has been "coding for fun" for as long as he can remember.  Outside the world of .NET and business applications, Brian enjoys developing both hardware and software projects in the areas of gaming, robotics, and whatever else strikes his fancy for the next ten minutes. He rarely passes up an opportunity to dive into a C/C++ or assembly language project.  You can reach Brian via his blog at http://www.brianpeek.com/.

Tags:

Follow the Discussion

  • KennyKenny

    This simple code section have saved me a lot of trouble.Am thinking of re-editing it to submit as my final year project.Pls if you can help me with more articles like this on any controls on c# pls do.Thanks

  • JamesJames

    I don't see why there are no comments on this. This is really cool, thanks! Smiley

  • kleykley

    ok im brand new at this can you do a step by step?

  • Clint RutkasClint I'm a "developer"

    In this application, Brian Peek demonstrates how to create two spooky Halloween applications to trick

  • AlesguzAlesguz

    Great. Thanks for the tips, I'm gonna try it now.

  • Clint RutkasClint I'm a "developer"

    @enrique doing a quick glance the the article, commenting out a few lines of code and this should be rather an easy task since it draws the blood on to a picture box control

  • enrique.prados@a-e.esenrique.​prados@a-e.​es

    FAntastic !!

    Can I apply the effect to a single image JPG ??

    any sample code about it ?? thanks

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.