I cannot press enter on the button - c

This is my first program in C using WINAPI.
When I click the button with my mouse, everything is OK, but I cannot press the button with Enter. On the other hand, Space is working.
I'm guessing that the problem is in "IsDialogMessage" but I cannot solve it.
This is my code in WinMain:
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage(&msg, NULL, 0, 0))
{
if (IsDialogMessage(hwnd, &msg) && msg.wParam != VK_RETURN )
{
/* Already handled by dialog manager */
}
else {
TranslateMessage(&msg); /* Translate virtual-key messages into character messages */
DispatchMessage(&msg); /* Send message to WindowProcedure */
}
}
and this is my LRESULT CALLBACK code :
LRESULT CALLBACK wg_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND cb_handle = 0;
static HWND g_hButtonLogin = 0;
static HWND g_hButtonConfig = 0;
static HWND hEditLogin = 0;
static HWND hLabelLogin = 0;
static HWND hEditPass = 0;
static HWND hLabelPass = 0;
static int pozycja_3 = 0;
struct sesslist slist;
switch (message) /* handle the messages */
{
case WM_CREATE:
{
// LOGIN
hLabelLogin = CreateWindowEx(0, "STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 20, 40, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
hEditLogin = CreateWindowEx(0, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 80, 20, 150, 25,
hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
// PASSWORD
hLabelPass = CreateWindowEx(0, "STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 50, 40, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
hEditPass = CreateWindowEx(0, "EDIT", NULL, ES_PASSWORD | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 80, 50, 150, 25,
hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
SetWindowText(hLabelLogin, "Login:");
SetWindowText(hLabelPass, "Hasło:");
// COMBOBOX
cb_handle = CreateWindowEx(0, "COMBOBOX", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST | WS_TABSTOP, 80, 80, 150, 25 * 4, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
get_sesslist(&slist, TRUE);
// MessageBox(hwnd, slist.sessions[1] , "yyyyy", 0);
int a = 1;
while (slist.sessions[a] != NULL)
{
SendMessage(cb_handle, CB_ADDSTRING, 0, slist.sessions[a]);
a++;
}
SendMessage(cb_handle, CB_SETCURSEL, 3, (LPARAM)"4");
/*SendMessage(cb_handle, CB_ADDSTRING, 0, (LPARAM)"MFG1");
SendMessage(cb_handle, CB_ADDSTRING, 0, (LPARAM)"MFG2");
pozycja_3 = SendMessage(cb_handle, CB_ADDSTRING, 0, (LPARAM)"3");
SendMessage(cb_handle, CB_ADDSTRING, 0, (LPARAM)"4");
SendMessage(cb_handle, CB_SETCURSEL, 0, (LPARAM)"4");*/
g_hButtonConfig = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "*", WS_CHILD | WS_VISIBLE,
260, 20, 20, 20, hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
Then I Create Button "Zaloguj"
g_hButtonLogin = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "Zaloguj", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
20, 120, 250, 30, hwnd, NULL , ((LPCREATESTRUCT)lParam)->hInstance, ((LPCREATESTRUCT)lParam)->hInstance ) ;
CenterWindow(hwnd);
SetFocus(hEditLogin);
// wg_hDlgCurrent = hEditLogin;
}
break;
case WM_COMMAND:
{
if ((HWND)lParam == g_hButtonConfig)
{
do_config();
}
if ((HWND)lParam == g_hButtonLogin || (HWND)wParam == g_hButtonLogin)
{
if (1 == 1)
{
int idx_row;
char *strText[256];
idx_row = SendMessage(cb_handle, CB_GETCURSEL, 0, 0);
SendMessage(cb_handle, CB_GETLBTEXT, idx_row, (LPARAM)strText);
wg_selected_sess = strText;
DestroyWindow(hwnd);
}
}
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;
}
When I hit the Enter key on the "zaloguj" button, nothing happens.

Related

How to call another screen in this code below

Good night, I would like some help with this code below, I have to do an exercise that calls another registration screen, the first screen I managed to assemble, make the buttons work too, but I don't find a practical example on the internet to be able to call this one another screen, I've tried in several ways and without success, I would like some help so to be able to call another screen in this code below. I have to call this other screen there on the Register button, you can see that I've already tried and nothing happens.
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <tchar.h>
const TCHAR CLSNAME[] = TEXT("helloworldWClass");
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp);
void addControls(HWND);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
{
//return MessageBox(NULL, "hello, world", "caption", 0);
WNDCLASSEX wc = { };
MSG msg;
HWND hwnd;
wc.cbSize = sizeof (wc);
wc.style = 0;
wc.lpfnWndProc = winproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
//wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLSNAME;
wc.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("Could not register window class"),
NULL, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL);
if (!hwnd) {
MessageBox(NULL, TEXT("Could not create window"), NULL, MB_ICONERROR);
return 0;
}
ShowWindow(hwnd, cmdshow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void addControls(HWND hwnd) {
CreateWindowW(L"Static", L"Login", WS_CHILD | WS_VISIBLE, 600, 0, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"", WS_CHILD | WS_VISIBLE, 600, 40, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Static", L"Senha", WS_CHILD | WS_VISIBLE, 600, 80, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"", WS_CHILD | WS_VISIBLE, 600, 120, 100, 18, hwnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Login", WS_CHILD | WS_VISIBLE, 600, 160, 100, 18, hwnd, (HMENU) 1, NULL, NULL);
CreateWindowW(L"Button", L"Cadastrar", WS_CHILD | WS_VISIBLE, 600, 200, 100, 18, hwnd, (HMENU) 2, NULL, NULL);
}
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp) {
HWND hwndCadastrar;
switch (wm) {
case WM_CREATE:
addControls(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_COMMAND:
if (LOWORD(wp) == 1) {
hwndCadastrar = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19 - Cadastrar - Paciente"),
WS_CHILDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hwnd,
NULL);
ShowWindow(hwndCadastrar, SW_SHOW);
SetForegroundWindow(hwndCadastrar);
SetFocus(hwndCadastrar);
Window(hwnd);
MessageBox(0, (LPCWSTR)L"Login Efetuado Com Sucesso", (LPCWSTR)L"Login", 0);
} else if (LOWORD(wp) == 2) {
MessageBox(0, (LPCWSTR)L"Cadastro Efetuado Com Sucesso", (LPCWSTR)L"Cadastrar", 0);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, wm, wp, lp);
}
}
The child window failed to create.
You cannot pass a HWND to a HINSTANCE parameter.(argument of type HWND is incompatible with parameter of type HINSTANCE)
You cannot create a top-level child window(ERROR_TLW_WITH_WSCHILD).
CW_USEDEFAULT is valid only for overlapped windows; if CW_USEDEFAULT is specified for a pop-up or child window, the nWidth and nHeight parameter are set to zero.
If you want to see the child window caption, add WS_CAPTION.
Finally, the code looks like this:
hwndCadastrar = CreateWindowEx(WS_EX_LEFT,
CLSNAME,
_T("Covid-19 - Cadastrar - Paciente"),
WS_CAPTION |WS_CHILDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1000,
1000,
hwnd,
NULL,
GetModuleHandle(NULL),
NULL);
For more information about child windows, see Creating, Enumerating, and Sizing Child Windows

Can I insert my code to my coded interface using Win32?

I have a C program and I am supposed to add an interface to it. Can I insert my code to my coded interface using Win32?
Example: Here is my code to convert binary into octal.
void biTodec(){
long long n;
int dec = 0, i = 0, rem;
printf("Enter a binary number: ");
scanf("%lld", &n);
while (n != 0) {
rem = n % 10;
n /= 10;
dec += rem * pow(2, i);
++i;
}
printf("%lld in binary = %d in decimal", n, dec);
return 0;
}
Now, I want my button in my API when clicked to perform the conversion. Here is my Win32 design
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <stdlib.h>
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM,LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow){
WNDCLASSW kim = {0};
kim.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
kim.hCursor = LoadCursor(NULL, IDC_ARROW);
kim.hInstance = hinst;
kim.lpszClassName = L"myWindowClass";
kim.lpfnWndProc = WindowProcedure;
if(!RegisterClassW(&kim))
return -1;
CreateWindowW(L"myWindowClass",L"Number System Converter",
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:
MessageBoxA(hWnd, "This project was made by bla bla for
seven (7) days. He had no any prior idea on interface so he spent
the 6 out of 7 days just for researching. Copyright 2021", "About
the
project", NULL);
break;
case 2:
MessageBeep(MB_OK);
break;
case 3:
PostQuitMessage(0);
break;
case 4:
MessageBeep(MB_OK);
break;
case 5:
MessageBeep(MB_OK);
break;
}
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd,msg,wp,lp);
}
}
void AddMenus(HWND hWnd){
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu,MF_STRING, 4, "File");
AppendMenu(hSubMenu,MF_STRING, 5, "Folder");
AppendMenu(hSubMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu,MF_POPUP,(UINT_PTR)hSubMenu, "Open");
AppendMenu(hFileMenu,MF_STRING, 2, "Save");
AppendMenu(hFileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu,MF_STRING, 3, "Exit");
AppendMenu(hMenu, MF_POPUP ,(UINT_PTR)hFileMenu, "Options");
AppendMenu(hMenu, MF_POPUP ,1, "Help");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd){
CreateWindowW(L"Static",L"Choose the number system to be converted",
WS_VISIBLE|WS_CHILD,100, 30, 300, 20, hWnd, NULL, NULL, NULL );
CreateWindowW(L"Edit", L"", WS_VISIBLE|WS_BORDER| WS_CHILD, 60, 80, 120, 30, hWnd, NULL, NULL,NULL);
CreateWindowW(L"Button", L"Generate", WS_VISIBLE|WS_BORDER|WS_CHILD,
200, 80, 80, 20, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Edit", L"", WS_VISIBLE|WS_BORDER| WS_CHILD, 300, 80,
120, 30, hWnd, NULL, NULL,NULL);
CreateWindowW(L"Button", L"Binary",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 60, 150,
120, 20, hWnd,NULL , NULL, NULL);
CreateWindowW(L"Button", L"Decimal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 60, 180,
120, 20, hWnd,NULL , NULL, NULL);
CreateWindowW(L"Button", L"Octal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 60, 210,
120, 20, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Hexadecimal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP,60, 240,
120, 20, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Binary",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 300, 150,
120, 20, hWnd,NULL , NULL, NULL);
CreateWindowW(L"Button", L"Decimal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 300, 180,
120, 20, hWnd,NULL , NULL, NULL);
CreateWindowW(L"Button", L"Octal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON|WS_TABSTOP, 300, 210,
120, 20, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Hexadecimal",
WS_VISIBLE|WS_BORDER|WS_CHILD|BS_RADIOBUTTON | WS_TABSTOP, 300,
240, 120, 20, hWnd,NULL, NULL, NULL);
}
Is it possible to insert my code to the API or not? If not, can you suggest what I have to learn to create a user interface in my program?
I have fixed your code and plugged your conversion function. I have not added more conversion - you'll do it yourself with my example - nor have I added enhancements.
To fix the Windows API part, note that I have:
Saved all HWND for the controls to be able to get/set values.
Used BS_AUTORADIOBUTTON and WS_GROUP so that radio button works as usual.
Used identifiers for all controls to be able to check which operation was requested.
Fixed various warnings using appropriate casts.
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <math.h>
#define ID_CONV_SRC_BINARY 0x100
#define ID_CONV_SRC_OCTAL 0x101
#define ID_CONV_SRC_DECIMAL 0x102
#define ID_CONV_SRC_HEXADECIMAL 0x103
#define ID_CONV_DST_BINARY 0x200
#define ID_CONV_DST_OCTAL 0x201
#define ID_CONV_DST_DECIMAL 0x202
#define ID_CONV_DST_HEXADECIMAL 0x203
#define ID_GENERATE 0x300
int srcConvert = 0;
int dstConvert = 0;
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
HWND hNum, hOut;
HWND hWndInEdit;
HWND hWndOutEdit;
HWND hWndSrcBinary;
HWND hWndSrcOctal;
HWND hWndSrcDecimal;
HWND hWndSrcHexadecimal;
HWND hWndDstBinary;
HWND hWndDstOctal;
HWND hWndDstDecimal;
HWND hWndDstHexadecimal;
void biTodec(
wchar_t * const inBuf,
wchar_t * const outBuf,
size_t outBufSize)
{
long long n;
int dec = 0, i = 0, rem;
if (swscanf(inBuf, L"%lld", &n) == 1) {
while (n != 0) {
rem = n % 10;
n /= 10;
dec += rem * (1 << i);//pow(2, i);
++i;
}
}
swprintf(outBuf, outBufSize, L"%d", dec);
}
int WINAPI WinMain(
_In_ HINSTANCE hinst,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd)
{
WNDCLASSW kim = { 0 };
kim.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
kim.hCursor = LoadCursor(NULL, IDC_ARROW);
kim.hInstance = hinst;
kim.lpszClassName = L"myWindowClass";
kim.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&kim))
return -1;
HWND hWnd = CreateWindowW(L"myWindowClass", L"Number System Converter", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 500, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
void Generate(HWND hWnd)
{
wchar_t inBuf[30];
wchar_t outBuf[30];
if (Button_GetCheck(hWndSrcBinary))
srcConvert = ID_CONV_SRC_BINARY;
else if (Button_GetCheck(hWndSrcDecimal))
srcConvert = ID_CONV_SRC_DECIMAL;
else if (Button_GetCheck(hWndSrcOctal))
srcConvert = ID_CONV_SRC_OCTAL;
else if (Button_GetCheck(hWndSrcHexadecimal))
srcConvert = ID_CONV_SRC_HEXADECIMAL;
else
srcConvert = 0;
if (Button_GetCheck(hWndDstBinary))
dstConvert = ID_CONV_DST_BINARY;
else if (Button_GetCheck(hWndDstDecimal))
dstConvert = ID_CONV_DST_DECIMAL;
else if (Button_GetCheck(hWndDstOctal))
dstConvert = ID_CONV_DST_OCTAL;
else if (Button_GetCheck(hWndDstHexadecimal))
dstConvert = ID_CONV_DST_HEXADECIMAL;
else
dstConvert = 0;
GetWindowText(hWndInEdit, inBuf, sizeof(inBuf) / sizeof(inBuf[0]));
if ((srcConvert & 0xFF) == (dstConvert & 0xFF))
wcscpy(outBuf, inBuf);
else if ((srcConvert == ID_CONV_SRC_BINARY) && (dstConvert == ID_CONV_DST_DECIMAL))
biTodec(inBuf, outBuf, sizeof(outBuf));
else {
MessageBox(hWnd, L"Not implemented yet", L"Warning", MB_OK);
outBuf[0] = 0;
}
SetWindowText(hWndOutEdit, outBuf);
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_COMMAND:
switch (wp) {
case ID_CONV_SRC_BINARY:
case ID_CONV_SRC_DECIMAL:
case ID_CONV_SRC_HEXADECIMAL:
case ID_CONV_SRC_OCTAL:
case ID_CONV_DST_BINARY:
case ID_CONV_DST_DECIMAL:
case ID_CONV_DST_HEXADECIMAL:
case ID_CONV_DST_OCTAL:
case ID_GENERATE:
Generate(hWnd);
break;
case 1:
MessageBox(hWnd, L"Copyright 2021", L"About the project", MB_OK);
break;
case 2:
MessageBeep(MB_OK);
break;
case 3:
PostQuitMessage(0);
break;
case 4:
MessageBeep(MB_OK);
break;
case 5:
MessageBeep(MB_OK);
break;
}
break;
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
return 0;
}
void AddMenus(HWND hWnd) {
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, 4, L"File");
AppendMenu(hSubMenu, MF_STRING, 5, L"Folder");
AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Open");
AppendMenu(hFileMenu, MF_STRING, 2, L"Save");
AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hFileMenu, MF_STRING, 3, L"Exit");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"Options");
AppendMenu(hMenu, MF_POPUP, 1, L"Help");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd) {
CreateWindowW(L"Static", L"Choose the number system to be converted",
WS_VISIBLE | WS_CHILD, 100,
30, 300, 20, hWnd, NULL, NULL, NULL);
hWndInEdit = CreateWindowW(L"Edit", L"", WS_VISIBLE | WS_BORDER | WS_CHILD, 60, 80, 120, 30, hWnd, NULL,
NULL, NULL);
CreateWindowW(L"Button", L"Generate", WS_VISIBLE | WS_BORDER | WS_CHILD, 200, 80, 80, 20, hWnd,
(HMENU)ID_GENERATE,
0, NULL);
hWndOutEdit = CreateWindowW(L"Edit", L"", WS_VISIBLE | WS_BORDER | WS_CHILD, 300, 80, 120, 30, hWnd, NULL,
NULL, NULL);
hWndSrcBinary = CreateWindowW(L"Button", L"Binary", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON | WS_TABSTOP | WS_GROUP,
60, 150, 120, 20, hWnd, (HMENU)ID_CONV_SRC_BINARY, NULL, NULL);
hWndSrcDecimal = CreateWindowW(L"Button", L"Decimal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON,
60, 180, 120, 20, hWnd, (HMENU)ID_CONV_SRC_DECIMAL, NULL, NULL);
hWndSrcOctal = CreateWindowW(L"Button", L"Octal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON,
60, 210, 120, 20, hWnd, (HMENU)ID_CONV_SRC_OCTAL, NULL, NULL);
hWndSrcHexadecimal = CreateWindowW(L"Button", L"Hexadecimal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON,
60, 240, 120, 20, hWnd, (HMENU)ID_CONV_SRC_HEXADECIMAL, NULL, NULL);
hWndDstBinary = CreateWindowW(L"Button", L"Binary", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON | WS_TABSTOP | WS_GROUP,
300, 150, 120, 20, hWnd, (HMENU)ID_CONV_DST_BINARY, NULL, NULL);
hWndDstDecimal = CreateWindowW(L"Button", L"Decimal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON, ,
300, 180, 120, 20, hWnd, (HMENU)ID_CONV_DST_DECIMAL, NULL, NULL);
hWndDstOctal = CreateWindowW(L"Button", L"Octal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON,
300, 210, 120, 20, hWnd, (HMENU)ID_CONV_DST_OCTAL, NULL, NULL);
hWndDstHexadecimal = CreateWindowW(L"Button", L"Hexadecimal", WS_VISIBLE | WS_BORDER | WS_CHILD | BS_AUTORADIOBUTTON,
300, 240, 120, 20, hWnd, (HMENU)ID_CONV_DST_HEXADECIMAL, NULL, NULL);
}
There are plenty room for enhancements. I made the minimum to answer your question. Open more questions if you need more help.

