SDL & OpenGL Game with C++ – Part II

Parts in the Series

Rendering a Quad with OpenGL and SDL

Ok, so if we are going to program a video game then we need to draw something with OpenGL.

That being said, last time we left off with a basic framework for creating a game with SDL. If you haven’t read it then you should check out part 1 here because we’ll be building off of that. This time around the goal is simply to get something rendering on the screen with OpenGL. So with that in mind here is the road map for what I wanted to accomplish:

  • Render a single quad
  • Render a textured quad

As you can see I am going to keep it simple for now. I’ll throw in the ability to swap textures at runtime as well just to keep it interesting.

The game so far will look a little something like this:


Drawing a Square With SDL

First on the list is to render a single quad. But, before you do anything make sure you add the OpenGL libraries to your project. You can accomplish that by going into the linker section of the project settings and adding opengl32.lib and glu32.lib to the additional dependencies section, just as we did for the SDL libraries in Part I.

I am just going to start out showing you the new main function and then we will go through it step by step. So here ya go!

Read the rest of this post »

December 8, 2009   Posted in: C/C++, Game Programming, Programming  4 Comments

SDL & OpenGL Game with C++ – Part I

Parts in the Series

Getting Started

I think I’ve spent too many late nights playing multiplayer Modern Warfare 2 and now I feel the need to build a small game of some kind. Game programming is fun, and although I’ve never done it professionally, I have dabbled with it as a hobby for many years. I’ll be documenting my progress here over time via a number of different postings. Maybe some of you will find it useful as a reference or small SDL tutorial or game programming tutorial. That being said, time to get to work!

I have no idea what type of game to build yet so the first thing to do is just get the basic framework setup. I’ll be using C++ for this game project. I thought about using C# and XNA but I need to dust off my C++. For the graphics system I decided to use OpenGL. This is mostly because I am familiar with it and didn’t want the extra overhead of boilerplate setup stuff associated with DirectX. I just want to get something going quickly. For the rest of the stuff needed (audio, input, etc) I am going to use SDL. SDL is a great tool to get things up and running fast and it easily interfaces with OpenGL. I am also thinking about putting in some UI stuff using CEGUI (Crazy Eddie’s GUI System).

SDL Setup Prerequisites

Before we get started you’ll want to make sure you have the SDL development libraries (I am using version 1.2.14). You can find them on the SDL website: http://www.libsdl.org. The ones I used specifically are:

Read the rest of this post »

November 23, 2009   Posted in: C/C++, Game Programming  4 Comments

Runtime Scripting in .Net

The ability to ship source code with your product that can be compiled or interpreted at runtime is a very valuable asset. Video games do this all the time with things like AI allowing the end-user to easily mod the game. In compiled languages like C++, this technique is highly advantageous as it allows you to avoid the costly compile-link cycle for every small change to a source file. This is also helpful in an environment where creating a new build, generating the installer, and deploying it is overkill or difficult to achieve. In this article we will examine how you can achieve this from .Net programs consuming a C# or VB.Net script. I’ll refer to this as “scripting”, even though an unambiguous definition of a “script” is somewhat difficult to nail down.

Using a C# or VB script from a .Net language is actually very simple. The basic idea is to read in a source file, which could come from the network or disk, and compile it into a temporary assembly on file or IL in memory. Then you can instantiate types from the script file and use them just as easily as any other types already defined. Normally the hard part in this process is locating and invoking the proper compiler. Luckily, we can compile IL code using a CodeDomProvider like CSharpCodeProvider. And, since these types are part of the .Net framework we know they are available on the end-user PC! Life is great eh?

Ok, so first make sure you have referenced the following namespaces:

    using System.CodeDom.Compiler;
    using Microsoft.CSharp;
    using Microsoft.VisualBasic;

Next you need to setup the compiler parameters. These are simply the options given to the compiler such as whether to create the resulting assembly in memory or if debug information should be included in the generated code. You can do this with the CompilerParameters type. Here is an example for creating an in memory assembly with debug information:

 CompilerParameters cparams = new CompilerParameters();
 
 cparams.GenerateInMemory = false;
 cparams.IncludeDebugInformation = true;
 cparams.CompilerOptions += " /debug:pdbonly";
 
 cparams.TreatWarningsAsErrors = false;
 cparams.GenerateExecutable = false;

You would also want to add any references that your code needs using CompilerParameters. ReferencedAssemblies. So, after you have the compiler options set you need to actually invoke the C# or Visual Basic compiler. You do this by creating a CodeDomCompiler of the appropriate type:

VBCodeProvider – for Visual Basic
CSharpCodeProvider – for C Sharp

Then you can use the provider to compile an assembly like so:

CodeDomProvider provider = CSharpCodeProvider();
CompilerResults result = provider.CompileAssemblyFromFile(cparams, script);

