Making some parts of the window transparent in WinAPI - c

I want to make only certain(rectangular) parts of the window transparent.
I have set the window as WS_EX_LAYERED and the WM_PAINT function is as follows:
case WM_PAINT:;
RECT rect;
GetWindowRect(hwnd, &rect);
HDC hdc = GetDC(hwnd);
HDC hdc1 = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
SelectObject(hdc, hBitmap);
SIZE size = {rect.right - rect.left, rect.bottom - rect.top};
BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 0, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd, hdc1, NULL, &size, hdc, NULL, RGB(0, 0, 0), &blendFunc, ULW_ALPHA);
DeleteObject(hBitmap);
DeleteDC(hdc);
ReleaseDC(hwnd, hdc1);
break;
I tried creating a child window, but that doesn't seem to work if I change it's opacity through SetLayeredWindowAttributes, possibly because it mimics the parent windows opacity. I am currently trying to use UpdateLayeredWindow to make certain parts transparent, but I can't even make the entire part transparent using UpdateLayeredWindow.
What is the general way to make certain parts of the window transparent?

I suggest you could refer to the Doc:Using Layered Windows
To have a dialog box come up as a translucent window, first create the
dialog as usual. Then, on WM_INITDIALOG, set the layered bit of the
window's extended style and call SetLayeredWindowAttributes with the
desired alpha value.
The third parameter of SetLayeredWindowAttributes is a value that ranges from 0 to 255, with 0 making the window completely transparent and 255 making it completely opaque.
In order to use layered child windows, the application has to declare itself Windows 8-aware in the manifest. Refer to the thread: How to use WS_EX_LAYERED on child controls

Related

Screenshot Windows.UI.Core.CoreWindow Immersive UWP

I am trying to capture a specific Window in Windows 10.1. The problem is that this window is a UWP application. I found the class and caption of the window using Spy++. However, when I capture the UWP window with my Screenshot function, the output is a black bitmap. My function works for any other windows except this specific one.
The class of the UWP application is Windows.UI.Core.CoreWindow
Here is my code:
HDC hScreenDC = GetWindowDC(ProgramData->TargetWnd);
RECT Rect = {0};
GetWindowRect(ProgramData->TargetWnd, &Rect);
INT Width = Rect.right - Rect.left;
INT Height = Rect.bottom - Rect.top;
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, Width, Height);
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hMemoryDC, hBitmap);
BitBlt(hMemoryDC, 0, 0, Width, Height, hScreenDC, 0, 0, SRCCOPY | CAPTUREBLT);
hBitmap = (HBITMAP) SelectObject(hMemoryDC, hOldBitmap);
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap);
CloseClipboard();
DeleteDC(hMemoryDC);
DeleteDC(hScreenDC);
Why is the window not being captured properly and how can I capture it?

Draw a line next to word in WinAPI

