Control on non-client area incorrectly painted as transparent - winapi

I customised the non-client area of window frame following the example in https://learn.microsoft.com/en-gb/windows/win32/dwm/customframe?redirectedfrom=MSDN. On this non-client area, I want to add a container dialog and a few custom buttons. I cannot get the color I want to be painted on my container dialog. Instead, it is always painted transparent in that area. The issue is demonstrated in the 2 figures below (the background there is for demonstrating the transparency).
The effect I want is:
But what has been painted is:
As you can see, the container dialog is wanted to be painted as purple but is painted as transparent and so is the customer picture button (gray cross inside circle).
The code I used to handle the WM_PAINT for the container dialog is:
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hwnd, &ps);
RECT rc;
GetClientRect(hwnd, &rc);
Gdiplus::Graphics g(hDC);
Gdiplus::Color clr(255, 0, 0, 0);
clr.SetFromCOLORREF(RGB( 85, 107, 47));
Gdiplus::SolidBrush b(clr);
g.FillRectangle(&b, rc.left, rc.top, RECT_WIDTH(rc), RECT_HEIGHT(rc));
EndPaint(hwnd, &ps);
I googled but could not find topic of similar issue (may be I didn't use the right keywords). I am not familiar in using winapi to draw non-client area. Any help pointing out what I have missed or direction to solution is much appreciated.
A VS project that demonstrate the problem is linked below:
CustomCaption.zip

Related

Prevent video from overdrawing window background

I have a 640x480 sized window. I want to put a 100x100 sized video in the top-left corner of that window. So I do:
RECT r;
r.left = 0;
r.top = 0;
r.right = 100;
r.bottom = 100;
m_pVideoDisplay->SetVideoPosition(NULL, &r);
This correctly puts the video in the top-left corner and scales it to 100x100 pixels but for some reason the Media Foundation video renderer will also fill all space in my window that is not occupied by the video with black now. How can I stop it from doing so? I've explicitly told the IMFVideoDisplayControl to only draw to the top-left 100x100 pixels of my window. But still it fills the remaining space of my window with black! What can I do to make Media Foundation not touch the rest of my window?
My WM_PAINT looks like this:
GetClientRect(hwnd, &rc);
BeginPaint(hwnd, &ps);
FillRect(ps.hdc, &rc, GetStockObject(WHITE_BRUSH));
m_pVideoDisplay->RepaintVideo();
EndPaint(hwnd, &ps);
I'd expect all window space that is not occupied by the video to be white but it is black instead.
I've also tried to do this but it didn't help either:
m_pVideoDisplay->SetRenderingPrefs(MFVideoRenderPrefs_DoNotRenderBorder);
Any ideas? Thanks!
To answer my own question, the trick here is to simply add a child window to my parent window using CreateWindowEx() and have Media Foundation render to the child window instead of the parent by calling SetVideoWindow() of IMFVideoDisplayControl. Then there will be no more overdrawing and everything is fine. I don't even have to use SetVideoPosition() any longer because I can simply move the video around (or apply scaling) by calling the normal MoveWindow() Win32 API on the child window. This really works very smoothly.

Win32 dialog based borderless window with bitmap background and visual styles

i'm new to StackOverflow so forgive me for any stupid mistakes I make on the post.
I'm having an issue to create a borderless window with a bitmap background using the Win32 API (no MFC) and a dialog based application. I'm using visual studio 2010.
The issue only happens if I use the windows XP Visual Styles, by linking the common controls lib with the following snippet:
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' "\
"language='*'\"")
I have a simple dialog and inside it a PictureControl with a bitmap image that will be the background of the window. I want this image to fill the entire Window, no resize or drag and drop will be needed, so i just put it centered on screen and defined both the dialog and the Picture Control dimensions to be the same in my RC file as shown below (both with dimensions 356, 210):
//Main Dialog
IDD_DIALOG_MAIN DIALOGEX 0, 0, 356, 210
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
//Picture Control
CONTROL 103,IDC_PB_SPLASH,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,0,0,356,210
DEFPUSHBUTTON "OK",IDOK,152,169,50,14
END
Now the issue is, when the I'm using the visual styles, the image doesn't fill the entire area of the dialog Window. A small white space can be seen on both sides of the dialog(if a remove the SS_CENTERIMAGE it's a white space on right side). This doesn't happen without the Visual Styles. The pictures below show the problem (The image used there is just an example, the actual background image is more complex, so just painting with a brush is not an option)
Without Visual Styles
http://postimg.org/image/hji8sa6j1/
With Visual Styles
http://postimg.org/image/b733ig3gt/
Sorry for the links, still don't have enough reputation to post images.
Any suggestions on how to make the bitmap fill the entire window with visual styles enabled?
I found this nice answer https://stackoverflow.com/a/17713810/3022281 by melak47 to making a borderless window but it's not dialog based. If nothing else works I guess I'll have to go with that solution.
Dont use a picture control. Draw directly on the dialog:
BOOL CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
HDC hdc;
RECT rt;
switch (message){
case WM_PAINT:
GetWindowRect(hDlg, &rt);
hdc = GetWindowDC(hDlg);
StretchBlt(hdc, 0, 0, rt.right, rt.bottom, hdcMemBitmap, 0, 0, width, height, SRCCOPY);
ReleaseDc(hDlg, hdc);
break;
default: //for messages that we don't deal with
return false;
}
return false;
}
width and height are for the bitmaps width and height.
valter
After a lot of fussing around, I got it to work by simply defining the image dimensions in the .RC code a little less than what the Visual Studio Dialog editor allowed me to.
By using the editor, if I pulled the Window Edges all the way down to the image width, or if I set the "Real Size Image" property to true, the editor came up with the dimensions (356,210), which was leaving the white space when Visual Styles were enabled. I just manually tuned the width down a little from 356 to 353 and the white space disappeared! So it was just Visual Studio Editor calculating the dimensions wrong for when the visual styles were enabled.

Winapi: The proper way to clear DrawText()

Hi I want to clear out the DrawText() and I don't know how to do it properly. I could simply SetTextColor to the color of my background but this is not elegant way to do it I think. I dont know maybe I could do something with a rectangle rc that holds my text.
I draw by case WM_PAINT and in it:
hdc=BeginPaint(hwnd, &paint);
.... //some other code here
DrawText(hdc, TEXT("some text"), -1, &rc, DT_SINGLELINE);
....//some other code here
EndPaint(hwnd, &paint);
and one more thing. I don't have DeleteDC(hdc); or ReleaseDC(hdc); in my WM_PAINT is that ok, or I should have them after or before EndPaint(hwnd, &paint);?
There's no way to "clear" text that you've drawn other than to draw something else over the top. If your background is a solid color then just draw a rectangle of that color (you can work out how big it needs to be by using the DT_CALCRECT flag with DrawText). If your background is an image then you need to blit the appropriate area of the image.
Note that drawing the text over the top of itself using the background color (as you suggest) may not work because of ClearType/anti-aliasing.
To answer your second question, no - the DC returned by BeginPaint is effectively deleted by the call to EndPaint and so you don't need to (and mustn't) delete it separately.