Where cparams are your compiler parameters and result is well, your results. Within results you will find out if the compilation was successful or generated warnings. It will also give you access to the resulting assembly. You can check for errors using results.Errors.HasErrors and reference the assembly with results.CompiledAssembly.

Read the rest of this post »

September 30, 2009   Posted in: C#  6 Comments

Using Ini Files In C#

An Initialization, or Ini file, is a common text based file format commonly used on the Windows platform. Today its mostly been succeeded in favor of XML files for application configuration and persisting user data. Never the less, these files still exist and are in use by many applications. In this post, we will explore how to work with Ini files via C#.

The structure of an Ini file is very simple and straight forward. You have three primary types of information: sections, parameters, and values. They look like this:

[SectionA]
Parameter1=value1
Parameter2=value2

[SectionB]
Parameter1=value1

Below we will create a class to read this data from a file. Keep in mind as you look at this C# Ini file implementation that this is just one way to do it. You could for example, create a much more concise solution using regular expressions, etc.

Parsing the Data

The first thing we should do if figure out how to get the data from the Ini file. We could read in all the text and manually parse the file; however there is an easier approach. The Win32 API contains a function called GetPrivateProfileString that we can use specifically for this task. We can use it to directly obtain the sections, parameters, and values. For a more detailed description of the GetPrivateProfileString function, check out this link on MSDN.

To use GetPrivateProfileString in C#, we need only reference it using the DLLImport attribute with the correct function signature.

        [DllImport("Kernel32.dll", EntryPoint = "GetPrivateProfileStringW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int GetPrivateProfileString(string lpAppName,
                                                         string lpKeyName,
                                                         string lpDefault,
                                                         [In, Out] char[] lpReturnString,
                                                         int nSize,
                                                         string lpFilename);

Reading from an Ini File

First, to make our job a little easier we will wrap the call to GetPrivateProfileString with our own method so that we can handle all of the details. Here is the wrapper:

        private string[] GetPrivateProfileString(string appName, string keyName, string defaultName, string inifile)
        {
            // the file inifile should exist as it's validated in the class constructor, however GetPrivateProfileString does not lock the file hence it could be locked or deleted by
            // another process between calls to this method
 
            // used to tell if we successfully read all requested data from the file 
            // from MSDN:
            //  If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one.
            //  If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two.
            int sizeReadOffset = (appName != null && keyName != null) ? 1 : 2;
 
            // try and read the entire amount of data from the ini file
            int sizeRead = Kernel32.GetPrivateProfileString(appName, keyName, defaultName, _readBuffer, _readBufferSize, inifile);
 
            // if unable to read all of the data because the buffer is to small, increase the size and try again, but only allow memory to increase up to _readBufferMaxSize
            while ((sizeRead >= _readBufferSize - sizeReadOffset) && (_readBufferSize < _readBufferMaxSize))
            {
                _readBufferSize += 512;
                _readBuffer = new char[_readBufferSize];
 
                sizeRead = Kernel32.GetPrivateProfileString(appName, keyName, defaultName, _readBuffer, _readBufferSize, inifile);
            }
 
            // if memory consumption exceeded _readBufferMaxSize then we have a problem
            if (_readBufferSize >= _readBufferMaxSize)
                throw new FileLoadException("ErrorBadIniLoad");
 
            // the buffer returned from GetPrivateProfileString will be null terminated C-strings followed by a double null at the end - so split the strings on the nulls
            char[] sep = new char[1];
            sep[0] = '\0';
 
            string s = new string(_readBuffer, 0, sizeRead);
 
            string[] result = s.Split(sep, StringSplitOptions.RemoveEmptyEntries);
 
            return result;
        }

Here, the MSDN terminology refers to what I call a section as an appName and what I refer to as a paramter as a keyName.

This method has a lot going on but is very easy to use. To get an array of strings containing all of the section names you simply say:
Read the rest of this post »

July 16, 2009   Posted in: C#  2 Comments

I’m Back

Hey guys, sorry I’ve been away for a bit. I’ll try and respond to your questions, especially those over on the C# dynamic web service page.

I’ll be adding a whole lot of new content as well. If anyone has any suggestions on a topic feel free to leave them for me.

See Ya!!

July 15, 2009   Posted in: General  4 Comments

Accessing the System Task Bar in C#

In this post I’ll show you how to access the system taskbar and obtain information like its location, size, etc. You may find yourself needing to do something like this if you had a “popup” window for instance that is always supposed to “pop up” from the system tray. This is a common feature in many of today’s applications; however the task bar may be docked somewhere other than the bottom of the screen or maybe even on a different monitor in a multi-monitor setup.

The Taskbar is an APPBAR

First, the task bar is considered an appbar (or desktop application toolbar) albeit with some special restrictions. Being an appbar we can talk to it with the Win32 API function SHAppBarMessage. SHAppBarMessage allows us to send a message to the system to get or set information about a registered appbar. The necessary C# definitions to access the function are as follows:

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
      public int top;
      public int right;
      public int bottom;
}
 
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public Int32 cbSize;
      public IntPtr hWnd;
      public Int32 uCallbackMessage;
      public ABEdge uEdge;
      public RECT rc;
      public IntPtr lParam;
}
 
