Sunday, November 27, 2011

Changing Icons in Visual C++ Express Edition

I recently started working on a game in C++, using (as a starting point) a game engine that I helped create in a Game Engine Architecture class I took at DeVry University this past year. I'll be revising the engine and tailoring it to my needs for the game, as well as abstracting the engine portion from the game portion (so it could potentially be reused, and also to get some experience with that kind of coding).

I decided that whenever I solved some troublesome problem or had something interesting to say about it, I'll blog it here. It didn't take long for me to find something.


Application Icons

Anyone who uses a computer knows what an icon is, right? It's used for a shortcut on your desktop, or the Title Bar for a window, or in the application window in the Taskbar. When programming in Windows, you can obviously customize that by using an .ico file, which is essentially a small bitmap image.



So... it seems like this should be something that's easy to change, yes? I thought so too, and ended up spending a few hours trying to figuring it out.

And before you say it, no, I'm not stupid. The problem stems from two things: 1) my relative green-ness at C++ coding (not an expert yet) and 2) the lack of features in the Express Editions of Microsoft's Visual C++ IDE. The Express Editions are free, which is great; however, they aren't as full featured as retail versions of Visual Studio, and that sometimes makes a task that should be very easy to do, a bit difficult.

Such is the case with the Express Edition. You can't programmatically add resources through the application and there's no resource editor. You can do it manually, though (anything can be done manually). Just a heads up, I currently use the 2008 edition and this tutorial will be written from that perspective.

Searching the Internet

Whenever I hit a roadblock in coding, the first thing I generally do is search the internet. Nine times out of ten, someone else has already asked the same question and gotten an answer. All you have to do is find it. So I start searching with Google.

The first thing that confused me about this problem, was that no one had a simple explanation of the entire process. It was in bits and pieces and I had to put it together (which prompted me to write this post). The second was that some people were talking about one or the other, i.e. the problem of the icon for the final .exe (desktop shortcut) you create vs. the icon used in the window title bar or taskbar. At first I didn't understand this distinction – I was focusing only on the window title bar icon, not the .exe one.

It took me a while to get this sorted out, so hopefully this complete explanation will help someone.

The Resource Header

The first thing you need when dealing with resources, is a header file that defines the resource variables you want to use in your project. We'll only need variables for small / large versions of your icon. Use Visual C++ to create a header file: right-click Header Files in the Solution Explorer, go to Add à New Item. In the templates, select Header File (.h), enter the name at the bottom (I called mine Resource.h) and click Add. There should be an empty .h file in your project now.

Open that header file and add this code:



    #define IDI_ICON_BIG 1
    #define IDI_ICON_SMALL 2



This defines two variables that we can use in our code. The compiler will treat them as integers (1 and 2), but a string version makes it easier for us to read in code. You can change those variables to whatever you want, but use the prefix of IDI_ since that's the standard format for icon resources and it's good practice to use that.

Before you save and close the file, add a few blank lines at the end. If you don't, you might get an error like this when you compile the header file later:

fatal error RC1004: unexpected end of file found

This is a bug in the compiler and is fixed by adding the extra lines at the end. I found the solution at a site called Code Library.

With your extra lines added, save and close the file.

The Resource File

Next, you can create the resource file itself. This file essentially associates resources (like an icon) to the variable that you use in code. In the IDE, a resource file is usually represented with a suffix of .rc. Aside from the resources themselves, all other files in a project/solution are generally text files. So the easiest way to create a resource file is to create a text file and save it in your project folder – the same folder as your winmain.cpp file – and use the .rc suffix instead of .txt when you save it. I named my file app.rc, but you can name it something else if you wish.

You can then edit the file in a generic editor like Notepad, or you can add it to your Solution in Visual C++ manually and edit there. To add it, right-click on Resource Files in the Solution Explorer and go to Add à Existing Item. Navigate to your .rc file, select it and click Add.

