Win32 Combobox, print the name of selected to edit text box - c++

I am testing out a thoery for the Combobox for win32. Many things have been tried but I am not understanding how to make it do what I want it to do. When the selection is made in the combo box I want it to print into the edit box. I believe this would be done through the handle maybe.
So if I add it to my button 1 through a cast for button 1 how do you get it to print out to the edit field??
My code is below. I left in some of the things I tried but commented it out. The problem is in add controls and I am thinking my switch and case.
I am missing that one part that populate the text to the edit box.
I am not so much new to programming so much as new to this type of programming. I am looking for a simple approach. Thanks in advance for your time.
Below is the updated code and what I got for now. I followed the guidelines for unicode. I even made friends with visual studio c++(I think).
#include <windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#define OPTINBT1 1
#define OPTINBT2 2
#define COMBO1 3
HWND hWnd, hComboOne;
void addControl(HWND);
LPCWSTR egClassName = L"myWindowClass";
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int nCmdShow)
{
WNDCLASSW wc = { 0 };
wc.lpszClassName = egClassName;
wc.lpfnWndProc = WindowProcedure;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hInstance = hInst;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (!RegisterClassW(&wc))
{
const wchar_t Error01[] = L"Register Issue To Check On : ";
const wchar_t Error01_Caption[] = L"Error 01";
MessageBoxW(hWnd, Error01, Error01_Caption, MB_OK | MB_ICONERROR);
return 0;
}
LPCWSTR parentWinTitle = L"My Window";
hWnd = CreateWindowW(egClassName, parentWinTitle, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL);
if (hWnd == NULL)
{
const wchar_t Error02[] = L"Window Creation Issue To Check On : ";
const wchar_t Error02_Caption[] = L"Window Creation Issue To Check On : ";
MessageBoxW(hWnd, Error02, Error02_Caption, MB_OK | MB_ICONERROR);
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
addControl(hWnd);
break;
case WM_COMMAND:
if (HIWORD(wp) == CBN_SELCHANGE)
{
if (LOWORD(wp) == COMBO1)
{
HWND hcombo = (HWND)lp;
LRESULT index = SendMessageW(hcombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
wchar_t buf[256];
SendMessageW(hcombo, (UINT)CB_GETLBTEXT, (WPARAM)index, (LPARAM)buf);
MessageBoxW(hWnd, buf, L"Good Example", 0);
}
break;
}
switch (LOWORD(wp))
{
case OPTINBT1:
MessageBoxW(hWnd, L"This is Radio button1: ", L"Radio Button 2 is good", MB_OK);
break;
case OPTINBT2:
MessageBoxW(hWnd, L"This is Radio button2: ", L"Radio Button 1 is good", MB_OK);
break;
default:break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}
void addControl(HWND hWnd)
{
HWND OptBt1, OptBt2;
const LPCWSTR cont1 = L"STATIC";
const LPCWSTR cont2 = L"COMBOBOX";
const LPCWSTR cont3 = L"BUTTON";
const LPCWSTR emptyS = L"";
const LPCWSTR bl = L"RButton 1";
const LPCWSTR b2 = L"RButton 2";
//Option buttons
OptBt1 = CreateWindowW(cont3, bl, WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 24, 8, 90, 25, hWnd, (HMENU)OPTINBT1, NULL, NULL);
OptBt2 = CreateWindowW(cont3, b2, WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 24, 40, 90, 25, hWnd, (HMENU)OPTINBT2, NULL, NULL);
SendMessage(OptBt1, BM_SETCHECK, BST_CHECKED, 0);
hComboOne = CreateWindowW(cont2, emptyS, WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | CBS_HASSTRINGS | WS_VSCROLL, 77, 70, 150, 150, hWnd, (HMENU)COMBO1, 0, 0);
LPCWSTR ComboBoxItems[] = { L"Subject1", L"Subject2", L"Subject3",
L"Subject4", L"Subject5" };
/** Or the array way */
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[0]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[1]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[2]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[3]);
SendMessageW(hComboOne, CB_ADDSTRING, 0, (LPARAM)ComboBoxItems[4]);
}

WM_CREATE should be inserted before addControl.
In WM_COMMAND respond to CBN_SELCHANGE notification to detect combobox selection change.
When you show a message box you can use the handle of your own window MessageBox(hWnd,...). If you supply NULL as the handle then the message box becomes the child of desktop window, it behaves as if it is displayed in modeless mode.
switch(msg)
{
case WM_CREATE:
addControl(hWnd);
break;
case WM_COMMAND:
if(HIWORD(wp) == CBN_SELCHANGE)
{
if(LOWORD(wp) == COMBO1)
{
HWND hcombo = (HWND)lp;
int index = SendMessage(hcombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
char buf[256];
SendMessage(hcombo, (UINT)CB_GETLBTEXT, (WPARAM)index, (LPARAM)buf);
MessageBox(hWnd, buf, 0, 0);
}
break;
}
switch(LOWORD(wp))
{
case OPTINBT1:
MessageBox(hWnd, "This is Radio button1: ", "ComboBox Working??", MB_OK);
break;
case OPTINBT2:
MessageBox(hWnd, "This is Radio button2: ", "ComboBox Working??", MB_OK);
break;
default:break;
}
break;
Not related to your problem, but you are mixing Unicode (example L"EDIT") with ANSI (example "EDIT").
Window functions like CreateWindow are macros. In ANSI it is CreateWindowA, and in Unicode it is the wide function CreateWindowW
You are compiling your program in old ANSI mode. CreateWindow is a macro to CreateWindowA which needs ANSI input. CreateWindow("EDIT",...)
If you compile your program in Unicode, CreateWindow is a macro for the wide function CreateWindowW which uses Unicode parameter CreateWindow(L"EDIT",...)
If you create a project in Visual Studio it will default to the new Unicode standard. Use wide char (L"Text") and Unicode functions everywhere. I would recommend compiling the program with warning level 4. Make sure the program compiles with zero warnings.

You want to respond to the CBN_SELCHANGE message that is sent to your window procedure. In the case of WM_COMMAND the low word of wParam will contain the control ID, the high word will contain an optional command code.
That command code is critical for properly responding to combo box messages. You will want to respond to the CBN_SELCHANGE message by sending the combo box a CB_GETCURSEL and then CB_GETLBTEXTLEN and CB_GETLBTEXT, after that you can send your edit control a WM_SETTEXT with the retrieved text.

Related

win32 GUI not loading properly after adding an edit window

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.

Why is C++ ShowWindow() not working properly when hiding a window and showing another?

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;
}

Edit control doesn't work correctly

I started to learning winapi c++ today. And i wrote this simple program that have to change window name to the name that i write in text box:
#include <Windows.h>
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void AddMenu(HWND);
void AddControl(HWND);
HWND hEdit;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrewInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"class";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
return -1;
CreateWindowW(L"class", L"Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (wp)
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION); break;
case 2:
DestroyWindow(hWnd); break;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
break;
}
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
void AddMenu(HWND hWnd)
{
HMENU hMenu;
hMenu = CreateMenu();
HMENU file;
file = CreateMenu();
HMENU Sub;
Sub = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)file, "File");
AppendMenu(file, MF_STRING, 1, "Open");
AppendMenu(file, MF_POPUP, (UINT_PTR)Sub, "Sub");
AppendMenu(file, MF_STRING, 2, "Exit");
AppendMenu(Sub, MF_STRING, 3, "Change");
SetMenu(hWnd, hMenu);
}
void AddControl(HWND hWnd)
{
CreateWindowW(L"Static", L"Enter text: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 20, hWnd, NULL, NULL, NULL);
hEdit = CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 200, 152, 100, 50, hWnd, NULL, NULL, NULL);
}
By default in text box i have .... So i run my program, starting to type hello world for expample but nothing changes. I highlited my 3 dots that had to change and boom, my text appeared. I go to the menu choose File -> Sub -> Change and my window name changes to 3 dots ....
BUT! If i delete these: | ES_MULTILINE | ES_AUTOVSCROLL then text box working correctly but menu doesnt show up in my window.
I found that i have to do smth with EN_CHANGE but idk what. I tried to change WM_COMMAND to EN_CHANGE and my textbox worked correctly, but other menu buttons didnt work at all...
Your failure is caused by handling all the edit control notifications the same way. You need to test the notification code (found in HIWORD(wParam)) to see whether it is EN_CHANGE, and let notifications you aren't handling pass through to DefWindowProc.
You also have an even bigger bug in that you reach the closing brace of a function with a non-void return type. You need to always return something; when you aren't calling DefWindowProc the system still expects a return value. The reason things start working when you change WM_COMMAND to EN_CHANGE is not because you are handling EN_CHANGE, it is because you no longer have incorrect handling of WM_COMMAND, and instead let the DefWindowProc take them.
The fall-through from WM_COMMAND into WM_CREATE isn't helping things either.
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (HIWORD(wParam)) /* command kind */
{
case 0: // menus
switch (LOWORD(wParam)) /* child ID */
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION);
return 0;
case 2:
DestroyWindow(hWnd);
return 0;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
return 0;
}
break;
}
break;
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
// break actions also reach here
return DefWindowProcW(hWnd, msg, wParam, lParam);
}