How do I draw a line like this that is right next to a word like "Counts", in WinAPI with C?
Using Dialog Resources
Create a static text control with no text that is 1 or 2 pixels in height, turn on the border (WS_BORDER), and set its style to Static Edge (WS_EX_STATICEDGE). Then create a static text control with the word "Counts" in it on top of that. Then use CreateDialog() or DialogBox() to show the dialog box.
IDD_DIALOG1 DIALOGEX 0, 0, 172, 63
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_STATIC,6,12,156,1,WS_BORDER,WS_EX_STATICEDGE
LTEXT "Counts ",IDC_STATIC,6,8,26,8
END
Note: This is verbatim what Visual Studio generated using the dialog designer.
Creating Static Controls Using CreateWindow() (as suggested by Jonathan Potter)
LRESULT OnCreate( HWND hWnd, LPCREATESTRUCT lpCreateStruct )
{
// Get default gui font
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, NULL);
HFONT hFont = CreateFontIndirect(&metrics.lfMessageFont);
// Create the line
CreateWindowEx(WS_EX_STATICEDGE, _T("STATIC"), NULL, WS_CHILD|WS_VISIBLE|WS_BORDER,
10, 17, 280, 1, hWnd, NULL, lpCreateStruct->hInstance, NULL);
// Create the Counts label
HWND hwndCounts = CreateWindow(_T("STATIC"), _T("Counts "), WS_CHILD|WS_VISIBLE,
10, 10, 50, 26, hWnd, NULL, lpCreateStruct->hInstance, NULL);
// Apply the default gui font
SendMessage(hwndCounts, WM_SETFONT, (WPARAM)hFont, TRUE);
// Cleanup the font object
DeleteObject(hFont);
}
Drawing manually on the WM_PAINT event
void OnPaint( HWND hWnd )
{
// Get the default font
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, NULL);
HFONT hFont = CreateFontIndirect(&metrics.lfMessageFont);
// Setup HDC
RECT rect;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Select the default font
SelectObject(hdc, hFont);
// Draw the line using the button shadow
SelectObject(hdc, GetStockObject(DC_PEN));
SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
MoveToEx(hdc, 10, 17, NULL);
LineTo(hdc, 280, 17);
// Draw the word Counts overtop of the line
SetRect(&rect, 10, 10, 280, 22);
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
DrawText(hdc, TEXT("Counts "), -1, &rect, DT_NOCLIP);
// Cleanup the font object
DeleteObject(hFont);
// Quit painting
EndPaint(hWnd, &ps);
}
Note: Something I did not account for in this example is the height of the default font. You will want to adjust the code for that.
Here is a screenshot of the output of this method.
In your example, it looked like a single one pixel line, so that's what I drew, but if you'd like to make the line look more like a 'Fixed 3D' or 'lowered bevel line' (which is what the group box tends to draw for it's border line), then you can draw another line below it with the button highlight color.
SetDCPenColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
MoveToEx(hdc, 10, 18, NULL);
LineTo(hdc, 280, 18);
As pointed out by Ben Voigt, it might be better to do this with DrawEdge though.
RECT line;
SetRect(&line, 10, 17, 280,17);
DrawEdge(hdc, &line, EDGE_ETCHED, BF_TOP );
Creating a Group Box Control (suggested by Hans Passant)
Hans Passant's suggestion of doing this with a Group Box did work when I tested it. It still drew a rectangle, and when you enabled visual styles it was very difficult to see. Nevertheless, this should get you started if you want to give it a go.
HWND hwndGroup = CreateWindow(_T("Button"), _T("Counts "),
WS_CHILD|WS_VISIBLE|BS_GROUPBOX, 10, 10, 280, 2, hWnd, NULL,
lpCreateStruct->hInstance, NULL);
SendMessage(hwndGroup, WM_SETFONT, (WPARAM)hFont, TRUE);
Additional Note
Something else I would like to suggest is that you use can use Spy++ which comes with Visual Studio to analyze the window you are looking at. This will tell you at the very least if it's a child control, or whether they are painting it manually. If it's a child control you will also be able to see the rectangle and styles that are applied to it, as well lots of additional information.

plain winapi c GUI changing static text background

I am using plain winapi c to create a GUI, I am new to this language and am struggling with something many might think is basic. Could someone please explain to me how I change the background colour for static text because currently is transparent. The code I am using for the text is:
hwndStatic = CreateWindow(TEXT("static"), TEXT(""),
WS_CHILD | WS_VISIBLE,
10, 70, 90, 25, hwnd, NULL, g_hinst, NULL);
In general, you change the drawing of static text controls by handling WM_GETCTLCOLORSTATIC.
In that handler, you can change things about the DC, like the text color, background mode, background color, even the font that's selected.
You can also return a handle to a GDI brush (using a cast to get it by the type system). The control will erase itself first with the brush and then draw the text.
The callback will happen for all static controls that are children of the current window, so you first test to see if it's the child you care about.
For example:
case WM_CTLCOLORSTATIC:
HWND hwnd = (HWND) lParam;
if (hwnd == hwndStatic) {
HDC hdc = (HDC) wParam;
::SetTextColor(hdc, RGB(0xFF, 0, 0)); // set the text to red
::SetBkMode(hdc, OPAQUE);
::SetBkColor(hdc, RGB(0x00, 0xFF, 0x00)); // set background to green
HBRUSH hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
return (INT_PTR) hbrBackground;
}
return 0;
This shows several things you can do. You probably don't want to do all of them, but it can be educational to see them all in action.
Note that if you create a brush to return, you have to keep track of it and delete it later. I've avoided this issue by relying on GetSysColorBrush. The system owns those, so you shouldn't delete them. You can also use GetStockObject for system GDI objects that you don't have to manage. But if you need a custom color, you'll have to use CreateSolidBrush and then clean it up.
Respond to the WM_CTLCOLORSTATIC message in your program and have it return a brush object of the proper color.
I've slightly modified the example from the link:
case WM_CTLCOLORSTATIC:
{
HWND hWnd = (HWND) lParam;
if (hWnd == hMyStatic)
{
HBRUSH hbrBkgnd = CreateSolidBrush(RGB(0,0,0));
return (INT_PTR)hbrBkgnd;
}
return 0;
}

Transparent Tooltip Background [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have 2 regions in a window, each with their own tooltip.
these tooltips are custom drawn by handling the WM_PAINT message (to prevent flicker).
This is the creation of the tooltips:
tooltips[MAIN_GRAPH_TT].tthWnd = CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,0,WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_NOFADE,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,g_hInst,0);
tooltips[SECONDARY_GRAPH_TT].tthWnd = CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,0,WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_NOFADE,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,g_hInst,0);
This is initialisation of the tooltips:
if (tooltips[MAIN_GRAPH_TT].tthWnd)
{
lpfnOldTTProc = (WNDPROC)SetWindowLong(tooltips[MAIN_GRAPH_TT].tthWnd,
GWL_WNDPROC, (DWORD) TooltipProc);
SetWindowLong(tooltips[MAIN_GRAPH_TT].tthWnd, GWL_EXSTYLE, WS_EX_LAYERED|WS_EX_TOOLWINDOW);
SetLayeredWindowAttributes(tooltips[MAIN_GRAPH_TT].tthWnd,RGB(255,0,0),0,ULW_COLORKEY);
SendMessage(tooltips[MAIN_GRAPH_TT].tthWnd,CWM_SETWNDPROC,0,(LPARAM)new WNDPROC(lpfnOldTTProc));
}
if (tooltips[SECONDARY_GRAPH_TT].tthWnd)
{
lpfnOldTTProc = (WNDPROC)SetWindowLong(tooltips[SECONDARY_GRAPH_TT].tthWnd, GWL_WNDPROC, (DWORD) TooltipProc);
SetWindowLong(tooltips[SECONDARY_GRAPH_TT].tthWnd, GWL_EXSTYLE, WS_EX_LAYERED|WS_EX_TOOLWINDOW);
SetLayeredWindowAttributes(tooltips[SECONDARY_GRAPH_TT].tthWnd,RGB(255,0,0),0,ULW_COLORKEY);
SendMessage(tooltips[SECONDARY_GRAPH_TT].tthWnd,CWM_SETWNDPROC,0,(LPARAM)new WNDPROC(lpfnOldTTProc));
}
And this is the WM_PAINT of the custom tooltip WNDPROC:
case WM_PAINT:
{
const int FRAME_WIDTH = 1;
const int CORNER_DIAMETER = 10;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
HDC hMemDC;
RECT cr;
GetClientRect(hWnd,&cr);
hMemDC = CreateCompatibleDC(hdc);
HBITMAP memBM = CreateCompatibleBitmap(hdc, cr.right-cr.left, cr.bottom-cr.top);
HBITMAP hOldBM = (HBITMAP) SelectObject(hMemDC,memBM);
//drawing start [draw to hMemDC]
{
FillSolidRect(hMemDC,0,0,cr.right-cr.left,cr.bottom-cr.top,RGB(255,0,0));
HPEN hFramePen = CreatePen(PS_SOLID,FRAME_WIDTH,BLACK);
HBRUSH hBGBrush = GetSysColorBrush(COLOR_INFOBK);
SetTextColor(hMemDC,GetSysColor(COLOR_INFOTEXT));
SetBkColor(hMemDC,WHITENESS);
SetBkMode(hMemDC,TRANSPARENT);
HBRUSH hOldBrush = (HBRUSH) SelectObject(hMemDC,hBGBrush);
HPEN hOldPen = (HPEN) SelectObject(hMemDC,hFramePen);
HFONT hOldFont = SelectFont(hMemDC,g_hFonts[FONT_TOOLTIP]);
RoundRect(hMemDC,cr.left,cr.top,cr.right,cr.bottom,CORNER_DIAMETER,CORNER_DIAMETER);
RECT textRec = cr;
textRec.left += FRAME_WIDTH*2;
textRec.right -= FRAME_WIDTH*2;
textRec.top += FRAME_WIDTH*2;
textRec.bottom -= FRAME_WIDTH*2;
if(hWnd == tooltips[MAIN_GRAPH_TT].tthWnd)
DrawText(hMemDC,tttBuffer[MAIN_GRAPH_TT],sizeof(tttBuffer),&textRec,DT_LEFT|DT_TOP);
else if(hWnd == tooltips[SECONDARY_GRAPH_TT].tthWnd)
DrawText(hMemDC,tttBuffer[SECONDARY_GRAPH_TT],sizeof(tttBuffer),&textRec,DT_LEFT|DT_TOP);
SelectObject(hMemDC,hOldBrush);
SelectObject(hMemDC,hOldPen);
SelectObject(hMemDC,hOldFont);
DeleteObject(hFramePen);
DeleteObject(hBGBrush);
}
//drawing end
BitBlt(hdc,
cr.left,
cr.top,
cr.right-cr.left, cr.bottom-cr.top,
hMemDC,
0,
0,
SRCCOPY);
SelectObject(hdc,hOldBM);
DeleteObject(memBM);
DeleteDC(hMemDC);
EndPaint(hWnd,&ps);
}
break;
The problem with these tooltips is, the corners (outside of the round rect) are supposed to be transparent, but i cant seem to get them to dissapear.
I have tried (naĆ­vely) to use HOLLOW_BRUSH to paint the background rect, but didnt work, and as you can see from the example i've tried using the layered window approach, again to no avail.
Can anyone help me get transparency for the background of my tooltips?
Here is a picture of the tooltip without transparency
[the corners have been recoloured white for visibility -- these are the parts that need to be transparent]
(Text blanked out)
When dealing with controls and transparency, I found that WS_EX_TRANSPARENT exStyle can save you some time. Also, you may want to check out if the tooltip sends a WM_CTLCOLORSTATIC message to the main window, if it does you may want to send back a hollow (null) brush handle in response. You may also need to set the background mode to transparent at that point in time, by calling SetBkMode on the hDC the WM_CTLCOLORSTATIC message provides.
Sorry for not testing any of this, but it works well with static and group controls. The only control up to now I evidenced is unresponsive to this method is the checkbox button, which I was unable to set background transparency for.
Regards.
You can use SetWindowRgn to make parts of a window transparent (create a region using CreateRoundRectRgn).
Alternatively, you can use SetLayeredWindowAttributes to use true alpha blending to make parts of the window transparent.