private enum ABMsg
{
ABM_NEW = 0,
      ABM_REMOVE = 1,
      ABM_QUERYPOS = 2,
      ABM_SETPOS = 3,
      ABM_GETSTATE = 4,
      ABM_GETTASKBARPOS = 5,
      ABM_ACTIVATE = 6,
      ABM_GETAUTOHIDEBAR = 7,
      ABM_SETAUTOHIDEBAR = 8,
      ABM_WINDOWPOSCHANGED = 9,
      ABM_SETSTATE = 10
}
 
private enum ABEdge
{
ABE_LEFT = 0,
      ABE_TOP = 1,
      ABE_RIGHT = 2,
      ABE_BOTTOM = 3,
}
 
private enum ABState
{
ABS_MANUAL = 0,
      ABS_AUTOHIDE = 1,
      ABS_ALWAYSONTOP = 2,
      ABS_AUTOHIDEANDONTOP = 3
}
 
[DllImport("shell32.dll")]
private static extern IntPtr SHAppBarMessage(ABMsg dwMessage, [In, Out] ref APPBARDATA pData);

Using SHAppBarMessage

In order to use SHAppBarMessage we must first fill out the APPBAR struct with at least the cbSize and hWnd members. For hWnd we need to get the handle to the system taskbar window. It just so happens that you can use the FindWindow API function with a system class name of “Shell_TrayWnd” to get the required handle. Of course, to the best of my knowledge the class name “Shell_TrayWnd” is not a “documented” part of the Win32 system therefore it could change with any Windows release. However, I think it’s probably a safe bet to rely on it given the number of applications in the field that already do. Without further ado, some code to get the size of the task bar.