Clearing a window contents in a blur behind window(DWM)

I have a window on which I call DwmExtendFrameIntoClientArea(),
the window hosts other child windows, I use Direct2D to paint on one of the child windows,
When a bitmap is loaded which has a black region on it, that region becomes blurred.
I wish to clear everything in the child window and paint it again on WM_PAINT, however I cannot seem to clear the contents.
I have tried to clear it using
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black))
This makes the child window region black, it erases all previous drawing, but no transparency.
I have tried to draw a bitmap which is just a black bar over the client area
m_pRenderTarget->DrawBitmap(m_pBkgrnd,D2D1::Rect<float> (0.f,0.f,GetWidth(),GetHeight()))
This makes whatever that had appeared before it, in black.
Tried the old GDI way of painting a black region over the entire child window,
RECT rc;
GetClientRect(m_hwnd, &rc);
HBRUSH brush = CreateSolidBrush(RGB(0,0,0));
HDC hc=GetDC(m_hwnd);
FillRect(hc, &rc, brush);
ReleaseDC(m_hwnd,hc);
DeleteObject(brush);
Doesn't work.
However if I don't do any of this and I try to resize the main window, it works right i.e. the previous painting dissappears.
Is there any API call or any way to clear the window manually before I draw it again?
How are you initializing your render target? Make sure you specify Premultipled Alpha, and not Straight or Ignore. Then, to clear everything to transparent, use ID2D1RenderTarget::Clear(D2D1::ColorF(0, 0, 0, 0)). You cannot use something like FillRectangle to draw with a transparent color, as that will blend the transparent color into what's already there and that is a no-op.

How can I extract text information from an owner-drawn window, given a HWND?

I'm writing a simple automated test application for Win32. It runs as a separate process and accesses the target application via the Windows API. I can read window hierarchies, find labels and textboxes, and click buttons by sending/posting messages etc. All fine.
Unfortunately many controls in the target application are composed of nothing more than an owner-drawn control/window. (For example, we use the BCG menus and controlbars). Finding the correct part of the control to send a 'click' to is problematic.
Is there any way, given a HWND, to extract GDI drawing commands? I'd like to know each piece of text drawn to that control, and its coordinates.
Failing that, is there any way to capture a single control/window (again by HWND) into a bitmap? Worse-case scenario, I could OCR it.
You can use TextGRAB SDK to do this. Unfortunately it is shareware and costs $30.
To capture a window as a bitmap:
RECT rc;
GetClientRect(hWnd, &rc);
int cx = rc.right-rc.left;
int cy = rc.bottom-rc.top;
HDC winDC = ::GetDC(hWnd);
HDC tempDC = ::CreateCompatibleDC(winDC);
HBITMAP newBMP = ::CreateCompatibleBitmap(winDC, cx, cy);
HBITMAP oldBmp = (HBITMAP)::SelectObject(tempDC, newBMP);
BitBlt(tempDC,0,0,cx,cy, winDC,0,0,SRCCOPY|CAPTUREBLT);
// now you have the window content in the newBMP bitmap, do with it as you please here
::SelectObject(tempDC, oldBmp);
::DeleteObject(newBMP);
::DeleteDC(tempDC);
::ReleaseDC(hWnd, winDC);

Resources