I'm trying to handle WM_KEYDOWN message using following wndproc and winmain but when I press a key(i.e. arrow keys which ascii value 24, 25, 26, 27) it doesn't handled.
WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
/*TO CHECK uMsg message*/
char buff[256];
_itoa_s(uMsg, buff, 10);
SetWindowText(hEdit, buff);
/**********************/
switch (uMsg)
case WM_CREATE:
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "", WS_CHILD | WS_VISIBLE |ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL, 735, 5, 150, 100, hWnd, NULL, hInst, NULL);
HButton1 = CreateWindowEx(NULL, "BUTTON", "START", WS_CHILD | WS_VISIBLE | SS_CENTER, 2, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON1, hInst, NULL);
HButton2 = CreateWindowEx(NULL, "BUTTON", "B", WS_CHILD | WS_VISIBLE | SS_CENTER, 82, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON2, hInst, NULL);
HButton3 = CreateWindowEx(NULL, "BUTTON", "STOP", WS_CHILD | WS_VISIBLE | SS_CENTER, 162, 2, 80, 20, hWnd, (HMENU)IDC_BUTTON3, hInst, NULL);
Hmainbmp = CreateWindowEx(NULL, "STATIC", "", WS_CHILD | WS_VISIBLE | SS_BITMAP | WS_THICKFRAME, 1, 23, 600, 500, hWnd, NULL, hInst, NULL);
break;
case WM_KEYDOWN:
PRESSED_KEY = wParam;
break;
case WM_COMMAND:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, uMsg, wParam, lParam));
return(0L);
}
WinMain
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){
MSG msg;
WNDCLASSEX wc;
HMENU MainMenu, FileMenu;
MainMenu = CreateMenu();
FileMenu = CreatePopupMenu();
AppendMenu(FileMenu, MF_STRING, IDC_OPEN, "Open");
AppendMenu(MainMenu, MF_POPUP, (UINT_PTR)FileMenu, "FILE");
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.lpszMenuName = lpszAppName;
wc.lpszClassName = lpszAppName;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = (HICON)LoadImage(hInstance, lpszAppName, IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wc)) return(FALSE);
hInst = hInstance;
hWnd = CreateWindowEx(0, lpszAppName, lpszTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 900, 600, NULL, MainMenu, hInstance, NULL);
if (!hWnd) return(FALSE);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Why below case doesn't work? And how can I handle WM_KEYDOWN?
case WM_KEYDOWN:
PRESSED_KEY = wParam;
break;
UPDATE
When I minimize and maximize window again, WM_KEYDOWN processed but if I click any button, it isn't working.
According to the WM_KEYDOWN document:
Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.
However, there are other buttons and edit boxes in your window. So when you press other buttons or click on the edit box, the focus will be on that window.which causes the WndProc function to be unable to process the WM_KEYDOWN message.
You can use the SetFocus function to set the keyboard focus window.Then you can get the WM_KEYDOWN message through the main window, and display the value through the Edit control.
Like the following code:
case WM_KEYDOWN:
PRESSED_KEY = wParam;
_itoa_s(wParam, buff, 10);
SetWindowTextA(hEdit, buff);
break;
Of course, if you don't want to focus on a specific window to get keyboard information, I recommend you use the SetWindowsHookEx function to get the global keyboard message, without focusing on a specific window.
Edit:
If you want to handle all WM_KEYDOWN messages, you can use the SetWindowsHookEx function.
You only need to modify a few parts of your code:
1.Add a function to handle the keyboard:
LRESULT __stdcall KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char buff[256] = "";
PKBDLLHOOKSTRUCT key = (PKBDLLHOOKSTRUCT)lParam;
//a key was pressed
if (wParam == WM_KEYDOWN && nCode == HC_ACTION)
{
_itoa_s(key->vkCode, buff, 10);
SetWindowTextA(hEdit, buff);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
2.Set the hook process to the keyboard in the main function:
HHOOK _k_hook;
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szCmdLine, _In_ int nCmdShow)
{
MSG msg;
WNDCLASSEX wc;
HMENU MainMenu, FileMenu;
_k_hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
...
}
3.Finally, don't forget to delete the hook process after the program ends:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HWND HButton1, HButton2, HButton3, Hmainbmp;
switch (uMsg)
{
...
case WM_DESTROY:
if (_k_hook)
UnhookWindowsHookEx(_k_hook);
PostQuitMessage(0);
break;
...
}
}
In this way, you don't need to process the message of WM_KEYDOWN in WndProc. The message of pressing the key is processed in the KeyboardProc function, and the value of the key is displayed in the Edit control.
Related
I'm learning to write basic Win32 apps in C++ and am trying to pass typed text from one editable textbox to a new window after pressing a button.
I noticed that the default text buffer capacity for such a transfer is 20 characters in Visual Studio 2019 (I am on 64-bit Windows 10). After I try to pass a string longer than 20 characters, I get an exception thrown.
I would like to know how to increase that buffer capacity, since eventually I want to be able to pass a filepath into the text input window and open that file.
My code:
#include <windows.h>
#include <string>
#include <iostream>
//lresult callback prototype
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
//window handles
HWND hMainWindow;
HINSTANCE hMainInstance;
HWND hLblOutput;
HWND hTxtInput;
HWND hButton;
#define IDC_TEXTBOX 1000
#define IDC_BUTTON 1001
//call to winmain - equivalent of main for win32 environments
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = TEXT("NiceWindowsApp");
if (!RegisterClass(&wc))
return 1;
hMainWindow = CreateWindow(wc.lpszClassName, TEXT("My Windows Application"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL);
hMainInstance = wc.hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//callback definition
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int offset = 0;
switch (message) {
case WM_CREATE:
hMainWindow = hWnd;
hTxtInput = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("Type something here"),
WS_VISIBLE | WS_CHILD | ES_LEFT, 50, 50, 400, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
hButton = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("BUTTON"), TEXT("Press Me!"), WS_VISIBLE | WS_CHILD | WM_COPY | ES_LEFT, 500, 30, 100, 60, hWnd,
(HMENU)IDC_BUTTON, hMainInstance, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_BUTTON)
{
//CANNOT HANDLE MORE THAN 20 CHARACTERS!!!
std::string input;
GetWindowTextA(hTxtInput, reinterpret_cast<char*> ((char*)input.c_str()), 400);
++offset;
hLblOutput = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), input.c_str(), WS_VISIBLE | WS_CHILD | ES_READONLY | ES_LEFT, 50, 200 + offset * 26, 800, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I have tried to increase the third parameter in GetWindowTextA() to various numbers up to 4000, but it didn't seem to help.
One correct way to do this is:
std::wstring text;
text.resize(GetWindowTextLengthW(hTxtInput));
text.resize(GetWindowTextW(hTxtInput, text.data(), text.size() + 1));
Solved as per the below:
#include <windows.h>
#include <string>
#include <iostream>
//lresult callback prototype
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
//window handles
HWND hMainWindow;
HINSTANCE hMainInstance;
HWND hLblOutput;
HWND hTxtInput;
HWND hButton;
CHAR s_text_1[]{ "Some text.." };
CHAR s_text_2[]{ 0 };
#define IDC_TEXTBOX 1000
#define IDC_BUTTON 1001
//call to winmain - equivalent of main for win32 environments
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = TEXT("NiceWindowsApp");
if (!RegisterClass(&wc))
return 1;
hMainWindow = CreateWindow(wc.lpszClassName, TEXT("My Windows Application"), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL);
hMainInstance = wc.hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//callback definition
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int offset = 0;
switch (message) {
case WM_CREATE:
hMainWindow = hWnd;
hTxtInput = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), s_text_1,
WS_VISIBLE | WS_CHILD | ES_LEFT, 50, 50, 400, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
hButton = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("BUTTON"), TEXT("Press Me!"), WS_VISIBLE | WS_CHILD | WM_COPY | ES_LEFT, 500, 30, 100, 60, hWnd,
(HMENU)IDC_BUTTON, hMainInstance, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_BUTTON)
{
//CANNOT HANDLE MORE THAN 20 CHARACTERS!!!
std::wstring input;
//GetWindowTextW(hTxtInput, reinterpret_cast<char*> ((char*)input.c_str()), 400);
int lgth = GetWindowTextLength(hTxtInput);
//GetWindowTextW(hTxtInput, reinterpret_cast<wchar_t*> ((wchar_t*)input.c_str()), lgth);
//GetWindowTextA(hTxtInput, char[], 400);
GetWindowText(hTxtInput, s_text_1, 255);
++offset;
hLblOutput = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), s_text_1, WS_VISIBLE | WS_CHILD | ES_READONLY | ES_LEFT, 50, 200 + offset * 26, 800, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
SetWindowText(hLblOutput, s_text_1);
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Thanks for your hints everybody.
EDIT: I now realise that this solution is not technically perfect and can lead to undefined behaviour and/or memory leaks. I'll take the advice presented in the other answers and comments into account and adjust the code accordingly.
EDIT 2.0 (2023.02.04): My most recent code is below. Hopefully it's more robust.
#include <windows.h>
#include <string>
#include <iostream>
//last update - 04.02.2023 as per StackOverflow thread recommendations.
//lresult callback prototype
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
//window handles
HWND hMainWindow;
HINSTANCE hMainInstance;
HWND hLblOutput;
HWND hTxtInput;
HWND hButton;
CHAR s_text_1[]{ "Some text.." };
#define IDC_TEXTBOX 1000
#define IDC_BUTTON 1001
//call to winmain - equivalent of main for win32 environments
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = TEXT("NiceWindowsApp");
if (!RegisterClass(&wc))
return 1;
hMainWindow = CreateWindow(wc.lpszClassName, TEXT("My Windows Application"), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, 0, 0, hInstance, NULL);
hMainInstance = wc.hInstance;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
//callback definition
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int offset = 0;
switch (message) {
case WM_CREATE:
hMainWindow = hWnd;
hTxtInput = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), s_text_1,
WS_VISIBLE | WS_CHILD | ES_LEFT, 50, 50, 400, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
hButton = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("BUTTON"), TEXT("Press Me!"), WS_VISIBLE | WS_CHILD | WM_COPY | ES_LEFT, 500, 30, 100, 60, hWnd,
(HMENU)IDC_BUTTON, hMainInstance, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_BUTTON)
{
std::wstring input;
//resize added as suggested
input.resize(GetWindowTextLengthW(hTxtInput));
GetWindowTextW(hTxtInput, input.data(), input.size() + 1);
++offset;
hLblOutput = CreateWindowEx(WS_EX_STATICEDGE, TEXT("EDIT"), s_text_1, WS_VISIBLE | WS_CHILD | ES_READONLY | ES_LEFT, 50, 200 + offset * 26, 800, 25, hWnd,
(HMENU)IDC_TEXTBOX, hMainInstance, NULL);
SetWindowTextW(hLblOutput, input.data());
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I am making a notepad in C++, and I want to clear the text box when a certain button is clicked. I can't take the text box from the WinMain() function from the LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {...} where my text box is. This is the code for my text box
HWND hWndEdit = CreateWindow(TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER | WB_LEFT | ES_AUTOVSCROLL | ES_MULTILINE, 0, 0, 1366, 768, hWnd, NULL, NULL, NULL);
I've tried googling to no avail, mulled over many forums, and even placed the text box inside the LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {...}, and using SetWindowText(hWndEdit, _T("")), which causes my program to freeze. I am not sure on what to do. Putting the text box code back in the WinMain function stops it from freezing, but then I can't clear it anymore. What can I do?
If you need all my code here it is.
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
// Global variables
HMENU menuStrip;
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("NoteRecorder");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void AddMenuStrip(HWND hWnd);
int WINAPI 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(wcex.hInstance, L"");
wcex.hIconSm = LoadIcon(wcex.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;
}
hInst = hInstance;
// Height and width
int x = 1366;
int y = 768;
HWND hWnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
x, y,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("NoteRecorder"),
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)
{
HWND hWndEdit = CreateWindow(TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER | WB_LEFT | ES_AUTOVSCROLL | ES_MULTILINE, 0, 0, 1366, 768, hWnd, NULL, NULL, NULL);
switch (message)
{
case WM_COMMAND:
switch (wParam)
{
case 11:
SetWindowText(hWndEdit, _T(""));
MessageBox(NULL,
_T("The function has executed successfully."),
_T("NoteRecorder"),
MB_ICONASTERISK);
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
break;
case 21:
break;
case 22:
break;
case 23:
break;
case 24:
break;
case 25:
break;
case 26:
break;
case 31:
break;
case 41:
break;
case 42:
break;
}
break;
case WM_CREATE:
AddMenuStrip(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
void AddMenuStrip(HWND hWnd)
{
menuStrip = CreateMenu();
HMENU fileMenu = CreateMenu();
AppendMenu(fileMenu, MF_STRING, 11, L"New");
AppendMenu(fileMenu, MF_STRING, 12, L"Open");
AppendMenu(fileMenu, MF_STRING, 13, L"Save");
AppendMenu(fileMenu, MF_STRING, 14, L"Save As");
AppendMenu(fileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(fileMenu, MF_STRING, 15, L"Exit");
HMENU editMenu = CreateMenu();
AppendMenu(editMenu, MF_STRING, 21, L"Undo");
AppendMenu(editMenu, MF_STRING, 22, L"Redo");
AppendMenu(editMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(editMenu, MF_STRING, 23, L"Cut");
AppendMenu(editMenu, MF_STRING, 24, L"Copy");
AppendMenu(editMenu, MF_STRING, 25, L"Paste");
AppendMenu(editMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(editMenu, MF_STRING, 26, L"Select All");
HMENU formatMenu = CreateMenu();
AppendMenu(formatMenu, MF_BYCOMMAND, 31, L"Font...");
HMENU helpMenu = CreateMenu();
AppendMenu(helpMenu, MF_STRING, 41, L"Get Help");
AppendMenu(helpMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(helpMenu, MF_STRING, 42, L"About WorkPlace 247...");
// Menu Items for the MenuStrip
AppendMenu(menuStrip, MF_POPUP, (UINT_PTR)fileMenu, L"File");
AppendMenu(menuStrip, MF_POPUP, (UINT_PTR)editMenu, L"Edit");
AppendMenu(menuStrip, MF_POPUP, (UINT_PTR)formatMenu, L"Format");
AppendMenu(menuStrip, MF_POPUP, (UINT_PTR)helpMenu, L"Help");
SetMenu(hWnd, menuStrip);
}
I am using VS2019 MSVC, with Win32.
I'm also really bad at C++, and I want to learn. Thanks in advance.
Here is your problem:
HWND hWndEdit = CreateWindow(TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER | WB_LEFT | ES_AUTOVSCROLL | ES_MULTILINE, 0, 0, 1366, 768, hWnd, NULL, NULL, NULL);
That edit control will be created every time your main window gets ANY message, quickly running out of resources.
You only need to create it once (for example, in response to WM_CREATE message), and save that window handle in some static (or global) variable, so that you can use it later.
One way: add this to your "Global" section
// Global variables
HMENU menuStrip;
HWND hWndEdit = 0; // <- new line
then move a call to create that control into WM_CREATE handler:
case WM_CREATE:
AddMenuStrip(hWnd);
hWndEdit = CreateWindow(TEXT("EDIT"), TEXT(""), WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOVSCROLL | ES_MULTILINE, 0, 0, 1366, 768, hWnd, NULL, NULL, NULL);
break;
WndProc is called everytime event occures like (mouse move, click, size, paint...)
so an hWndEdit is created every message, that's the problem
you can do this:
you can keep it there but make it static
create hWndEdit in WinMain, give it ID, then in WM_COMMAND call hWndEdit = GetDlgItem(hWnd, ID)
create hWndEdit in WM_CREATE and do the same as in step two
make hWndEdit global and create it in WinMain, WM_CREATE or at any stage
I am writing my first Win32 app in C++ and I am trying to create 3 windows between which to redirect based on what buttons the user clicks on. I initialised the windows (window1,window2,window3) as children of the main window hwnd and only set window1 as visible. window1 also has two buttons, each of which is supposed to direct either to window2 or window3.
I tried to hide window1 and show which window I want to switch to using the ShowWindow() function. However, it is not working (clicking the buttons does nothing). Could you help me understand why?
On another piece of code I had before, where I had not created window1, and the buttons and the other two windows were just children of hwnd, pressing the button did show the right window, but the button remained there, even if it did not belong on that window.
Also, is there a more efficient way of switching between windows (without deleting and creating them again and again?
Thanks!!!
EDIT: I managed to solve my problem. It arose from the fact that I had declared windows 1,2 and 3 as static. By declaring them under the same class as hwnd, I was able to process the messages from the buttons under the main WindowProcedure(). Since my program is gonna be quite simple, I do not need to create a different procedure for the new windows, but thanks to the comments, now I also know how to do that!
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
window1 = CreateWindow("STATIC","Window 1",WS_VISIBLE|WS_BORDER|WS_CHILD,0,0,600,600,hwnd,NULL,NULL,NULL);
window2 = CreateWindow("STATIC","Window 2",WS_BORDER|WS_CHILD,0,0,600,600,hwnd,NULL,NULL,NULL);
button2 = CreateWindow(
"BUTTON",
"SECOND WINDOW",
WS_CHILD | WS_VISIBLE | WS_BORDER,
350, 480,
200, 20,
window1, (HMENU) 2, NULL, NULL);
window3 = CreateWindow("STATIC","Window 3",WS_BORDER|WS_CHILD,0,0,600,600,hwnd,NULL,NULL,NULL);
button3 = CreateWindow(
"BUTTON",
"THIRD WINDOW",
WS_CHILD | WS_VISIBLE | WS_BORDER,
50, 480,
200, 20,
window1, (HMENU) 3, NULL, NULL);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 2:
ShowWindow(window1,SW_HIDE);
ShowWindow(window2,SW_SHOW);
break;
case 3:
ShowWindow(window1,SW_HIDE);
ShowWindow(window3,SW_SHOW);
break;
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
First, create a new window1 as in the steps of creating the main form.
Then create a windowprocessforwindow1 for window1, process the WM_COMMAND message in this function.
Here is the sample:
#include <Windows.h>
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK windowprocessforwindow1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
static HWND window1, window2, button2, window3, button3;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("hello windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WindowProcedure;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
static HINSTANCE hInstance;
static WNDCLASSEX win1;
case WM_CREATE:
hInstance = (HINSTANCE)::GetWindowLong(hwnd, GWL_HINSTANCE);
win1.hInstance = hInstance;
win1.lpszClassName = L"Window 1";
win1.lpfnWndProc = (WNDPROC)windowprocessforwindow1; /* This function is called by windows */
win1.style = CS_DBLCLKS; /* Catch double-clicks */
win1.cbSize = sizeof(WNDCLASSEX);
win1.hIcon = LoadIcon(NULL, IDI_APPLICATION);
win1.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
win1.hCursor = LoadCursor(NULL, IDC_ARROW);
win1.lpszMenuName = NULL; /* No menu */
win1.cbClsExtra = 0; /* No extra bytes after the window class */
win1.cbWndExtra = 0; /* structure or the window instance */
win1.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if (!RegisterClassEx(&win1))
return 0;
window1 = CreateWindowEx(
0, /* Extended possibilites for variation */
L"Window 1", /* Classname */
L"Window 1", /* Title Text */
WS_VISIBLE | WS_BORDER | WS_CHILD, /* default window */
0, /* Windows decides the position */
0, /* where the window ends up on the screen */
600, /* The programs width */
600, /* and height in pixels */
hwnd, /* The window is a child-window to desktop */
NULL, /* No menu */
hInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
window2 = CreateWindow(L"STATIC", L"Window 2", WS_BORDER | WS_CHILD, 0, 0, 600, 600, hwnd, NULL, NULL, NULL);
button2 = CreateWindow(
L"BUTTON",
L"SECOND WINDOW",
WS_CHILD | WS_VISIBLE | WS_BORDER,
350, 480,
200, 20,
window1, (HMENU)2, NULL, NULL);
window3 = CreateWindow(L"STATIC", L"Window 3", WS_BORDER | WS_CHILD, 0, 0, 600, 600, hwnd, NULL, NULL, NULL);
button3 = CreateWindow(
L"BUTTON",
L"THIRD WINDOW",
WS_CHILD | WS_VISIBLE | WS_BORDER,
50, 480,
200, 20,
window1, (HMENU)3, NULL, NULL);
ShowWindow(window1, SW_SHOW);
break;
case WM_DESTROY:
PostQuitMessage(0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK windowprocessforwindow1(HWND handleforwindow1, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
{
switch (wParam) {
case 2:
ShowWindow(window1, SW_HIDE);
ShowWindow(window2, SW_SHOW);
break;
case 3:
ShowWindow(window1, SW_HIDE);
ShowWindow(window3, SW_SHOW);
break;
}
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(handleforwindow1, msg, wParam, lParam);
}
return 0;
}
I've created in plain win32 c++ an options menu with an edit box using embedded resources. The edit box ID_EDIT_OPTIONS_BOX has a default value of 30. I can change to value in the edit box to eg 10. I've used the OK-button the place the code for reading and writing the editbox. After I click OK, this new value is stored in my variable INT testInt. But when i re-open the options menu, the edit box still reflects the default value as stored in the resource file.
The basic code I use is this:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
Do I need to refresh the window or am I missing something really trivial? Below I've listed the full program code, resource header and file.
The program code:
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
// Global variables
static TCHAR szWindowClass[] = _T("DesktopApp");
static TCHAR szTitle[] = _T("Windows Desktop Guided Tour Application");
HINSTANCE hInst;
int testInt;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM 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 = MAKEINTRESOURCE(IDR_MENU);
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;
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
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 message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
case ID_EDIT_OPTIONS:
DialogBox(hInst, MAKEINTRESOURCE(ID_EDIT_OPTIONS), hWnd, (DLGPROC)CheckOptionsProc);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_EDIT_OPTIONS_OK:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
EndDialog(hDlg, IDOK);
break;
}
}
return 0;
}
The resource header
#define IDR_MENU 10
#define ID_FILE_EXIT 20
#define ID_EDIT_OPTIONS 30
#define ID_EDIT_OPTIONS_BOX 40
#define ID_EDIT_OPTIONS_OK 50
And resource file
#include "resource.h"
#include <windows.h>
IDR_MENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Options...", ID_EDIT_OPTIONS
END
END
ID_EDIT_OPTIONS DIALOGEX 0, 0, 260, 128
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Options"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
FONT 9, "SEGOE UI"
BEGIN
CONTROL "&OK", ID_EDIT_OPTIONS_OK, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 145, 110, 50, 11
CONTROL "30", ID_EDIT_OPTIONS_BOX, EDIT, ES_RIGHT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 200, 13, 18, 10
END
Use SetDlgItemInt when dialog received WM_INITDIALOG message:
LRESULT CALLBACK CheckOptionsProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
SetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, testInt, FALSE);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_EDIT_OPTIONS_OK:
testInt = GetDlgItemInt(hDlg, ID_EDIT_OPTIONS_BOX, NULL, FALSE);
EndDialog(hDlg, IDOK);
break;
}
}
return 0;
}
and remember to initialize testInt:
int testInt = 30;
So, I have two functions. First for handling parent events and second for handling child ones. Just a trivial approach.
// Parent
LONG WINAPI WndProc(HWND hwnd, UINT Message,
WPARAM wparam, LPARAM lparam) {
// задаются пользователем, по идее.
HDC hdc;
PAINTSTRUCT ps;
switch (Message) {
case WM_LBUTTONDOWN:
{
ShowWindow(hChildWnd, SW_SHOW | SW_SHOWNORMAL);
UpdateWindow(hChildWnd);
}
break;
case WM_COMMAND:
switch (lparam) {
case 300:
showNotification(L"Hey"); // not working???
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
// Child
LONG WINAPI WndProc1(HWND hwnd, UINT Message,
WPARAM wparam, LPARAM lparam) {
switch (Message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
switch (lparam) {
case 300:
showNotification(L"Hey"); // not working???
break;
}
break;
default:
return DefWindowProc(hwnd, Message, wparam, lparam);
}
return 0;
}
And of course I create, register classes, and init these windows in my WinMain function:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MSG msg;
// parent
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = CreateSolidBrush(0x00FFFFFF);
wc.lpszClassName = L"My Class";
RegisterClass(&wc);
// Child
WNDCLASS wcChild1;
memset(&wcChild1, 0, sizeof(WNDCLASS));
wcChild1.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcChild1.lpfnWndProc = (WNDPROC)WndProc1;
wcChild1.hInstance = hInstance;
wcChild1.hbrBackground = CreateSolidBrush(0x00FFFFFF);
wcChild1.lpszClassName = L"My Dialog Class";
RegisterClass(&wcChild1);
hWnd = CreateWindowW(L"My Class", L"График функции loga(x)",
WS_OVERLAPPEDWINDOW,
00, 00, 1366, 768, NULL, NULL,
hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hChildWnd = CreateWindowW(
L"My Dialog Class", L"Диалог",
WS_OVERLAPPED | WS_CAPTION,
10,
10,
90,
170,
NULL,
NULL,
hInstance,
NULL);
HWND hButton1 = CreateWindow(_T("button"), _T("OK"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
10,//x
90,//y
80,//width
30,//height
hChildWnd,
(HMENU)300,//id кнопки
hInstance, NULL);
ShowWindow(hChildWnd, SW_HIDE);
UpdateWindow(hChildWnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
But I can't handle this click event within WndProc1. And within WndProc, too. My debugger just bypasses my WM_COMMAND case entry. Maybe I register classes with wrong names? No, I copy-pasted them. I googled but found no answers. Please help.
From MSDN WM_COMMAND.
lParam represents a handle to a control window and in case of menu or
accelerator its 0.
You should use the LOWORD(wparam) to get the command id.