Using GDI+ in C++ Win32 programming

If you do any Win32 programming in C++, then I strongly recommend you learn about GDI+. It’s been around for a while now, but not everybody knows about it. It can be great to have on hand even just to illustrate tests and prototypes.

Why is it so good? It provides an object-oriented way to draw graphics using the GDI, which is much nicer and easier to user than the basic C-style GDI functions and resources that used to be the norm. It also provides a lot of additional functionality which otherwise was not possible (or at least not easy) with the regular GDI functions alone, such as proper alpha blending, matrix transformations, file input/output, and loads more. It’s quite easy to setup too, as I will explain…

Unicode!

One thing to be aware of first: GDI+ requires Unicode to be enabled. That means that all string literals need to be preceded by “L” (without the quotes), or encased in a “TEXT(..)” macro. It also means that you might find you need to change any string classes or functions… it can be a nightmare to port existing code, but it’s alright once you get there (or if you’re starting from scratch).

Setup the Project

I’m using Visual C++ Express Edition 2008, which is free to download and use. The best thing to do is setup a simple windows application first… just create a basic window, and your regular message pump/handler. Next, you need to make sure Unicode is enabled for your code, which just means going into your project properties page, select “C/C++” → “Preprocessor”, and beside “Preprocessor Definitions”, add “UNICODE”. Do this for Debug and Release configurations, or whatever your configurations are.

Next, you need to link to the Gdiplus library. Still in Project Properties, go to “Linker” → “Input”, and beside “Additional Dependencies”, add “gdiplus.lib”. (Once again, do it for all configurations.)

Last step in getting everything setup is to add in the code to initialise and cleanup the GDI+ system. Somewhere near the start of your WinMain function (before you create any windows), put the following code:

GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

Somewhere near the end of your WinMain function (after ALL other GDI+ objects you might be using has been deleted or fallen out of scope), put the following code (obviously making sure the “gdiplusToken” variable from above is still in scope):

GdiplusShutdown(gdiplusToken);

Somewhere near the top of your source code file(s) where you will be using GDI+, you’ll want to put this:

#include <gdiplus.h>
using namespace Gdiplus;

Using It!

You’ll usually want to use GDI+ in your window’s “paint” event (although it can be used to write out to files too, if you want). The main class you’ll be working with is the Graphics class, which handles most of your drawing. You have to start by getting a Graphics object linked to the device context of your window, so it can draw to it safely. There’s lots of ways to handle a paint event, but I’ll follow my preferred approach here (remember to make sure you’re window area is invalidated before doing this!):

// Assuming you've got your window handle in "hWnd":
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Graphics g(hdc);

Just like with the regular GDI, you draw and paint using pens and brushes, but thankfully these are much easier. We will fill in a rectangle with a red brush, and draw a green circle inside it:

SolidBrush redBrush(Color::Red);
Pen greenPen(Color::Green, 2.0);
g.FillRectangle(&redBrush, 20, 20, 100, 100);
g.DrawEllipse(&greenPen, 30, 30, 80, 80);

And that’s just about it! We just need to tell our window to finish painting now (this bit isn’t GDI+):

EndPaint(hWnd, &ps);

Conclusion

As you can see, it’s fairly easy to setup and use GDI+ (although I guess that’s still probably a bit scary for novice Win32 programmers!). Fear not though! There is plenty of GDI+ documentation on MSDN.

I am also working on a fairly simple object-oriented windowing system at the moment, called “avidwin”. It will hopefully provide a really simple way to handle and manage Win32 windows, and there will be different class specialisations for things like GDI+ and OpenGL. (The idea is that you just inherit one of those classes to add some of your own functionality, and setup a very simple WinMain function, and that’s it. Easy!)

5 comments on “Using GDI+ in C++ Win32 programming

  1. I’ve literally implemented this piece of code but it seems it does nothing, literally nothing. I used GDI at first but switched to GDI+ for more C++ style usability. Any idea what to do when nothing shows up ?

  2. Sorry to hear you’re having trouble. I’ve just checked the code in the original post, and it definitely works if it’s in the right place.

    Unfortunately there’s lots of potential reasons why it wouldn’t seem to work. If your GDI drawing code was working before, then perhaps you’re not initialising GDI+?

    Other things to check are:

    1. Make sure your drawing code is getting executed in the WM_PAINT handler (it won’t work anywhere else).
    2. Make sure you’re using the correct window handle (hWnd).
    3. Make sure you call InvalidateRect() on your window regularly if you want to redraw constantly.

    If you still can’t get it working, then feel free to send me your code and I’ll take a look. You can use the “Contact Me” form on the main menu. 🙂

  3. I’ve wasted a lot of time with my unresolved symbols problems,… thank you much, your post gave me the solution… (gdiplus.lib)

  4. how can i compare 1 color?

    Gdiplus::Color clrBackColor =Gdiplus::Color::Transparent;
    if (clrBackColor == Gdiplus::Color(Gdiplus::Color::Transparent))

    i get an error:
    “no match for ‘operator==’ (operand types are ‘Gdiplus::Color’ and ‘Gdiplus::Color’)”
    why these error?

    • That error means an equality operator (==) hasn’t been declared for the Color class. Instead, I think you could compare the underlying values directly by using the GetValue() method:

      Color c1, c2;
      if (c1.GetValue() == c2.GetValue()) {
          // colors are the same
      }

Leave a Reply

Your email address will not be published. Required fields are marked *