[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
 
APPBARDATA appBar = new APPBARDATA();
 
appBar.hWnd = FindWindow("Shell_TrayWnd", "");
appBar.cbSize = Marshal.SizeOf(appBar);
 
System.IntPtr ret = SHAppBarMessage(ABMsg.ABM_GETTASKBARPOS, ref appBar);
 
Size s = new Size(appBar.rc.right - appBar.rc.left, appBar.rc.bottom - appBar.rc.top);

Simple right?

Modifying the Taskbar

Remember earlier I said the system taskbar is not quite like a normal appbar? Well it’s special in that you can’t really change any of its properties like its size or position. This makes sense as you wouldn’t just want any program you install to play with the users taskbar; it’s sort of like an invasion of privacy. I’ve seen claims around the Internet that this can be pulled off in application code, which may be true prior to Vista; however I’ve tried all kinds of tricks based on SHAppBarMessage and can’t change the taskbar properties under Vista. Do you know how this can be done or if it’s even possible? I have found that you can change the task bar state. That is, you can toggle between “autohide” mode and “always on top” mode.

Example Taskbar Code

So, here is a little class I’ve put together to wrap the SHAppBarMessage functionality. I really haven’t paid attention to error handling or anything with it so if you use this you would need to address that.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
 
namespace TaskbarInfoExample
{
    /// <summary>
    /// Provides methods for obtaining and modifying information for the system taskbar.
    /// </summary>
    class TaskBar
    {
        #region Native API
        // The native API functions/enums/structs needed to access taskbar info
        // consult MSDN for more detailed information about them
        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }
 
        [StructLayout(LayoutKind.Sequential)]
        private struct APPBARDATA
        {
            public Int32 cbSize;
            public IntPtr hWnd;
            public Int32 uCallbackMessage;
            public ABEdge uEdge;
            public RECT rc;
            public IntPtr lParam;
        }
 
        private enum ABMsg
        {
            ABM_NEW = 0,
            ABM_REMOVE = 1,
            ABM_QUERYPOS = 2,
            ABM_SETPOS = 3,
            ABM_GETSTATE = 4,
            ABM_GETTASKBARPOS = 5,
            ABM_ACTIVATE = 6,
            ABM_GETAUTOHIDEBAR = 7,
            ABM_SETAUTOHIDEBAR = 8,
            ABM_WINDOWPOSCHANGED = 9,
            ABM_SETSTATE = 10
        }
 
        private enum ABEdge
        {
            ABE_LEFT = 0,
            ABE_TOP = 1,
            ABE_RIGHT = 2,
            ABE_BOTTOM = 3,
        }
 
        private enum ABState
        {
            ABS_MANUAL = 0,
            ABS_AUTOHIDE = 1,
            ABS_ALWAYSONTOP = 2,
            ABS_AUTOHIDEANDONTOP = 3
        }
 
        [DllImport("shell32.dll")]
        private static extern IntPtr SHAppBarMessage(ABMsg dwMessage, [In, Out] ref APPBARDATA pData);
 
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        #endregion
 
        /// <summary>
        /// Represents the edge of the screen the task bar is docked to.
        /// </summary>
        public enum TaskBarEdge
        {
            Left = ABEdge.ABE_LEFT,
            Top = ABEdge.ABE_TOP,
            Right = ABEdge.ABE_RIGHT,
            Bottom = ABEdge.ABE_BOTTOM
        }
 
        /// <summary>
        /// The states the task bar can be in.
        /// </summary>
        [Flags]
        public enum TaskBarState
        {
            /// <summary>
            /// No autohide, not always top
            /// </summary>
            None = ABState.ABS_MANUAL,
 
            /// <summary>
            /// Hides task bar when mouse exits task bar region
            /// </summary>
            AutoHide = ABState.ABS_AUTOHIDE,
 
            /// <summary>
            /// Taskbar is always on top of other windows
            /// </summary>
            AlwaysTop = ABState.ABS_ALWAYSONTOP
        }
 
        /// <summary>
        /// Gets the location, in screen coordinates of the task bar.
        /// </summary>
        /// <returns>The taskbar location.</returns>
        public static Point GetTaskBarLocation()
        {
            APPBARDATA appBar = GetTaskBarData();
 
            return new Point(appBar.rc.left, appBar.rc.top);
        }
 
        /// <summary>
        /// Gets the size, in pixels of the task bar.
        /// </summary>
        /// <returns>The taskbar size.</returns>
        public static Size GetTaskBarSize()
        {
            APPBARDATA appBar = GetTaskBarData();
 
            return new Size(appBar.rc.right - appBar.rc.left, appBar.rc.bottom - appBar.rc.top);
        }
 
        /// <summary>
        /// Gets the edge of the screen that the task bar is docked to.
        /// </summary>
        /// <returns></returns>
        public static TaskBarEdge GetTaskBarEdge()
        {
            APPBARDATA appBar = GetTaskBarData();
 
            return (TaskBarEdge)appBar.uEdge;
        }
 
        /// <summary>
        /// Gets the current state of the taskbar.
        /// </summary>
        /// <returns></returns>
        public static TaskBarState GetTaskBarState()
        {
            APPBARDATA appBar = CreateAppBarData();
 
            return (TaskBarState)SHAppBarMessage(ABMsg.ABM_GETSTATE, ref appBar);
        }
 
        /// <summary>
        /// Sets the state of the task bar.
        /// </summary>
        /// <param name="state">The new state.</param>
        public static void SetTaskBarState(TaskBarState state)
        {
            APPBARDATA appBar = CreateAppBarData();
 
            appBar.lParam = (IntPtr)state;
 
            SHAppBarMessage(ABMsg.ABM_SETSTATE, ref appBar);
        }
 
        /// <summary>
        /// Gets an APPBARDATA struct with valid location,size,and edge of the taskbar.
        /// </summary>
        /// <returns></returns>
        private static APPBARDATA GetTaskBarData()
        {
            APPBARDATA appBar = CreateAppBarData();
 
            System.IntPtr ret = SHAppBarMessage(ABMsg.ABM_GETTASKBARPOS, ref appBar);
 
            return appBar;
        }
 
        /// <summary>
        /// Creats an APPBARDATA struct with its hWnd member set to the task bar window.
        /// </summary>
        /// <returns></returns>
        private static APPBARDATA CreateAppBarData()
        {
            APPBARDATA appBar = new APPBARDATA();
 
            appBar.hWnd = FindWindow("Shell_TrayWnd", "");
            appBar.cbSize = Marshal.SizeOf(appBar);
 
            return appBar;
        }
    }
}

That’s All!

That’s all I’ve got for now. I have included a little demo app you can download to demonstrate the class. You can find that here Basically it just allows you to modify the task bar state and shows you all of its properties.

Hope you found this useful and saved yourself some time!

May 10, 2009   Posted in: C#, Programming  6 Comments

Launching and Viewing Processes in C#

You can launch a new process from a C# application by using the Process class located in the System.Diagnostics namespace. The Process class also allows you to obtain a collection of all running processes on the system.

How to Launch a New Process

Starting a process is really easy.

Process.Start( "Notepad.exe" );

And that’s it. If Notepad.exe exists on your system then it will start. Make sure that if you do not specify a complete path then the name you do present is available in your environment path. You can wait for the newly created process to terminate as well.

Process p = Process.Start( "Notepad.exe");
 
p.WaitForExit();