How do I make a tab control with children elements?

I'm learning WINAPI, I read there's no children control in the sense a C#'s TabControl control does, so you have to create elements and show/hide by yourself. I read it may be done by drawing a dialog box inside tab page's area so I went to create a borderless dialog box being tab control's child, to make it have effect like C#'s. But I still couldn't make it. My dialog box is floating rather being tab control's child. I don't know to make it inside the tab page, I've tried setting the hWndParent to tab control's HWND and WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT flags in dwExStyle but still is floating over the tab control. Different approaches to solve this are welcome. I'm creating the tab control like this:
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
0, 30, 250, 250,
hwnd,
(HMENU) 9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text)
{
TCITEMW tci = {0};
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = lstrlenW(text);
if(SendMessage(tabHwnd, TCM_INSERTITEMW, id, (LPARAM) &tci) == -1) {
MessageBox(NULL,
L"couldn't create the new tab page",
L"tab errror",
MB_OK | MB_ICONERROR);
}
}
And the dialog box like this:
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_POPUP | WS_SYSMENU,
100, 100, 400, 150,
hTab, NULL, ghInstance, NULL
);
}
the result is:
the expected result (made from C#, just for example, ignore the color differences, I'll fix this later):
here's the full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#define UNICODE
#include <windows.h>
#include <Commctrl.h>
#include <strsafe.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
void CreateDialogBox(HWND);
void RegisterDialogClass(HWND);
void AddTabControl(HWND hwnd);
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text);
HINSTANCE ghInstance;
HWND mainWindow;
HWND hTab;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR pCmdLine, int nCmdShow) {
MSG msg = {0};
HWND hwnd;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
RegisterClassW(&wc);
hwnd = CreateWindowW(wc.lpszClassName, L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 500, 350, NULL, NULL, hInstance, NULL);
mainWindow = hwnd;
ghInstance = hInstance;
while( GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
RegisterDialogClass(hwnd);
AddTabControl(hwnd);
CreateDialogBox(hwnd);
break;
case WM_COMMAND:
CreateDialogBox(hwnd);
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
case WM_CREATE:
CreateWindowW(L"button", L"A",
WS_VISIBLE | WS_CHILD ,
50, 50, 80, 25, hwnd, (HMENU) 1, NULL, NULL);
CreateWindowW(L"button", L"B",
WS_VISIBLE | WS_CHILD ,
150, 50, 80, 25, hwnd, (HMENU) 2, NULL, NULL);
CreateWindowW(L"button", L"C",
WS_VISIBLE | WS_CHILD ,
250, 50, 80, 25, hwnd, (HMENU) 3, NULL, NULL);
break;
case WM_COMMAND:
DestroyWindow(hwnd);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
}
return (DefWindowProcW(hwnd, msg, wParam, lParam));
}
void RegisterDialogClass(HWND hwnd)
{
WNDCLASSEXW wc = {0};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.lpfnWndProc = (WNDPROC) DialogProc;
wc.hInstance = ghInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszClassName = L"DialogClass";
RegisterClassExW(&wc);
}
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_POPUP | WS_SYSMENU,
100, 100, 400, 150,
hTab, NULL, ghInstance, NULL
);
}
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
0, 30, 250, 250,
hwnd,
(HMENU) 9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
void InsertTabItem(HWND tabHwnd, UINT id, LPWSTR text)
{
TCITEMW tci = {0};
tci.mask = TCIF_TEXT;
tci.pszText = text;
tci.cchTextMax = lstrlenW(text);
if(SendMessage(tabHwnd, TCM_INSERTITEMW, id, (LPARAM) &tci) == -1) {
MessageBox(NULL,
L"couldn't create the new tab page",
L"tab errror",
MB_OK | MB_ICONERROR);
}
}
When you created the dialog box control, you lacked the WS_CHILD style and added the WS_POPUP style, which caused the dialog box you generated to float.
You only need to modify it to the WS_CHILD style, and appropriately modify the size of the control to achieve your desired effect.
void CreateDialogBox(HWND hwnd)
{
CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT, // WS_EX_TOOLWINDOW to hide window from ALT+TAB
L"DialogClass", L"Dialog Box",
WS_VISIBLE | WS_SYSMENU | WS_CHILD ,
10, 30, 350, 150,
hTab, NULL, ghInstance, NULL
);
}
void AddTabControl(HWND hwnd)
{
hTab = CreateWindowW(WC_TABCONTROLW, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP,
10, 30, 400, 250,
hwnd,
(HMENU)9,
NULL,
NULL);
InsertTabItem(hTab, 10, L"A");
InsertTabItem(hTab, 11, L"B");
}
It works like this:

