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.
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/
  • The Helper The Helper:
    I think we need to add something to the bottom of the front page that shows the Headline News forum that has a link to go to the News Forum Index so people can see there is more news. Do you guys see what I am saying, lets say you read all the articles on the front page and you get to the end and it just ends, no kind of link for MOAR!
  • The Helper The Helper:
    Happy Wednesday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top