C++ WinAPI: HWND To String Returning Hex

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;
}

How to use custom icons for toolbars in winapi programming

I'm trying to use my own custom images for creating a toolbar in a win32 winapi program. This is what I have ( in my WM_CREATE case ):
#define IDT_MAIN_TOOL 101
TBBUTTON tbb[ 1 ];
TBADDBITMAP tbab;
HWND hToolbar = CreateWindowEx( 0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT, 0, 0, 0, 0, hwnd, ( HMENU )IDT_MAIN_TOL, NULL, NULL );
SendMessage( hToolbar, TB_BUTTONSTRUCTSIZE, ( WPARAM )sizeof( TBBUTTON ), 0 );
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_HIST_LARGE_COLOR;
SendMessage( hToolbar, TB_ADDBITMAP, 0, ( LPARAM )&tbab );
ZeroMemory( tbb, sizeof( tbb ) );
tbb[ 0 ].iBitmap = HIST_BACK;
// I've also tried tbb[ 0 ].iBitmap = LoadIcon( NULL, "browse_back.ico" );
// However, iBitmap must be an integer and can't figure out how to use my 'browse_back.ico' image
tbb[ 0 ].fsState = TBSTATE_ENABLED;
SendMessage( hToolbar, TB_ADDBUTTONS, sizeof( tbb ) / sizeof( TBBUTTON ), ( LPARAM )&tbb );
I would like to use my own icon image: 'browse_back.ico' as the image for that toolbar button. How is this accomplished? Not sure if this is necessary but I'm using Microsoft Visual C++ 2010 Express.
Read the documentation:
iBitmap
Type: int
Zero-based index of the button image. Set this member to I_IMAGECALLBACK, and the toolbar will send the TBN_GETDISPINFO notification code to retrieve the image index when it is needed.
Version 5.81. Set this member to I_IMAGENONE to indicate that the button does not have an image. The button layout will not include any space for a bitmap, only text.
If the button is a separator, that is, if fsStyle is set to BTNS_SEP, iBitmap determines the width of the separator, in pixels. For information on selecting button images from image lists, see TB_SETIMAGELIST message.
So you need to create an image list using ImageList_Create(), add your ICO image to it using ImageList_Add() or ImageList_ReplaceIcon(), associate it with the toolbar using TB_SETIMAGELIST, and then you can set tbb[0].iBitmap to the ICO's index within the image list.
There are two ways that I know doing it. One is using TBADDBITMAP and the other one is using HIMAGELIST. In this example I use TBADDBITMAP but I personally prefer HIMAGELIST.
project.rc
#include "resource.h"
IDB_DOCUMENT BITMAP "document.bmp"
IDB_DRUGS BITMAP "drugs.bmp"
resource.h
#define IDTB_TOOLBAR 1000
#define IDB_DOCUMENT 1001
#define IDB_DRUGS 1002
#define ID_ADD_NEW 2000
tb.c
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
const char ClassName[] = "ToolbarExample";
HWND hWndToolBar;
HINSTANCE g_hInstance;
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_CREATE:
{
TBADDBITMAP tbab1, tbab2;
TBBUTTON tbb[2];
hWndToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd,
(HMENU)IDTB_TOOLBAR, g_hInstance, NULL);
if (!hWndToolBar)
{
MessageBox(NULL, "ToolBar Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
SendMessage(hWndToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(hWndToolBar, TB_SETBITMAPSIZE, (WPARAM)0, (LPARAM)MAKELONG(32, 32));
// Add Bitmaps
tbab1.hInst = g_hInstance;
tbab1.nID = IDB_DOCUMENT;
SendMessage(hWndToolBar, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tbab1);
tbab2.hInst = g_hInstance;
tbab2.nID = IDB_DRUGS;
SendMessage(hWndToolBar, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tbab2);
// Add Buttons
ZeroMemory(tbb, sizeof(tbb));
tbb[0].iBitmap = 0; // The index of the bitmap on toolbar bitmap collection
tbb[0].idCommand = ID_ADD_NEW;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = TBSTYLE_BUTTON;
tbb[0].iString = SendMessage(hWndToolBar, TB_ADDSTRING, 0, (LPARAM)TEXT("Add New"));
tbb[1].iBitmap = 1;
tbb[1].idCommand = 0;
tbb[1].fsState = TBSTATE_ENABLED;
tbb[1].fsStyle = TBSTYLE_BUTTON;
tbb[1].iString = SendMessage(hWndToolBar, TB_ADDSTRING, 0, (LPARAM)TEXT("Drugs"));
SendMessage(hWndToolBar, TB_ADDBUTTONS, sizeof(tbb) / sizeof(TBBUTTON), (LPARAM)&tbb);
}
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case ID_ADD_NEW:
{
MessageBox(NULL, "Toolbar Button One", "Success", MB_OK | MB_ICONINFORMATION);
}
break;
}
return 0;
}
break;
case WM_SIZE:
SendMessage(hWndToolBar, TB_AUTOSIZE, 0, 0);
break;
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)
{
InitCommonControls();
g_hInstance = hInstance;
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)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 = ClassName;
if (!RegisterClass(&wc))
{
MessageBox(NULL, "Failed To Register The Window Class.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
HWND hWnd;
hWnd = CreateWindow(ClassName, "Toolbars", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
MessageBox(NULL, "Window Creation Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}