I want to handle a c++ win32 API button press in a native window, I'm currently attempting doing it like so -
#include <stdint.h>
#include <Windows.h>
#include <process.h>
#include <iostream>
#include <sstream>
#include <tchar.h>
#include <strsafe.h>
#include <crtdefs.h>
#include <stdafx.h>
#include <stdio.h>
#include "stdafx.h"
#include "name.h"
#include "libobs/obs.h"
#include "libobs/obs-module.h"
#define uploadName "Upload Window"
#define uploadWNDWidth 500
#define uploadWNDHeight 500
#define IDC_SELECT_VIDEO (100)
HWND hBtnParent = HWND("UploadVideo");
HWND SelectVideoBTN, UploadBTN, hWnd, hBtn;
WPARAM wmId, wmEvent;
HINSTANCE hUpload;
WNDCLASSEX wcexUpload;
int nCmdShowUpload = 1;
using namespace std;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
//load obs modules
class load{
public:
void static loading(){
obs_module_load;
obs_module_load_locale;
}
};
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case BM_CLICK:
if (wParam == IDC_SELECT_VIDEO) {
MessageBox(hWnd, L"if", L"if", 0);
}
else{
MessageBox(hWnd, L"else", L"else", 0);
}
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
bool obs_module_load(void)
{
//init handler
//HANDLE messageLoopThreadHandler;
//set the handler to the thread
//messageLoopThreadHandler = (HANDLE)_beginthreadex(0, 0, &messageLoopThread, 0, 0, 0);
//wait for object to be in specified state
//WaitForSingleObject(messageLoopThreadHandler, INFINITE);
//startMessageThreadLoop ThreadLoopInstance;
//ThreadLoopInstance.startMyThread();
MessageBox(hWnd, L"ThreadStart", L"ThreadStart", 0);
//create message loop for buttons
//cleanup thread created by _beginThreadEx
//CloseHandle(messageLoopThreadHandler);
WNDCLASSEX vidUploader;
vidUploader.cbSize = sizeof(WNDCLASSEX);
vidUploader.style = CS_HREDRAW | CS_VREDRAW;
vidUploader.lpfnWndProc = WndProc;
vidUploader.cbClsExtra = 0;
vidUploader.cbWndExtra = 0;
vidUploader.hInstance = hUpload;
vidUploader.hIcon = LoadIcon(hUpload, MAKEINTRESOURCE(IDI_P2GOVIDEOUPLOADER20));
vidUploader.hCursor = LoadCursor(NULL, IDC_ARROW);
vidUploader.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
vidUploader.lpszMenuName = MAKEINTRESOURCE(IDC_P2GOVIDEOUPLOADER20);
vidUploader.lpszClassName = (LPCWSTR)(L"UploadVideo");
vidUploader.hIconSm = LoadIcon(wcexUpload.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&vidUploader);
hInst = hUpload; // Store instance handle in our global variable
// 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 dows not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
hWnd = CreateWindow((LPCWSTR)(L"UploadVideo"), (LPCWSTR)(L"Upload Video's"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hUpload, NULL);
SelectVideoBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Select Video's", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
10, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
(HMENU)IDC_SELECT_VIDEO, // Assign appropriate control ID
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
UploadBTN = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
L"Upload", // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
390, // x position
460, // y position
100, // Button width
25, // Button height
hWnd, // Parent window
NULL, // No menu.
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL); // Pointer not needed.
RECT rect = { 0, 0, uploadWNDWidth, uploadWNDHeight };
AdjustWindowRect(&rect, GetWindowLong(hWnd, GWL_STYLE), FALSE);
SetWindowPos(hWnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE);
if (!hWnd)
{
MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
return 1;
}
MSG msge = { 0 };
while (PeekMessage(&msge, NULL, 0, 0, PM_REMOVE) > 0)
{
//translate and send messages
TranslateMessage(&msge);
DispatchMessage(&msge);
}
MSG msg;
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
//nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd, nCmdShowUpload);
UpdateWindow(hWnd);
load::loading();
return true;
}
When I currently load OBS, after having included the dll what happens is -
OBS starts
Window pops u
I click on window
Nothing happens
where on step 4, right after clicking on the button a MessageBox should popup saying - MessageBox(hWnd, L"else", L"else", 0); if it goes into the else, and if the if statement is true then MessageBox(hWnd, L"if", L"if", 0);
However my code won't even enter the callback function.
edit -
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
load::loading();
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
This is where the WndProc references refer to.
You're handling the receive of the button click incorrect. You should handle a WM_COMMAND message and check the high word of the WPARAM for the notification code.
You should use GetMessage, it won't hang the program.
You can use PeekMessage if you want constant update. For example in a game where you need to constantly paint the window. It has to be something like this:
//create window...
//show window...
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
//default message processing
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//constantly paint the window when there is no other message
render_window(hwnd);
}
}
//do cleanup here
return 0;
Note that the program terminates when the above while loop is finished. You cannot put ShowWindow/UpdateWindow after that.
Second, your main window seems to be vidUploader. And the window procedure for it is set to vidUploader.lpfnWndProc = WndProc; But you have not defined WndProc. Instead you have something else called WindowProcedure
To check for button notification:
case WM_COMMAND:
if (LOWORD(wParam) == IDC_SELECT_VIDEO)
MessageBox...;
break;
Related
When I build the program in visual studio It takes a long time to build and does not display properly, during this proccess it loads and unloads lots of what appears to be dll files in the console. If I remove the one line that starts with CreateWindowW(L"EDIT" the program will run perfectly. I have read through the documentation and I cant find what is wrong with it. Any help is appreciated.
Here is full code
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include<iostream>
#define file_menu_new 1
#define help_menu 2
#define file_menu_open 3
#define file_menu_exit 4
void AddMenus(HWND hwind);
HMENU hMenu;
void AddControls(HWND hwnd);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,_In_ PSTR szCmdLine, _In_ int iCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
//regesters class above with operateing system
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW | WS_VISIBLE, // Window style
// Size and position
500, 200, 800, 500,//WS_DEFAULT OR SOMETHING LIKE THAT
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, iCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
{
switch (wParam)
{
case file_menu_new:
MessageBeep(MB_OK);//this creates a sound
break;
case file_menu_exit:
DestroyWindow(hwnd);
break;
case file_menu_open:
MessageBeep(MB_ICONINFORMATION);
default:
break;
}
}
case WM_CREATE:
{
AddControls(hwnd);
AddMenus(hwnd);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
break;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void AddMenus(HWND hwind)
{
hMenu = CreateMenu();//main menu bar
HMENU hFileMenu = CreateMenu();//this is a drop down menu for the file part of main menu
//AppendMenu(hMenu, MF_STRING, 1, L"File");//1 is the identity of this main menu
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"File");//this is how you make it pop up another menu
AppendMenu(hFileMenu, MF_STRING, file_menu_new, L"New");//adds stuff to hFileMenu with the id of 1
AppendMenu(hFileMenu, MF_STRING, file_menu_open, L"Open");//adds stuff to hFileMenu with the id of 3
AppendMenu(hFileMenu, IMFT_SEPARATOR, NULL, NULL);//creates a seperator or a line under open
AppendMenu(hFileMenu, MF_STRING, file_menu_exit, L"Exit");
AppendMenu(hMenu, MF_STRING, help_menu, L"Help");//2 is the identity of this main menu
//sets the hMenu to the hwind menu or the main menu
SetMenu(hwind, hMenu);
}
void AddControls(HWND hwnd)
{
CreateWindowW(L"static", L"Enter Text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER | WS_EX_TRANSPARENT,
200, 100, 100, 50, hwnd, NULL, NULL, NULL);
CreateWindowW(L"EDIT", L"Enter Text here: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER,
200, 160, 100, 50, hwnd, NULL, NULL, NULL);
}
Add wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); and remove WM_PAINT. If you don't set a class background you need to handle WM_ERASEBKGND or otherwise validate the background color painting.
I have successfully opened a win32 window(without OpenGL context). Opening the window, then resizing it causes a lot of issues. How do we properly handle resizing inside the win32 api? I create a window with WS_OVERLAPPEDWINDOW and making the window resizable. Mainly, I attempt to handle the resizing with the WM_SIZE event handler.
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <iostream>
using namespace std;
HINSTANCE hInstanceGlobal;
LRESULT CALLBACK wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
switch (message) {
default:
return DefWindowProcA(hWnd, message, wParam, lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;
case WM_KEYDOWN:
break;
case WM_SETCURSOR:
if (LOWORD(lParam) == HTCLIENT) {
SetCursor(LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
break;
}
return DefWindowProcA(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd) {
#ifdef _DEBUG
AllocConsole();
//SetWindowPos(GetConsoleWindow(), 0, 1920, 200, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
AttachConsole(GetCurrentProcessId());
freopen("CON", "w", stdout);
#endif
hInstanceGlobal = hInstance;
const char* CLASSNAME = "APIOPENGL";
WNDCLASS cl = { };
cl.lpfnWndProc = wndproc;
cl.hCursor = LoadCursor(NULL, IDC_ARROW);
cl.hInstance = hInstance;
cl.lpszClassName = CLASSNAME;
RegisterClass(&cl);
HWND hWnd = CreateWindowEx(
WS_EX_APPWINDOW|WS_EX_CLIENTEDGE,
CLASSNAME,
"Opengl Window",
WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (hWnd == NULL)
{
return 0;
}
ShowWindow(hWnd, nShowCmd);
MSG msg;
MessageBox(NULL, (char*)GetLastError(), "Hello", NULL);
bool bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (GetKeyState(VK_RMENU) & 0x8000)
{
cout << "Pressed" << endl;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Check this out: Resize window with Win32 API
In your WM_PAINT handler, it's possible that your getting that strange result because you aren't calling the FillRect function.
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(m_hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 6));
EndPaint(m_hwnd, &ps);
The problem in the screenshot (black background) is because you have not set the hbrBackground member of the window class. According to the document:
When this member is NULL, an application must paint its own
background whenever it is requested to paint in its client area. To
determine whether the background must be painted, an application can
either process the WM_ERASEBKGND message or test the fErase
member of the PAINTSTRUCT structure filled by the
BeginPaint function.
Like the answer of #Stra, use FillRect to fill the background.
Or initialize hbrBackground:
hInstanceGlobal = hInstance;
const char CLASSNAME[] = "APIOPENGL";
WNDCLASS cl = { };
cl.lpfnWndProc = wndproc;
cl.hCursor = LoadCursor(NULL, IDC_ARROW);
cl.hInstance = hInstance;
cl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
cl.lpszClassName = CLASSNAME;
RegisterClass(&cl);
Then you don’t need to process the WM_SIZE message.
In addition, you don’t need to call GetKeyState to get the VK_RMENU key Presse event, just process the WM_SYSKEYDOWN message and Indicates whether the key is an extended key:
/*case WM_SIZE:
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;*/
case WM_SYSKEYDOWN:
if (VK_MENU == wParam)
{
BOOL bit = (lParam >> 24) & 1;
if (bit)
cout << "Pressed" << endl;
}
return 0;
I'm trying to make button change background color of window when clicked. I know that I need to handle this event in WM_COMMAND, where I also check ID of this button, but nothing happens. I tried to debug and my program recognizes ID correctly. The piece of code used for changing color works well when in main loop but it doesn't do anything when in WM_COMMAND. How do I solve this problem? Whole code:
#include <Windows.h>
#define BUTTON_ID 100
struct status_info {
const char* waiting = "Waiting for connection...";
const char* connected = "Connected.\nWaiting for frajer to copy number.";
const char* changed = "Number changed.";
}status_info;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
const wchar_t CLASS_NAME[] = L"Name";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = (LPCSTR)CLASS_NAME;
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
RegisterClass(&wc);
//main window
HWND hwnd = CreateWindowEx(0, (LPCSTR)CLASS_NAME, (LPCSTR)"Hacker", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 500, 300, NULL, NULL, hInstance, NULL);
//number window
HWND number = CreateWindowEx(WS_EX_WINDOWEDGE, TEXT("Static"), TEXT("Account number:\n00 1234 1234 1234 1234 1234 1234"), WS_CHILD | WS_VISIBLE, 5, 5, 240, 40, hwnd, NULL, NULL, NULL);
//status window
const char* status_message = status_info.waiting;
HWND status = CreateWindowEx(WS_EX_WINDOWEDGE, TEXT("Static"), TEXT(status_message), WS_CHILD | WS_VISIBLE, 5, 55, 240, 40, hwnd, NULL, NULL, NULL);
//button
HWND button = CreateWindowEx(0, "BUTTON", "Nightmode", WS_CHILD | WS_VISIBLE, 100, 100, 150, 30, hwnd, (HMENU)BUTTON_ID, hInstance, NULL);
MSG msg;
WNDCLASS okno;
while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
SetWindowText(status, status_message);
}
return msg.wParam;
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//MessageBox(hwnd, L"1", L"1", 0);
return (0);
case WM_DESTROY:
//MessageBox(hwnd, L"2", L"2", 0);
PostQuitMessage(0);
return (0);
case WM_COMMAND: {
if (LOWORD(wParam) == BUTTON_ID) {
PAINTSTRUCT ps;
RECT rc;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetBkColor(hdc, BLACK_BRUSH);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, 0, 0, 0);
EndPaint(hwnd, &ps);
}
break;
}
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
BeginPaint/EndPaint should be used in response to WM_PAINT only.
You can use GetDC(hwnd)/ReleaseDC(hwnd, hdc) to obtain hdc for painting on device context outside of WM_PAINT, but this will be temporary. The next refresh message causes the window to be erased and repainted according to what's in WM_PAINT
SetDCBrushColor can be used if the goal is to avoid creating brush handle.
static COLORREF bkcolor = RGB(255,255,255);
switch(message)
{
case WM_COMMAND:
if(LOWORD(wparam) == BUTTON_ID)
{
bkcolor = RGB(255, 0, 0);
InvalidateRect(hwnd, NULL, TRUE);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
HDC hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetDCBrushColor(hdc, bkcolor);
FillRect(hdc, &rc, (HBRUSH)GetStockObject(DC_BRUSH));
//or use ps.rcPaint to repaint only the section which requires update
//FillRect(hdc, &ps.rcPaint, (HBRUSH)GetStockObject(DC_BRUSH));
EndPaint(hwnd, &ps);
return 0;
}
case WM_ERASEBKGND:
//return 0 means WM_PAINT handles the background
return 0;
Alternatively, use SetClassLongPtr to replace the background brush:
static HBRUSH bkbrush = NULL;
switch(message)
{
case WM_COMMAND:
if(LOWORD(wparam) == BUTTON_ID)
{
COLORREF bkcolor = RGB(rand() % 256, rand() % 256, rand() % 256);
if(bkbrush)
DeleteObject(bkbrush);
bkbrush = CreateSolidBrush(bkcolor);
SetClassLongPtr(hwnd, GCL_HBRBACKGROUND, (LONG)bkbrush);
InvalidateRect(hwnd, NULL, TRUE);
}
break;
I am using WinAPI and im trying to make a program which allows you to change the title.
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#include <tchar.h>
#include <windows.h>
#include <string>
#include <sstream>
using namespace std;
string HWNDToString(HWND inputA);
void setTitle(string inputA);
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(255,128,0));
if (!RegisterClassEx (&wincl)) return 0;
hwnd = CreateWindowEx
(
0,
szClassName,
_T("Title Changer"),
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
400 + 22,
400 + 49,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL
);
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
HWND textout, titlebutton , powerbutton, textin;
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
textout = CreateWindow("STATIC", "Enter new window title here:", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 0, 230, 20, hwnd, NULL, NULL, NULL);
textin = CreateWindow("EDIT", "New Title", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, 0, 20, 250, 25, hwnd, (HMENU) NULL, NULL, NULL);
titlebutton = CreateWindow("BUTTON", "Set as New Window Title", WS_VISIBLE | WS_CHILD | WS_BORDER, 0, 45, 210, 25, hwnd, (HMENU) /*=*/1/*=*/, NULL, NULL);
powerbutton = CreateWindow("BUTTON", "Power Off", WS_VISIBLE | WS_CHILD | WS_BORDER, 316, 0, 100, 25, hwnd, (HMENU) 2, NULL, NULL);
break;
case WM_COMMAND:
if (LOWORD(wParam) == 1)
{
SetWindowText(hwnd, HWNDToString(textin).c_str());
MessageBox(hwnd, string("Title changed to: " + HWNDToString(textin)).c_str(), "Title Changed", MB_OK | MB_ICONINFORMATION);
}
if (LOWORD(wParam) == 2)
{
PostQuitMessage(0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
break;
}
return 0;
}
string HWNDToString(HWND inputA)
{
stringstream stringstreamBuffer;
stringstreamBuffer << inputA;
return stringstreamBuffer.str();
}
But the program sets the title to a random hex-like string (for example, 0x123abc).
What is wrong with the HWNDToString function I defined? Do I need to use sprintf to convert hex to string?
OS: Windows 7 Ultimate x64
IDE: Codeblocks
Compiler: GNU GCC Compiler (MinGW32)
An HWND is a pointer (struct HWND__* or void*, depending on whether STRICT is enabled or disabled, respectively). Passing such a pointer to operator<< of an std::ostream-based class will invoke operator<<(const void*) which formats the pointed-to memory address as a hex string.
Since you are trying to accept a string value from the user using an EDIT control and then set your main window's title with the value of that string, you should be using the GetWindowTextLength() and GetWindowText() functions instead:
string HWNDToString(HWND inputA)
{
string s;
int len = GetWindowTextLength(inputA);
if (len > 0)
{
s.resize(len + 1);
len = GetWindowText(inputA, &s[0], s.size());
s.resize(len);
}
return s;
}
case WM_COMMAND:
if (LOWORD(wParam) == 1)
{
string s = HWNDToString(textin);
SetWindowText(hwnd, s.c_str());
MessageBox(hwnd, string("Title changed to: " + s).c_str(), "Title Changed", MB_OK | MB_ICONINFORMATION);
}
...
On a side note, your "Power Off" button should be sending a WM_CLOSE message to your main window, not calling PostQuitMessage() directly:
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
...
case WM_COMMAND:
....
if (LOWORD(wParam) == 2)
{
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
// By default, DefWindowProc() handles WM_CLOSE by destroying the window
// using DestroyWindow(). WM_CLOSE is also received when the user closes
// the window manually. This allows you to close down your app correctly
// regardless of how the window is closed. You can handle WM_CLOSE
// manually if you want to prompt the user before allowing the
// window to be destroyed...
/*
case WM_CLOSE:
if (MessageBox(hwnd, "Are you sure you want to power down?", "Power Down?", MB_YESNO) == IDYES)
DestroyWindow(hwnd);
break;
*/
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
See MSDN's documentation on Destroying a Window for more details.
For those who stumble upon this question, here is a very simple function to do that:
#include <string>
#include <windows.h>
string HWNDToString(HWND input)
{
string output = "";
size_t sizeTBuffer = GetWindowTextLength(input) + 1;
if(sizeTBuffer > 0)
{
output.resize(sizeTBuffer);
sizeTBuffer = GetWindowText(input, &output[0], sizeTBuffer);
output.resize(sizeTBuffer);
}
return output;
}
I found that for some unknown reason when focus is in Edit control, the Escape key never produces a messages.
Below is a code to create a parent window, and Edit control above it. In MyCallBckProcedure() I laid printf() under a *WM_COMMAND*, to catch a messages, produced by Edit. More over -- I even tried to print all the messages catched in MyCallBckProcedure(); but if focus on Edit, the escape key never produces any of messages.
What a weird problem could be here?
#include <iostream>
#include <windows.h>
#include <stdio.h>
#define IDC_MAIN_EDIT 101
LRESULT __stdcall MyCallBckProcedure( HWND window, unsigned msg, WPARAM wp, LPARAM lp ){
printf("%x ",msg);
switch(msg){
case WM_COMMAND://here should be catched the escape key of Edit
printf("%x ",msg);
break;
case WM_KEYDOWN:
printf("%x ",msg);
if(wp == VK_ESCAPE)PostQuitMessage(0);
break;
case WM_DESTROY:
std::cout << "\ndestroying window\n" ;
PostQuitMessage(0);
return 0;
default:
return DefWindowProc( window, msg, wp, lp ) ;
break;
case WM_SIZE:{
HWND hEdit;
RECT rcClient;
GetClientRect(window, &rcClient);
hEdit = GetDlgItem(window, IDC_MAIN_EDIT);
SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
}
break;
}
}
int main(){
const char* const myclass = "myclass";
WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyCallBckProcedure,
0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
0, myclass, LoadIcon(0,IDI_APPLICATION) };
if(RegisterClassEx(&wndclass)<0){
printf("ERR: in registering window class\n");
return 1;
}
//Creating window
HWND window = CreateWindowEx( 0, myclass, "title",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0 );
if(!window){
printf("ERR: in creating window\n");
return 1;
}
ShowWindow( window, SW_SHOWDEFAULT );
MSG msg;
//creating TextBox on the window
HFONT hfDefault;
HWND hEdit;
hEdit = CreateWindowEx(0, "edit", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
window, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
if(hEdit == NULL){
MessageBox(window, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
return 1;
}
hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
//Now resize TextBox to fill whole parent window
RECT RectSize;
GetClientRect(window,&RectSize);
hEdit = GetDlgItem(window,IDC_MAIN_EDIT);
SetWindowPos(hEdit, 0,0,0,RectSize.right,RectSize.bottom,SWP_NOZORDER);
//Process messages
while(GetMessage(&msg,0,0,0) ){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Pressing ESC while the Edit is in focus does not generate a WM_COMMAND message to the Edit's parent window. It generates WM_KEYDOWN, WM_KEYUP, WM_CHAR and WM_UNICHAR messages to the Edit window itself.
Update: You are only handling messages that are destined for the parent window. You need to assign a message procedure to the edit window instead, eg:
WNDPROC lpEditWndProc;
LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
{
PostQuitMessage(0);
return 0;
}
return CallWindowProc(lpEditWndProc, hWnd, uMsg, wParam, lParam);
}
...
HWND hEdit = CreateWindowEx(...);
#ifdef _WIN64
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#else
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWL_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#endif
Alternatively:
LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
{
PostQuitMessage(0);
return 0;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
...
HWND hEdit = CreateWindowEx(...);
SetWindowSubclass(hEdit, &MyEditCallBckProcedure, 0, 0);