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.
Related
First, if this isn't a great way to do this, PLEASE suggest better. I can't seem to find an exact solution to what must be a common desire (see post title).
My approach was to trap the WM_PAINT message and check whether the window position is maximized. If it is, then run this code:
SetWindowLong(hCDGWnd, GWL_STYLE, 0); // remove all styling
SetWindowPos(hCDGWnd, HWND_TOP, 0, 0, 1280, 720, SWP_SHOWWINDOW); // full screen is 1280 x 720
StretchDIBits(hdc, 0, 0, 1280, 720, CDG_XOFFSET, CDG_YOFFSET, CDG_RENDER_WIDTH, CDG_RENDER_HEIGHT,
bmBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS, SRCCOPY);
What I want to see is my BITMAP stretched to fill the entire client area, which should just fill the entire screen. Actually it is a section taken out of a larger bitmap. It seems like the window is in fact full screen, but the bitmap is its normal size and not stretched. Curiously, when I was fiddling with the window positioning stuff I had all kinds of attempts leaving the styling but trying to position the title bar and frame offscreen (see below) - the bitmap was appearing stretched just fine during those close but failed attempts. Now I've got the window right, suddenly the bitmap no longer stretches. Is there something about removing the styling that would screw up the StretchDIBits function?
Also, when I attempt leaving the style in place, and use AdjustWindowRect() to have my client size be fullscreen, it returns {-3, -26, 1283, 723 } which makes sense - 3 pixel border plus 23 more for title bar on top. But, just to explore things, when I don't even test for maximized state, and just make the window have x = -3, y = -26, cx = 1286, cy = 749, then almost everything is fine except the bottom of the window is shy of fullscreen by about 4 pixels. When I make the window height much bigger - say 760 - IT STAYS THE SAME HEIGHT!? I so confused. If try this maneuver only when maximized, it seems like windows ignores my attempts to have the title bar off the top of the screen.
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
I'm working on a project that requires me to draw a thin line horizontally across the screen and drag it vertically. To add a bit of flair I'm trying to add the DWM glass effect to the window so that it will match window boders in Windows 7 and 8 (though I know I won't get transparency in Windows 8).
I've got the line drawn by creating a child window with the non client area extended into the client area using the sheet of glass trick with DwmExtendFrameIntoClientArea like this:
MARGINS margins = { -1, -1, -1, -1 };
DwmEnableComposition(DWM_EC_ENABLECOMPOSITION);
DwmExtendFrameIntoClientArea(DIV_HWND, &margins);
And I create the window like this:
HWND DIV_HWND = CreateWindow(DIV_NAME,
NULL,
WS_VISIBLE,
0, 0, mon_info.rcWork.right, mon_info.rcWork.top + 3,
top->hwnd, NULL,
hInstance, NULL);
And the window class like this:
const wchar_t DIV_NAME[] = L"DIV";
WNDCLASS DIV = {};
DIV.lpfnWndProc = DIV_PROC;
DIV.hInstance = hInstance;
DIV.lpszClassName = DIV_NAME;
DIV.hCursor = LoadCursor(NULL, IDC_SIZEALL);
RegisterClass(&DIV);
I've gotten the window down to a width of 16 pixels with all the nice borders and drop shadow effects I expect to see around a windows border by handling the WM_GETMINMAXINFO message and returning 2 as the ptMinTrackSize.x and y but I can't seem to get it smaller than that.
I can get a "glassy" window by using DwmEnableBlurBehindWindow on a region I set with SetWindowRgn but the color is that of a background window even when it is in focus. Additionally I miss the slight drop shadow and border.
It seems like I might be hitting the size restriction due to border sizes since each border is 8 pixels wide.
Any help is greatly appreciated!
I've found my answer so I'll leave it here on the off chance someone else needs it. All I had to do was call DwmSetWindowAttribute(hwmd, DWMWA_NCRENDERING_POLICY, DWMNCRP_ENABLED, sizeof(int)); to ensure the DWM rendering policy was not based on the window style. This allowed me to use a WS_POPUP window to get the size I wanted with a nicely glass filled interior.
There are a few bugs here:
There is a strange shadow along the top and bottom if the Y dimension of the window is smaller than 16px.
On Vista\7 the rounded window edges give the window a strange oval-like shape.
I have two monitors that are running at different resolutions. Left monitor is 1920x1200. Right monitor (the primary monitor) is 1920x1080.
I want to use SetWindowPos to make a window take up the full vertical height of the left hand monitor.
Here's what I do:
x = GetSystemMetrics(SM_XVIRTUALSCREEN);
hMonitor = monitorFromPoint(x, 0, MONITOR_DEFAULTTONEAREST);
MONITORINFO moninfo;
moninfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMonitor, moninfo);
height = moninfo.rcWork.bottom - moninfo.rcWork.top;
SetWindowPos(hwnd, 0, moninfo.rcWork.left, moninfo.rcWord.top, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
I have confirmed that height is computing to 1200 (expected b/c that is the target monitor's vertical resolution).
However, after the call to SetWindowPos, the window rectangle doesn't fill the entire height of the screen (it is actually 1080 high).
I even tried this in VBA just for giggles:
Public Sub testSWP()
Dim hwnd As Long
hwnd = &H1D2F2C
SetWindowPos &H1D2F2C, 0, -1900, 0, 150, 1200, SWP_NOZORDER Or SWP_NOACTIVATE
Dim r As RECT
GetWindowRect hwnd, r
' at this point, r.bottom = 1080
End Sub
This is well and good (GetWindowRect documentation says coordinates will be in Client space, and I'm assuming that win32 is translating between the resolution of my primary and secondary monitor.
I'm getting ready to inflate the vertical dimension by the ratio of the heights of the target and primary monitor. I'm pretty sure this is going to work, but it seems like a lot of hoops to have to jump through - am I maybe just not aware of a better way of determining the screen dimensions in 'client coordinates'?
The issue isn't with coordinate transformation. It is that windows isn't allowing SetWindowPos to adjust the window so it is larger than the screen. Of course, it is basing this on the primary monitor size.
See: Can a window be resized past the screen size/offscreen?
Do you want a normal window (with titlebar etc) or do you want a fullscreen window (like youtube fullscreen video playback or games).
I think you want the latter i.e. make a fullscreen window which covers the entire screen. For that, in the call to CreateWindow, pass WS_POPUP as the window style (see dwStyle param). This will create the window without the titlebar and it will cover the entire screen.
Also, I don't think the way you're getting the left monitor is correct. You should be using EnumMonitors to iterate through all the monitors, get the left most monitor and then use GetMonitorInfo to retrieve the monitor's rects if you want to make this a generic application.
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.