Keep in mind that WaitForExit will block the calling thread. If you don’t want that behavior considering launching the new process on a thread of its own. You can also use the ProcessStartInfo class to pass information to the Start method. This example launches the new process on a thread from the thread pool via an anonymous method. Remember to include System.Threading.

// launch the program / process on a new thread from the thread pool
ThreadPool.QueueUserWorkItem( (WaitCallback)delegate(object state)
{
    ProcessStartInfo psi = new ProcessStartInfo("Notepad.exe", "");
 
    Process p = Process.Start(psi);
 
    p.WaitForExit();
});

Passing Arguments to the New Process

You can also pass arguments to a new process. The next example will launch Notepad and tell it to open the file MyFile.txt.

ProcessStartInfo psi = new ProcessStartInfo("Notepad.exe", @"C:\My\Path\MyFile.txt");
 
Process p = Process.Start(psi);

Launching a Document and Setting the Verb

There are some other interesting things you can do with the Process class. For instance, instead of specifying a file name in Process.Start like we did above with Notepad.exe, we could specify a file or document. The method would then open that file with the registered default application for that type of file. You can also specify a verb that is associated with that file type. A verb represents an action that is associated with that file type. So, if I wanted to launch the default application for a .txt file and have that file printed I could do the following:

ProcessStartInfo psi = new ProcessStartInfo(@"C:\My\Path\MyFile.txt");
psi.Verb = "print";
 
Process p = Process.Start(psi);
 
p.WaitForExit();

Listing All Running Processes

The last thing I want to show you is how easy it is to view a list of all processes running on the system with C#. Assuming you have a ListBox name listbox1, the following code fragment would add an entry to the ListBox with the name of each process running on the system.

Process[] processes = Process.GetProcesses();
 
foreach( Process process in processes )
   listBox1.Items.Add( process.ProcessName );

Well, that’s it for today. Hope this information comes in handy for some of you!

April 15, 2009   Posted in: C#, Programming  3 Comments

How To Get Screen Shot Capture in C#

It’s often necessary to programmatically get a screen shot of the desktop and save it to a file. This is pretty easy with C#; we can create a simple method that will save an image of whatever is on the screen or desktop.

Saving a Bitmap Image of the Screen

First make sure you include the System.Drawing.Imaging namespace. Now, all we really have to do is create a new bitmap and use the CopyFromScreen method of the bitmaps Graphics device.

/// <summary>
/// Saves a screen capture in the specified image format to a file.
/// </summary>
/// <param name="filename"></param>
/// <param name="format"></param>
private void SaveScreenShot(string filename, ImageFormat format)
{
        Bitmap screenShot = CaptureScreenShot();
 
  	screenShot.Save(filename, format);
}
 
/// <summary>
/// Saves a picture of the screen to a bitmap image.
/// </summary>
/// <returns>The saved bitmap.</returns>
private Bitmap CaptureScreenShot()
{
 	// get the bounding area of the screen containing (0,0)
        // remember in a multidisplay environment you don't know which display holds this point
    	Rectangle bounds = Screen.GetBounds(Point.Empty);
 
    	// create the bitmap to copy the screen shot to
   	Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
 
    	// now copy the screen image to the graphics device from the bitmap
   	using (Graphics gr = Graphics.FromImage(bitmap))
   	{
       	   gr.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
   	}
 
  	return bitmap;
}

And that’s really all there is to capturing a screen shot. You can save it to whatever file you would like and in any of the image formats supported by ImageFormat such as PNG or JPEG. Keep in mind if your working in a multidisplay environment you’ll want to be careful which display your targeting. Or perhaps you may want a huge image of all the desktop displays.

You can use the above code simply by calling the SaveScreenShot method with a file name and image format to save to:

//save screen shot in PNG image format
SaveScreenShot("MyScreenShot.png", ImageFormat.Png);

With a really small change you can modify the above code to save a screen shot of an arbitrary control instead of the entire desktop display.

Saving a Screen Capture of a Control

/// <summary>
/// Saves a screen capture of the specified control to a file.
/// </summary>
/// <param name="control"></param>
/// <param name="filename"></param>
/// <param name="format"></param>
private void SaveControlShot(Control control, string filename, ImageFormat format)
{
   	Bitmap controlShot = CaptureControlShot(control);
 
   	controlShot.Save(filename, format);
}
 
/// <summary>
/// Gets a bitmap image of the specified control.
/// </summary>
/// <param name="control"></param>
/// <returns></returns>
private Bitmap CaptureControlShot(Control control)
{
        // get control bounding rectangle
     	Rectangle bounds = control.Bounds;
 
   	// create the new bitmap that holds the image of the control
     	Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
 
   	// copy controls image data to the bitmaps graphics device
    	using (Graphics gr = Graphics.FromImage(bitmap))
    	{
        	gr.CopyFromScreen(control.Location, Point.Empty, bounds.Size);
     	}
 
    	return bitmap;
}

