Remove an item from a list-view control - c++

I have a list-view control in my program and I want to remove the selected item. This is done with a button press.
The problem is that no matter what item I select it always deletes the first one...
I think the problem is with the list-view focus being lost. When the button is pressed, the list-view loses focus first, then it tries to remove an item that's not selected anymore, thus it removes the first one.
My question is: Is there any option to make the list-view not to lose its focus?
EDIT:
Here's the code :
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here
Main.cpp
#include "stdafx.h"
LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
void CreateList();
void CreateButtons();
enum
{
IDC_REMOVE_BUTTON = 1000,
IDC_LIST
};
struct ListBox
{
HWND hwnd;
LVCOLUMN lvc;
LVITEM lv;
ListBox(HWND h = 0, LVCOLUMN l = { 0 }, LVITEM lvi = { 0 })
{
hwnd = h;
lvc = l;
lv = lvi;
}
};
int selitm = -1;
HINSTANCE g_hInstance;
HWND hwndRemoveButton;
HWND g_hwnd;
ListBox List;
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
LPSTR Args, int WinMode)
{
HWND hWnd;
MSG Message;
WNDCLASSEX WinClass = { 0 };
INITCOMMONCONTROLSEX icc = { 0 };
g_hInstance = hThisInst;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icc);
WinClass.cbSize = sizeof(WNDCLASSEX);
WinClass.hInstance = hThisInst;
WinClass.lpszClassName = "Test";
WinClass.lpfnWndProc = WindowFunc;
WinClass.style = 0;
WinClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WinClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
WinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WinClass.lpszMenuName = NULL;
WinClass.cbClsExtra = 0;
WinClass.cbWndExtra = 0;
WinClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
if (!RegisterClassEx(&WinClass)) return 0;
hWnd = CreateWindow("Test", "Test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 660, 350,
NULL, NULL, hThisInst, NULL);
ShowWindow(hWnd, WinMode);
UpdateWindow(hWnd);
while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
LRESULT CALLBACK WindowFunc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_CREATE:
g_hwnd = hWnd;
CreateList();
CreateButtons();
ListView_InsertItem(List.hwnd, &List.lv);
ListView_SetCheckState(List.hwnd, List.lv.iItem, true);
ListView_SetItemText(List.hwnd, List.lv.iItem, 1, "One");
ListView_SetItemText(List.hwnd, List.lv.iItem, 2, "$1");
ListView_SetItemText(List.hwnd, List.lv.iItem++, 3, "2010-05-05");
ListView_InsertItem(List.hwnd, &List.lv);
ListView_SetCheckState(List.hwnd, List.lv.iItem, true);
ListView_SetItemText(List.hwnd, List.lv.iItem, 1, "Two");
ListView_SetItemText(List.hwnd, List.lv.iItem, 2, "$2");
ListView_SetItemText(List.hwnd, List.lv.iItem++, 3, "2008-05-05");
ListView_InsertItem(List.hwnd, &List.lv);
ListView_SetCheckState(List.hwnd, List.lv.iItem, false);
ListView_SetItemText(List.hwnd, List.lv.iItem, 1, "Three");
ListView_SetItemText(List.hwnd, List.lv.iItem, 2, "$3");
ListView_SetItemText(List.hwnd, List.lv.iItem++, 3, "2006-05-05");
break;
case WM_COMMAND:
// The low word of wParam contains the menu ID.
switch (LOWORD(wParam))
{
case IDC_REMOVE_BUTTON:
selitm = ListView_GetFocusedGroup(List.hwnd);
ListView_DeleteItem(List.hwnd, selitm);
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd,
Message,
wParam,
lParam);
}
return 0;
}
void CreateButtons()
{
hwndRemoveButton = CreateWindow("Button", "Remove",
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
20, 265, 70, 30,
g_hwnd, (HMENU)IDC_REMOVE_BUTTON,
g_hInstance, NULL);
}
void CreateList()
{
List.hwnd = CreateWindow(WC_LISTVIEW, NULL,
WS_CHILD | WS_VISIBLE | LVS_REPORT,
20, 30, 600, 230,
g_hwnd, (HMENU)IDC_LIST, g_hInstance, NULL);
ListView_SetExtendedListViewStyle(List.hwnd, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
List.lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT;
List.lvc.fmt = LVCFMT_LEFT;
/* Add four columns to the list-view (first column contains check box). */
List.lvc.iSubItem = 0;
List.lvc.cx = 50;
List.lvc.pszText = "Good?";
ListView_InsertColumn(List.hwnd, List.lvc.iSubItem++, &List.lvc);
List.lvc.cx = 300;
List.lvc.pszText = "Name";
ListView_InsertColumn(List.hwnd, List.lvc.iSubItem++, &List.lvc);
List.lvc.cx = 150;
List.lvc.pszText = "Cost";
ListView_InsertColumn(List.hwnd, List.lvc.iSubItem++, &List.lvc);
List.lvc.cx = 100;
List.lvc.pszText = "Watched Since";
ListView_InsertColumn(List.hwnd, List.lvc.iSubItem++, &List.lvc);
List.lv.iItem = 0;
}

Your problem has nothing to do with focus. You are using the wrong API to determine the selected item. You are using ListView_GetFocusedGroup() when you need to use ListView_GetNextItem() instead:
selitm = ListView_GetNextItem(List.hwnd, -1, LVNI_SELECTED);
if (selitm != -1)
ListView_DeleteItem(List.hwnd, selitm);

You are calling ListView_GetFocusedGroup. As documented this:
Gets the group that has the focus
Groups are a somewhat advanced feature of list views. Again, as documented:
Grouping allows a user to arrange lists into groups of items that are visually divided on the page, using a horizontal divider and a group title.
So, that's just not what you want. The API that you need to get the selected item is ListView_GetNextItem. Call it like this:
int selectedIndex = ListView_GetNextItem(List.hwnd, -1, LVNI_ALL | LVNI_SELECTED);
if (selectedIndex != -1)
ListView_DeleteItem(List.hwnd, selitm);

Related

WinAPI rebar control not showing up

I'm working on a pure WinAPI application in C++ and I want to add a toolbar that lives inside/on a rebar control. I can create and add the toolbar but I can't get the rebar to show up (there are no grippers even though I set the RBBS_GRIPPERALWAYS style):
I took the code from the MSDN pages about toolbar/rebar controls and assembled a minimal sample but still no success. Return codes of CreateWindow and SendMessage etc. look okay to me. I also tried the solution of this question but I can't get it working anyways. Any help would be greatly appreciated.. here's the complete source code:
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <CommCtrl.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "Resource.h"
#pragma comment(lib, "comctl32.lib")
// Enable visual styles
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
// Toolbar defines
#define IDM_NEW 100
#define IDM_OPEN 101
#define IDM_SAVE 102
#define NUM_TBBUTTONS 3
// Global variables
HINSTANCE g_hInst;
HIMAGELIST g_hImageList = NULL;
// Forward declarations
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND CreateSimpleToolbar(HWND hwndParent);
HWND CreateSimpleRebar(HWND hwndParent, HWND hwndToolbar);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
// Initialize common controls.
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_REBARTEST));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_REBARTEST);
wcex.lpszClassName = _T("RebarTest");
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassExW(&wcex);
HWND hwndMainWindow = CreateWindowW(_T("RebarTest"), _T("AppTitle"),
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
nullptr, nullptr, hInstance, nullptr);
if (!hwndMainWindow)
return FALSE;
ShowWindow(hwndMainWindow, nCmdShow);
UpdateWindow(hwndMainWindow);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
static HWND hwndToolbar, hwndRebar;
switch (message)
{
case WM_CREATE:
{
hwndToolbar = CreateSimpleToolbar(hwnd);
hwndRebar = CreateSimpleRebar(hwnd, hwndToolbar);
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Menüauswahl analysieren:
switch (wmId)
{
case IDM_EXIT:
DestroyWindow(hwnd);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
HWND CreateSimpleToolbar(HWND hwndParent) {
// Create the toolbar.
HWND hwndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0, hwndParent, NULL, g_hInst, NULL);
if (hwndToolbar == NULL)
return NULL;
// Create the image list.
g_hImageList = ImageList_Create(16, 16, ILC_COLOR16 | ILC_MASK, NUM_TBBUTTONS, 0);
// Set the image list and add buttons
const int imageListID = 0;
SendMessage(hwndToolbar, TB_SETIMAGELIST, (WPARAM)imageListID, (LPARAM)g_hImageList);
SendMessage(hwndToolbar, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
// Initialize button info.
TBBUTTON tbButtons[NUM_TBBUTTONS] =
{
{ MAKELONG(STD_FILENEW, imageListID), IDM_NEW, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)L"New" },
{ MAKELONG(STD_FILEOPEN, imageListID), IDM_OPEN, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)L"Open"},
{ MAKELONG(STD_FILESAVE, imageListID), IDM_SAVE, 0, BTNS_AUTOSIZE, {0}, 0, (INT_PTR)L"Save"}
};
// Add buttons.
SendMessage(hwndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(hwndToolbar, TB_ADDBUTTONS, (WPARAM)NUM_TBBUTTONS, (LPARAM)&tbButtons);
// Resize the toolbar, and then show it.
SendMessage(hwndToolbar, TB_AUTOSIZE, 0, 0);
ShowWindow(hwndToolbar, TRUE);
return hwndToolbar;
}
HWND CreateSimpleRebar(HWND hwndParent, HWND hwndToolbar) {
// Check parameters.
if (!hwndParent || !hwndToolbar)
return NULL;
// Create the rebar.
HWND hwndRebar = CreateWindowEx(WS_EX_TOOLWINDOW,
REBARCLASSNAME, NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
RBS_VARHEIGHT | CCS_NODIVIDER | RBS_BANDBORDERS,
0, 0, 0, 0,
hwndParent, NULL, g_hInst, NULL);
if (!hwndRebar)
return NULL;
// Get the height of the toolbar.
DWORD dwBtnSize = (DWORD)SendMessage(hwndToolbar, TB_GETBUTTONSIZE, 0, 0);
REBARBANDINFO rbBand;
rbBand.cbSize = sizeof(REBARBANDINFO);
rbBand.fMask =
RBBIM_STYLE // fStyle is valid.
| RBBIM_TEXT // lpText is valid.
| RBBIM_CHILD // hwndChild is valid.
| RBBIM_CHILDSIZE // child size members are valid.
| RBBIM_SIZE; // cx is valid
rbBand.fStyle = RBBS_CHILDEDGE | RBBS_GRIPPERALWAYS;
rbBand.lpText = (LPWSTR)_T("");
rbBand.hwndChild = hwndToolbar;
rbBand.cyChild = LOWORD(dwBtnSize);
rbBand.cxMinChild = NUM_TBBUTTONS * HIWORD(dwBtnSize);
rbBand.cyMinChild = LOWORD(dwBtnSize);
rbBand.cx = 0; // The default width is the width of the buttons.
// Add the band with the toolbar.
SendMessage(hwndRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
return hwndRebar;
}
As described in the comments on this question, you need to have a _WIN32_WINNT defined, which I assume you may have in your "targetver.h" header. Since you are declaring common-controls version 6, I think you need to target WS-2003/Vista at a minimum, according to this. I first tried #define WINVER 0x0601 and #define _WIN32_WINNT_WIN7 0x0601 with your code and it worked on my machine.
I think the question you linked is a little out of date, this table says the structure size for common-controls version 6 should be REBARBANDINFO_V6_SIZE. However, I encountered the 4 pixel height issue from your linked question when using that structure size. Keeping your sizeof code as-is worked for me.
I think the real issue you have is your toolbar is handling its own resizing and positioning. As described on this About Toolbar Control page, you need to change this
HWND hwndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0, hwndParent, NULL, g_hInst, NULL);
to this
HWND hwndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_WRAPABLE | CCS_NORESIZE | CCS_NOPARENTALIGN, 0, 0, 0, 0, hwndParent, NULL, g_hInst, NULL);
in your CreateSimpleToolbar function so the host rebar can take control of the toolbar sizing and positioning.

How can I retrieve Combobox's GWLP_USERDATA from WM_CTLCOLORLISTBOX?

Most messages I've been using so far pass the HWND in the lParam. So I was using that value to retrieve the associated hwnd's object with GWLP_USERDATA, so I could do something like this:
case WM_COMMAND:
{
auto sender = (HWND)lParam;
auto obj = getObj(sender);
obj->myMethod();
}
And get the method associated to the hwnd called. However, WM_CTLCOLORLISTBOX for Combobox doesn't send the Combobox's HWND in the lParam. I have to send a CB_GETCOMBOBOXINFO message but that requires the control's hwnd, that in that design, isn't available. So my question is: How can I retrieve the object associated to the combobox from WM_CTLCOLORLISTBOX? I couldn't think any other way to loop over all objects created so far(So I needed to keep an array of them), somehow filter that objects that are associated with a combobox control type, then use that hwnd in the CB_GETCOMBOBOXINFO message. This seems kinda of bruta force. Are there a better approach than this? here's how I'm doing that currently:
case WM_CTLCOLORLISTBOX:
{
auto dc = (HDC) wParam;
SetBkMode(dc, TRANSPARENT);
COMBOBOXINFO info;
for(int i = 0; i < COUNTOF(instances); i++)
{
auto obj = instances[i];
if(obj->type != ControlType_combobox)
continue;
memset(&info, 0, sizeof(COMBOBOXINFO));
info.cbSize = sizeof(COMBOBOXINFO);
auto hCombo = instances[i];
SendMessage(obj->hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM) &info);
if((HWND)lParam == info.hwndList)
{
return (LRESULT) obj->hBrush;
}
}
}
break;
}
full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "Comdlg32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <winuser.h>
#include <assert.h>
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
enum ControlType
{
ControlType_none,
ControlType_button,
ControlType_combobox
};
class Foo
{
public:
int n = 0;
const wchar_t *str = nullptr;
HBRUSH hBrush = nullptr;
ControlType type = ControlType_none;
HWND hwnd = nullptr;
void sayHello()
{
MessageBox(NULL, str, L"", MB_OK);
}
Foo() { }
~Foo()
{
if(hBrush) {
DeleteObject(hBrush);
hBrush = nullptr;
}
}
};
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HFONT getDefaultFont();
void SetDefaultFont(HWND hwnd);
void saveInstance(Foo *f);
void freeInstances();
void associateObj(HWND hwnd, Foo *instance);
Foo* getObj(HWND hwnd);
Foo *instances[12];
int instance_size = 0;
HFONT hDefaultSystemFont;
HINSTANCE g_hinst;
const wchar_t *items[] =
{
L"Windows", L"Mac",
L"FreeBSD", L"Arch",
};
enum
{
ID_COMBO = 10,
ID_BTN1,
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow) {
HWND hwnd;
MSG msg ;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Application";
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0,IDC_ARROW);
g_hinst = hInstance;
RegisterClassW(&wc);
hwnd = CreateWindowW(wc.lpszClassName, L"",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 300, 170, 0, 0, hInstance, 0);
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:
{
HWND hwndCombo = CreateWindow(L"Combobox", NULL,
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
10, 10, 120, 110, hwnd, (HMENU) ID_COMBO, g_hinst, NULL);
auto f = new Foo;
f->n = 10;
f->str = L"Hello from combo!";
f->hBrush = CreateSolidBrush(RGB(0, 128, 0));
f->type = ControlType_combobox;
associateObj(hwndCombo, f);
for (int i = 0; i < COUNTOF(items); i++)
{
SendMessageW(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
}
SetDefaultFont(hwndCombo);
HWND btn1 =
CreateWindow(L"Button", L"Click me!",
WS_CHILD | WS_VISIBLE,
5, 40, 90, 25, hwnd, (HMENU) ID_BTN1, g_hinst, NULL);
auto f2 = new Foo;
f2->n = 20;
f2->str = L"Hello from button!";
f2->type = ControlType_button;
associateObj(btn1, f2);
SetDefaultFont(btn1);
}
break;
case WM_DESTROY:
DeleteObject(hDefaultSystemFont);
hDefaultSystemFont = NULL;
freeInstances();
PostQuitMessage(0);
break;
case WM_COMMAND:
{
auto sender = (HWND)lParam;
auto o = getObj(sender);
o->sayHello();
}
break;
case WM_CTLCOLORLISTBOX:
{
auto dc = (HDC) wParam;
SetBkMode(dc, TRANSPARENT);
COMBOBOXINFO info;
for(int i = 0; i < COUNTOF(instances); i++)
{
auto obj = instances[i];
if(obj->type != ControlType_combobox)
continue;
memset(&info, 0, sizeof(COMBOBOXINFO));
info.cbSize = sizeof(COMBOBOXINFO);
auto hCombo = instances[i];
SendMessage(obj->hwnd, CB_GETCOMBOBOXINFO, 0, (LPARAM) &info);
if((HWND)lParam == info.hwndList)
{
return (LRESULT) obj->hBrush;
}
}
}
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
void associateObj(HWND hwnd, Foo *instance)
{
instance->hwnd = hwnd;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)(void*)instance);
saveInstance(instance);
}
Foo* getObj(HWND hwnd)
{
return (Foo*)(void*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
void saveInstance(Foo *f)
{
instances[instance_size++] = f;
}
void freeInstances()
{
for(int i = 0; i < COUNTOF(instances); i++) {
delete instances[i];
instances[i] = nullptr;
}
}
HFONT getDefaultFont()
{
if(hDefaultSystemFont == NULL) {
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
hDefaultSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
}
return hDefaultSystemFont;
}
void SetDefaultFont(HWND hwnd)
{
SendMessage(hwnd, WM_SETFONT, (LPARAM) getDefaultFont(), TRUE);
}
When you create a ComboBox, use CB_GETCOMBOBOXINFO to get its ListBox's HWND, and then use SetProp() to save your object pointer in it. That way, in your WM_CTLCOLORLISTBOX handler, you can use GetProp() on the provided HWND to access your object. No hunting needed.
UPDATE: as stated in a comment, you can also use GetParent() on the HWND provided by WM_CTLCOLORLISTBOX to get its owning ComboBox's HWND, from which you can then access your associated object pointer using getObj().

Adding Different Components in Tab Control Win32

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.

Painting a Win32 child window

Hello all I have been trying to paint to my child window outside of WM_PAINT and Instead of painting on the child window it paints off of the window onto the screen I think it may be because of the location of x and y but shouldn't point (0,0) be the top left of the child window not of my actual screen?
Here is what the code I wrote to try to paint onto the child window:
#pragma warning(disable:4996)
#pragma comment(lib, "Ws2_32.lib")
#include <Windows.h>
#define WIDTH 800
#define HEIGHT 600
#define CLASS_NAME "Class"
#define IDC_MAIN_EDIT 101
#define IDC_WINDOW 102
int x = 0, y = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void print_line(HWND hwnd, char *Msg);
void Println();
int Run();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
MSG msg;
HWND hwnd = NULL;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = CLASS_NAME;
wcex.hInstance = hInstance;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBoxA(NULL, "Failed to register class", "Error", MB_OK | MB_ICONERROR);
return -1;
}
hwnd = CreateWindow(CLASS_NAME //Name of the window class
, CLASS_NAME//Title of the window
, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN// the window style
, 0 //x Postition of the window
, 0// y position of the windpo
, WIDTH, HEIGHT, // Width and Height
NULL,//Parent window(we have no parent window)
NULL,//Menu(we are not using menu's)
hInstance,//application handle
NULL);//Creates the window
if (!hwnd)
{
MessageBoxA(NULL, "Failed to register class", "Error", MB_OK | MB_ICONERROR);
return -2;
}
ShowWindow(hwnd, nCmdShow);
return Run();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hEdit = NULL;
HWND hWindow = NULL;
#define Print(msg2) print_line(hWindow, msg2)
switch (msg)
{
case WM_CREATE:
hWindow = CreateWindowEx(WS_EX_CLIENTEDGE, "Window", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOHSCROLL | WS_CLIPSIBLINGS,
0, 0, WIDTH, HEIGHT - 25, hwnd, (HMENU)IDC_WINDOW, GetModuleHandle(NULL), NULL);
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOHSCROLL,
0, 535, WIDTH, 25, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
Print("Hello");
break;
default:
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
}
int Run()
{
MSG msg = { 0 };
WSAData wsa;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsa) != 0) return -1;
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
void print_line(HWND hwnd, char *Msg)
{
HDC hdc;
hdc = GetDC(hwnd);
TextOut(hdc,
x,
y,
Msg,
strlen(Msg));
ReleaseDC(hwnd, hdc);
}
void Println()
{
x = 0;
y += 20;
}
Yes I know there are other questions concerning this topic but none of them seemed to answer my question or address any of the problems I have been experiencing while trying to paint on the child window.
It Seems to me you create your windows in WndProc, but they do not get returned, so both windows created in WndProc end up being NULL when WM_CREATE returns (AS the are only declared in WndProc).
Perhaps you need to set these both to globals, the use for example GetDC(hEdit) to draw to them. Overall it still looks like an odd bit of code.
It seems to me that you want to write text to the edit control you created with id=IDC_MAIN_EDIT by manually drawing the text into the control?
Try
case WM_COMMAND:
//Print("Hello");
hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); // get handle to edit window
if (hEdit != NULL) // did we get a handle to the edit window?
{
int len = GetWindowTextLength(hEdit);
SendMessage(hEdit , EM_SETSEL, len, len); // select end of contents
SendMessage(hEdit , EM_REPLACESEL, 0, (LPARAM)"Hello"); // replace end with new textt
}
break;
and the edit control will draw the text for you.
If you want to manually write the text to the window created by you modify the Print macro as follows:
#define Print(msg2) print_line(hwnd, msg2)

