I'm trying to wrap my head around the Win32 API, and when creating the window I get inconsistent results. The call to CreateWindowEx will fail and the result from GetLastError() yields the ERROR_NOT_ENOUGH_MEMORY error code. But sometimes the application successfully creates the window and runs fine. This has left me rather confused.
// Standard Includes
#include <windows.h>
#include <iostream>
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#define UNUSED_PARAM(x) (void)(x)
const char szWindowClass[] = "Program";
const char szTitle[] = "Program Desc";
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
UNUSED_PARAM(hPrevInstance);
UNUSED_PARAM(lpCmdLine);
WNDCLASSEX wcex;
HWND hWnd;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 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, "Call to RegisterClassEx failed!", szWindowClass, MB_ICONEXCLAMATION | MB_OK);
return 1;
}
hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, // dwExStyle
szWindowClass, // lpClassName
szTitle, // lpWindowName
WS_OVERLAPPEDWINDOW, // dwStyle
CW_USEDEFAULT, CW_USEDEFAULT, // x, y
240, 120, // width, height
NULL, NULL, // hWndParent, hMenu
hInstance, NULL); // hInstance, lpParam
std::cout << GetLastError();
if(hWnd == NULL) {
MessageBox(NULL, "Call to CreateWindow failed!", szWindowClass, MB_ICONEXCLAMATION | MB_OK);
return 1;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Main message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
You're not initializing WNDCLASSEX.cbWndExtra which defines how many extra bytes of storage your window class needs.
You should add:
wcex.cbWndExtra = 0;
Before your call to RegisterClassEx. Alternatively you could start with this:
WNDCLASSEX wcex = { sizeof(wcex) };
Which will initialize the cbSize member to the size of the structure and all other members to 0 (or NULL) for you.
Related
What changes have to be done to make this Windows textbox from 2011, work now, in 2019?
I tried compiling the code in this question from 2011 about making a C++ Textbox...
#include <windows.h>
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmdLine, int nCmdShow)
{
LPTSTR windowClass = TEXT("WinApp");
LPTSTR windowTitle = TEXT("Windows Application");
WNDCLASSEX wcex;
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = windowClass;
wcex.lpszMenuName = NULL;
wcex.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, TEXT("RegisterClassEx Failed!"), TEXT("Error"), MB_ICONERROR);
return EXIT_FAILURE;
}
HWND hWnd;
if (!(hWnd = CreateWindow(windowClass, windowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL)))
{
MessageBox(NULL, TEXT("CreateWindow Failed!"), TEXT("Error"), MB_ICONERROR);
return EXIT_FAILURE;
}
HWND hWndEdit = CreateWindow(TEXT("Edit"), TEXT("test"), WS_CHILD | WS_VISIBLE | WS_BORDER, 100, 20, 140, 20, hWnd, NULL, NULL, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return EXIT_SUCCESS;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return FALSE;
}
But trying to build it in Visual Studio 2019, I get errors about being unable to convert a "t_char" to a "LPTSTR".
So, how do I update the code to work? And is it possible without Including any other files?
Use LPCTSTR instead of LPTSTR:
LPCTSTR windowClass = TEXT("WinApp");
LPCTSTR windowTitle = TEXT("Windows Application");
LPTSTR is TCHAR *
LPCTSTR is const TCHAR *
TEXT("literal") produces a const TCHAR [].
A string literal is const data. Since C++11, you can no longer assign a string literal to a pointer-to-non-const.
Get out of the TCHAR business entirely. Those TEXT macros are for cross-compiling with code meant to run on Windows 9x.
Changes these lines:
LPTSTR windowClass = TEXT("WinApp");
LPTSTR windowTitle = TEXT("Windows Application");
To this:
LPCWSTR windowClass = L"WinApp";
LPCWSTR windowTitle = L"Windows Application";
And then all subsequent usages of TEXT macros like in the following:
MessageBox(NULL, TEXT("RegisterClassEx Failed!"), TEXT("Error"), MB_ICONERROR);
To just be wide strings:
MessageBox(NULL, L"RegisterClassEx Failed!", L"Error", MB_ICONERROR);
I am trying to learn Win32 through msdn but I am having problems with RegisterClassEx, I checked other threads stating that maybe not all members are initialized but I am sure they are.
#include <Windows.h>
#include <tchar.h>
static const TCHAR windowclass_sz[] = _T("WindowClass1");
static const TCHAR windowtitle_sz[] = _T("DirectX 12 Demo");
bool Stop = true;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE PrevhInstance, LPSTR
lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = windowclass_sz;
wcex.lpszMenuName = nullptr;
wcex.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wcex);
if (!RegisterClassEx(&wcex))
{
GetLastError();
MessageBox(NULL, _T("RegisterClassEx Call Error!"), _T("ERROR"),
MB_ICONERROR && MB_OK );
return 1;
}
hWnd = CreateWindowEx(NULL, windowclass_sz, windowtitle_sz,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
800, 600, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, _T("CreateWindowEx Call Error!"), _T("ERROR"),
MB_ICONERROR && MB_OK);
return 1;
}
else
{
Stop = false;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (Stop == false)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
As you can see, the RegisterClassEx error is triggered but I have no clue what is wrong.
A message box pops up with "RegisterClassEx Call Error!" and so the program ends there, what is the problem here?
You are calling RegisterClassEx twice with the same argument. The second call will fail, since the class already exists, and GetLastError returns error code 1410 (ERROR_CLASS_ALREADY_EXISTS)1).
Solution: Register any given window class at most once.
1) You can convert error codes into human-readable representations by calling FormatMessage. Working sample code is available in this answer.
I recently decided to learn a bit of WinApi, but I hit a snag. I want to display a massage in my window after a keypress, but it doesn't seem to work. If I press the key multiple times or if I hold it down, still nothing happens. Can you tell me what I'm doing wrong?
This is the full code:
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <tchar.h>
LRESULT CALLBACK WndProc (HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
LPCWSTR display_str = L"hello";
switch(uMsg)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if(GetAsyncKeyState(VK_UP))
{
TextOut(hdc,
15, 15,
display_str,
_tcslen(display_str));
}
EndPaint(hwnd, &ps);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hwnd;
MSG uMsg;
HINSTANCE hInst;
WNDCLASSEX wcex;
LPCWSTR class_name = L"myWindowClass";
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_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = class_name;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if(!RegisterClassEx(&wcex))
{
MessageBox(NULL, L"Call to RegisterClassEx failed!", L"Win32 Guided Tour!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hInst = hInstance;
hwnd = CreateWindowEx(
NULL,
class_name,
L"Test",
WS_OVERLAPPEDWINDOW,
200, 200,
740, 540,
NULL,
NULL,
hInstance,
NULL
);
if(!hwnd)
{
MessageBox(NULL, L"Window Creation Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&uMsg, NULL, 0, 0) > 0)
{
TranslateMessage(&uMsg);
DispatchMessage(&uMsg);
}
return uMsg.wParam;
}
Windows sends WM_KEYDOWN message when a key is pressed. In WndProc handle WM_KEYDOWN message, call InvalidateRect with the Client rect of the window and draw the text you want to display in WM_PAINT message handler.
Here's my example, if pressed F11 key, print in console string.:
case WM_KEYDOWN:
if(wParam==VK_F11)
{
std::cout << "Hello in my example!";
}
break;
I'm Trying to create a second window on the c++ winApi and I have an error when i'm trying to register second window class. However, this classes are registered, if i'm using UnregisterClass on the first class, consequently, classes are spelled correctly.
#include "stdafx.h"
#include "rgr.h"
#include <stdio.h>
#define MAX_LOADSTRING 100
// GLOBAL:
HINSTANCE hInst;
HWND childWnd;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];
WCHAR childTitle[MAX_LOADSTRING];
WCHAR childWindowClass[MAX_LOADSTRING];
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM RegisterChildClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_RGR, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
/*UnregisterClass(szWindowClass, hInst);
LoadStringW(hInstance, IDC_RGR, childWindowClass, MAX_LOADSTRING);*/
RegisterChildClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_RGR));
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW 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_RGR));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_RGR);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
if (!RegisterClassEx(&wcex)) {
MessageBox(NULL, L"Error registering MAIN class", L"ERROR", MB_OK);
return 0;
}
}
ATOM RegisterChildClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = ChildProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_RGR));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = childWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
if (!RegisterClassEx(&wcex)) {
MessageBox(NULL, L"Error registering CHILD class", L"ERROR", MB_OK);
return 0;
}
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDM_OPEN:
{
childWnd = CreateWindow(szWindowClass, L"Save", WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CHILD , 100, 100, 100, 100, hWnd, (HMENU)107, hInst, NULL);
if (!childWnd)
{
return FALSE;
}
ShowWindow(childWnd, 1);
UpdateWindow(childWnd);
break;
}
case IDM_EXIT:
DestroyWindow(childWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
What i'm doing wrong?
A Window class ...
... is a set of attributes that the system uses as a template to create a window.
With one exception (lpszClassName), all members of the WNDCLASSEX structure define properties of a window of that class. The class name is used to identify the window class. This is explained here:
Registering a window class associates a window procedure, class styles, and other class attributes with a class name.
Since it serves as an ID, the class name needs to be unique throughout the process. In your code, however, you are trying to register two window classes with the same name (the string resource referenced by IDC_RGR). The second call fails, and GetLastError returns 1410: ERROR_CLASS_ALREADY_EXISTS ("Class already exists.").
This can be verified1 using this minimal and complete test case:
#include <windows.h>
int main() {
WNDCLASSEXW wcex = { sizeof( wcex ) };
wcex.lpszClassName = L"TestWindowClass";
if ( !::RegisterClassExW( &wcex ) ) {
DWORD dwError = ::GetLastError();
return dwError;
}
if ( !::RegisterClassExW( &wcex ) ) {
DWORD dwError = ::GetLastError();
return dwError;
}
}
The solution is to use a unique window class name for each window class that a process registers. Note, that there are lots more errors in your code that I didn't address (like incompatible window styles in the CreateWindow call, mismatching character encodings, and so on).
1 By single-stepping through the code using a debugger.
I have been trying very hard to get my window to work. I am looking at the MSDN Page on how to make a window and i can't see the difference. When i run my program, it comes up with the message box saying NO WINDOW.
Code:
#include <windows.h>
static const LPSTR CLASSNAME = "Win32Window";
LRESULT CALLBACK WndProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
DefWindowProc(window, msg, wParam, lParam);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_ARROW));
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = CLASSNAME;
wcex.lpszMenuName = NULL;
wcex.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, "Failed to register window class", "ERROR", MB_ICONERROR);
return 1;
}
HWND window = CreateWindow(CLASSNAME, "title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
if (!window)
{
MessageBox(NULL, "NO WINDOW", "ERROR", MB_ICONERROR); // THIS IS BEING CALLED!!!! WHY??
return 1;
}
ShowWindow(window, nCmdShow);
UpdateWindow(window);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.lParam;
}
If someone can tell me what is wrong here that would be great.
Your window procedure (WndProc) needs to return the value returned by DefWindowProc. At the moment you're just returning 0 for all unhandled messages, which has side effects like (in response to WM_NCCREATE) causing your window creation to fail.