SetBkMode(hdc, TRANSPARENT) doesn't work

When I use SetBkMode(hdc, TRANSPARENT); in the code below, I got the following effect when I resize the main window (and hence when the child receives the WM_PAINT message):
The problem is : When I resize the main window, The old area of "Find:" shoule be erased, I guess. But it just remains there.
If I don't use SetBkMode(hdc, TRANSPARENT);, I don't have this problem. It looks like:
, i.e it has white background. Furthermore, if I use SetBkMode(hdc, TRANSPARENT);, it looks like the same as above, before I resize the main window. So I don't think SetBkMode(hdc, TRANSPARENT); works here.
the hwnd is a static child with style SS_BITMAP.
Do you know why this issue occurs?
switch (message) {
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, gDefaultGuiFont);
SetBkMode(hdc, TRANSPARENT);
RECT rc;
GetClientRect(hwnd, &rc);
DrawText(hdc, _TR("Find:"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
.............
}
Try to use "fixed" rectangles. For example
RECT rc;
GetClientRect(hwnd, &rc);
rc.left += ...; rc.top += ...; // shift up-left point
DrawText(hdc, _TR("Find:"), -1, &rc, DT_SINGLELINE | DT_LEFT | DT_TOP);
The idea is you draw text in wrong position (once) and in right position (twice) while backgound updated only once. Can't say more on part of code.
The problem is that windows is not updating the control (in time) that's behind your static control, you are now responsible for it's contents. So you want to use the background provided by the parent. Well just ask the parent to draw it for you in the child window:
RECT rc;
GetClientRectRelative(m_hWnd, GetParent(m_hWnd), &rc);
SetWindowOrgEx(m_mdc, rc.left, rc.top, NULL);
SendMessage(GetParent(m_hWnd), WM_PAINT, (WPARAM)(HDC)m_mdc);
SetWindowOrgEx(m_mdc, 0, 0, NULL);
In which
bool GetClientRectRelative(HWND hWnd, HWND hWndRelativeTo, RECT *pRect)
{
RECT rcWnd, rcRelativeTo;
if (!GetClientRect(hWnd, &rcWnd) ||
!ClientToScreen(hWnd, (POINT*)&rcWnd) ||
!ClientToScreen(hWnd, (POINT*)&rcWnd + 1) ||
!GetClientRect(hWndRelativeTo, &rcRelativeTo) ||
!ClientToScreen(hWndRelativeTo, (POINT*)&rcRelativeTo) ||
!ClientToScreen(hWndRelativeTo, (POINT*)&rcRelativeTo + 1))
return false;
pRect->top = rcWnd.top - rcRelativeTo.top;
pRect->left = rcWnd.left - rcRelativeTo.left;
pRect->right = rcWnd.right - rcRelativeTo.left;
pRect->bottom = rcWnd.bottom - rcRelativeTo.top;
return true;
}
Now draw anything you like, I suggest you'd use the TRANSPARENT background mode.
Please create all your child windows with the styles WS_CLIPCHILDREN and WS_CLIPSIBLINGS, then these problems will become apparent immediately and you avoid flicker.

Resources