Applying Windows theme to custom control with WS_BORDER style - c++

I have a custom control created using CreateWindowEx with the WS_BORDER style. Everything works fine apart from the border appearing in a different colour to other controls in the dialog box. The border in my control is black, the other controls have a blue border. I've tried calling EnableThemeDialogTexture(_dialogHandle, ETDT_ENABLE) after creating the control, as well as the logic from http://www.patchou.com/projects/richedit/ but to no avail. I'm using C++ and the Winapi. ie. no MFC, no .Net. Any guidance very much appreciated.
EDIT: Here's the logic that worked for me:
HDC hdc = GetWindowDC(hwnd);
HTHEME themeHandle = OpenThemeData(hwnd, L"Edit");
if(themeHandle)
{
int cxBorder = GetSystemMetrics(SM_CXBORDER);
int cyBorder = GetSystemMetrics(SM_CYBORDER);
RECT rc;
GetClientRect(hwnd, &rc);
OffsetRect(&rc, cxBorder, cyBorder);
ExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
InflateRect(&rc, cxBorder, cyBorder);
DrawThemeBackground(themeHandle, hdc, 0, 0, &rc, NULL);
CloseThemeData(themeHandle);
}
ReleaseDC(hwnd, hdc);

You have to draw the border yourself, using the theme from another control (for example, the listview or treeview control). For a custom child control, drawing the border is quite easy - simply handle the WM_NCPAINT message. The part ID and state ID when you draw the border should both be 0.

Related

Is focus rect drawn automatically for listbox (WC_LISTVIEW)?

I have created a listbox similar to the code provided here. In my UI, will the tab focus rect be automatically drawn by DefWindowProc() or do I need to take care of that ? I don't see the focus rect being drawn on tab focus.
Thanks.
HWND CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect (hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW,
L"",
WS_CHILD | WS_VISIBLE | LVS_LIST,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
(HMENU)IDM_CODE_SAMPLES,
g_hInst,
NULL);
return (hWndListView);
}
Normally,the default window procedure draws a focus rectangle for the list box item drawn by the owner in response to the WM_DRAWITEM message.
In MSDN
For an empty list box or combo box, itemID can be -1. This allows
the application to draw only the focus rectangle at the coordinates
specified by the rcItem member even though there are no items in the
control. This indicates to the user whether the list box or combo box
has the focus. How the bits are set in the itemAction member
determines whether the rectangle is to be drawn as though the list box
or combo box has the focus.
If you are not using owner/custom draw then all Windows common controls will draw the focus rectangle for you automatically.
Windows 2000 (and later) hide keyboard accelerators and focus rectangles by default unless you are interacting with the window by using your keyboard.
Windows enables applications to hide or show various features in its UI. These settings are known as the UI state. The UI state includes the following settings:
focus indicators (such as focus rectangles on buttons)
keyboard accelerators (indicated by underlines in control labels)

PrintWindow causes flicker, strange artifacts in titlebar

I'm trying to take a screenshot of a Chrome window. It looks like this:
When I use PrintWindow to get the screenshot, I can see a flicker on the window titlebar/Chrome tab area. The captured screenshot contains a strange rendering of a titlebar in Windows Basic style (even though my machine runs the Aero theme):
I've noticed that some other apps also exhibit a similar behavior where they flicker on-screen but the titlebar artifact is not visible in the captured screenshot. Apps that do this include Office 2010, IE 10, and the Trillian tabbed chat window — in other words, windows that extend the non-client area seem to have this issue.
The code that reproduces this is simple:
void Screenshot(HWND hWnd) {
RECT rc;
GetClientRect(hWnd, &rc);
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen,
rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);
//Print to memory hdc
PrintWindow(hWnd, hdc, PW_CLIENTONLY);
}
Why am I seeing flickering and strange visual artifacts? What can I do to stop it?
For those, who have the same problem, do this:
const uint PW_RENDERFULLCONTENT = 0x00000002;
PrintWindow(hWnd, hDC, PW_RENDERFULLCONTENT);
If Aero is enabled, use BitBlt instead.
This comment in the chromium desktop capture source code was especially helpful:
// When desktop composition (Aero) is enabled each window is rendered to a
// private buffer allowing BitBlt() to get the window content even if the
// window is occluded. PrintWindow() is slower but lets rendering the window
// contents to an off-screen device context when Aero is not available.

