Can't drag or resize custom frame window - c

I'm programming an application that has a window that has custom frame.
I visited these sites and use them both to create my own app:
Winprog
And also:
Microsoft Docs: Custom frame window using dwm
I use TDM_GCC and c language to write this app.
This app compiled using some linkers successfully; but my custom frame window is undraggable and non-resizable.
Please help me to resolve my problem.
My codes are below:
#include <windows.h>
#include <windowsx.h>
#include <winuser.h>
#include <dwmapi.h>
#include <stdbool.h>
const char g_szClassName[] = "myWindowClass";
LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
POINT ptMouse = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
RECT rcWindow;
GetWindowRect(hWnd, &rcWindow);
RECT rcFrame = { 0 };
AdjustWindowRectEx(&rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, false, WS_EX_CLIENTEDGE);
USHORT uRow = 1;
USHORT uCol = 1;
bool fOnResizeBorder = false;
if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + 50)
{
fOnResizeBorder = (ptMouse.y < (rcWindow.top - rcFrame.top));
uRow = 0;
}
else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - 50)
{
uRow = 2;
}
if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + 50)
{
uCol = 0; // left side
}
else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - 50)
{
uCol = 2; // right side
}
LRESULT hitTests[3][3] =
{
{ HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT },
{ HTLEFT, HTNOWHERE, HTRIGHT },
{ HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT },
};
return hitTests[uRow][uCol];
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
MARGINS m = {50,50,50,50};
bool f = false;
LRESULT l = 0;
HRESULT hr = S_OK;
RECT rcClient;
if(msg == WM_ACTIVATE){
hr = DwmExtendFrameIntoClientArea(hwnd, &m);
f = true;
l = 0;
}
if(msg == WM_NCCALCSIZE){
wParam = true;
return 0;
}
if(msg == WM_CREATE){
GetWindowRect(hwnd, &rcClient);
SetWindowPos(hwnd,
NULL,
rcClient.left, rcClient.top,
800, 600,
SWP_FRAMECHANGED);
f = true;
l = 0;
}
if ((msg == WM_NCHITTEST) && (l == 0)){
l = HitTestNCA(hwnd, wParam, lParam);
if (l != HTNOWHERE)
f = false;
}
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 = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(NULL_PEN);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE ,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
And my project is here in a zip file:
a.zip

Related

WinAPI - Blurring a window fails

