Why the MyRegisterClass() function is necessary in WIN32 projects?

1.3k Views Asked by At

In the default code that Visual Studio generates when creating a Win32 project, there's a function called MyRegisterClass with the comment:

//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
    ...
    return RegisterClassEx(&wcex);
}

But this function uses RegisterClassEx that is not exists prior Windows 95. I really don't understand the comment. What they are mean?

What the main purpose to have MyRegisterClass function, and why it's so necessary for compatibility with earlier versions of Windows?

1

There are 1 best solutions below

0
Cody Gray - on strike On BEST ANSWER

The MyRegisterClass function is a helper function. It encapsulates the call to the API function RegisterClass[Ex], since there's a lot of messy parameter setup that needs to be done in order to make the call. The complete function definition looks like this:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wcex;

  wcex.cbSize         = sizeof(WNDCLASSEX);
  wcex.style          = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc    = WndProc;
  wcex.cbClsExtra     = 0;
  wcex.cbWndExtra     = 0;
  wcex.hInstance      = hInstance;
  wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYAPP));
  wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_MYAPP);
  wcex.lpszClassName  = szWindowClass;
  wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

  return RegisterClassEx(&wcex);
}

Extracting this out into a helper function—as opposed to inlining it—keeps your code clean and more readable. As far as performance goes, the compiler will inline it automatically, if that's appropriate.

Another reason why it makes sense for this to be a helper function is historical, and that is what's described in the comments:

//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.

You see, the Ex suffix on an API denotes "EXtended". The RegisterClassEx function was introduced with 32-bit Windows (API v4.0, Windows 95). Back in 16-bit Windows, there was only RegisterClass. 32-bit Windows supported both variants, for backwards-compatibility, but the "extension" that RegisterClassEx added was the ability to set a small icon. If you want to have nice small icons (instead of ugly ones, generated by a low-quality stretching algorithm from the large icon), you need to call RegisterClassEx. But if you want to target 16-bit Windows, you can't call RegisterClassEx; you need to stick with RegisterClass. So, if you encapsulate the call to RegisterClass[Ex] in a helper function, you can easily modify the code, changing which API function it calls and therefore which version(s) of Windows your app can target.

The comment is trying to convey this information, but doing a relatively poor job of expressing itself.

You can completely ignore this today. Nobody targets 16-bit Windows anymore. Always call RegisterClassEx, and forget that RegisterClass even exists. That doesn't eliminate the advantage of encapsulating this code in a function for readability.

Note, further, that the default Win32 project template bundled with Visual Studio separates the small and large icons in separate ICO files and thus assigns them separate resource IDs. This was presumably done for the same historical reasons, so you could compile for 16-bit Windows without having the small icon getting in the way, but again is completely unnecessary today. You can combine both icons into a single ICO file, and load them selectively:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
  WNDCLASSEX wcex;

  wcex.cbSize         = sizeof(wcex);
  wcex.style          = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc    = WndProc;
  wcex.cbClsExtra     = 0;
  wcex.cbWndExtra     = 0;
  wcex.hInstance      = hInstance;
  wcex.hIcon          = (HICON)LoadImage(hInstance,
                                         MAKEINTRESOURCE(IDI_MYAPP),
                                         IMAGE_ICON,
                                         GetSystemMetrics(SM_CXICON),
                                         GetSystemMetrics(SM_CYICON),
                                         LR_DEFAULTCOLOR | LR_SHARED);
  wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_MYAPP);
  wcex.lpszClassName  = szWindowClass;
  wcex.hIconSm        = (HICON)LoadImage(hInstance,
                                         MAKEINTRESOURCE(IDI_MYAPP),
                                         IMAGE_ICON,
                                         GetSystemMetrics(SM_CXSMICON),
                                         GetSystemMetrics(SM_CYSMICON),
                                         LR_DEFAULTCOLOR);

  return RegisterClassEx(&wcex);
}