Text highlighting and UNDO in Richedit

I'm trying to implement a text highlighting and undo in RichEdit. The code below marks 5 and 6 chars but undo doesn't work (the text doesn't change) though Edit_CanUndo returns 1. If I turn off a updateHighlighting then undo works but it rolls back too much at once (e.g. input a long text, paste a text by Ctrl+V, input another text - it's required only 3 undo to rollback all).
What is wrong with my code? Maybe I should return a specific value from updateHighlighting?
#define UNICODE
#define _UNICODE
#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <richedit.h>
#define IDC_EDITOR 1000
#define IDC_BUTTON 1001
HWND hEditorWnd;
bool updateHighlighting(HWND hWnd) {
int carriagePos = 0;
SendMessage(hWnd, EM_GETSEL, (WPARAM)&carriagePos, (WPARAM)&carriagePos);
CHARFORMAT cf = {0};
cf.cbSize = sizeof(CHARFORMAT) ;
cf.dwMask = CFM_COLOR | CFM_BOLD;
cf.crTextColor = RGB(0, 0, 200);
cf.dwEffects = CFM_BOLD;
SendMessage(hWnd, EM_SETSEL, 0, -1);
SendMessage(hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
cf.dwMask = CFM_COLOR | CFM_BOLD;
cf.dwEffects = cf.dwEffects & ~CFM_BOLD;
cf.crTextColor = RGB(200, 0, 0);
SendMessage(hWnd, EM_SETSEL, 4, 6);
SendMessage(hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
SendMessage(hWnd, EM_SETSEL, carriagePos, carriagePos);
_tprintf(TEXT("End highlight\n"));
return true;
}
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_COMMAND: {
if (LOWORD(wParam) == IDC_EDITOR && HIWORD(wParam) == EN_CHANGE)
return updateHighlighting(hEditorWnd);
if (LOWORD(wParam) == IDC_BUTTON && HIWORD(wParam) == BN_CLICKED)
_tprintf(TEXT("UNDO: can %i => result: %i\n"), Edit_CanUndo(hEditorWnd), Edit_Undo(hEditorWnd));
}
break;
default:
return DefWindowProc (hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
InitCommonControls();
LoadLibrary(TEXT("msftedit.dll"));
HWND hWnd;
MSG msg;
WNDCLASSEX wincl;
wincl.hInstance = hThisInstance;
wincl.lpszClassName = TEXT("AppClass");
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) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
hWnd = CreateWindowEx (0, TEXT("AppClass"), TEXT("Test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 300, 400, 310, 375, HWND_DESKTOP, NULL, hThisInstance, NULL);
CreateWindowEx(0, WC_BUTTON , L"UNDO", WS_VISIBLE | WS_CHILD | WS_TABSTOP, 10, 310, 280, 30, hWnd, (HMENU)IDC_BUTTON, hThisInstance, NULL);
hEditorWnd = CreateWindowEx(0, TEXT("RICHEDIT50W"), NULL, WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | ES_NOHIDESEL, 0, 0, 300, 300, hWnd, (HMENU)IDC_EDITOR, hThisInstance, NULL);
SendMessage(hEditorWnd, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_UPDATE | ENM_KEYEVENTS);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
P.S. I use Code::Block 17.12 + gcc5.1 on Win7x64 (but build a 32bit app).
What you mean exactly with "doesn't work" or with when it "does work" is unclear, however, changing color is something that can be undone too so if you do not want that, then you have to turn off undo before coloring and resume it after coloring.
I don't know if there are easier ways to do it, but in C I use the following functions:
//#include <windows, richedit, ...>
#include <TOM.h>
extern HWND ghEditWnd;
static IUnknown *pUnk;
static ITextDocument *pDoc;
static const IID IID_ITextDocument = {
0x8CC497C0, 0xA1DF, 0x11CE,
{0x80,0x98,0x00,0xAA,0x00,0x47,0xBE,0x5D}
};
static int tomInit(void)
{
if (!pUnk) SendMessage(ghEditWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk);
if (!pUnk || pUnk->lpVtbl->QueryInterface(pUnk,&IID_ITextDocument, &pDoc) != NOERROR)
{pUnk= 0; return FALSE;}
return TRUE;
}
void undoSuspend(void)
{
if (!pUnk) if (!tomInit()) return;
pDoc->lpVtbl->Undo(pDoc,tomSuspend,0); //Suspends Undo.
}
void undoResume(void)
{
if (!pUnk) if (!tomInit()) return;
pDoc->lpVtbl->Undo(pDoc,tomResume,0); // resume Undo.
}
void releaseTOM(void)
{
if (pUnk) {
pUnk->lpVtbl->Release(pUnk); pUnk= 0; pDoc= 0;
}
}
See also https://learn.microsoft.com/en-us/windows/win32/api/tom/
EDIT: in question How to disable Undo in Rich Text Box in WPF? the suggestion was to set UndoLimit to zero. It is not clear if that would clear the existing undo stack too.
Undo can be suspended and resumed in RichEdit 3.0, Microsoft says.
Here is the working example (undo removes symbols char-by-char as I want) based on Paul Ogilvie's reply and codepilot answer.
Hint: use freeze/unfreeze to prevent flickering. That is similar to SetWindowRedraw(hWnd, TRUE/FALSE) but the last operation arouse unnecessary EN_SELCHANGE notification messages.
#define UNICODE
#define _UNICODE
#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <richedit.h>
// Code::Block doesn't have a tom.h :(
// https://github.com/kinke/mingw-w64-crt/blob/master/mingw-w64-headers/include/tom.h
#include "tom.h"
#include <richole.h>
#include <unknwn.h>
IUnknown *tr_code = NULL;
ITextDocument *td_code;
#define DEFINE_GUIDXXX(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
DEFINE_GUIDXXX(IID_ITextDocument,0x8CC497C0,0xA1DF,0x11CE,0x80,0x98, 0x00,0xAA,0x00,0x47,0xBE,0x5D);
#define IDC_EDITOR 1000
#define IDC_BUTTON 1001
HWND hEditorWnd;
bool updateHighlighting(HWND hWnd) {
int carriagePos = 0;
SendMessage(hWnd, EM_GETSEL, (WPARAM)&carriagePos, (WPARAM)&carriagePos);
CHARFORMAT cf = {0};
cf.cbSize = sizeof(CHARFORMAT) ;
cf.dwMask = CFM_COLOR | CFM_BOLD;
cf.crTextColor = RGB(0, 0, 200);
cf.dwEffects = CFM_BOLD;
SendMessage(hWnd, EM_SETSEL, 0, -1);
SendMessage(hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
cf.dwMask = CFM_COLOR | CFM_BOLD;
cf.dwEffects = cf.dwEffects & ~CFM_BOLD;
cf.crTextColor = RGB(200, 0, 0);
SendMessage(hWnd, EM_SETSEL, 4, 6);
SendMessage(hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
SendMessage(hWnd, EM_SETSEL, carriagePos, carriagePos);
_tprintf(TEXT("End highlight\n"));
return true;
}
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_COMMAND: {
if (LOWORD(wParam) == IDC_BUTTON && HIWORD(wParam) == BN_CLICKED)
_tprintf(TEXT("UNDO: can %i => result: %i\n"), Edit_CanUndo(hEditorWnd), Edit_Undo(hEditorWnd));
if (LOWORD(wParam) == IDC_EDITOR && HIWORD(wParam) == EN_CHANGE) {
long cnt = 0;
td_code->Undo(tomSuspend, NULL); // <---
td_code->Freeze(&cnt); // <---
updateHighlighting(hEditorWnd);
td_code->Unfreeze(&cnt); // <---
td_code->Undo(tomResume, NULL); // <---
return 1;
}
}
break;
default:
return DefWindowProc (hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
InitCommonControls();
LoadLibrary(TEXT("msftedit.dll"));
HWND hWnd;
MSG msg;
WNDCLASSEX wincl;
wincl.hInstance = hThisInstance;
wincl.lpszClassName = TEXT("AppClass");
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) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
hWnd = CreateWindowEx (0, TEXT("AppClass"), TEXT("Test"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 300, 400, 310, 375, HWND_DESKTOP, NULL, hThisInstance, NULL);
CreateWindowEx(0, WC_BUTTON , L"UNDO", WS_VISIBLE | WS_CHILD | WS_TABSTOP, 10, 310, 280, 30, hWnd, (HMENU)IDC_BUTTON, hThisInstance, NULL);
hEditorWnd = CreateWindowEx(0, TEXT("RICHEDIT50W"), NULL, WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | ES_NOHIDESEL, 0, 0, 300, 300, hWnd, (HMENU)IDC_EDITOR, hThisInstance, NULL);
SendMessage(hEditorWnd, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_UPDATE | ENM_KEYEVENTS);
// \/
SendMessage(hEditorWnd, EM_GETOLEINTERFACE, 0, (LPARAM)&tr_code);
if(tr_code == (IRichEditOle*)NULL) {
MessageBox(0, TEXT("Error when trying to get RichEdit OLE Object"), NULL, 0);
return 0;
}
tr_code->QueryInterface(IID_ITextDocument,(void**)&td_code);
// /\
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

Hiding and showing container windows based on tab

I have created a tab control that contains two tabs. Inside each tab there will be a container window to hold other controls (in the code example, a static control for instance). The idea is that when a new tab is selected, it will hide/show the correct container window that holds a bunch of controls. However I am struggling to get the container windows holding the static controls to show. This is the code so far:
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#define ID_TABCTRL 1
#define ID_STATIC0 2
#define ID_STATIC1 3
#define ID_TAB0 4
#define ID_TAB1 5
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND hTab, hTab0, hTab1;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wc = { 0 };
wc.lpszClassName = TEXT("Tab control");
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
CreateWindow(wc.lpszClassName, TEXT("Tab control"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 200, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCITEM tie;
INITCOMMONCONTROLSEX icex;
switch (msg)
{
case WM_CREATE:
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
tie.mask = TCIF_TEXT;
///// Create Tab Control /////
hTab = CreateWindow(WC_TABCONTROL, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hwnd, (HMENU)ID_TABCTRL, NULL, NULL);
///// Create Individual Tabs /////
tie.pszText = TEXT("First");
SendMessage(hTab, TCM_INSERTITEM, 0, (LPARAM)(LPTCITEM)&tie);
tie.pszText = TEXT("Second");
SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM)(LPTCITEM)&tie);
///// Create Container windows for each tab /////
hTab0 = CreateWindow(0, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 200, 150, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(0, NULL, WS_CHILD, 0, 0, 200, 150, hTab, (HMENU)ID_TAB1, NULL, NULL);
///// Add example control to one of the tab container windows /////
CreateWindow(TEXT("Static"), TEXT("Yay!"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 50, 25, hTab0, (HMENU)ID_STATIC0, NULL, NULL);
CreateWindow(TEXT("Static"), TEXT("It appears to be working"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 30, 100, 50, hTab1, (HMENU)ID_STATIC1, NULL, NULL);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case TCN_SELCHANGE:
switch (TabCtrl_GetCurSel(hTab))
{
///// Show or Hide the appropriate tabs /////
case 0:
ShowWindow(hTab1, SW_HIDE);
ShowWindow(hTab0, SW_SHOW);
case 1:
ShowWindow(hTab0, SW_HIDE);
ShowWindow(hTab1, SW_SHOW);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, msg, wParam, lParam));
}
Is it just a case of the container windows hTab0 and hTab1 being stuck behind the tab window (hTab)?
First, you need to change the position of the tab and static form, otherwise it will block the generated content.
Then you can define the generated static text directly through CreateWindow, by using WC_STATIC.
#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 , hwndStatic1,hwndStatic2;
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, L"",
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, L"tab1");
tie.pszText = tabLBL1;
TabCtrl_InsertItem(hwndTab, 0, &tie);
wsprintf(tabLBL1, L"tab2");
TabCtrl_InsertItem(hwndTab, 1, &tie);
hwndStatic1 = CreateWindow(WC_STATIC, L"123",
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);
hwndStatic2 = CreateWindow(WC_STATIC, L"456",
WS_CHILD | WS_VISIBLE | WS_BORDER,
400, 200, 100, 100, // Position and dimensions; example only.
hwndTab, NULL, hInstance, // g_hInst is the global instance handle
NULL);
ShowWindow(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
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(hwndStatic1, TRUE);
ShowWindow(hwndStatic2, FALSE);
break;
case 1:
ShowWindow(hwndStatic1, FALSE);
ShowWindow(hwndStatic2, TRUE);
break;
default:
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
Zhu Song's answer helped solved the problem (the container windows needing to be a static control, and needing to be positioned inside the tab control's space, below the clickable tabs).
Here is the result, swapping the two container window creation lines:
hTab0 = CreateWindow(TEXT("Static"), NULL, WS_CHILD | WS_VISIBLE, 1, 25, 197, 123, hTab, (HMENU)ID_TAB0, NULL, NULL);
hTab1 = CreateWindow(TEXT("Static"), NULL, WS_CHILD, 1, 25, 197, 123, hTab, (HMENU)ID_TAB1, NULL, NULL);
Note how the container window sizes and position are small enough to just fit inside the main tab control window (you can add WS_BORDER to the style to see where exactly it fits).

Resources