I use this code to create a rebar control, and introduction a band with toolbar into the rebar.
But when window is shown up, I can not see the toolbar. and when I check the height of the rebar, in this line of code: int height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; I find rebar's height is only 4 pixels.
#include <windows.h>
#include <stdlib.h>
#include <CommCtrl.h>
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE instance;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
instance = hInstance;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"Example";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
RegisterClassEx(&wcex);
HWND hWnd = CreateWindow(L"Example", L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
500, 500, NULL, NULL, hInstance, NULL);
// Initialize common controls.
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
HWND hwndRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
0, 0, 100, 50, hWnd, NULL, instance, NULL);
// create toolbar
HWND hWndToolbar = CreateWindowEx(0 , TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_TOOLTIPS,
0, 0, 0, 0, hwndRebar, (HMENU)0, instance, NULL);
HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_COLOR16 | ILC_MASK, 3, 0);
SendMessage(hWndToolbar, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)hImageList);
SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[4] =
{
{0,0,TBSTATE_ENABLED,TBSTYLE_BUTTON},
{1,1,TBSTATE_ENABLED,TBSTYLE_BUTTON},
{2,2,TBSTATE_ENABLED,TBSTYLE_BUTTON},
};
SendMessage(hWndToolbar, (UINT) TB_ADDBUTTONS, 3, (LPARAM)&tbb);
SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0);
ShowWindow(hWndToolbar , SW_SHOW);
// Initialize band info.
REBARBANDINFO rbBand = { sizeof(REBARBANDINFO) };
rbBand.fMask = RBBIM_STYLE | RBBIM_TEXT | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_COLORS;
rbBand.fStyle = RBBS_GRIPPERALWAYS;
// Get the height of the toolbar.
DWORD dwBtnSize = (DWORD)SendMessage(hWndToolbar, TB_GETBUTTONSIZE, 0,0);
// Set values unique to the band with the toolbar.
rbBand.clrFore = RGB(233, 233, 233);
rbBand.clrBack = RGB(200, 200, 200);
rbBand.lpText = TEXT("");
rbBand.hwndChild = hWndToolbar;
rbBand.cyChild = LOWORD(dwBtnSize);
rbBand.cyMinChild = LOWORD(dwBtnSize);
rbBand.cxMinChild = 3 * HIWORD(dwBtnSize);
// The default width is the width of the buttons.
rbBand.cx = 0;
// Add the band
SendMessage(hwndRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
// show the main window
ShowWindow(hWnd, nCmdShow);
// check the rebar size
WINDOWPLACEMENT wp;
GetWindowPlacement(hwndRebar, &wp);
int height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
As follows from the comments, the solution was:
REBARBANDINFO rbBand;
rbBand.cbSize = REBARBANDINFO_V3_SIZE;
// initialize the rest here
This seems to affect older versions of Windows (specifically, XP), because the original code compiles and runs fine on Windows 7.
This was mentioned in the comments to a MSDN page: http://msdn.microsoft.com/en-us/library/windows/desktop/bb774393.aspx
As was already stated, the cbSize member of the REBARBANDINFO struct needed to be set.
Note the following about the provided code as well:
The images on the toolbar buttons don't show up. Right after creating the image list you have to make the following call to load the images:
SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
The TBBUTTON array is declared with a size of 4 but it only gets populated with 3 items. Technically it should be declared as:
TBBUTTON tbb[3]
Related
We have updated our windows code to use Styles and since then we get a flicker in various parts of the code when using STM_SETIMAGE to update a bitmap on a window.
I have created a minimal reproducible example here. Can anyone tell me what I need to do to get rid of the flicker please ?
The code simply redraws a bitmap every 1/100 second and calls the windows function to set the image onto the window. It worked without a flicker before we added Windows Styles.
Thanks
Shaun
#include <windows.h>
#include <CommCtrl.h>
#include <math.h>
#include <objbase.h>
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
//--------------------------------------
#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif
//--------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
//--------------------------------------
HWND logo;
HWND m_hwnd;
HBITMAP testBitmap;
int counter=0;
typedef unsigned char u8;
typedef unsigned int u32;
//--------------------------------------
HRESULT App_Initialize()
{
HRESULT hr;
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);;
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = TEXT("myApp");
RegisterClassEx(&wcex);
int dpiX = 0;
int dpiY = 0;
HDC hdc = GetDC(NULL);
if (hdc)
{
dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(NULL, hdc);
}
m_hwnd = CreateWindow( TEXT("myApp"), TEXT("Simple Set image Example"), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 640, 640, NULL,NULL,HINST_THISCOMPONENT,0);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
ShowWindow(m_hwnd, SW_SHOWNORMAL);
UpdateWindow(m_hwnd);
}
logo = CreateWindow("Static", NULL, SS_BITMAP | WS_CHILD | WS_VISIBLE, 40, 40,512,512, m_hwnd, NULL, NULL, NULL);
return hr;
}
//----------------------------------------------
void Redraw()
{
DeleteObject(testBitmap);
testBitmap=0;
u8 * RenderImageData=(u8*)malloc(512*512*4);
u32 * p=(u32*)RenderImageData;
for(int i=0;i<512;i++)
{
p[i+counter*512]=0xff000000;
p[i*512+counter]=0xff000000;
}
testBitmap = CreateBitmap(512,512, 4, 8, RenderImageData);
SendMessage(logo,STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) testBitmap);
free(RenderImageData);
counter=(counter+1)&511;
}
//----------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance ,HINSTANCE hPrevInstance ,LPSTR lpCmdLine ,int nCmdShow)
{
if (SUCCEEDED(CoInitialize(NULL)))
{
if (SUCCEEDED(App_Initialize()))
{
MSG msg;
while(1)
{
while (PeekMessage(&msg, NULL, 0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
Redraw();
}
}
CoUninitialize();
}
return 0;
}
//----------------------------------------------
I found this code which seems to work.
Instead of
HBITMAP hbm=(HBITMAP)SendMessage(hWndPic,STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) pD->hbitmap);
I call
GDI_SetImageX(pD->hbitmap,hWndPic, xs, ys);
void GDI_SetImageX( HBITMAP hBM, HWND hCtrl , int w, int h)
{
HDC hdcSrc=CreateCompatibleDC(0);
HDC hdcDst=GetDC(hCtrl);
HGDIOBJ hbmOld=SelectObject(hdcSrc,hBM);
HGDIOBJ hbmNew=CreateBitmap(w,h,4,8,0);
HGDIOBJ hbmOld2=SelectObject(hdcDst,hbmNew);
BitBlt(hdcDst,0,0,w,h,hdcSrc,0,0,0x00cc0020);
SelectObject(hdcSrc,hbmOld);
DeleteDC(hdcSrc);
ReleaseDC(hCtrl,hdcDst);
SendMessage(hCtrl,0x0b,0,0);
LRESULT oBM=SendMessage(hCtrl,STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBM);
SendMessage(hCtrl,0x0b,1,0);
DeleteObject(hBM);
}
I'm using a SwapChain created with CreateSwapChainForHwnd with DXGI_SCALING_STRETCH scaling. When the sizes of the swapchain and the window client area differ, the SwapChain's associated bitmap is correctly scaled, but its origin is moved as if the window borders were accounted in the stretch process although there sizes are constant.
Is there a way to fix or circumvent this issue ?
Thank you for the help !
(More precisely : for a client area larger that swapchain, the origin of the bitmap in shifted down, right proportionally respectively to title-bar height and left border width, the part of the bitmap thus moved outside the client area being invisible; a reverse shift is produced with client area smaller than swapchain).
Below a minimal code to reproduce this issue based on visual studio desktop app template. I put everything in InitInstance() (I know it's bad), appart from classical DX #includes and declarations. It corresponds to https://learn.microsoft.com/en-us/windows/win32/direct2d/devices-and-device-contexts except I create the swapchain with CreateSwapChainForHwnd() instead of CreateSwapChainForCoreWindow() :
The pb appears fror MDI childs, as well as for SDI windows with a menu. The way the buffer bitmap is drawn, CopyFromMemory, DrawBitmap or even D2D drawing doesn't matter, as shown in images with the two diagonals made with DrawLine().226707-stretchedout.png
Actually the white bands are flickering during resizing.
Example, starting from Visual Studios's destop app template, replace InitInstance() below and add D2D includes and declarations...
...
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
ATOM aMainClass;
ATOM aChildClass;
const TCHAR lpszMainClassName[] = TEXT("FCLAYERMAIN");
const TCHAR lpszChildClassName[] = TEXT("FCLAYERCHILD");
hInst = hInstance;
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
//prepare MDI windows (main + MDI client + one child)
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = 0;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = lpszMainClassName;
wcex.hIconSm = NULL;
aMainClass = RegisterClassEx(&wcex);
wcex.lpfnWndProc = ChildWndProc;
wcex.lpszClassName = lpszChildClassName;
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
aChildClass = RegisterClassEx(&wcex);
hWndMDI = CreateWindow((LPCTSTR)aMainClass,
szTitle,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
hInst,
NULL);
CLIENTCREATESTRUCT ccs;
ccs.idFirstChild = 5000;
hwndClient = CreateWindow(TEXT("mdiclient"),
NULL,
WS_CLIPCHILDREN | WS_CHILD | WS_HSCROLL | WS_VSCROLL | MDIS_ALLCHILDSTYLES,
0,
0,
0,
0,
hWndMDI,
0,
hInst,
(LPSTR)&ccs);
ShowWindow(hWndMDI, SW_SHOW);
ShowWindow(hwndClient, SW_SHOW);
//so as the initial child's client are fits the D2D swapchain (256*256px)
RECT Rect;
Rect.left = 0;
Rect.top = 0;
Rect.right = 256;
Rect.bottom = 256;
AdjustWindowRect(&Rect,
WS_OVERLAPPED | WS_VISIBLE | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU| WS_SIZEBOX, FALSE);
HWND hWnd = CreateMDIWindow(
(LPCTSTR)aChildClass,
szTitle,
WS_OVERLAPPED | WS_VISIBLE | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU| WS_SIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
hwndClient,
hInst,
NULL);
ShowWindow(hWnd, SW_SHOW);
//create D2D + D3D + DXGI machinery
D2D1_FACTORY_OPTIONS debugOptions;
debugOptions.debugLevel = D2D1_DEBUG_LEVEL_NONE;
HRESULT hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1),
&debugOptions,
(void*)&m_D2DFactory
);
if (SUCCEEDED(hr))
{
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
hr = D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
0,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&m_pD3D11device,
NULL,
NULL
);
}
if (SUCCEEDED(hr))
{
IDXGIDevice1 dxgiDevice;
hr = m_pD3D11device->QueryInterface(__uuidof(IDXGIDevice), (void*)&dxgiDevice);
if (SUCCEEDED(hr))
{
hr = m_D2DFactory->CreateDevice(
dxgiDevice,
&m_d2dDevice
);
if (SUCCEEDED(hr))
{
m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_d2dContext
);
}
}
IDXGIAdapter dxgiAdapter;
if (SUCCEEDED(hr))
{
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
if (SUCCEEDED(hr))
{
hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&m_dxgiFactory));
SafeRelease(&dxgiAdapter);
dxgiDevice->SetMaximumFrameLatency(1);
SafeRelease(&dxgiDevice);
}
}
}
if (SUCCEEDED(hr))
{
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
swapChainDesc.Width = 256;
swapChainDesc.Height = 256;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = FALSE;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 2;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH; //DXGI_SCALING_ASPECT_RATIO_STRETCH seems not supported
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc.Flags = 0;
hr = m_dxgiFactory->CreateSwapChainForHwnd(
m_pD3D11device,
hWnd,
&swapChainDesc,
nullptr,
nullptr,
&(m_swapChain)
);
}
if (SUCCEEDED(hr))
{
hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_dxgiBackBuffer));
if (SUCCEEDED(hr))
{
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
0,
0,
NULL
);
/
//just in case dpi=0 doesn't work:
bitmapProperties.dpiX = GetDpiForWindow(hWnd);
bitmapProperties.dpiY = GetDpiForWindow(hWnd);
/
hr = m_d2dContext->CreateBitmapFromDxgiSurface(
m_dxgiBackBuffer,
&bitmapProperties,
&(m_pBitmap)
);
}
}
if (SUCCEEDED(hr))
{
D2D1_SIZE_U bitmapSize = m_pBitmap->GetPixelSize();
m_d2dContext->BeginDraw();
m_d2dContext->SetTarget(m_pBitmap);
ID2D1SolidColorBrush* m_pBlackBrush;
hr = m_d2dContext->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red, 1.0f),
&m_pBlackBrush
);
m_d2dContext->DrawLine(
D2D1::Point2F(0.0f, 0.0f),
D2D1::Point2F(bitmapSize.height, bitmapSize.width),
m_pBlackBrush,
2.0f,
NULL);
m_d2dContext->DrawLine(
D2D1::Point2F(0.0f, bitmapSize.width),
D2D1::Point2F(bitmapSize.height, 0.0f),
m_pBlackBrush,
2.0f,
NULL);
}
hr = m_d2dContext->EndDraw();
hr = m_swapChain->Present(1, 0);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Analyse les sélections de menu :
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefFrameProc(hWnd, hwndClient, message, wParam, lParam);
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefFrameProc(hWnd, hwndClient, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
...
Replace your AdjustWindowRect with AdjustWindowRectEx and specify WS_EX_MDICHILD extended window style.
Another thing, you’re rendering and even presenting some graphics from within InitInstance method. That’s not the right time for that, too early. Instead, you should move rendering into WM_PAINT handler of the window for which you have created the swap chain.
P.S. This sample might help.
The streching error only occurs for windows with borders and/or menu bar. A possible workaround is thus to add a borderless child window (hWndPic) to the MDI child (hWnd) itself:
//initialization :
hWnd = CreateMDIWindow(
(LPCTSTR)aChildClass,
szTitle,
WS_SIZEBOX|WS_OVERLAPPED | WS_VISIBLE | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU ,
CW_USEDEFAULT,
CW_USEDEFAULT,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
hwndClient,
hInst,
NULL);
hWndPic = CreateWindow(
(LPCTSTR)aPicClass,
NULL,
WS_CHILD,
0,
0,
256,
256,
hWnd,
0,
hInst,
NULL);
Then resize this picture window in response to WM_SIZE sent to the MDI child hWnd; that's all! then there is no need to repaint the picture when the window is resized and the stretch process is correctly handled by D2D, benefitting from hardware acceleration.
// windows procedures :
LRESULT CALLBACK ChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SIZE:
{
RECT Rect;
GetClientRect(hWnd,&Rect);
SetWindowPos(
hWndPic,
HWND_TOP,
0,
0,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
0
);
}
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK PicWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
TreeView_EditLabel(tv, item) fails(returns zero).
item is valid, and is the only item in the treeview.
What's the problem? Is there some prerequisite? Or it just doesn't work?
I'm on Windows 10.
Here's a minimal reproducible example
#include <windowsx.h>
#include <CommCtrl.h>
#include <assert.h>
#pragma comment(lib, "Comctl32.lib")
HWND hTv;
HTREEITEM hItem;
auto className = L"someclass";
ATOM MyRegisterClass(HINSTANCE hInstance);
void InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
InitCommonControls();
MyRegisterClass(hInstance);
InitInstance(hInstance, nCmdShow);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex{};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = className;
return RegisterClassExW(&wcex);
}
void InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd = CreateWindowW(className, L"", WS_OVERLAPPEDWINDOW, 400, 400, 400, 400, nullptr, nullptr, hInstance, nullptr);
assert(hWnd);
hTv = CreateWindowW(WC_TREEVIEW, L"Tree View", WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES, 0, 0, 300, 300, hWnd, 0, 0, NULL);
assert(hTv);
{
TVITEM tvi{};
TVINSERTSTRUCT tvins{};
tvi.mask = TVIF_TEXT;
wchar_t name[] = L"item";
tvi.pszText = name;
tvins.item = tvi;
hItem = TreeView_InsertItem(hTv, &tvins);
}
ShowWindow(hWnd, nCmdShow);
SetFocus(hTv);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_NOTIFY:
{
switch (reinterpret_cast<LPNMHDR>(lParam)->code)
{
case NM_CLICK:
assert(TreeView_EditLabel(hTv, hItem));
break;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
A tree-view control needs the TVS_EDITLABELS control style set to support editing labels of tree-view items.
You need to replace the tree-view control creation code
hTv = CreateWindowW(
WC_TREEVIEW,
L"Tree View",
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
0, 0, 300, 300,
hWnd,
0,
0,
NULL);
with this:
hTv = CreateWindowW(
WC_TREEVIEW,
L"Tree View",
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES | TVS_EDITLABELS,
0, 0, 300, 300,
hWnd,
0,
0,
NULL);
The tree-view controls overview overview provides additional details under the section titled tree-view label edition.
The DATETIMEPICKERINFOstructure obtained by sending the DTM_GETDATETIMEPICKERINFOmessage has a field hwndEdit which might be what I'm looking for. However, I'm getting always NULL for it so I'm wondering what's its actual meaning. If not, is there a way to get the handle of the entry field?
hwndEdit only seems to be valid when the control has the DTS_APPCANPARSE style and you click the date text with the mouse (I tested this with OutputDebugString and a timer). The edit control is created and destroyed dynamically. The hwndUD handle is only valid if DTS_UPDOWN is set and the hwndDropDown is only valid while the dropdown is visible.
It is not called out in the documentation but DTM_GETDATETIMEPICKERINFO is marked Vista+ and this often means the feature is only implemented in ComCtl32 v6 so you also have to make sure you have a manifest that requests this version.
To change the color you can try DTM_SETMCCOLOR but only MCSC_BACKGROUND is documented to work when Visual Styles are active.
I'm afraid there is no way to get what you wanted. I just created a simple Win32 application just to test the possibility. If I use the DTM_GETDATETIMEPICKERINFO, hwndDropDown, hwndEdit and hwndUD give me NULL. If I try to enum child window, well before I do so I check it with Spy++, no luck, there is no child window associated with it.
Finally, I tried GetFocus() and WindowFromPoint(), both give me the HWND of the DateTimePicker itself only.
Here is my testing code:
#pragma comment(lib, "comctl32.lib")
#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
enum MYID {
MYID_FIRST = WM_APP,
MYID_DTP
};
LPCTSTR const g_MyWndClass = _T("DTPTest");
LPCTSTR const g_MyWndTitle = _T("DTPTest");
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void OnWindowCreate(HWND);
void OnTimer(HWND);
int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int nCmdShow)
{
INITCOMMONCONTROLSEX icex{};
icex.dwSize = sizeof(icex);
icex.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&icex);
WNDCLASSEX wcex{};
wcex.cbSize = sizeof(wcex);
wcex.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = g_MyWndClass;
wcex.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wcex);
HWND hwnd = CreateWindowEx(0,
g_MyWndClass, g_MyWndTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 600, 400,
nullptr, nullptr, nullptr, nullptr);
if (!hwnd) { return 99; }
SetTimer(hwnd, 0, 100, nullptr);
ShowWindow(hwnd, nCmdShow);
MSG msg{};
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l)
{
switch (msg) {
case WM_CREATE:
OnWindowCreate(hwnd);
break;
case WM_TIMER:
OnTimer(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, w, l);
}
return 0;
}
void OnWindowCreate(HWND hwnd)
{
HWND hwndDTP = CreateWindowEx(0, DATETIMEPICK_CLASS, nullptr,
WS_CHILD | WS_VISIBLE | DTS_SHOWNONE,
20, 50, 220, 20,
hwnd, reinterpret_cast<HMENU>(MYID_DTP), nullptr, nullptr);
DATETIMEPICKERINFO info{};
info.cbSize = sizeof(DATETIMEPICKERINFO);
SendMessage(hwndDTP, DTM_GETDATETIMEPICKERINFO, 0,
reinterpret_cast<LPARAM>(&info));
if (!info.hwndDropDown && !info.hwndEdit && !info.hwndUD)
{
MessageBox(hwnd, _T("No luck with DTM_GETDATETIMEPICKERINFO"),
nullptr, MB_ICONERROR);
}
}
void OnTimer(HWND hwnd)
{
POINT pt{};
GetCursorPos(&pt);
HWND hwndPoint = WindowFromPoint(pt);
HWND hwndFocus = GetFocus();
TCHAR buf[99]{};
wsprintf(buf, _T("Pointing at %p, focusing %p"),
hwndPoint, hwndFocus);
SetWindowText(hwnd, buf);
}
When I move the selection, character spacing and characters themselves change.
Test project code:
#include <windows.h>
#include <Richedit.h>
class RichEditLib
{
HMODULE lib;
public:
RichEditLib()
{
lib = ::LoadLibrary(L"riched20.dll");
}
~RichEditLib()
{
if (lib) ::FreeLibrary(lib);
}
} libraryLoader;
class RichEdit
{
public:
RichEdit(HWND parent)
{
hwnd = ::CreateWindowEx (
NULL, // extended window style
RICHEDIT_CLASSW, // name of a registered window class
L"", // window caption
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP |
WS_VSCROLL | ES_LEFT |ES_MULTILINE | ES_WANTRETURN | ES_AUTOVSCROLL, // window style
0, // x position
0, // y position
400, // width
400, // height
parent, // handle to owner window
NULL, // handle to menu
::GetModuleHandle(NULL), // application instance
NULL);
::ShowWindow(hwnd, SW_SHOW);
}
~RichEdit()
{
if (hwnd) ::DestroyWindow(hwnd);
}
private:
HWND hwnd;
};
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
default:
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
HWND CreateMainWindow(HINSTANCE hInst, int CmdShow,
LRESULT (WINAPI *pWndProc) (HWND,UINT,WPARAM,LPARAM))
{
WNDCLASSEX wc;
wc.cbSize = sizeof(wc);
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = pWndProc;
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 = L"WndClass";
wc.hIconSm = ::LoadIcon(NULL, IDI_APPLICATION);
::RegisterClassEx(&wc);
HWND hWnd = ::CreateWindow(L"WndClass", L"",
WS_OVERLAPPEDWINDOW,
100, 100,
500, 500,
NULL, (HMENU) NULL, hInst, NULL);
::ShowWindow(hWnd, CmdShow);
return hWnd;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmLine, int nCmdShow)
{
HWND parent = CreateMainWindow(hInstance, nCmdShow, WndProc);
RichEdit re(parent);
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return msg.wParam;
}
Text:
യൗവനം നശിക്കാത്തവനു മാത്രമേ സുന്ദരികളുടേയും സുന്ദരന്മാരുടേയും കഥ പറയാനാകൂ. പി.സി കുട്ടികൃഷ്ണന് ആ ഗണത്തില്പ്പെടും. അതുകൊണ്ടാവും അദ്ദേഹം യൗവനം നശിക്കാത്തവന് എന്നര്ത്ഥം വരുന്ന ഉറൂബ് എന്ന പേര് തൂലികാനാമമായി സ്വീകരിച്ചത്.
'സുന്ദരികളും സുന്ദരന്മാരും'-ഇതിഹാസസമൃദ്ധിയുള്ള ആ ഒറ്റ നോവല് മതിയല്ലോ ഉറൂബിനെ മലയാളി നിത്യവും ഓര്മ്മിക്കാന്. 1920-കളിലെ ഖിലാഫത്ത് പ്രസ്ഥാനം, ദേശീയ സ്വാതന്ത്ര്യ സമരം, മലബാര് കലാപം, കമ്മ്യൂണിസ്റ്റ് മുന്നേറ്റം, രണ്ടാം ലോകമഹായുദ്ധം തുടങ്ങിയവയുടെ പശ്ചാത്തലത്തില് മലബാര് കേന്ദ്രമാക്കി നിരവധി വ്യക്തികളുടെ ജീവിതങ്ങളിലൂടെ രാഷ്ട്രീയ-സാമൂഹിക-കുടുംബ ബന്ധങ്ങളില്വന്ന വമ്പിച്ച മാറ്റങ്ങള് അവതരിപ്പിക്കുന്ന നോവലാണ് 'സുന്ദരികളും സുന്ദരന്മാരും'. ഉമ്മാച്ചു, അണിയറ, മിണ്ടാപ്പെണ്ണ്, അമ്മിണി, ആമിന, തേന്മുള്ളുകള് എന്നീ നോവലുകളും 'രാച്ചിയമ്മ'യും 'ഗോപാലന്നായരുടെ താടി'യും പോലുള്ള സുന്ദരങ്ങളായ നിരവധി ചെറുകഥകളും ഉറൂബ് മലയാളത്തിനു നല്കി. നാടകം, കവിത, ഉപന്യാസം എന്നീ മേഖലകളിലും ഉറൂബിന്റെ സംഭാവനകളുണ്ട്.
Any ideas what it can be?