I want to blur a window, and I have used DwmEnableBlurBehindWindow(), DwmExtendFrameIntoClientArea() and DwmSetWindowAttribute() (to enable the client area rendering). However, it fails to blur, and instead makes the client area white.
Minimum reproducible code:
#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>
HWND hwnd;
HRESULT enableNCRendering(HWND hWnd)
{
enum DWMNCRENDERINGPOLICY ncrp = DWMNCRP_ENABLED;
HRESULT hr = DwmSetWindowAttribute(hWnd,
DWMWA_NCRENDERING_POLICY,
&ncrp,
sizeof(ncrp));
if (!SUCCEEDED(hr))
printf("Failed 0\n");
return hr;
}
HRESULT EnableBlurBehind(HWND hwnd)
{
DWM_BLURBEHIND bb = {0};
bb.dwFlags = DWM_BB_ENABLE;
bb.fEnable = true;
bb.hRgnBlur = NULL;
HRESULT hr = DwmEnableBlurBehindWindow(hwnd, &bb);
if (!SUCCEEDED(hr))
printf("Failed 1\n");
return hr;
}
HRESULT ExtendIntoClientAll(HWND hwnd)
{
MARGINS margins = {-1};
HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
if (!SUCCEEDED(hr))
printf("Failed 2\n");
return hr;
}
ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = styles;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.lpszClassName = (LPCWSTR)name;
return RegisterClassExW(&wc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wp, lp);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(255, 0, 0), WndProc);
hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
return 1;
SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);
enableNCRendering(hwnd);
EnableBlurBehind(hwnd);
ExtendIntoClientAll(hwnd);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
I have also tried SetWindowCompositionAttributes() but it was undefined in Mingw, and I wasn't able to find much information on using that. It also doesn't give the desired effect and gives barely any blur:
#include <Winerror.h>
#include <dwmapi.h>
#include <gdiplus.h>
#include <stdio.h>
#include <windows.h>
HWND hwnd;
struct ACCENTPOLICY
{
int na;
int nf;
int nc;
int nA;
};
struct WINCOMPATTRDATA
{
int na;
PVOID pd;
ULONG ul;
};
typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
void makeBlur()
{
const HINSTANCE hm = LoadLibraryW(L"user32.dll");
if (hm)
{
const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hm, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttribute)
{
struct ACCENTPOLICY policy = {3, 0, 0, 0};
struct WINCOMPATTRDATA data = {19, &policy, sizeof(ACCENTPOLICY)};
SetWindowCompositionAttribute(hwnd, &data);
}
FreeLibrary(hm);
}
}
ATOM MyRegisterClass(HINSTANCE hInst, LPCWSTR name, UINT styles, COLORREF bkg_colour, WNDPROC proc)
{
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = styles;
wc.lpfnWndProc = proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wc.hbrBackground = (HBRUSH)CreateSolidBrush(bkg_colour); // CreateSolidBrush(RGB(255, 0, 0))
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIconW(hInst, (LPCWSTR)IDI_APPLICATION);
wc.lpszClassName = (LPCWSTR)name;
return RegisterClassExW(&wc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wp, lp);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
//getting accent colors
DWORD color = 0;
BOOL opaque = FALSE;
DwmGetColorizationColor(&color, &opaque);
BYTE blue = color;
color = color >> 8;
BYTE green = color;
color = color >> 8;
BYTE red = color;
color = color >> 8;
BYTE alpha = color;
MyRegisterClass(hInstance, L"Main", CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, RGB(red, green, blue), WndProc);
hwnd = CreateWindowExW(WS_EX_LAYERED, L"Main", L"main", WS_POPUP, 0, 0, 1000, 500, NULL, NULL, hInstance, NULL);
if (!hwnd)
return 1;
SetLayeredWindowAttributes(hwnd, 0, 100, LWA_ALPHA);
makeBlur();
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
How can I make my window blur?
The DwmEnableBlurBehindWindow documentation states:
Beginning with Windows 8, calling this function doesn't result in the blur effect, due to a style change in the way windows are rendered.
Aero Glass was officially discontinued in Windows 8. However, Aero Glass made a comeback (sort of) in Windows 10, as the Taskbar and some system notifications still use it. You have to use the undocumented SetWindowCompositionAttribute() API to enable the blur effect now, see:
How do you set the glass blend colour on Windows 10?
You are looking for the ACCENT_ENABLE_BLURBEHIND option.

Background image fails to get set for a window in WinApi

I am learning to how to set a background image for a window in C.
Here is my code:
#include <stdio.h>
#include <windows.h>
char* window_name = "Window";
char* window_title = "Window Title";
char* background_name = "test.bmp";
int window_width = 600;
int window_height = 400;
HBITMAP hbackground_image;
WNDCLASSEX wc;
HWND hwnd, hbackground;
MSG msg;
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
hbackground = CreateWindow("STATIC", "background", SS_BITMAP | WS_CHILD | WS_VISIBLE, 0, 0, 300, 300, hwnd,
NULL, NULL, NULL);
hbackground_image = (HBITMAP)LoadImage(NULL, background_name, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
SendMessage(hbackground, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbackground_image);
break;
default:
return DefWindowProc(hwnd, msg, wp, lp);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
wc.lpszClassName = window_name;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Windows registration failure", NULL, MB_RETRYCANCEL);
return 1;
}
hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, window_name, window_title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, window_width, window_height, NULL, NULL, hInstance, NULL);
// hwnd = CreateWindow("test", "test title", WS_OVERLAPPED | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL); // This fails
if (!hwnd) // If fails
{
MessageBox(NULL, "Window creation failed :(", NULL, MB_RETRYCANCEL);
return 2;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
However, the background image doesn't get set even though there is a bitmap in the same folder as the .exe. I also tried different bitmaps from the internet, and one I made in paint. Any help would be appreciated.
This line is wrong:
wc.lpfnWndProc = DefWindowProc;
You are not seeing your background image because you are not using your WindowProcedure() with the window class, and thus it is never called to load/display the bitmap.
That line needs to be this instead:
wc.lpfnWndProc = WindowProcedure;
Also, when processing WM_CREATE, you are not return'ing any value, so the result is indeterminate, which is undefined behavior. You need to return 0; for that message:
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_CREATE:
...
return 0;
...
}
return DefWindowProc(hwnd, msg, wp, lp);
}

