I recently finished an introductory lesson on C++ and decided to jump into Visual C++ to try to make a little application.
So far, all I want is to at least create and show a window, didn't go any further.
I used many Microsoft Tutorials to get the code I have.
Please note that I have many comments to help me understand what I am doing.
I`m using Microsoft Visual Studio 2015
#include <tchar.h> //A Win32 character string that can be used to describe ANSI, DBCS, or Unicode strings
//Enclose the strings in _T() if an incompatibility error occures or (LPCWSTR)L""
#include <windows.h>
// Global variable
HINSTANCE hinst;
//Function prototype for the window procedure so the inside of the program knows wazup
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
//Instead of your usual console program, you get WinMain() instead of int main(int argc,char *argv[])
INT WINAPI wWinMain(HINSTANCE hInst, //Instance of the program being executed
HINSTANCE hPrevInst, //Previous instance, not used much anymore
LPWSTR lpCmdLine, //Holds command line arguments
INT nShowCmd) //Tells how the program should start(minumised, maximised...)
{
/*Steps to create a window:
- Register a window class
- Create the window
- Show the window
- Setup a callback procedure
*/
//We can tell if the window class has failed if RegisterClassEx() returns 0.
//Fortunatley, there is another handy function, namely GetLastError().
//GetLastError() will return an error code, which can then be used to track down the cause of the error.
//https://msdn.microsoft.com/en-us/library/ms681381.aspx
if (!InitApplication(hInst))
{
int nResult = GetLastError();
MessageBox(NULL,
_T("Window class creation failed"),
_T("Window Class Failed"),
MB_ICONERROR);
return 1;
}
//Window creation & display:
if (!InitInstance(hInst, nShowCmd)){
int nResult = GetLastError();
MessageBox(NULL,
_T("Window creation failed"),
_T("Window Creation Failed"),
MB_ICONERROR);
return 1;
}
//The windows 'callback procedure' is necessary to continue
MSG msg; //Message handler
ZeroMemory(&msg, sizeof(MSG));
//Main loop for the program
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//translates virtual key messages to character messages
DispatchMessage(&msg); //Sends any messages to the callvack procedure, so it can be handled
}
//Still returns an int!
return 0;
}
BOOL InitApplication(HINSTANCE hinstance)
{
//The window class defines the overall 'look and feel' of the window that we want to create.
//First we create an instance of a window class
WNDCLASSEX wClass;
//For more about WNDCLASSEX: https://msdn.microsoft.com/en-us/library/ms633577(VS.85).aspx
//Clearing all the parameters of the WNDCLASSEX instance wClass to zero
ZeroMemory(&wClass, sizeof(WNDCLASSEX));
//Now we are setting up all sotrts of parameters for our instance:
wClass.cbClsExtra = NULL; // cbClsExtra Additional parameters
wClass.cbSize = sizeof(WNDCLASSEX); // cbSize Specifies the size of the window class
wClass.cbWndExtra = NULL; // cbWndExtra Additional parameters
wClass.hbrBackground = (HBRUSH)COLOR_WINDOW; // hbrBackground Sets background color for the window
wClass.hCursor = LoadCursor(NULL, IDC_ARROW); // hCursor The cursor that will appear in the window
wClass.hIcon = NULL; // hIcon Icon for the window
wClass.hIconSm = NULL; // hIconSm Small icon for the window
wClass.hInstance = hinstance; // hInstance Handle to the application instance
wClass.lpfnWndProc = (WNDPROC)WinProc; // lpfnWndProc The callback procedure (more on that later)
wClass.lpszClassName = _T("Window Class"); // lpszClassName The unique name of the window class
wClass.lpszMenuName = NULL; // lpszMenuName Used for menus
wClass.style = CS_HREDRAW | CS_VREDRAW; // style The look and feel of the window
// Register the window class.
return RegisterClassEx(&wClass);
}
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
// Save the application-instance handle.
hinst = hinstance;
// Create the main window.
//CreateWindowEx returns a HWND
HWND hwnd = CreateWindowEx( // A "handle" is a generic identifier + like "new"
0, // DWORD, extended window style of the window being created https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
_T("MainsWClass"), // LPCTSTR, A null-terminated string or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
_T("Sample"), // LPCTSTR, The window name.
WS_OVERLAPPEDWINDOW, // DWORD, Style of the window created
CW_USEDEFAULT, // int, X - default horizontal position
CW_USEDEFAULT, // int, Y - default vertical position
CW_USEDEFAULT, // int, nWidth - default width
CW_USEDEFAULT, // int, nHeight - default height
(HWND)NULL, // HWND, hWndParent - handle to the parrent or owner window of the window being created (opptional for pop-up)
(HMENU)NULL, // HMENU, hMenu
hinstance, // HINSTANCE, hInstance - A handle to the instance of the module to be associated with the window.
(LPVOID)NULL); // LPVOID, Pointer to a value to be passed to the window through the CREATESTRUCT structure
//If the creation fails, returns FALSE
if (!hwnd)
return FALSE;
else{
// Show the window and send a WM_PAINT message to the window procedure.
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
}
//callback procedure
LRESULT CALLBACK WinProc(
HWND hWnd, //Handle of the window that we want to monitor
UINT msg, //Message we are receiving
WPARAM wParam, //Additionnal info for the received message
LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: //Message sent to the application if the program was closed using the X on the top of the window
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
You are registering a window class named "Window Class", but try to create a window of class "MainsWClass". That class is unknown. You need to create window of a window class that has previously been registered (either by yourself, or one of the pre-defined window classes like "BUTTON").
Related
I am making a desktop application, and I got it to display a button. Now what I am trying to do is somehow handle the button press, but I do not know how. Here is my code so far:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
// Global variables
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("First Desktop Application");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
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, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL,
NULL,
hInstance,
NULL
);
HWND hwndButton = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Test2", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
100, // y position
100, // Button width
20, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Test");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// Here your application is laid out.
// For this introduction, we just print out "Hello, Windows desktop!"
// in the top left corner.
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
// End application-specific layout section.
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
It is a Windows Desktop Wizard project on Visual Studio 2019. I just want it to do something simple like display some text on the screen or something when the button is pressed.
This is what the window looks like:
When a BUTTON is clicked, it sends a BN_CLICKED notification message to its parent window. You would simply handle that message in your WndProc(), eg:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
...
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED)
{
// LOWORD(wParam) is the button's ID
// HWND(lParam) is the button's HWND
// do something with them as needed...
return 0;
}
break;
}
...
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
This is explained in the BUTTON documentation on MSDN:
Button Messages
Handling Messages from a Button
Notifications from a button are sent as either WM_COMMAND or WM_NOTIFY messages. Information about which message is used can be found on the reference page for each notification.
For more information on how to handle messages, see Control Messages. See also Button Messages.
Notification Messages from Buttons
When the user clicks a button, its state changes, and the button sends notification codes, in the form of WM_COMMAND messages, to its parent window. For example, a push button control sends the BN_CLICKED notification code whenever the user chooses the button. In all cases (except for BCN_HOTITEMCHANGE), the low-order word of the wParam parameter contains the control identifier, the high-order word of wParam contains the notification code, and the lParam parameter contains the control window handle.
I am able to create a window with a Tile. How can I add now new text line inside the Window ?
All what I succeed to did was only to change the title of the window which is not what I want . I want to add some text line in the window box.
SendMessage function was not working for me.
Please if somebody has some tip for this to tell me !
#include <windows.h>
const char g_szClassName[] = "myWindowClass";
//The Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
// Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Title of window",
WS_OVERLAPPEDWINDOW,
1390, 540, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
To draw text in the client area, your wndProc would normally use something like DrawText or TextOut. You typically do that in response to WM_PAINT.
To be able to respond to an external message, you'd typically send a message containing the text. The window would receive that, store (a copy of) the text it received, and (usually) invalidate the window's rectangle. Since the window is now invalidated, the next chance it gets, Windows will send your window a WM_PAINT message (and then you'll draw out the text).
Handling the WM_PAINT message and drawing the text directly on the window's HDC is one option.
Another option is to create a child STATIC control in your window, and then you can assign the desired text to that child using SetWindowText() or the WM_SETTEXT message. No manual drawing needed.
In the end I figure out how to finish this:
win32 app picture
#ifndef UNICODE
#define UNICODE
#endif
using namespace std;
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
int X_Coordinate = 215;
int Y_Coordinate = 415;
int Width = 700;
int Height = 500;
char Text[] = {"abc123"};
char Window_Title[] = "My title";
char Window_Image[] = "D:\\bitmap1.bmp";
const char* csWindow_Title = Window_Title;
const char* csWindow_Image = Window_Image;
HBITMAP bitmap; // Creates bitmap object based on a handle to a Windows Windows Graphics Device Interface (GDI) bitmap and a handle to a GDI palette.
// Utilities
bool ConvertConstChartoLPWSTR (const char* as , wchar_t* wString )
{
memset(wString,0,sizeof(wString));
MultiByteToWideChar(CP_ACP, 0, as, -1, wString, 4096);
return wString;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
//Registering the Window Class
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255)); // set window background color ( RGB ) - white
RegisterClass(&wc); // register the window class with the operating system
wchar_t* wWindow_Title=new wchar_t[4096];
memset(wWindow_Title,0,sizeof(wWindow_Title)); // init variable
ConvertConstChartoLPWSTR(csWindow_Title,wWindow_Title); // convert
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
wWindow_Title, // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
X_Coordinate, Y_Coordinate, Width, Height,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// ----------------------------- START -> SWITCH case -----------------------------------------------------
switch (uMsg)
{
// ----------------------------- START -> case WM_DESTROY -------------------------------------------------
case WM_DESTROY:
PostQuitMessage(0);
return 0;
// ----------------------------- END -> case WM_DESTROY ---------------------------------------------------
// ----------------------------- START -> case WM_PAINT ---------------------------------------------------
case WM_PAINT:
{
wchar_t* wWindow_Image=new wchar_t[4096];
memset(wWindow_Image,0,sizeof(wWindow_Image));
ConvertConstChartoLPWSTR(csWindow_Image,wWindow_Image); // convert
bitmap=(HBITMAP)LoadImage(NULL, // A handle to the module that contains the image to be loaded. To load a stand-alone resource (icon, cursor, or bitmap file)—for example, c:\myimage.bmp — set this parameter to NULL
wWindow_Image, // The image to be loaded.
IMAGE_BITMAP, // The type of image to be loaded.
690, // The width, in pixels, of the icon or cursor.
540, // he height, in pixels, of the icon or cursor.
LR_LOADFROMFILE); //Loads the stand-alone image from the file specified by lpszName (icon, cursor, or bitmap file).
PAINTSTRUCT ps; // declare structure with information for an application
HDC hdc = BeginPaint(hwnd, &ps); // prepare the specified window for painting
int index = sizeof(Text);
HDC hMemDC=CreateCompatibleDC(hdc); // create a compatible DC ( hMemDC ) o be the same like another one ( hdc )
::SelectObject(hMemDC,bitmap); // Selects an object into the specified device context (DC). The new object replaces the previous object of the same type.
long retval=SetTextAlign(hdc,TA_TOP); // alignment of written area
const char* theval;
int u = 5;
for(int b = 0; b < sizeof(Text); b++)
{
string sym(1, Text[b]); // convert char to const char*
theval = sym.c_str();
cout<<b<<theval;
wchar_t wtext[sizeof(Text)];
memset(wtext,0,sizeof(wtext));
ConvertConstChartoLPWSTR(theval,wtext); // convert
// Here application is laid out.
TextOut (hdc, 5, u, wtext, sizeof(Text));
u = u + 15;
}
index = index + u; // claculate the size of written area
BitBlt( hdc, // handler
0, // The x-coordinate, in logical units, of the upper-left corner of the destination rectangle.
index, // The y-coordinate, in logical units, of the upper-left corner of the destination rectangle.
700, // The width, in logical units, of the source and destination rectangles.
980, // The height, in logical units, of the source and the destination rectangles.
hMemDC, // handler for source ( image ).
0, // The x-coordinate, in logical units, of the upper-left corner of the source rectangle.
0, // The y-coordinate, in logical units, of the upper-left corner of the source rectangle.
SRCCOPY ); // A raster-operation code. These codes define how the color data for the source rectangle is to be combined with the color data for the destination rectangle to achieve the final color.
// SRCCOPY - Copies the source rectangle directly to the destination rectangle.
EndPaint(hwnd, &ps); // function marks the end of painting in the specified window
}
return 0;
// ----------------------------- END -> case WM_PAINT ---------------------------------------------------
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
// ----------------------------- END -> SWITCH case -----------------------------------------------------
} // END -> LRESULT CALLBACK WindowProc
I'm trying to create two instances of a window class.
When the primary one is closed it should close the application but when the secondary one is closed it should just close that window.
However when either window is closed the application exits, and I'm not sure why. I've tried comparing the hWnd to check which window is being closed.
// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
//Forgive me now
#define MAX_WINDOWS 1024
HWND hWindows[MAX_WINDOWS];
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";
RegisterClassEx(&wc);
hWindows[0] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
hWindows[1] = CreateWindowEx(NULL,
L"WindowClass1", // name of the window class
L"Our First Windowed Program", // title of the window
WS_OVERLAPPEDWINDOW, // window style
300, // x-position of the window
300, // y-position of the window
500, // width of the window
400, // height of the window
hWindows[0], // primary window
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
ShowWindow(hWindows[0], nCmdShow);
ShowWindow(hWindows[1], nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);
// send the message to the WindowProc function
DispatchMessage(&msg);
}
// return this part of the WM_QUIT message to Windows
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch (message)
{
case WM_CLOSE:
{
if (hWnd = hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
else {
DestroyWindow(hWnd);
}
return 0;
} break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
}
if (hWnd = hWindows[0])
That's assignment. Since hWindows[0] is non-zero, that expression always evaluates true.
You mean:
if (hWnd == hWindows[0])
You should call PostQuitMessage in response to WM_DESTROY. And since the default window procedure calls DestroyWindow in response to WM_CLOSE, you can write it like this:
switch (message)
{
case WM_DESTROY:
{
if (hWnd == hWindows[0]) {
// close the application entirely
PostQuitMessage(0);
}
return 0;
}
break;
}
// Handle any messages the switch statement didn't
return DefWindowProc(hWnd, message, wParam, lParam);
I am fairly new to C++ coding so this could be a really easy fix. I have recently created a basic WinMain window. When I run the program from either the IDE or .exe file the application doesn't open at the proper size.
I can resize the window but I'm not sure why it isn't opening at that size set.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Function prototypes
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
bool CreateMainWindow(HINSTANCE, int);
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);
// global variable
HINSTANCE hinst;
// Constants
const char CLASS_NAME[] = "WinMain";
const char APP_TITLE[] = "Hello World";
const char WINDOW_WIDTH = 400;
const char WINDOW_HEIGHT = 400;
//==================================
// Starting point for the windows application
// Parameters are
// hInstance. Handle to the current instance of the application
// hPrevInstance. Always NULL, obsolete parameter
// lpCmdLine. Pointer to null-terminated string of command arguements
// nCmdShow. Specifies how the window is to be shown
//=================================
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg;
// Create thw window
if (!CreateMainWindow(hInstance, nCmdShow))
return false;
// Main message loop
int done = 0;
while (!done)
{
// PeekMessage is a non blocking message for Windows messages
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Look for quit message
if (msg.message == WM_QUIT)
done = 1;
// Decode and pass messages on to WinProc
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
// Window event callback function
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
//Tell windows to kill this program
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
// Create the window, returns False on error
bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hwnd;
// Fill in the window class structure with parameters
// That describe the main window
wcx.cbSize = sizeof(wcx); // Size of the structure
wcx.style = CS_HREDRAW | CS_VREDRAW; // Redraw if the size changes
wcx.lpfnWndProc = WinProc; // Points to windows procedure
wcx.cbClsExtra = 0; // No extra class memory
wcx.cbWndExtra = 0; // No extra window memory
wcx.hInstance = hInstance;
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // Predifined arrow
// Background brush
wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcx.lpszMenuName = NULL; // Name of menu resource
wcx.lpszClassName = CLASS_NAME; // Name of window class
wcx.hIconSm = NULL;
// Register the window class
// RegisterClassEx return 0 on error
if (RegisterClassEx(&wcx) == 0) // if error
return false;
// Create Window
hwnd = CreateWindow(
CLASS_NAME, // Name of window class
APP_TITLE, // Title bar text
WS_OVERLAPPEDWINDOW, // Window style
CW_USEDEFAULT, // Default horizontal postion of window
CW_USEDEFAULT, // Default vertical postion of window
WINDOW_WIDTH, // Width of window
WINDOW_HEIGHT, // Height of window
(HWND) NULL, // No parent window
(HMENU) NULL, // No menu
hInstance, // Handle to application window
(LPVOID) NULL); // No window parameters
// If there was an error the window
if (!hwnd)
return false;
// Show the window
ShowWindow(hwnd, nCmdShow);
// Send a WM_PAINT message to the window procedure
UpdateWindow(hwnd);
return true;
}
Change the two constant definitions from char to int:
const int WINDOW_WIDTH = 400;
const int WINDOW_HEIGHT = 400;
Assuming a signed character is 8-bits then char x = 400 actually sets x to 16.
I am writing the beginnings of a game as a Win32 application. Everything worked fine when I registered the class within Main.cpp, but now I'm trying to move it to a Game class to make the code easier for me to use.
Since I have moved the code into the Game class, window class registration fails. Here is my code, please note that some functions are empty simply because I haven't got that far yet.
GetLastError() returns 87.
Main.cpp
#include "Main.h"
// entry point for the program, see Game for explanation of parameters
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
game = std::unique_ptr<Game>(new Game(hInstance, hPrevInstance, lpCmdLine, nCmdShow));
game->Init();
// main game loop
while(game->IsRunning())
{
game->HandleMessages();
game->Update(0.0f);
game->Render();
}
return EXIT_SUCCESS;
}
Game.cpp
#include "Game.h"
#include <Windows.h>
LPCWSTR g_szClassName = L"Life Simulator Window Class";
Game::Game(HINSTANCE _hInstance, // handle to an instance of the application
HINSTANCE _hPrevInstance, // handle to previous instance of the application
LPSTR _lpCmdLine, // command line parameters
int _nCmdShow) // controls how the window is show)
{
hInstance = _hInstance;
hPrevInstance = _hPrevInstance;
lpCmdLine = _lpCmdLine;
nCmdShow = _nCmdShow;
return;
}
Game::~Game(void)
{
}
bool
Game::Init()
{
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = Game::WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
}
// window procedure for the game
LRESULT CALLBACK
Game::WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
return 0;
}
void
Game::HandleMessages()
{
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on to its window procedure (i.e. WndProc)
}
return;
}
void
Game::Update(float elapsedTime)
{
return;
}
void
Game::Render()
{
return;
}
Previously working Main.cpp
#include <Windows.h>
// global variables
LPCWSTR g_szClassName = L"Life Simulator Window Class"; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 800;
static const int wndWidth = 600;
// window procedure for the program
LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
}
// entry point for the program
int WINAPI WinMain(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow) // controls how the window is show
{
// initialise variables
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
// message loop
while(true){ // program closes instantly otherwise
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on the its window procedure (i.e. WndProc)
}
}
return msg.wParam; // contains the exit code from the last message, most likely WM_QUIT
}
Game.h
#pragma once
#include <Windows.h>
class Game
{
public:
Game(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow); // controls how the window is show
~Game(void);
bool Init();
bool IsRunning(){return isRunning;}
// window procedure for the game
static LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam); // even more additional message information
void HandleMessages(); // messages are translated and dispatched here
void Update(float elapsedTime); // game logic
void Render(); // display results
public: // changed to public until I can get it all working
bool isRunning;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
LPCWSTR g_szClassName; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 600; // window height
static const int wndWidth = 800; // window width
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
};
The problem is that you have g_szClassName declared as both a member variable and a global variable. The member variable g_szClassName is not initialized anywhere and can point to anything.
There is also no reason to have wc and msg declared as member variables as they do not need to persist throughout the lifetime of the object. Make them local variables instead.