HomeDigital EditionSearch Dotnet Cd
ASP.NET C# Certification Exams The CLI Data Access Editorials Extending .NET Fundamentals Interoperability Interviews Migrate Mobile .NET Mono .NET Interface Object-Oriented Programming Open Source Optimization Product/Book Reviews Security Source Code UML Visual Studio .NET

When I started this article, there were a lot of interesting points to highlight about changes that needed to be made when porting a GDI+ desktop application to Pocket PC. Then Visual Studio .NET 2003 (codenamed Everett) came on the scene. If porting an application created with the Compact Framework was already easy, the subtle changes in the Compact Framework, which is now delivered as part of Everett, make things even simpler.

The .NET Framework opens whole new horizons to programmers ­ especially to game programmers ­ with its ability to run the same code across different devices running different operating systems. Of course this compatibility will never be 100%, since every device has its own characteristics, strengths, and weaknesses, but it's really great to be able to write a program for a PC and then make it run on a Pocket PC with just a few adjustments!

In previous versions of Visual Studio (before .NET), if we wanted to create a program to run on a mobile device such as the Pocket PC we had to use a specific version of the compiler, and the operating system made no compromises to provide compatible functions. Porting a program was sometimes a matter of erasing and rewriting everything. This portability problem was especially evident when dealing with graphical functions. Even simple programs sometimes needed adjustments before running on a different device.

Creating a Smart Device Application on Everett
Visual Studio .NET 2003 already has built-in support for the .NET Compact Framework, with the corresponding assemblies and project templates to support projects targeting mobile devices. The new project templates are named "Smart Device Application" and "ASP.NET Mobile Application", and they allow us to create applications to be used on either Pocket PC or Windows CE­based devices. Figure 1 shows the "New Solution" window of Visual Studio, highlighting the Smart Device Application item.

Figure 1

Once the project is created, we can see that we have new menu options: in the Tools menu, there's a "Connect to Device" option, and under the Build menu there is a new option to "Deploy".

After creating a program, we can press the Start button on the Visual Studio toolbar just like we would do in any project targeting common PCs. Visual Studio will then build the program with the proper libraries according to the platform we choose, and open a window that will allow us to choose the target device for the application, as presented in Figure 2.

Figure 2

If we choose to deploy the program to the emulator, Visual Studio will load the emulator before deployment. The emulator is an exact copy of the Pocket PC system, including all programs (yes, it comes with "Solitaire," too) and allows us to even choose an emulator "skin," which is a bitmap with active buttons. It allows us to test our application in the exactly same way we would with a real device, without needing a real device.

Once the emulator is loaded or the device is connected, Visual Studio .NET will deploy not only the application but also any necessary libraries to make the program run on the desired device. The application will be deployed to the \Windows directory on the device, and Visual Studio will automatically run it, even allowing us to debug it.

Porting an Existing Application to Pocket PC
We will be able to run any simple desktop PC program with very few adjustments using the Smart Device Application template, and some programs won't need any updates, just a new compilation and, of course, replacing the form interface controls with the corresponding ones for the Smart Device Application.

As for the graphical functions, of course GDI+ is not completely present in the mobile device, but many of its functions are there and use the same interfaces, so porting graphical applications is simpler than in any previous version of Visual Studio.

To illustrate some common problems we face when porting an application based on GDI+ to Pocket PC, we will create a Tetris clone called .Nettrix. This sample comes from my book, .NET Game Programming, in which a desktop version is created in Chapter 1. We will not present all code here, just some highlights, but the full code is available below.

Creating the Interfaces
The first, somewhat tedious, step in porting an application to a mobile device is re-creating all the interface elements, since there's no wizard to port the forms for us. Figure 3 presents similar screens created for Pocket PC and desktop PC.

Figure 3

Copying the Code
After creating the interface elements, we can copy all code (from the forms and other modules) to the mobile device program. In our sample game, the code is organized in four modules: the main form and three classes, as presented in the simplified class diagram shown in Figure 4.

Figure 4

The Square class draws and erases a square on the screen; the Block class draws, erases, and moves four squares to form basic .Nettrix blocks with different shapes, and the GameEngine class has some general- use functions, such as the collision-detection support array and the basic functions to deal with it. Besides these classes, I implemented the game logic directly in the main form events. The game variables are initialized in the Load event; the game loop is in the Tick event of a timer, and the input handling routine is in the KeyPress event.