WinAPI, TreeView: a gray item by TVIS_CUT

I want to make a item gray. According to docs I set TVIS_CUT in stateMask and mask.
But it doesn't work (the item is black as usual). TVIS_BOLD works perfect.
I use CodeBlocks17 (gcc)/Win7x64. Also I tried VS2005 and another OS (WinXP) with the same result.
What did I miss?
#define _UNICODE
#define UNICODE
#include <windows.h>
#include <commctrl.h>
LRESULT CALLBACK cbMain (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
MSG msg;
WNDCLASSEX wc{0};
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("MyAppClass");
wc.lpfnWndProc = cbMain;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof (WNDCLASSEX);
wc.hIcon = LoadIcon(0, IDC_ICON);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.lpszMenuName = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wc))
return EXIT_FAILURE;
HWND hMainWnd = CreateWindowEx (0, TEXT("MyAppClass"), NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 500, 600, 160, 300, HWND_DESKTOP, NULL, hInstance, NULL);
HWND hTreeWnd = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS, 0, 0, 150, 200, hMainWnd, (HMENU)100, hInstance, NULL);
TVITEM tvi{0};
tvi.mask = TVIF_TEXT | TVIF_STATE;
tvi.pszText = TEXT("Item");
tvi.cchTextMax = 40;
tvi.stateMask = TVIS_CUT;
tvi.state = TVIS_CUT;
TVINSERTSTRUCT tvins{0};
tvins.item = tvi;
tvins.hInsertAfter = TVI_ROOT;
tvins.hParent = TVI_ROOT;
SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK cbMain (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
I used Custom Draw as Jonathan Potter said.
Here is one pitfall: while a current item changing, old item has CDIS_FOCUS and CDIS_SELECTED flags in pCustomDraw->nmcd.uItemState member, and new item doesn't have. So pCustomDraw->clrText = (pNMTVCD->nmcd.uItemState & CDIS_FOCUS) == CDIS_FOCUS) ? ... will works a little bit strange. I checked pCustomDraw->clrTextBk instead. But it can be broken when user used a custom theme.
I use this article and an applied code to build the example.
#define _UNICODE
#define UNICODE
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0500
#include <windows.h>
#include <commctrl.h>
#define IDC_TREEVIEW 100
LRESULT CALLBACK cbMain (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) {
MSG msg;
WNDCLASSEX wc{0};
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("MyAppClass");
wc.lpfnWndProc = cbMain;
wc.style = CS_DBLCLKS;
wc.cbSize = sizeof (WNDCLASSEX);
wc.hIcon = LoadIcon(0, IDC_ICON);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.lpszMenuName = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wc))
return EXIT_FAILURE;
HWND hMainWnd = CreateWindowEx (0, TEXT("MyAppClass"), NULL, WS_OVERLAPPED | WS_VISIBLE | WS_SYSMENU, 500, 600, 160, 300, HWND_DESKTOP, NULL, hInstance, NULL);
HWND hTreeWnd = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS, 0, 0, 150, 200, hMainWnd, (HMENU)IDC_TREEVIEW, hInstance, NULL);
TVITEM tvi{0};
TVINSERTSTRUCT tvins{0};
tvi.mask = TVIF_TEXT | TVIF_STATE;
tvi.pszText = TEXT("Item1");
tvi.cchTextMax = 40;
tvi.stateMask = 0;
tvi.state = 0;
tvins.item = tvi;
tvins.hInsertAfter = TVI_ROOT;
tvins.hParent = TVI_ROOT;
SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
tvi.pszText = TEXT("Item2");
tvins.item = tvi;
SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
tvi.stateMask = TVIS_CUT;
tvi.state = TVIS_CUT;
tvi.pszText = TEXT("Item3");
tvins.item = tvi;
SendMessage(hTreeWnd, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK cbMain (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY: {
PostQuitMessage (0);
}
break;
case WM_NOTIFY: {
NMHDR* pHdr = (LPNMHDR)lParam;
if (pHdr->idFrom == IDC_TREEVIEW && pHdr->code == NM_CUSTOMDRAW) {
LPNMTVCUSTOMDRAW pCustomDraw = (LPNMTVCUSTOMDRAW)lParam;
if (pCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
return CDRF_NOTIFYITEMDRAW;
if (pCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
BOOL isCut = TreeView_GetItemState(pHdr->hwndFrom, (HTREEITEM)pCustomDraw->nmcd.dwItemSpec, TVIS_CUT) & TVIS_CUT;
pCustomDraw->clrText = pCustomDraw->clrTextBk != RGB( 255, 255, 255) ? RGB( 255, 255, 255) :
isCut ? RGB( 128, 128, 128 ) : RGB( 0, 0, 0);
}
return CDRF_DODEFAULT;
}
}
break;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
return 0;
}

Column filter in ListView on win api

I'm doing some research and I would like to know how I can implement a column filter in a ListView using purely win32 api.
Something like this:
I wrote a simple test code, to generate a List View to show the CSV content.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <commctrl.h>
#include <string.h>
#define WND_CLASS_NAME "CSVVIEW"
char* filename;
HWND hList;
int rgb(int r, int g, int b) { return r + (g << 8) + (b << 16); }
void onCreate(HWND hWnd, LPARAM lParam) {
LVCOLUMN col;
LVITEM item;
int iCol, iCount, dwStyle;
CREATESTRUCT* lp = (CREATESTRUCT*)lParam;
FILE* fp;
char buf[256];
char* field;
memset(&item, 0, sizeof(item));
hList = CreateWindowEx(0, WC_LISTVIEW, 0,
WS_CHILD | WS_VISIBLE | LVS_REPORT,
0, 0, 100, 100, hWnd, (HMENU)1, lp->hInstance, NULL);
dwStyle = SendMessage(hList, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
dwStyle = dwStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT |
LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP;
SendMessage(hList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
fp = fopen(filename, "r");
if (fp == NULL) {
sprintf(buf, "Fail to open the file...", filename);
MessageBox(hWnd, buf, "Error", MB_OK);
exit(1);
}
fgets(buf, 255, fp);
field = strtok(buf, ",");
for (iCol = 0; field != NULL; iCol++) {
if (field[1] != ':') { col.fmt = LVCFMT_LEFT; }
else if (field[0] == 'l') { col.fmt = LVCFMT_LEFT; field += 2; }
else if (field[0] == 'c') { col.fmt = LVCFMT_CENTER; field += 2; }
else if (field[0] == 'r') { col.fmt = LVCFMT_RIGHT; field += 2; }
col.cx = strlen(field) * 13;
col.iSubItem = iCol;
col.pszText = field;
SendMessage(hList, LVM_INSERTCOLUMN, iCol, (LPARAM)&col);
field = strtok(NULL, ",\n");
}
item.mask = LVIF_TEXT;
for (iCount = 0; fgets(buf, 255, fp) != NULL; iCount++) {
item.pszText = strtok(buf, ",");
item.iItem = iCount;
item.iSubItem = 0;
SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&item);
for (iCol = 1; (field = strtok(NULL, ",\n")) != NULL; iCol++) {
item.pszText = field;
item.iItem = iCount;
item.iSubItem = iCol;
SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&item);
}
}
}
void onSize(HWND hwnd, WPARAM wp, LPARAM lp) {
RECT rc;
GetClientRect(hwnd, &rc);
MoveWindow(hList, 0, 0, rc.right - rc.left, rc.bottom - rc.top, TRUE);
}
int onNotify(HWND hwnd, WPARAM wp, LPARAM lp) {
NMHDR* pnmhdr = (NMHDR*)lp;
if (pnmhdr->code == NM_CUSTOMDRAW) {
NMLVCUSTOMDRAW* lpCustomDraw = (NMLVCUSTOMDRAW*)pnmhdr;
switch (lpCustomDraw->nmcd.dwDrawStage) {
case CDDS_PREPAINT:
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
if (lpCustomDraw->nmcd.dwItemSpec % 2 == 1)
lpCustomDraw->clrTextBk = rgb(209, 240, 179);
else
lpCustomDraw->clrTextBk = rgb(250, 250, 250);
return CDRF_NEWFONT;
}
}
return DefWindowProc(hwnd, WM_NOTIFY, wp, lp);
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE: onCreate(hWnd, lParam); break;
case WM_SIZE: onSize(hWnd, wParam, lParam); break;
case WM_NOTIFY: return onNotify(hWnd, wParam, lParam);
case WM_DESTROY: PostQuitMessage(0); break;
default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
char buf[256];
HWND hWnd;
WNDCLASS wcl;
MSG msg;
filename = lpCmdLine;
if (filename == NULL) return FALSE;
InitCommonControls();
memset(&wcl, 0, sizeof(wcl));
wcl.hInstance = hInstance;
wcl.lpszClassName = WND_CLASS_NAME;
wcl.lpfnWndProc = WindowProc;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
if (!RegisterClass(&wcl)) return FALSE;
wsprintf(buf, "%s - %s", "CSV View", lpCmdLine);
hWnd = CreateWindowEx(0, WND_CLASS_NAME, buf,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 900, 300, NULL, NULL, hInstance, NULL);
if (!hWnd) return FALSE;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
CSV test file:
COL 1,COL 2,COL 3,COL 4
CA_002,CB_002,CB_002,CB_002
CA_003,CB_003,CB_003,CB_003
What is necessary to change in the code so that it is possible to create the search fields in the list view header?
How to capture the events for each text field in the Header?

SB_THUMBTRACK is not sent repeatedly

MSDN says the following about SB_THUMBTRACK:
The user is dragging the scroll box. This message is sent repeatedly
until the user releases the mouse button. The HIWORD indicates the
position that the scroll box has been dragged to.
However, I am only getting this message once (when I click on the scroll box).
This is my code:
#include <Windows.h>
HWND hEdit;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_HSCROLL:
if (LOWORD(wParam) == SB_THUMBTRACK)
{
// Display some text
SendMessage(hEdit, WM_CHAR, 'a', 0);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = 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_BTNFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
//--------------------------------------------
// Create Window
HWND hWnd = CreateWindowEx(0, "WinClass", "My Title", WS_OVERLAPPEDWINDOW, 200, 200, 500, 300, NULL, NULL, hInstance, NULL);
// Create horizontal Scrollbar
CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE| SBS_HORZ, 50, 50, 300, 20, hWnd, NULL, hInstance, NULL);
// Create Edit control
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 10, 10, 250, 21, hWnd, NULL, hInstance, NULL);
// Show Window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//--------------------------------------------
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Because you do not set the scrollbar info, the system could not calculate the track position.
After setting the scrollinfo,
#include "stdafx.h"
#include <Windows.h>
#include <string.h>
#include <stdlib.h>
#include <Commctrl.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#pragma comment(lib, "Comctl32.lib")
HWND hEdit;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_HSCROLL:
if (LOWORD(wParam) == SB_THUMBTRACK)
{
int i = 0;
char buf[3];
_itoa_s(HIWORD(wParam), buf, 3, 10);
SetWindowText(hEdit, buf);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = 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_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "WinClass";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
//--------------------------------------------
InitCommonControls();
// Create Window
HWND hWnd = CreateWindowEx(0, "WinClass", "My Title", WS_OVERLAPPEDWINDOW, 200, 200, 500, 300, NULL, NULL, hInstance, NULL);
// Create horizontal Scrollbar
HWND hScroll = CreateWindowEx(0, "SCROLLBAR", NULL, WS_CHILD | WS_VISIBLE | SBS_HORZ, 50, 50, 300, 20, hWnd, NULL, hInstance, NULL);
// Create Edit control
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, 10, 10, 250, 21, hWnd, NULL, hInstance, NULL);
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = 100;
si.nPage = 10;
si.nPos = 0;
si.nTrackPos = 0;
SetScrollInfo(hScroll, SB_CTL, &si, true);
// Show Window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//--------------------------------------------
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
everything should work well.

Resources