Win32 C++ Window Creation Not Working

D.V.D

Make a wish
Reaction score
73
So I started to read this(http://www.stromcode.com/2008/03/02/win32-basic-window-creation/) tutorial on how to create a window and use win32 API for C++. I tried using the code they wrote in my program and I was getting a lot of errors. I made a Win32 App in Visual and compared the two and tried to get some stuff to work but I still have no idea how or why some of the changes work and why others do.

For example, in the tutorial, it tells me to use the variable hInstance but visual is telling me that the variable is undeclared. WndProcedure or WndProc is also a undeclared identifier.

My other problem is szTitle and szWindowClass and MAXLOADSTRING. Im not sure why I can't just follow the tutorial and write strings. Im not really sure how to set the variables, I only know you initialize them from looking at Win32 App in Visual. How do I set these variables into the names I want? Also what is MAXLOADSTRINGS?

The last problem I have is using CreateWindowEx. Visual is telling me the second parameter needs to be LPCWSTR which I have no idea what that is or why its telling me that. How do I fix it?
(I created my code in a console application)
Code:

Code:
// Create Engine.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
// Win32 Libraries
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
 
#define MAX_LOADSTRING 100
 
// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                    // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];   
 
int _tmain(int argc, _TCHAR* argv[]) {
    return 0;
}
   
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
            char * cmdParam, int cmdShow);
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    char * cmdParam, int cmdShow) {
    // Window Class
 
    WNDCLASSEX GameWindow; // Populate the WNDCLASSEX structure
   
    GameWindow.cbSize = sizeof(WNDCLASSEX); // always set to size of WNDCLASSEX or WNDCLASS depending which you use
    GameWindow.style =CS_HREDRAW | CS_VREDRAW; // designates when that the window is resized horizontally and vertically
    GameWindow.lpfnWndProc = WndProcedure; // pointer to the start of the windows message handler
    GameWindow.cbClsExtra = 0;
    GameWindow.cbWndExtra = 0;
    GameWindow.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Window icon
    GameWindow.hCursor = LoadCursor(NULL, IDC_ARROW); // Window cursor
    GameWindow.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // Color of the background
    GameWindow.lpszMenuName = NULL;
    GameWindow.lpszClassName = szWindowClass; // unique name to the window class. Used when we call CreateWindow(Ex) to tell the function which window class we want an object instance of
    GameWindow.hInstance = hInstance;// the handle to the instance of your app. This is given to your WinMain function and is passed there
    GameWindow.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
    // Register the class
    RegisterClassEx(&GameWindow);
   
    // HWND is a handle to a window object
    // We have a opportunity to chose window style and to add a menu.
    HWND hWnd = CreateWindow("GameWindow", // Choses my window class
                        szTitle, // Gives a title to the window
                        WS_OVERLAPPEDWINDOW, // Sets a window style. If window style is WS_VISIBLE, window is shown noramlly
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);
 
    // Show the Window
    ShowWindow(hWnd, SW_SHOWNORMAL); // Second parameter is a style to show the window
    UpdateWindow(hWnd);
 
 
   
    return 0;
}
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
Attention: Wall of text incoming.

I can't download the source code from the page you've provided (page error) so I'll stick to what you've pasted.

(I created my code in a console application)

You have to use the right application style if you want to use WinMain as entry point for your program. You said above you've created a Win32 project (which is correct) but let's just make sure.
In VS go to Project Options -> Linker -> System -> Subsystem. That value should be set to Windows (/SUBSYSTEM: WINDOWS).

For example, in the tutorial, it tells me to use the variable hInstance but visual is telling me that the variable is undeclared. WndProcedure or WndProc is also a undeclared identifier.

hInstance is the first parameter passed to WinMain. I'm not sure where you've tried to use it, but the example code works perfectly fine in that regard. The hInstance variable is a handle to your program's process, basically. It'll be set by Windows itself before WinMain is called.

WndProcedure or WndProc is also a undeclared identifier.

Yes, in the code you've pasted there is no WindowProcedure. WinProc is simply a function that you have to declare. Then you tell your windows to send all messages (WINDOW_MOVED, WINDOW_CLOSED, WINDOW_RESIZED, ...) through that function to handle it.

So we'll have to create a simple standard winproc function to start with:
[gist]3069744[/gist]

This one really only says: if WM_DESTROY is called (that happens when you click the 'x' in the upper right corner, for example) then tell Windows to shut down this application, else just handle the message in some way.

My other problem is szTitle and szWindowClass and MAXLOADSTRING. Im not sure why I can't just follow the tutorial and write strings. Im not really sure how to set the variables, I only know you initialize them from looking at Win32 App in Visual. How do I set these variables into the names I want? Also what is MAXLOADSTRINGS?

#define MAX_LOADSTRINGS 100
That's just like writing: const int MAX_LOADSTRINGS = 100;

A #define is a pre-processor macro. If you press the Compile button in your VS the first thing that happens is that every place where you've written MAX_LOADSTRINGS will be replaced with 100. Only then will compilation start.
Defines are a relic from C, where there were no constant variables. They're almost completely obsolete today, but Windows makes EXCESSIVE use of them.
So, MAX_LOADSTRINGS is only there to define the array-size of your tchar arrays.

But luckily we don't need all that crap. You can just go ahead and write the strings like you are used to. With a small exception:

The difference between char and tchar.
char is a variable that can hold any ASCII character. tchar can hold any UNICODE character. Different charsets, different variables.
By default VS makes your programs use the UNICODE standard. So we either have to change that to ASCII or keep it that way.

How to change it:
Go to Project Settings -> General -> Character Set. And set from "Unicode" to it "Not Set"