Fixing the Errors
Although it's not my goal here to discuss all the possible issues you can face when porting a GDI+ application to a mobile device, I will provide a good example of each of the error classes:

  • Compilation errors due to modifications in the functions or event interfaces or other programming elements
  • Compilation errors due to missing features in the target platform
  • Runtime errors due to different behavior of compatible functions or object initialization
  • Program malfunctions in which there are no visible errors, but the program doesn't work as expected, due to slightly different behavior in compatible functions
  • Modifications in functions, events, and other programming elements

    An example of this last type of error is the modification of the parameters of the MessageBox Show event, which are different on the Pocket PC version. The last parameter (the default button) is mandatory, and we also have to take care selecting the icon used, since some icons are not used. For instance, the Stop icon corresponds, in the Pocket PC, to the Hand icon, the name formerly used on the desktop platform. So the desktop PC code line

    MessageBox.Show("GAME OVER", ".NetTrix",
    MessageBoxButtons.OK, _ MessageBoxIcon.Stop)

    must be ported to Pocket PC as

    MessageBox.Show("GAME OVER",
    ".NetTrix", MessageBoxButtons.OK, _ MessageBoxIcon.Hand,
    MessageBoxDefaultButton.Button1)

    This illustrates perfectly the first type of error we would expect to find when porting games to mobile devices: some functions take slightly different parameters, and some of the overrides (different ways to call the same functions) are missing. These are the easier problems to solve, since all we have to do is make simple adjustments such as completing the extra parameters or correcting the parameter values.

    Another example of this kind of error is the modification of some events names and arguments. For example, the Activated event for the form doesn't exist on the Pocket PC, which uses the corresponding event, GotFocus.

    Missing Features
    The second type of problem we face when porting games to mobile devices is that some functions, methods, and events are missing or correspond to different ones. This kind of error may be somewhat difficult to fix, since we must look for the relevant method, event, or function and, if there's no exact match, sometimes we'll need to rewrite part of the program.

    In my sample game, I came across one error of this type in the Show method of the Square class: the Graphics object for the Pocket PC is far simpler than the one for desktop computers; and it doesn't support the DrawPath method used to draw a gradient square on the desktop version of the game. In this case I needed to rewrite the Draw method of this class to make it simply draw a square with a solid border.

    The desktop PC version of the Show method, which draws a nice rectangle filled with a gradient path, is presented in Listing 1 The Pocket PC version of the same method is far simpler, as you can see in Listing 2.

    Another error of this type pertains to the creation of the Graphics object. While we can create a graphic for desktop PCs using the handle of any control, the Pocket PC version can only be created from an image. In fact, the controls on the Compact Framework don't have handles, so we must avoid functions that take a handle as a parameter, since they will not work on mobile devices.

    Fixing Runtime Errors
    After fixing the compilation errors, programs will run on the Pocket PC, but sometimes they abort as soon as they are run. In the first betas of the Compact Framework we faced some similar problems because all bitmap images from PictureBoxes had to be explicitly created, or else any command issued over them would fail. Fixing this problem was as simple as adding one extra line to the form's Load event.

    PicBackground.Image = New Bitmap(PicBackground.Width,
    PicBackground.Height)

    This type of error doesn't happen in Everett; but it illustrates very well the third variety of error that we can find when moving programs to other platforms such as mobile devices: there are no more build errors, but the program generates a runtime error because something (a function, method, or event) doesn't behave as expected.

    This class of errors is a little more difficult than the previous ones to fix, since the error can occur in a different place from where it is generated. For example, if we don't explicitly create the image for the PictureBox, the error will occur when the Square class tries to draw a square and, depending on how we created the error-trapping routines, we might need to set breakpoints and do a step-by-step debug to discover where the error is occurring and how.

    Fixing Program Malfunctioning
    Once all compilation and runtime errors have been fixed, we are ready to face the last and toughest error category we will encounter when porting programs: everything works fine, but something doesn't behave as expected. Or, in other words, there are no errors, but our program doesn't work as planned.

    Figure 5 presents one such error that occurred when porting .Nettrix to an earlier version of Visual Studio with the Compact Framework. The screen was not updated by the drawing routines, and we could only see the blocks on the game field after closing the "game over" dialog box, which forced a redraw of the underlying PictureBox.

    Figure 5

    In Everett this undesirable behavior is fixed, but let's continue with this example just to see what we should do in this situation. The code has no intrinsic errors, since this same code ran on a normal desktop computer. Taking a new look at the program, we can't find anything wrong, and even the documentation for mobile devices gives us no clues. What to do?

    There are no magic tricks here: we must look for something similar that works, like SDK samples. If we look through the samples downloaded with the .NET Compact Framework, we'll find a simple graphical example called Bubbles. This program presents some circles moving on the screen, providing an illusion of floating soap bubbles.

    If we run through this example, we will discover that the main difference between the way our program updates the screen and the way this sample does is that this sample draws directly to the screen using a Graphics object created by the CreateGraphics function that receives the form handle as a parameter. In contrast, our program does the drawing in a Graphics object created from a bitmap contained in a PictureBox.

    To make .Nettrix run in Visual Studio .NET 2001, we needed to modify the drawing routines to draw directly on the form, forgetting the PictureBoxes. In Everett, fortunately, the same routines would run in both platforms.

    Final Touches
    Creating any extra interface elements is a final touch that can enhance the usability of the program. In our .Nettrix game, we created a set of buttons that can be used by tapping with a pen on the Pocket PC, while allowing keyboard input so desktop PC users can use navigation keys to play the game. Figure 6 presents the game, running on the Pocket PC emulator.

    Figure 6

    Conclusion
    One of the most interesting details about the migration of this specific game is that once we have migrated the code to Pocket PC, we can copy all the code back to the desktop .Nettrix project, and it will run without any modification. After the updates, the code is 100% compatible with both platforms, since the GDI+ on the Pocket PC is a subset of the GDI+ for desktops, and all other functions used are present on both platforms.

    About The Author
    Alexandre Santos Lobäo got his first computer in 1981 at age 12 and immediately began creating simple games in Basic. Since then, computers have evolved greatly and so has he. After many years of working on informatics in areas ranging from banking to small business, and computers ranging from the IBM 3090 to Pocket PCs, he managed to return to his first passion, putting his knowledge gained as a long-term nonprofessional game developer into his first technical book, .Net Game Programming with DirectX 9.0, published in March by APress. aslobao@hotmail.com

    	
    
    
    
    Listing 1
    
    Public Sub Show(ByVal Graph As Graphics)
            Dim graphPath As Drawing2D.GraphicsPath
            Dim brushSquare As Drawing2D.PathGradientBrush
            Dim surroundColor() As Color
            Dim rectSquare As Rectangle
    
    
            ' Create a path consisting of one rectangle
            graphPath = New Drawing2D.GraphicsPath()
            rectSquare = New Rectangle(location.X, location.Y, _
                                       size.Width, size.Height)
            graphPath.AddRectangle(rectSquare)
    
    
            ' Creates the gradient brush which will draw the square
            ' Note: Therešs one center color and an array of border colors 
            brushSquare = New
    		Drawing2D.PathGradientBrush(graphPath)
            brushSquare.CenterColor = forecolor
            surroundColor = New Color() {backcolor}
            brushSquare.SurroundColors = surroundColor
    
    
            ' Finally draws the square
            Graph.FillPath(brushSquare, graphPath)
        End Sub
    
    
    
    Listing 2
    
     Public Sub Show(ByVal Graph As Graphics)
            ' Draws the square
            Graph.FillRectangle(New Drawing.SolidBrush(backcolor),
           _location.X, location.Y, size.Width, size.Height)
            ' Draws the square border
            Graph.DrawRectangle(New Pen(forecolor), _
                            location.X, location.Y, size.Width -
    1, size.Height - 1)
    End Sub
    

    Additional Code: ~13.7 KB
    (Pocket PC Nettrix Folder)

    Additional Code... ~13.8 KB
    (DesktopNettrix Folder)

    All Rights Reserved
    Copyright ©  2004 SYS-CON Media, Inc.

      E-mail: info@sys-con.com