And you can use this just as easily as the previous screen capture method:

// if "this" is a control, like a form
SaveControlShot(this, "MyControlShot.png", ImageFormat.Png);

And there you have it, an example of simple methods for saving a screen shot or an image of a control. I Hope you find this helpful.

April 13, 2009   Posted in: C#, Programming  11 Comments

Introduction to Multithreading in C#

This article is a very basic introductory tutorial for using multiple threads in C#. I’ll explain what threads are, why you would want to use them, and how to use them. I’ll also show you several examples for creating threads, killing threads, etc.

What’s a Thread?

A computer program is generally very linear. That is, you have a sequence of instructions that get executed one after another in an orderly and predictable fashion. This scenario only affords you one path of execution. Threads allow you to execute multiple paths of code simultaneously. Now, simultaneously in this case does not necessarily mean physically at the same time. Both your operating system and processor must support this for that to be true. Threads are not particular to C#; most modern programming languages such as Visual Basic.Net support the concept of threads.

So Why Do I Need Multiple Threads?

Threading is handy because many programming tasks are asynchronous. That is, I can start the task and go on about my business and when that task is finished it can let me know and I can take action. An example of this would be downloading files from a remote location. I can start downloading three files and when the first is finished I can process it while the others continue to download.

There are numerous other reasons. Consider for instance a long task like sorting a million numbers. If I start that task on the thread that runs the GUI then I couldn’t update my user interface which means I couldn’t respond to user requests like button clicks.

Ok, lets move on to an example of creating a new thread via C#.

Creating a Thread with C#

Creating a thread is easy; we make use of the Thread object from the System.Threading namespace. When we create the thread we must pass it a ParameterizedThreadStart or ThreadStart delegate. This will be the method that gets invoked on the new thread – it’s the starting point. New threads begin life in a stopped state. To make it run we call the Thread.Start method.

Thread myThread = new Thread(MyThreadFunction);
myThread.Start();
 
private void MyThreadFunction()
{
   MessageBox.Show("HI");
}

Congratulations, you’ve created your first thread that runs in parallel with your main thread.

Passing an Argument to the New Thread

You can easily pass an argument to the thread like so:

Thread myThread = new Thread(MyThreadFunction);
myThread.Start("HELLO WORLD");
 
private void MyThreadFunction(object x)
{
   MessageBox.Show(x as string);
}

Keep in mind that this is not the best way to pass data to the thread. Since Thread.Start accepts only an object this is not very type safe. Image if we didn’t pass a string or the object didn’t have a ToString method. The best way to accomplish this would be to encapsulate your thread function in a class with data members you could set ahead of time.

Waiting for a Thread to Stop

Now that we have our thread up and running, we may at some point wish to wait for it to complete. This is accomplished with the Thread.Join method. Here is an example for Thread.Join:

myThread = new Thread(MyThreadFunction);
myThread.Start("HELLO WORLD");
 
myThread.Join();
 
MessageBox.Show("ALL DONE!");
 
//-elsewhere
private void MyThreadFunction(object x)
{
   MessageBox.Show(x as string);
}

When the first piece of code executes it will create a new thread that will begin running in MyThreadFunction. After calling myThread.join that thread will go to sleep and stop executing until MyThreadFunction returns. This will happen after you dismiss the message box. Finally, when MyThreadFunction exits and the thread is destroyed, the original thread will continue execution at the next statement and pop its message box.

One thing to watch out for is what happens if the thread function never returns meaning the thread never dies. In this situation you can specify a timeout value in Thread.Join. The method will block for a predetermined amount of time waiting for the thread to terminate. If the thread did not terminate then Thread.Join would return false.

Stopping a Thread

Stopping a thread is simple. You call Thread.Abort on the thread you wish to stop.

myThread.Abort();

This will cause a ThreadAbortException to be raised on the thread you are trying to stop. Now this usually stops the thread. It’s possible that the thread can abort your abort and continue living. There are a few other circumstances that can prevent the thread from aborting.

Sharing Variables

When you have two or more threading running it’s possible that they could be executing at the same time. This can create problems when both threads are trying to read/write to the same variable. You have to synchronize thread access to shared variables. There are many synchronization primitives available to you in C# via the .Net Framework Library such as AutoResetEvent, Monitor, and Mutex. This is a big subject so I will defer it till another post.

Along those same lines here’s a tip: If you create secondary threads they cannot modify controls on your GUI. Only the thread that created a control can modify its properties. You will generate the dreaded illegal cross thread exception. I’ve already posted a brief work around for this problem