what is the simplest way to create edit box in c++

i need to create edit box in c++ without using mfc.....
only win32
CreateWindow("EDIT", ...);. You can use CreateWindowEx if you prefer, but it's not necessary. To use it, you'll also normally want to have your window respond to WM_FOCUS by calling SetFocus to set the focus on the edit control. You'll typically also want to respond to WM_MOVE (or is it WM_SIZE - I can't remember) by resizing the edit control to fit the client area of the parent window.
Of course you can also create a dialog (DialogBox or DialogBoxEx) containing an edit control. This avoids having to manually set the focus and such.
So, here's a simple demo program. This creates a main window, and fills its client area with an edit control. It can open and save files, do cut/copy/paste of the data in the control, and select a font in which to display the data in the control. It has an accelerator table, so it knows about the usual keyboard shortcuts for most of those (e.g., ctrl-x = cut, ctrl-c = copy, ctrl-v = paste).
First, the main source code:
// notepad.cpp
#include <windows.h>
#include "notepad.h"
#include <string.h>
#include <string>
#include <fstream>
#include <sstream>
HINSTANCE hInst;
HWND hwnd;
static const HMENU edit_id = HMENU(100);
static HWND hwndEdit;
void Invalidate(HWND window) {
RECT rect;
GetClientRect(window, &rect);
InvalidateRect(window, &rect, TRUE);
}
class file {
std::string filename;
char buffer[FILENAME_MAX];
void write_file() {
size_t size = SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
std::string buffer(size+1, '\0');
SendMessage(hwndEdit, WM_GETTEXT, size + 1, (LPARAM)&buffer[0]);
std::ofstream out(filename);
out.write(&buffer[0], size);
}
long long get_size(std::string const& filename) {
WIN32_FIND_DATA data;
auto h = FindFirstFile(filename.c_str(), &data);
long long size = data.nFileSizeHigh;
size <<= 32;
size |= data.nFileSizeLow;
return size;
}
void read_file() {
std::ifstream in(filename);
std::string buffer;
long long size = get_size(filename);
if (size > 1024 * 1024) {
MessageBox(hwnd, "File too large", "", MB_OK);
return;
}
buffer.resize(size+1);
in.read(&buffer[0], size);
std::string::size_type pos = 0;
unsigned count = 0;
while ((pos = buffer.find('\n', pos)) != std::string::npos) {
buffer.replace(pos, 1, "\r\n");
pos += 2;
++count;
}
SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)buffer.c_str());
}
public:
file() : buffer("\0\0") {}
bool open() {
if (SendMessage(hwndEdit, EM_GETMODIFY, 0, 0)) {
if (MessageBox(hwnd, "Open without saving current text?", "Buffer Modified", MB_OKCANCEL) == IDCANCEL)
return false;
}
OPENFILENAMEA spec{};
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpstrFile = buffer;
spec.nMaxFile = sizeof(buffer);
spec.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_SHAREAWARE | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&spec)) {
filename = spec.lpstrFile;
read_file();
return true;
}
return false;
}
bool save() {
if (filename.empty())
return save_as();
write_file();
SendMessage(hwndEdit, EM_SETMODIFY, 0, 0);
return true;
}
bool save_as() {
OPENFILENAMEA spec{};
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpstrFile = buffer;
spec.nMaxFile = sizeof(buffer);
spec.Flags = OFN_OVERWRITEPROMPT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_SHAREAWARE;
if (GetSaveFileName(&spec)) {
filename = spec.lpstrFile;
write_file();
SendMessage(hwndEdit, EM_SETMODIFY, 0, 0);
return true;
}
return false;
}
} file;
class font {
HFONT current;
LOGFONT log_font;
CHOOSEFONT spec;
bool choose() {
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpLogFont = &log_font;
spec.Flags = CF_INITTOLOGFONTSTRUCT | CF_FORCEFONTEXIST | CF_SCREENFONTS;
return ChooseFont(&spec);
}
public:
font()
: current(NULL)
, log_font{}
, spec{}
{}
bool select() {
if (!choose())
return false;
current = CreateFontIndirect(&log_font);
SendMessage(hwndEdit, WM_SETFONT, *reinterpret_cast<WPARAM *>(&current), TRUE);
return true;
}
} font;
LRESULT CALLBACK MainWndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
PAINTSTRUCT ps;
HDC dc;
RECT rect;
int i;
switch (message) {
case WM_PAINT:
dc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CREATE:
hwndEdit = CreateWindowEx(
0,
"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN,
0, 0, 0, 0,
hwnd,
edit_id,
hInst,
NULL);
if (hwndEdit == nullptr)
return -1;
return 0;
case WM_SIZE: {
int width = LOWORD(lparam);
int height = HIWORD(lparam);
MoveWindow(hwndEdit, 0, 0, width, height, TRUE);
break;
}
case WM_SETFOCUS:
SetFocus(hwndEdit);
break;
case WM_COMMAND :
switch(LOWORD(wparam)) {
case ID_EXIT:
if (wparam == ID_EXIT)
PostMessage(hwnd, WM_DESTROY, 0, 0);
break;
case ID_FILE_OPEN:
if (file.open())
return 0;
break;
case ID_FILE_SAVE:
if (file.save())
return 0;
break;
case ID_FILE_SAVEAS:
if (file.save_as())
return 0;
break;
case ID_EDIT_UNDO:
if (SendMessage(hwndEdit, EM_CANUNDO, 0, 0))
SendMessage(hwndEdit, WM_UNDO, 0, 0);
return 0;
case ID_EDIT_SELECT_ALL:
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
return 0;
case ID_EDIT_CUT:
SendMessage(hwndEdit, WM_CUT, 0, 0);
break;
case ID_EDIT_COPY:
SendMessage(hwndEdit, WM_COPY, 0, 0);
break;
case ID_EDIT_PASTE:
SendMessage(hwndEdit, WM_PASTE, 0, 0);
break;
case ID_VIEW_FONT:
return font.select();
default: {
return DefWindowProc(hwnd, message, wparam, lparam);
}
}
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
BOOL Init(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wc;
hInst = hInstance;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = (HICON)LoadImage(hInstance,
MAKEINTRESOURCE(IDI_APPICON),
IMAGE_ICON,
16, 16,
0);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = "MAINMENU";
wc.lpszClassName = title;
if (!RegisterClassEx(&wc))
return FALSE;
hwnd = CreateWindow(title,
title,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL,
NULL,
hInstance,
NULL);
if (!hwnd) {
return FALSE;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL AccelTable;
if (!Init(hInstance, nCmdShow))
return FALSE;
AccelTable = LoadAccelerators(hInstance, "SHORTCUTS");
while (GetMessage(&msg, NULL, 0, 0))
if (!TranslateAccelerator(hwnd, AccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
The, the header:
// notepad.h
#define ID_EXIT 100
#define ID_FILE_OPEN 101
#define ID_FILE_SAVE 102
#define ID_FILE_SAVEAS 103
#define ID_EDIT_CUT 201
#define ID_EDIT_COPY 202
#define ID_EDIT_PASTE 203
#define ID_EDIT_UNDO 204
#define ID_EDIT_FIND 211
#define ID_EDIT_FIND_NEXT 212
#define ID_EDIT_REPLACE 213
#define ID_EDIT_SELECT_ALL 214
#define ID_VIEW_WRAP 301
#define ID_VIEW_FONT 302
#define IDI_APPICON 400
static char title[] = "Minimum Window";
Note: the header includes defines for a few commands (find/find-next/replace) that aren't implemented in the program.
Then you need a resource file, on this general order:
// notepad.rc
#include "notepad.h"
MAINMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "Open\tCtrl+O", ID_FILE_OPEN
MENUITEM "Save\tCtrl+S", ID_FILE_SAVE
MENUITEM "Save As", ID_FILE_SAVEAS
MENUITEM "E&xit", ID_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO
MENUITEM "Cut\tCtrl+X", ID_EDIT_CUT
MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY
MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE
MENUITEM SEPARATOR
MENUITEM "Find...\tCtrl+F", ID_EDIT_FIND
MENUITEM "Find Next", ID_EDIT_FIND_NEXT
MENUITEM "Replace...\tCtrl+H", ID_EDIT_REPLACE
MENUITEM "Select All\tCtrl+A", ID_EDIT_SELECT_ALL
END
POPUP "Format"
BEGIN
MENUITEM "&Font", ID_VIEW_FONT
END
END
SHORTCUTS ACCELERATORS
BEGIN
"^O", ID_FILE_OPEN, ASCII
"^S", ID_FILE_SAVE, ASCII
"^A", ID_EDIT_SELECT_ALL, ASCII
"^Z", ID_EDIT_UNDO, ASCII
"^X", ID_EDIT_CUT, ASCII
"^C", ID_EDIT_COPY, ASCII
"^V", ID_EDIT_PASTE, ASCII
END
Although not strictly necessary, a Makefile to build it comes in handy:
notepad.exe: notepad.obj notepad.res
link notepad.obj user32.lib gdi32.lib comdlg32.lib notepad.res
notepad.res: notepad.rc
rc -r notepad.rc
notepad.obj: notepad.cpp
cl -c notepad.cpp
clean:
del *.res
del *.obj
So, if you save those into a directory, open a command prompt for Microsoft's compiler, and type nmake in that directory, it should build a notepad.exe, which will be a mildly stripped down version of the normal Windows notepad. It's missing find/replace, printing, and a couple of other things, but at least has enough to give a decent starting point for how to create and use an edit control.
Oh--one other note. This is mostly quickly hacked together from bits and pieces of old code, with a little bit of new duct tape (so to speak) to hold them together. It is not, by any means, exemplary of the best possible coding practices throughout (to put it nicely).
HWND CreateTextBox(CONST INT iX, CONST INT iY, CONST UINT uWidth, CONST UINT uHeight, HWND hWnd, CONST UINT uId, HINSTANCE hInstance)
{
HWND hWndRet = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), NULL, WS_CHILD, iX, iY, (signed)uWidth, (signed)uHeight, hWnd, (HMENU)uId, hInstance, NULL);
SetBkColor(GetDC(hWndRet), RGB(255, 255, 255));
return hWndRet;
}
Just a small function I use for creating default, blank text boxes.