Changing taskbar icon programmatically (Win32,C++) [duplicate]

This question already has an answer here:
Is there a Windows API for adding badges to taskbar icons?
(1 answer)
Closed 9 years ago.
I have a C++ win32 program, and I'd like to edit the taskbar icon at runtime to display alerts, etc about the program, however I'm not too experienced with the win32 api, and I haven't been able to find anything online. The closest I've found is http://www.windows-tech.info/17/52a5bfc45dac0ade.php which tells how to load the icon off the disc at runtime and change it.
I would like to do what they do in this question: Create an icon in memory with win32 in python but in C++ and without an external library.
I would like to do what they do in this question: Create an icon in memory with win32 in python but in C++ and without an external library
Since the accepted answer uses the wxWidgets library, which is just a wrapper of the Win32 API, the solution translates pretty nicely.
All you need to do is create a bitmap in memory using the CreateCompatibleBitmap function. Then you can draw into that bitmap using the standard GDI drawing functions. Finally, you create the icon using the CreateIconIndirect function.
The hardest part is keeping track of your resources and making sure that you free them all when you're finished to prevent memory leaks. It's way better if it's all wrapped up in a library that makes use of RAII to ensure the objects are properly freed, but if you're writing C code in C++, it would look like this:
HICON CreateSolidColorIcon(COLORREF iconColor, int width, int height)
{
// Obtain a handle to the screen device context.
HDC hdcScreen = GetDC(NULL);
// Create a memory device context, which we will draw into.
HDC hdcMem = CreateCompatibleDC(hdcScreen);
// Create the bitmap, and select it into the device context for drawing.
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height);
HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
// Draw your icon.
//
// For this simple example, we're just drawing a solid color rectangle
// in the specified color with the specified dimensions.
HPEN hpen = CreatePen(PS_SOLID, 1, iconColor);
HPEN hpenOld = (HPEN)SelectObject(hdcMem, hpen);
HBRUSH hbrush = CreateSolidBrush(iconColor);
HBRUSH hbrushOld = (HBRUSH)SelectObject(hdcMem, hbrush);
Rectangle(hdcMem, 0, 0, width, height);
SelectObject(hdcMem, hbrushOld);
SelectObject(hdcMem, hpenOld);
DeleteObject(hbrush);
DeleteObject(hpen);
// Create an icon from the bitmap.
//
// Icons require masks to indicate transparent and opaque areas. Since this
// simple example has no transparent areas, we use a fully opaque mask.
HBITMAP hbmpMask = CreateCompatibleBitmap(hdcScreen, width, height);
ICONINFO ii;
ii.fIcon = TRUE;
ii.hbmMask = hbmpMask;
ii.hbmColor = hbmp;
HICON hIcon = CreateIconIndirect(&ii);
DeleteObject(hbmpMask);
// Clean-up.
SelectObject(hdcMem, hbmpOld);
DeleteObject(hbmp);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
// Return the icon.
return hIcon;
}
Adding the error checking and the code to draw something interesting onto the bitmap is left as an exercise for the reader.
As I said in a comment above, once you have created the icon, you can set the icon for a window by sending it a WM_SETICON message and passing the HICON as the LPARAM:
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
You can also specify ICON_SMALL in order to set the window's small icon. If you set only a big icon, it will be scaled down to create the small icon automatically. However, if you set only the small icon, the window will continue to use the default icon as its big icon. Big icons typically have a dimension of 32x32, while small icons typically have a dimension of 16x16. This is not, however, guaranteed, so do not hardcode these values. If you need to determine them, call the GetSystemMetrics function with SM_CXICON and SM_CYICON to retrieve the width and height of big icons, or SM_CXSMICON and SM_CYSMICON to retrieve the width and height of small icons.
A fairly good tutorial on drawing in Windows using GDI is available here. I recommend reading it thoroughly if this is your first time doing this and have no prior experience with GDI.