Now edit the file. You can have a different icon for each thing (executable, window title bar and taskbar), so we'll set it up that way even though you might want to use the same icon for all three. If you try to double-click the .rc file to edit it, you most likely will get this warning:

Curse you, Express Edition!!

To get around this, right-click the .rc file, select Open With on the menu, then in the dialog that appears, select "Source Code (Text) Editor." You'll now be able to edit it in the Code Window. Add this code:



    #include "Resource.h"
 
    IDI_MAIN_ICON ICON "res/app.ico"
    IDI_ICON_BIG ICON "res/XXXX.ico"
    IDI_ICON_SMALL ICON "res/YYYY.ico"



Where app.ico is the name of the icon file you want for the executable, and XXXX.ico and YYYY.ico are the names of your big and small icons for the windows, respectively. Replace those with your own names, but Windows will use app.ico as the default filename for the executable icon, so you'll need to use that for that specific icon file.

This associates your resource variables with the files themselves. You need to include Resource.h so the compiler knows their definitions. The ICON term denotes that it's an icon resource, and the path in quotes is the path to the file in your project.

Now, you could just put the .ico files in your main project folder, but if you have a lot of resources, it's better to keep them separated and organized. I put mine in a folder called res in the main project folder. You can put them wherever – just make sure the path is updated accordingly.

You can read more about Resource Files here.

Icon Files
If you don't already have your .ico files, go get them now and come back. If you're looking for some to test or whatnot, you can find free ones on the internet. I like this site, personally: Icon Archive.

If you have picture files that you want to convert to an icon, there are numerous websites that will do this for you. Here are a few to start with:
  
Once you have them, name them appropriately (app.ico for the executable, of course). Make sure the names match up to your .rc file and you have saved the files in the right location within your project folder tree. Add them to the Solution Explorer in the same manner as the .rc file previously (add existing item). You don't technically have to add them to the Explorer, as the compiler will know where to get them from the .rc file, but it's good practice and helps you keep tabs on your files.

Load the Icons

Everything is now in place to add your icons to the window / taskbar. In your code (winmain.cpp), you should have something that initializes the window class that you're using. Here are the pertinent lines of mine (the full code is linked further below):



    bool initWindow(HINSTANCE hInstance) {
 
    // initialize the window class
    WNDCLASSEX wcex;

    wcex.hIcon = LoadIcon(hInstance,
                     MAKEINTRESOURCE(IDI_ICON_BIG));
    wcex.hIconSm = LoadIcon(hInstance,
                     MAKEINTRESOURCE(IDI_ICON_SMALL));
    // other wcex properties excised...

    RegisterClassEx(&wcex);

    // code excised...

    return true
    }



For the hIcon and hIconSm properties, you merely load the icon with LoadIcon, using the variables we set up in the resource header and resource file. Rebuild your project and voila, the window, taskbar and executable should have the correct icons!

Compiler Notes

If you're experimenting a lot and your project doesn't take too long to build, a good thing to do is to clean your solution before rebuilding it. What this does is delete the compile-time files that are generated, like the executable, or a .res file.

Speaking of .res files, this is a compiled file that consists of all resource objects (icons, bitmaps, etc) and associated .rc files. Visual C++ will compile this for you from the files in your project, and it should appear in the Debug folder under the main project folder after rebuilding.

You can compile these files yourself by using the Resource Compiler (rc.exe) that comes with the Windows SDK. Search for it on your computer, place any .rc and associated resource files in the same folder, then use rc.exe via the command line. Here's a good article on how to use it. And the full documentation on MSDN.

My Project

The game I'm working on is called You Are Cat. The code I'm working with is visible as an open source project (Eclipse Public License 1.0) on Google Code. You can view it here.

I've decided to make it available since it will hardly be the final version of the game (if I ever finish) and because I'm taking parts of the code from the basic engine created at DeVry with some other students.

As far as the game, I'm not going to explain what it is about or what you actually do. You'll have to figure it out from the code, if you're so inclined.  

No comments:

Post a Comment