However, let's just keep it for shits and giggles.

First of all, let's get rid of szTitle, szWindowClass and MAX_LOADSTRINGS. No use for that stuff.

We will fill in the blanks manually:
[gist]3069767[/gist]

So, now we've exchanged the variables with our usual strings. With the exception that they're prefixed with an L.
That's the C++ way to tell the program that this is a Unicode string, and not a normal ASCII string.
If you have not set your Character Set to "Not Set" then you'll have to use tchar for all Windows functions and thus have to prefix your strings with L.
You can still use char for everything else, of course. You only talk to windows through tchar, however.

The old szTitle and szWindowClass were never initialized to any value, and it's quite a hassle to do so.
To set such a variable you have to do:
Code:
wcscpy_s( szChars,  L"Hi" ); //Writes "Hi" into szChars
That's quite ugly. But since we're using strings directly now we don't have to care.

Last but not least: Take note that the first parameter of CreateWindow has the exact same value as GameWindow.lpszClassName.
This parameter tells the window you're about to create to get it's information from the window class you've just registered.

The last problem I have is using CreateWindowEx. Visual is telling me the second parameter needs to be LPCWSTR which I have no idea what that is or why its telling me that. How do I fix it?

That's just the tchar problem again.

LPCWSTR is defined as const WCHAR which is defined as wchar_t
TCHAR is also defined as WCHAR, which is also wchar_t.

So TCHAR (or tchar as I called it) and LPCWSTR is the same (almost). Yea. Windows programming hurray :D

So, basically, they only asked you (in a very complicated way) to write L in front of their strings.
[gist]3069852[/gist]

The final code (looks a bit different)
https://gist.github.com/3069862
 

D.V.D

Make a wish
Reaction score
73
So thats what hInstance is, guess the tutorial never really explained everything in detail -__-.

Why did Windows even bother adding the other string classes? :p They could have simply used wchar or Tchar. Also, is there any specific reason why in your code, the Tchar is a pointer?

Also, when I run the code, you can't actually click the x button on the window to turn it off. The cursor is always loading and it won't let you do anything with the window, it just gets closed once the time runs out.

Code:
ATOM                MyRegisterClass(HINSTANCE hInstance);

Also, what does ATOM stand for?

Looking at other parts of Visuals Win32 Application, for return values in functions, they have 2 sperate words but I thought your not allowed that in C++.

Code:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

Why is that allowed?

My last question is about the Paintstruct. Why does windows require a struct to handle modifications to the window in terms of setting pixels or drawing bitmaps? It seems so inefficient and isn't apparent to provide any benefits to the window itself o_O
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
Why did Windows even bother adding the other string classes? :p They could have simply used wchar or Tchar. Also, is there any specific reason why in your code, the Tchar is a pointer?

They're actually not other string classes, but type definitions. So they both refer to the exact same class, just that one is the "actual" and one is the "alias" name. Windows typedef'd pretty much everything they use in their systems.
The reason is that they can easily change the alias. If, at any point, they don't want their BOOL type to be an int but a bool they can do so (for compatibility reasons Windows booleans are actually integers). So if they ever would upgrade/change something there would be no change in the API itself.
It would still be called BOOL, but under the hood it's now suddently a different real type.

I'm using a tchar pointer, just like you would be using a char pointer:
Code:
char* hello_text = "Hi, this is my hello text";
Basically, hello_text POINTS to the place in memory where this text is, it doesn't CONTAIN it like a char array would.
The other option would be to use a tchar-array. I've explained in my previous post why that's ugly (keyword: wcscpy_s..).


Code:
ATOM                MyRegisterClass(HINSTANCE hInstance);

Also, what does ATOM stand for?

ATOM is another one of their typedefs. The ATOM can uniquely identify the class you've just registered (if I remember correctly, been a while).
So, in this example you're using the class name string to identify the windows class, but you could use this atom too.

Code:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

Why is that allowed?

That's actually allowed in all of C++, but it isn't what you think it is.
LRESULT is the normal return type.
CALLBACK is the calling-convention of this function. CALLBACK is a typedef, meaning __stdcall. Think of it as a modifier like static or Java's private and public, just that it's effects aren't visible.
It tells the Compiler how to call the function on assembler-level (so it's generally not important to know).
There's also __cdecl, __thiscall, __fastcall and a few others.
Every normal function call is __cdecl by default. So they switch it to __stdcall for x reason.

I don't know about the paintstruct question. That's a design choice that the Windows team decided on. I don't think it's horribly inefficient, though. In old DOS times graphic buffers and video ram were left to the program, but that caused a lot of problems ,especially after you were able to execute more than one program at the same time.
So Windows itself took over that task.
The paintstruct is the way to communicate with Windows that your application wants control over the framebuffer, then draw your stuff and finally release it again.

Also, when I run the code, you can't actually click the x button on the window to turn it off. The cursor is always loading and it won't let you do anything with the window, it just gets closed once the time runs out.

Yea, that's because of the sleep(xyz) command. I only put it there so you could actually see the window.
During sleep() your program becomes unresponsive, it literally sleeps and does nothing. So it won't handle any messages that you pass to it.

For that you need the program loop and message pump:
[gist]3076797[/gist]

Insert that in place of the sleep(xxx). It'll ask Windows for new messages (PeekMessage) constantly (it's a never-ending loop after all), if it's a quit message then it'll cancel the loop, otherwise it'll dispatch it and continue.
 

D.V.D

Make a wish
Reaction score
73
Oh I see, that explains a LOT :p Way more than any tutorial I could find online. Thanks for all the help haha :p +rep if I can find out how to rep you
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top