So that’s it for my C# threading tutorial. Now you know the basics of how to create a thread, how to kill a thread, how to wait for a thread, and some general threading principles. This is a big subject and I’ve hardly done it justice with this little bit of writing. If there are sufficient interests, I will elaborate on some more advance multithreading techniques that are applicable in all .Net languages – not just C#. I’ll leave you with a small incomplete pro and con list about using multiple threads.

Advantages of Multithreading

  • Improved performance – Multiple threads can execute concurrently.
  • Streamline application logic – Some tasks are easier to conceptualize this way
  • Improves responsiveness of an application – GUI still works under heavy load.

Disadvantages of Multithreading

  • Hard to write and debug – Nuff said!!
  • Performance impact from synchronizing access to shared variables
  • There is a limit to how many threads an operating system can handle efficiently
  • Context switching between threads can hurt performance

April 8, 2009   Posted in: C#, Programming  2 Comments

C# – Dynamically Invoke Web Service At Runtime

Web services have become an integral part of the communications between software over a network. There are a lot of ugly details behind how they work but thankfully C# hide a lot of those gory details. What you need to know is that there is a web service description (WSDL) that describes the available services and the data types they use (via XML).

You can use the WSDL to create types in C# that can communicate with the web service. There are a couple of ways that you can do this. You can generate a proxy class using the WSDL utility in the .NET SDK and add it to your project. You can also download the WSDL file at runtime, create the proxy class, compile it into an assembly, and execute the methods on it. This allows you to dynamically invoke methods from a web service that aren’t known at build time and is the approach I will explore today.

Step 1 – Obtain a ServiceDescriptionImporter

We want to create a ServiceDescriptionImporter object that we can use to generate the web service proxy class. We have to pass to it the WSDL location which is an XML document.

XmlTextReader xmlreader = new XmlTextReader(“MyWebService” + "?wsdl");
 
ServiceDescription serviceDescription = ServiceDescription.Read(xmlreader);
 
// build an importer, that assumes the SOAP protocol, client binding, and generates properties
ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
descriptionImporter.ProtocolName = "Soap";
descriptionImporter.AddServiceDescription(serviceDescription, null, null);
descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

Step 2 – Compile an Assembly from the importer

Now that we have the ServiceDescriptionImporter we need to use it to compile a proxy assembly that we can use to communicate with the web service. The assembly will exist in the users’ temporary folder.

// a namespace and compile unit are needed by importer
CodeNamespace codeNamespace = new CodeNamespace();
CodeCompileUnit codeUnit = new CodeCompileUnit();
 
codeUnit.Namespaces.Add(codeNamespace);
 
ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);
 
if (importWarnings == 0) // no warnings
{
     // create a c# compiler
     CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");
 
     // include the assembly references needed to compile
     string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
 
     CompilerParameters parameters = new CompilerParameters(references);
 
     // compile into assembly
     CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit);
 
     foreach (CompilerError oops in results.Errors)
     {
          // trap these errors and make them available to exception object
          throw new Exception("Compilation Error Creating Assembly");
     }
 
     // all done....
     return results.CompiledAssembly;
}
else
{
     // warnings issued from importers, something wrong with WSDL
     throw new Exception("Invalid WSDL");
}

Step 3 – Execute Methods from the Web Service

Finally we have an assembly built from the web service description and now we can invoke methods from it just like any other ordinary assembly we might use. To accomplish this we must use reflection to discover the correct method.

object obj = this.webServiceAssembly.CreateInstance(serviceName);
 
Type type = obj.GetType();
 
return (T)type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args);

And there you have it, dynamic invocation of web service methods at runtime. Using this technique you can invoke methods from any arbitrary web service at runtime.

Here is a full example class for dynamically invoking a web service method in C#.

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Discovery;
using System.Xml;
 
namespace DynamicWebExample
{
    class WebServiceInvoker
    {
        Dictionary<string, Type> availableTypes;
 
        /// <summary>
        /// Text description of the available services within this web service.
        /// </summary>
        public List<string> AvailableServices
        {
            get{ return this.services; }
        }
 
        /// <summary>
        /// Creates the service invoker using the specified web service.
        /// </summary>
        /// <param name="webServiceUri"></param>
        public WebServiceInvoker(Uri webServiceUri)
        {
            this.services = new List<string>(); // available services
            this.availableTypes = new Dictionary<string, Type>(); // available types
 
            // create an assembly from the web service description
            this.webServiceAssembly = BuildAssemblyFromWSDL(webServiceUri);
 
            // see what service types are available
            Type[] types = this.webServiceAssembly.GetExportedTypes();
 
            // and save them
            foreach (Type type in types)
            {
                services.Add(type.FullName);
                availableTypes.Add(type.FullName, type);
            }
        }
 