Is it possible to make a Static control transparent?

I am trying to implement a static control which refreshes(change text) in response to some event, which occurs once every second. Since I didn't want to paint the entire client area every second and so I decided to use a static control, now the problem is the parent window is skinned, meaning it has custom bitmap as its background, and the static control doesn't fit in, so am looking for ways to make the static control's background transparent.
This is what I have now:
hHandle = CreateWindowEx( WS_EX_TRANSPARENT, "STATIC", "", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 60, 212, 477, 20, hwnd, 0, hInstance, 0) ;
case WM_CTLCOLORSTATIC:
{
HDC hdC = (HDC)wParam;
SetTextColor( hdC, RGB(31,122,179) );
SetBkMode( hdC, TRANSPARENT );
return 0;//(HRESULT)GetStockObject(NULL_BRUSH);
}
break;
I tried returning NULL brush to paint the background, hoping it would make its background transparent but it didn't what more it forced the static control to not repaint properly, what I mean is that the text gets painted on top of the old text so its all messy.
Is subclassing is the only option ?
The only way I've found to do this reliably is to sub-class the static control and paint the background manually.
WS_EX_TRANSPARENT does not make a control truly transparent to underlying pixels (although it may appear like that) and WS_EX_COMPOSITED can not be used for child windows.
Instead, sub-class the static, and catch the WM_ERASEBKGND message. You can then paint the appropriate portion of the underlying bitmap.
The way to get a WC_STATIC control to show only text in the color you choose (over an image or other surface) is the return, as I understand this. This is what worked for me from this link.
case WM_CTLCOLORSTATIC:
SetTextColor((HDC)wParam, RGB(255, 0, 0));
SetBkMode((HDC)wParam, TRANSPARENT);
// the correct return needs HOLLOW_BRUSH
return (LRESULT)GetStockObject(HOLLOW_BRUSH);
break;
You don't mention the window styles on the static control, specifically the extended styles WS_EX_TRANSPARENT seems intended to solve the problem you describe with the repaint. Also as I understand it WS_EX_COMPOSITED might be useful in your context.
You also might consider whether the background window should have WS_CLIPCHILDREN set as that might affect the repaint.

screenshots of covered/minimized windows

I have the following code to take screenshots of a window:
HDC WinDC;
HDC CopyDC;
HBITMAP hBitmap;
RECT rt;
GetClientRect (hwnd, &rt);
WinDC = GetDC (hwnd);
CopyDC = CreateCompatibleDC (WinDC);
hBitmap = CreateCompatibleBitmap (WinDC,
rt.right - rt.left, //width
rt.bottom - rt.top);//height
SelectObject (CopyDC, hBitmap);
//Copy the window DC to the compatible DC
BitBlt (CopyDC, //destination
0,0,
rt.right - rt.left, //width
rt.bottom - rt.top, //height
WinDC, //source
0, 0,
SRCCOPY);
ReleaseDC(hwnd, WinDC);
ReleaseDC(hwnd, CopyDC);
It is someone elses code, slightly modified, as I am not really familiar with DC and how windows draws stuff to screen.
When I have one window slightly covering another, the covering window appears on screenshots of the covered one, which is kind of inconvenient. Also, when the window is minimized, this code produces nothing much interesting.
Is there any way around this? I would imagine that taking screenshots of a minimized application would be quite difficult, but I hope that getting screenshots of covered windows is possible. Perhaps there is a different method of implementing this to get around these problems?
No, a screenshot is exactly what it sounds like. You'll read the pixels out of the video adapter, what you get is what you see. You'll have to restore the window and bring it to the foreground to get the full view. WM_SYSCOMMAND+SC_RESTORE and SetForegroundWindow() respectively. Plus some time to allow the app to repaint its window if necessary.
The WM_PRINT message is available to ask a window to draw itself into a memory context. That could handle the overlapped window problem. But that can only work if is your window. And rarely has the expected result, programmers don't often implement WM_PRINT correctly.