I am creating a Windows desktop application using win32 api in visual studio 2019. I know there are many other options avialable to build UI like MFC, XAMAL and C#, but i needed to build it in win32. I have learnt some basics in win32 api but recently i was working on tabControll and there i got an issue or i missed some thing. I am creating two tabs and want to add different content withing them. My current code is working and creating the tabs but it is adding same content in both tabs. How should i define each tab's content differently.
void createTabView(HWND hWnd) {
RECT rcClient;
INITCOMMONCONTROLSEX icex;
static HWND hwndTab_1_1_1;
HWND hwndTab;
TCITEM tie;
int i;
TCHAR achTemp[256];
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
GetClientRect(hWnd, &rcClient);
hwndTab = CreateWindow(WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hWnd, NULL, hInst, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 1, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 2, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
HWND hwndStatic = CreateWindow(WC_STATIC, L"",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInst, // g_hInst is the global instance handle
NULL);}
The tab control triggers the WM_NOTIFY signal when the tab page is switched, so as long as we process the WM_NOTIFY message, we can control the tab control message.
In the WM_NOTIFY message:
wParam: a control ID that identifies the WM_NOTIFY message sent.
lParam: a pointer to the NMHDR structure.
Therefore, we can determine the notification code sent by the Tab control in the WM_NOTIFY message processing program by judging the code value in the NMHDR structure.
We can use TCN_SELCHANGE to handle the operation when the Tab tab changes, and use TabCtrl_GetCurSel to get the index of the current tab and define the content of the current tab.
Here is the sample:
#include <Windows.h>
#include <commctrl.h>
LRESULT CALLBACK WndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
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 WndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
static HINSTANCE hInstance;
static HWND hwndTab = 0 , hwndStatic = 0;
TCITEM tie;
RECT rcClient;
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
TCHAR tabLBL1[256];
GetClientRect(hwnd, &rcClient);
switch (message)
{
case WM_CREATE:
{
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hwndTab = CreateWindow(WC_TABCONTROL, "",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
0, 0, rcClient.right, rcClient.bottom,
hwnd, NULL, hInstance, NULL);
// Add tabs for each day of the week.
tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
wsprintf(tabLBL1, "tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, "tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
SendMessage(hwndTab, WM_SETFONT,
reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), 0);
hwndStatic = CreateWindow(WC_STATIC, "",
WS_CHILD | WS_VISIBLE | WS_BORDER,
200, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic,TRUE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NOTIFY:
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
{
int tabID = TabCtrl_GetCurSel(hwndTab);
switch (tabID)
{
case 0:
ShowWindow(hwndStatic, TRUE);
break;
case 1:
ShowWindow(hwndStatic, FALSE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Not sure if this is the solution, but the iItem parameter to TabCtrl_InsertItem is zero-based. Try:
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
tie.pszText = tabLBL2;
TabCtrl_InsertItem(hwndTab, 1, &tie);
Also (and I'm not sure if this is relevant), you look like you intended to call InitCommonControlsEx in your code but fail to do so.
Related
My goal is to create 5 groups of radio buttons (i know it contradict with the title but you still get the point) for user choice using only Win32 API (so no window form here).
I tried using a combination of groupbox and SetWindowLongPtr but it still not working as expected (note that im using GWLP_WNDPROC as the index). If i use SetWindowLongPtr to a group box then that groupbox is gone and everything else work as expected.
I could use a "virtual" group box but it reduce the efficency of my code. Some one might recommend using WS_GROUP but it only apply if there are 2 group of radio buttons ( I think ). And i also dont like using resource so is there any solution to this problem or i just have to stuck with the "virtual" group box?
Minimal reproducible sample:
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
L"Sample window",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, // Window style
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL,
NULL,
hinst,
NULL);
HWND groupbox = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 10, 100, 100, NULL, NULL, hinst, NULL);
HWND radiobutton1 = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 10, 60, 60, groupbox, NULL, hinst, NULL);
SetWindowLongPtr(groupbox, GWLP_WNDPROC, (LONG)WndProc);
SendMessage(groupbox, NULL, NULL, TRUE);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Due to i stripped so much of the necessary function away, you need to go to task manager and kill the process named "Autoclicker" for some reason to be able to recompile it again
Make sure you handle WM_DESTROY otherwise window won't close properly.
The radio buttons, all child dialog items, and all child windows should be created in WM_CREATE section of parent window. They need the HWND handle from parent window.
SetWindowLongPtr(.. GWLP_WNDPROC ...) is an old method used for subclassing. Your usage is incorrect. You don't need it anyway.
It's unclear what SendMessage(groupbox, NULL, NULL, TRUE); is supposed to do.
Just add the radio buttons, make sure the first radio button has an added WS_TABSTOP|WS_GROUP as shown below
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
case WM_CREATE:
{
HINSTANCE hinst = GetModuleHandle(0);
auto add = [&](const wchar_t* name,
int id, int x, int y, int w, int h, bool first = false)
{
DWORD style = WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON;
if (first) style |= WS_GROUP | WS_TABSTOP;
return CreateWindowEx(0, L"Button", name, style,
x, y, w, h, hwnd, (HMENU)id, hinst, NULL);
};
HWND groupbox1 = CreateWindowEx(0, L"Button", L"Groupbox1",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 2, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio1 = add(L"radio1", 1, 10, 30, 200, 20, true);
HWND radio2 = add(L"radio2", 2, 10, 51, 200, 20);
HWND radio3 = add(L"radio3", 3, 10, 72, 200, 20);
HWND radio4 = add(L"radio4", 4, 10, 93, 200, 20);
HWND groupbox2 = CreateWindowEx(0, L"Button", L"Groupbox2",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 280, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio11 = add(L"radio1", 11, 300, 30, 200, 20, true);
HWND radio12 = add(L"radio2", 12, 300, 51, 200, 20);
HWND radio13 = add(L"radio3", 13, 300, 72, 200, 20);
HWND radio14 = add(L"radio4", 14, 300, 93, 200, 20);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Sample window",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 600,
NULL, NULL, hinst, NULL);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
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 am very new to Win32 so please be gentle as I am surely not describing my question well at all, but am extremely serious about learning more. So, I have modified my main window to include the option to edit, both write and delete, text, but in order to feel comfortable moving forward, I need to know where exactly the main window knew to create the edit controls.
Are the edit controls creation part of the CreateWindowEx that creates the main window? Or are they only created when I click on the update region that then informs my WM_CREATE case to begin the second CreateWindowEx that actually includes the Edit Styles that enable the controls? This is the only way I can make the order of things make sense, but I need to make sure I'm not just jumping at the first "logical" conclusion. Is my theory correct or completely wrong?
#include <Windows.h>
#include "resource.h"
LPCWSTR g_szClassName{ L"My Window Class" };
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
{
HFONT hfDefault;
HWND hEdit;
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", L"",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
0, 0, 100, 100,
hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
if (hEdit == NULL) {
MessageBox(hwnd, L"Could not create edit box.", L"Error!", MB_OK | MB_ICONERROR);
}
hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
break;
}
case WM_SIZE:
{
HWND hEdit;
RECT rcClient;
GetClientRect(hwnd, &rcClient);
hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT);
SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
break;
}
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 32, 32, 0);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wc.lpszClassName = g_szClassName;
wc.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 32, 32, 0);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"Windows registration failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
L"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL) {
MessageBox(NULL, L"Windows registration failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Before CreateWindow/Ex() exits, it sends a WM_CREATE message (among several other mesages) to the window that is being created. CreateWindow/Ex() does not exit until all of those messages have been processed (unless an error occurs).
So, by the time CreateWindowEx() in your main() has exited, your main window has been fully created, including any child controls that its WM_CREATE handler creates.
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;
}