        /// <summary>
        /// Gets a list of all methods available for the specified service.
        /// </summary>
        /// <param name="serviceName"></param>
        /// <returns></returns>
        public List<string> EnumerateServiceMethods(string serviceName)
        {
            List<string> methods = new List<string>();
 
            if (!this.availableTypes.ContainsKey(serviceName))
                throw new Exception("Service Not Available");
            else
            {
                Type type = this.availableTypes[serviceName];
 
                // only find methods of this object type (the one we generated)
                // we don't want inherited members (this type inherited from SoapHttpClientProtocol)
                foreach (MethodInfo minfo in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
                    methods.Add(minfo.Name);
 
                return methods;
            }
        }
 
        /// <summary>
        /// Invokes the specified method of the named service.
        /// </summary>
        /// <typeparam name="T">The expected return type.</typeparam>
        /// <param name="serviceName">The name of the service to use.</param>
        /// <param name="methodName">The name of the method to call.</param>
        /// <param name="args">The arguments to the method.</param>
        /// <returns>The return value from the web service method.</returns>
        public T InvokeMethod<T>( string serviceName, string methodName, params object[] args )
        {
            // create an instance of the specified service
            // and invoke the method
            object obj = this.webServiceAssembly.CreateInstance(serviceName);
 
            Type type = obj.GetType();
 
            return (T)type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args);
        }
 
        /// <summary>
        /// Builds the web service description importer, which allows us to generate a proxy class based on the 
        /// content of the WSDL described by the XmlTextReader.
        /// </summary>
        /// <param name="xmlreader">The WSDL content, described by XML.</param>
        /// <returns>A ServiceDescriptionImporter that can be used to create a proxy class.</returns>
        private ServiceDescriptionImporter BuildServiceDescriptionImporter( XmlTextReader xmlreader )
        {
            // make sure xml describes a valid wsdl
            if (!ServiceDescription.CanRead(xmlreader))
                throw new Exception("Invalid Web Service Description");
 
            // parse wsdl
            ServiceDescription serviceDescription = ServiceDescription.Read(xmlreader);
 
            // build an importer, that assumes the SOAP protocol, client binding, and generates properties
            ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
            descriptionImporter.ProtocolName = "Soap";
            descriptionImporter.AddServiceDescription(serviceDescription, null, null);
            descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
            descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;
 
            return descriptionImporter;
        }
 
        /// <summary>
        /// Compiles an assembly from the proxy class provided by the ServiceDescriptionImporter.
        /// </summary>
        /// <param name="descriptionImporter"></param>
        /// <returns>An assembly that can be used to execute the web service methods.</returns>
        private Assembly CompileAssembly(ServiceDescriptionImporter descriptionImporter)
        {
            // a namespace and compile unit are needed by importer
            CodeNamespace codeNamespace = new CodeNamespace();
            CodeCompileUnit codeUnit = new CodeCompileUnit();
 
            codeUnit.Namespaces.Add(codeNamespace);
 
            ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);
 
            if (importWarnings == 0) // no warnings
            {
                // create a c# compiler
                CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");
 
                // include the assembly references needed to compile
                string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
 
                CompilerParameters parameters = new CompilerParameters(references);
 
                // compile into assembly
                CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit);
 
                foreach (CompilerError oops in results.Errors)
                {
                    // trap these errors and make them available to exception object
                    throw new Exception("Compilation Error Creating Assembly");
                }
 
                // all done....
                return results.CompiledAssembly;
            }
            else
            {
                // warnings issued from importers, something wrong with WSDL
                throw new Exception("Invalid WSDL");
            }
        }
 
        /// <summary>
        /// Builds an assembly from a web service description.
        /// The assembly can be used to execute the web service methods.
        /// </summary>
        /// <param name="webServiceUri">Location of WSDL.</param>
        /// <returns>A web service assembly.</returns>
        private Assembly BuildAssemblyFromWSDL(Uri webServiceUri)
        {
            if (String.IsNullOrEmpty(webServiceUri.ToString()))
                throw new Exception("Web Service Not Found");
 
            XmlTextReader xmlreader = new XmlTextReader(webServiceUri.ToString() + "?wsdl");
 
            ServiceDescriptionImporter descriptionImporter = BuildServiceDescriptionImporter(xmlreader);
 
            return CompileAssembly(descriptionImporter);
        }
 
        private Assembly webServiceAssembly;
        private List<string> services;
    }
}

This C# class can be easily used to invoke web service methods:

WebServiceInvoker invoker = new WebServiceInvoker(new Uri("http://localhost/services/test.php"));
 
string service = “MyService”;
string method = “MyMethod”;
 
string[] args = new string[] { “arg1”, “arg2” };
 
string result = invoker.InvokeMethod<string>(service, method, args);

I’ve put together an example application that you can download to evaluate the class. It allows you to invoke methods from a web service entered on the GUI and see the return value. You can download it here.

I hope you find this useful and if you have any questions or comments be sure to leave them here.

April 8, 2009   Posted in: Programming  57 Comments