Enumerating devices, and obtain their context - windows

Developing an OpenGL application, I create a window, get the associated device context using GetDC, and create an OpenGL context on the device context handle returned by GetDC. It all ok.
Before creating the OpenGL context, I shall call SetPixelFormat. Documentation says that SetPixelFormat shall be called only once (I think once per device context handle).
Well. For systems having only one device it's very simple, but what about systems having two or more devices? how this could work?
First, I don't know how created windows are associated with device contexts. I thought to enumerated every available devices on system, query every pixel format for each device, and then create windows after having setup every device context. In this case I don't have to worry about device pixel format, and I can setup multiple devices for having compatible pixel formats (usefull for sharing objects between OpenGL contexts).
Is it possible to enumerated available video devices? I haven't found any Windows API for enumerating graphical devices to obtain the same handle returned by GetDC...
It is possible to associate a window to a specific video device context?

Device Contexts are rather dynamic objects and are created and disposed of over the course of an applications life. DC's can be display DCs (created using the monitor APIs or CreateDC), window DCs (retrieved from the Window managers DC cache usign the GetDC api) and memory DCs (created using CreateCompatibleDC).
SetPixelFormat wants a window DC. Namely, it wants the window DC of the window you are going to be doing OpenGL rendering on. You MUST call it once, and only once, for every window you create.
Either in your frameworks Window::OnCreate method, or in your WM_CREATE handler, or when CreateWindow returns, you would have code like this:
HGLRC InitWindowForOpenGL(HWND hwnd)
{
HGLRC glctx;
PIXELFORMATDESCRIPTOR pfd = { /*initialization data*/ };
HDC hdc = GetDC(hwnd); // get a DC to use with OpenGL
int pf = ChoosePixelFormat(hdc,&pfd);
SetPixelFormat(hdc,pf,&pfd); //sets the pixel format of the associated window
glctx = wglCreateContext(hdc)
ReleaseDC(hdc,hwnd);
return glctx;
}
OpenGL maintains a seperate context for every window in your application. This means you need to store the HGLRC with each window object (As a member of your CWnd (or equivalent) derived class), as well as ensuring that the appropriate context is made current before calling any OpenGL functions.
A lot of OpenGL sample code on the net simply stores the gl context in a global variable, which is very limiting if you ever want to expand to using OpenGL in more than one window. If you are using only one window however, it is acceptable to simple call wglMakeCurrent once on app startup and forget about it.
If you want to support more than one OpenGL window you need to set the context before calling any OpenGL code for a window:
HDC SetGLContext(HWND hwnd, HGLRC hglrc, HDC hdc=NULL)
{
if(!hdc)
hdc = GetDC(hwnd);
wglMakeCurrent(hdc,hglrc);
return hdc;
}
void ResetGLContext(HWND hwnd, HDC hdc)
{
wglMakeCurrent(hdc,NULL);
if(hdc)
ReleaseDC(hwnd,hdc);
}
Your WindoProc might have entries like this:
HDC hdc;
case WM_PAINT:
hdc = BeginPaint(m_hwnd,&ps);
SetGLContext(m_hwnd,m_hglctx,hdc);
PaintOpenGLScene();
ResetGLContext(m_hwnd,NULL); // dont pass the DC as its owned by EndPaint
EndPaint(m_hwnd,&ps);
return 0;
case WM_TIMER:
hdc = SetGLContext(m_hwnd,m_hglctx,NULL);
DoOnIdleRendering();
ResetGLContext(m_hwnd,hdc);
return 0;

DescribePixelFormat.
https://learn.microsoft.com/nb-no/windows/win32/opengl/examining-a-devices-supported-pixel-formats
// local variables
int iMax ;
PIXELFORMATDESCRIPTOR pfd;
int iPixelFormat ;
// initialize a pixel format index variable
iPixelFormat = 1;
// keep obtaining and examining pixel format data...
do {
// try to obtain some pixel format data
iMax = DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd);
// if there was some problem with that...
if (iMax == 0)
// return indicating failure
return(FALSE);
// we have successfully obtained pixel format data
// let's examine the pixel format data...
myPixelFormatExaminer (&pfd);
}
// ...until we've looked at all the device context's pixel formats
while (++iPixelFormat <= iMax);

Related

Draw BITMAP over Window Handle (HWND) of another process

I have bitblt a screenshot of the entire screen, and its indeed a valid BITMAP since after writing it to a file, I can clearly see its there.
Lets say I have the window handle of Calculator. I want to be able to constantly BitBlt the BITMAP (containing the desktop screenshot) onto the window of Calculator so that whenever calculator is open, whether its the background window (visible or overlapped by other windows) or foreground - It will always show the latest screenshot instead of the default Calculator application & its buttons.
I took a screenshot (bitmap) of the desktop and expected to use StretchDIBits to cover the region of the target application with my bitmap. However, when calculator is opened, nothing happens to it/it doesnt get replaced by the screenshot of the desktop, although the StretchDIBits function still returns the number of scan lines copied to the destination.
void* calculator_hwnd = (void*) FindWindowA("ApplicationFrameWindow", "Calculator");
void* composition_window = GetWindowDC((HWND)GetDesktopWindow());
if (composition_window)
{
void* composition_environment = 0;
if ((composition_environment = CreateCompatibleDC((HDC)composition_window)))
{
int window_x_axis = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int window_y_axis = GetSystemMetrics(SM_CYVIRTUALSCREEN);
void* bitmap = CreateCompatibleBitmap((HDC)composition_window, window_x_axis, window_y_axis);
if (bitmap)
{
void* composition_bitmap = SelectObject((HDC)composition_environment, bitmap);
int status = PrintWindow((HWND) GetDesktopWindow(), (HDC)composition_environment, 0x00000002);
if (!status)
BitBlt((HDC)composition_environment, 0, 0, window_x_axis, window_y_axis, (HDC)composition_window, 0, 0, SRCCOPY);
BITMAPINFO* pbi = CreateBitmapInfoStruct((HBITMAP)bitmap);
BITMAPINFOHEADER* pbih = (PBITMAPINFOHEADER)pbi;
unsigned char* lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
GetDIBits((HDC)composition_environment, (HBITMAP)bitmap, 0, (WORD)pbih->biHeight, lpBits, pbi,
DIB_RGB_COLORS);
void* calculator_window_environment = GetDC((HWND)calculator_hwnd);
StretchDIBits((HDC)calculator_window_environment, 0, 0, window_x_axis, window_y_axis, 0, 0, window_x_axis, window_y_axis, lpBits, pbi, DIB_RGB_COLORS, SRCCOPY);
GlobalFree(lpBits);
SelectObject((HDC)composition_environment, composition_bitmap);
DeleteObject(bitmap);
}
}
DeleteDC((HDC)composition_environment);
ReleaseDC((HWND)GetDesktopWindow(), (HDC)composition_window);
}
This is where I got CreateBitmapInfoStruct
This question says what I am trying to do is possible, but doesn't explain how - can anyone answer that with respect to my code?
This isn't supported by the OS. Window rendering is at the discretion of the window owner (i.e. the thread that called CreateWindowEx), and there aren't any customization points external threads or processes can hook into.
While you can render into a device context that belongs to a foreign window, there's no way for you to (reliably) find out when you need to update, nor is there any way to let the destination know that it shouldn't overwrite part or all of the window contents you just rendered.
That's as far as GDI rendering goes, which is really only supported for compatibility with applications that haven't been updated to take advantage of desktop composition (introduced in Windows Vista). With this model, applications can choose to render window contents without ever providing a redirection surface (which is required if you wish to BitBlt/StretchBlt into a device context).
So, in essence, there's no way for you to reliably render onto a window you did not create. The common workaround is to create a (partially transparent) overlay window, which you would then move around to keep it in sync with the window it is supposed to augment. This is undoubtedly going to create a pretty poor user experience, as your contents are inevitably going to lag behind as the user moves the window.

Why should I call `GetDC` and `ReleaseDC` again and again?

Every example code I have seen are GetDC and ReleaseDC being called again and again. Or BeginPaint and EndPaint.
But I think drawing on the screen happens very frequently (especially in a game), so storing the drawing in memory is better than getting and releasing device contexts all time.
So I went the route of getting a DC and "keeping it", only releasing it when the program ends. But why don't people do it like this? Is it because GetDC and ReleaseDC cost very little?
case WM_CREATE:
hdc = GetDC(hWnd); //hdc is declared as global HDC
MyBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
return 0;
case WM_PAINT:
MemDC = CreateCompatibleDC(hdc);
OldBitmap = (HBITMAP)SelectObject(MemDC, MyBitmap);
BitBlt(hdc, 0, 0, 300, 300, MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
return 0;
The code you presented here is wrong. First off, you need to read a little more of the documentation. Here is a useful link: Painting and Drawing. Basically there are two ways to update a window:
In response to the WM_PAINT message. Use the BeginPaint and EndPaint functions to paint the client area properly. This message is sent by the system when a part of the client area is "invalidated" (as a result of resizing, restoring from minimized state, moving a window previously obscured, or programmatically invalidating it.) WM_PAINT is a low-priority message, received just before the message-queue gets empty.
Specifically drawing a part or the whole client area without having an invalidated region on it. Use GetDC and ReleaseDC for this. Useful if you want to make changes immediately visible, when the application (CPU) is busy.
Writing some code to process the WM_PAINT message is normally almost mandatory, while specifically drawing as well is optional, depending on the requirements of your application.
Never send or post a WM_PAINT message yourself, instead invalidate a part or the client area - the application will receive a WM_PAINT message before becoming idle. If you want the painting to occur immediately call UpdateWindow - this bypasses the message queue.
A recent (Aug 2016) security update in Windows 10 prevents the reuse of printer device contexts. After printing one document Windows 10 will refuse to print again with that same DC. It has always been a preferred practice to create a new DC for each document, but now it seems to be a requirement in Windows 10.

How to identify Windows 10 background store processes that have non-displayed windows that are programmatically visible and minimizable?

I have a Win32 application that determines whether there are any visible, non-iconic, minimizable windows being shown. To the best of my knowledge it's worked fine for Win9x through to Win8.1, but under Windows 10 it often finds several windows that aren't actually visible on the screen.
To try to identify what's going on I've written a simple test application that enumerates and records all such windows. Here's the essence of the EnumWindows callback code:
BOOL CALLBACK EnumFunc( HWND hWnd, LPARAM lParam )
{
if ( IsWindowVisible( hWnd ) )
{
if ( !IsIconic( hWnd ) )
{
const LONG style = GetWindowLong( hWnd, GWL_STYLE );
if ( WS_MINIMIZEBOX & style )
{
// record window info
}
}
}
return TRUE;
}
Most of the phantom windows under Windows 10 belong to background store app processes such as Mail, Calculator, and Photos. These are listed under the Background processes section of Task Manager, and if I use Task Manager to end those background tasks, their phantom window is no longer found by my test application.
In the above screen shot from my test application you can see that all but 1 of the offending windows belong to threads of the same process id 7768, which is ApplicationFrameHost.exe. The final window with process id 11808 is explorer.exe.
I've looked at the phantom windows with Spy++ and can't see any particular style combination that would help in uniquely identifying them.
I've had a suggestion that the undocumented Windows "bands" may be involved, but I've tried using the (undocumented, so this may be wrong) API:
BOOL WINAPI GetWindowBand (HWND hWnd, PDWORD pdwBand);
but it returns a band of 1 for any window, so doesn't differentiate these phantoms.
How to reliably identify these phantom windows?
The approved way of detecting these phantom windows is to use DwmGetWindowAttribute and DWMWA_CLOAKED.
Here's the code I've used:
static bool IsInvisibleWin10BackgroundAppWindow( HWND hWnd )
{
int CloakedVal;
HRESULT hRes = DwmGetWindowAttribute( hWnd, DWMWA_CLOAKED, &CloakedVal, sizeof( CloakedVal ) );
if ( hRes != S_OK )
{
CloakedVal = 0;
}
return CloakedVal ? true : false;
}
Thanks to Scot Br from MS for posting the answer here
Top-level windows of class ApplicationFrameWindow are containers for Windows Store apps. First, here is the window of Mail shown in Spy:
This is truly visible (not phantom). You can tell that it is because the first child is a window of class Windows.UI.Core.CoreWindow. Interestingly, the owner process of the ApplicationFrameWindow is APPLICATIONFRAMEHOST, but the owner process of the Windows.UI.Core.CoreWindow is a different one: HXMAIL. (I've not seen a child window owned by a different process than the parent one before!)
Compare that with a phantom window (as identified in your RWTool):
It is missing the child of class Windows.UI.Core.CoreWindow.
This suggests an answer to your question: If a top-level window is of class ApplicationFrameWindow, iterate it's children. If the first child has class Windows.UI.Core.CoreWindow, the window is visible, otherwise it is not (i.e. it is phantom).
But what if an old-fashioned, non-store app happened to have a top-level window of class ApplicationFrameWindow? It would not have a child of Windows.UI.Core.CoreWindow. Yet it is visible. How to tell this is an ordinary app and not a Windows Store app? I don't have a foolproof way. You could also check for the existence of the other child windows of a Store app: ApplicationFrameTitleBarWindow and ApplicationFrameInputSinkWindow. The chances of a non-Store app having this exact Windows hierarchy is vanishingly small.
EDIT
The ApplicationFrameWindow's (and also Windows.UI.Core.CoreWindow) have the WS_EX_NOREDIRECTIONBITMAP style set:
The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
At minimum, you could check for this style instead of special casing ApplicationFrameWindow. Though to see if any content was truly visible, you'd still need to make that depend on whether it has a child of Windows.UI.Core.CoreWindow.

Flicker when moving/resizing window

I have developed an application to display jpeg images. It can display 4 images, one in each quadrant of the screen. It uses 4 windows for that. The windows have no border (frame) nor titlebar.
When a new image is loaded, the window size is adjusted for the new image and then the image is displayed.
Especially when the window is made larger, there is often a flicker. With my eyes to slits, it seems that the old contents is moved when resizing before the new contents is displayed.
I consulted many resources and used all tricks:
the window has only style CS_DBLCLKS (no CS_HREDRAW or CS_VREDRAW);
the background brush is NULL;
WM_ERASEBKGND returns 1;
WM_NCPAINT returns 0;
WM_NCCALCSIZE tells to align to the side not moved (can you tell it to discard the client area?);
WM_WINDOWPOSCHANGING returns 0;
SetWindowPos has flags SWP_NOCOPYBITS | SWP_DEFERERASE | SWP_NOREDRAW | SWP_NOSENDCHANGING.
Still, the flicker (or the contents move) occurrs when resizing the window. What I want is to:
SetWindowPos to new size and position;
InvalidateRect (hWnd, NULL, FALSE);
UpdateWindow(hWnd);
without any painting, background erasing or content moving until WM_PAINT.
WM_PAINT does:
hDC= BeginPaint (hWnd, &ps);
hMemDC= CreateCompatibleDC (hDC);
hOldBitmap = SelectObject (hMemDC, hNewBitmap);
BitBlt (hDC,...,hMemDC,0,0,SRCCOPY);
SelectObject (hMemDC, hOldBitmap);
DeleteDC (hMemDC);
EndPaint (hWnd, &ps);
Can anyone tell me if/where I make a mistake that causes the old content of the window to be moved?
Hardware etc: Windows 7 on HP Elitebook Core7 64 bits with NVIDIA Quadro K1000m driver 9.18.13.3265 (updated to 341.44).
UPDATE (Jul '17)
I have seen the behavior of the pogram also on another Windows computer (Windows 8/10). It does not seem to be the NVIDIA display driver.
The behavior is the most visible when resizing a window tiled to the centre of the screen (right bottom = w/2, h/2) to the left or left upper corner (0, 0).
I may have problems with the calculations for the WM_NCCALCSIZE message to tell Windows not to do anything. Could anyone give an example calculation for my purpose? See also How do I force windows NOT to redraw anything in my dialog when the user is resizing my dialog?
You have an impressive list of anti-flickering tricks :-)
I don't know if this is of importance (since it depends on how your tool windows are created and espacially if they are child windows to a common parent):
Try setting window style WS_CLIPCHILDREN in the parent window of the tool windows (if there is one).
If not set the parent window will erase it's (entire) background and then forward the paint messages to the child windows which will cause flickering. If WS_CLIPCHILDREN is set the parent window does nothing to the client area occupied by child windows. As a result the area of child windows isn't drawn twice and there is no chance for flickering.
This is a theory more than an answer:
By default, in modern Windows, your window is just a texture on the video card, and the desktop window manager is mapping that to a rectangle on the screen. You've seem to have done everything necessary to make sure that texture gets updated in one fell swoop.
But when you resize the window, perhaps the desktop compositor immediately updates its geometry, causing the (still unchanged) texture to be appear in the new position on the screen. It's only later, when you do the paint, that the texture is updated.
You can test this theory by temporarily turning off desktop compositing. On Windows 7, you navigate to System Properties, choose the Advanced tab, under Performance choose Settings..., on the Visual Effects tab, deselect the "Enable desktop composition" setting. Then try to reproduce the problem. If it goes away, then that supports (but doesn't absolutely prove) my theory.
(Remember to re-enable compositing, since that's how most of your users will be running most of the time.)
If the theory is true, it seems the goal is to get to the paint as soon possible after the window resize. If the window of time is small enough, then both could happen within a monitor refresh cycle and there would be no flicker.
Ironically, your efforts to eliminate flicker may be working against you here, since you've intentionally suppressed the invalidation and redraw that would normally result from SetWindowPos until you do it manually at a later step.
A debugging tip: Try introducing delays (e.g., Sleep(1000);) at key points in the process so you can see whether the resize and redraw are actually rendering on screen as two distinct steps.
You have indeed got a nice set of tricks.
First I can suggest a few variants on the existing tricks that might help especially on XP/Vista/7, and second I want to mention where the persistent flicker you see on Win8/10 is likely coming from and some tricks to reduce that.
First, despite advice to the contrary in other OP posts, you may find that if you set the CS_HREDRAW|CS_VREDRAW window styles that you avoided before, it actually eliminates the BitBlt that is done inside the internal SetWindowPos Windows does during window resizing (but---and this is the confusing part---on Windows 8/10 you will still see flicker from another source...more on that below).
If you don't want to include CS_HREDRAW|CS_VREDRAW, you can also intercept WM_WINDOWPOSCHANGING (first passing it onto DefWindowProc) and set WINDOWPOS.flags |= SWP_NOCOPYBITS, which disables the BitBlt inside the internal call to SetWindowPos() that Windows makes during window resizing.
Or, you could add to your WM_NCCALCSIZE trick by having it return a set of values that will tell Windows to just BitBlt 1 pixel on top of itself so that even if the BitBlt does happen, it doesn't do anything visibly:
case WM_NCCALCSIZE:
{
RECT ocr; // old client rect
if (wParam)
{
NCCALCSIZE_PARAMS *np = (NCCALCSIZE_PARAMS *)lParam;
// np->rgrc[0] is new window rect
// np->rgrc[1] is old window rect
// np->rgrc[2] is old client rect
ocr = np->rgrc[2];
}
else
{
RECT *r = (RECT *)lParam;
// *r is window rect
}
// first give Windoze a crack at it
lRet = DefWindowProc(hWnd, uMsg, wParam, lParam);
if (wParam)
{
NCCALCSIZE_PARAMS *np = (NCCALCSIZE_PARAMS *)lParam;
// np->rgrc[0] is new client rect computed
// np->rgrc[1] is going to be dst blit rect
// np->rgrc[2] is going to be src blit rect
//
ncr = np->rgrc[0];
RECT &dst = np->rgrc[1];
RECT &src = np->rgrc[2];
// FYI DefWindowProc gives us new client rect that
// - in y
// - shares bottom edge if user dragging top border
// - shares top edge if user dragging bottom border
// - in x
// - shares left edge if user dragging right border
// - shares right edge if user dragging left border
//
src = ocr;
dst = ncr;
// - so src and dst may have different size
// - ms dox are totally unclear about what this means
// https://learn.microsoft.com/en-us/windows/desktop/
// winmsg/wm-nccalcsize
// https://learn.microsoft.com/en-us/windows/desktop/
// api/winuser/ns-winuser-tagnccalcsize_params
// - they just say "src is clipped by dst"
// - they don't say how src and dst align for blt
// - resolve ambiguity
// essentially disable BitBlt by making src/dst same
// make it 1 px to avoid waste in case Windoze still does it
dst.right = dst.left + 1;
dst.bottom = dst.top + 1;
src.right = dst.left + 1;
src.bottom = dst.top + 1;
lRet = WVR_VALIDRECTS;
}
else // wParam == 0: Windoze wants us to map a single rect w->c
{
RECT *r = (RECT *)lParam;
// *r is client rect
}
return lRet;
So that's all very nice, but why does Windows 8/10 look so bad?
Apps under Windows 8/10 Aero don't draw directly to the screen, but rather draw to offscreen buffers that are then composited by the evil DWM.exe window manager. DWM actually adds another layer of BitBlt-type behavior on top of the existing legacy XP/Vista/7 BitBlt behavior.
And the DWM blit behavior is even more crazy because they don't just copy the client area, but they actually replicate pixels at the edges of your old client area to make the new one. Unfortunately, making DWM not do its blit is much harder than just passing some extra flags.
I don't have a 100% solution, but I hope the above info will help, and please see this Q&A for a timing trick you can use to reduce the chances of the DWM-layer blit happening to your app:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Just in addition to your list of tricks. I have the same problem with flicker on my Dell XPS notebook while resizing window using left/top edge. I've tried all the tricks you mentioned. As far as I understand window border is drawn in GPU and the window content is prepared in GDI subsystem and transferred to video memory for window composition (DWM introduced in Windows 8.1). I tried to remove GDI rendering completely (setting WS_EX_NOREDIRECTIONBITMAP style) which makes window without any content, and then create content surface directly using DXGI subsystem (using CreateSwapChainForComposition, there are few examples on how to do this). But the problem remains. There is still a lag between rendering a window frame and resizing/displaying content surface.
However it may solve your problem, as you don't have the border and you will not notice this lag. But you will have full control over window repaint and it will be made on GPU side.

Resizing Render Target Direct2D after WM_SIZE

Quick question guys... I am currently working with Directx3D and 2D and I was wondering if I have to recreate the render target when the Windows is resized or does Direct2D automatically detects this, since it's bound to the DXGISurface(back-buffer of the swapchain) when I created it.
Here is the code that I used to bind the render targets together:
ComPtr<IDXGISurface1> dxgibackBuffer;
hr = m_pDxSwapchain->GetBuffer(0, IID_PPV_ARGS(&dxgibackBuffer));
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),
96.0f,
96.0f);
hr = m_pD2DContext->CreateBitmapFromDxgiSurface(dxgibackBuffer.Get(), &bitmapProperties, &m_pD2DTargetBitmap);
// last step
m_pD2DContext->SetTarget(m_pD2DTargetBitmap.Get());
See Care_and_Feeding_of_the_Swap_Chain and Handling_Window_Resizing
Quote1:
Naturally, the application's best route is to respond to WM_SIZE, and call IDXGISwapChain::ResizeBuffers, passing the size contained in the message's parameters.
Quote2:
Before you call ResizeBuffers, you must release all outstanding references to the swap chain's buffers. The object that typically holds a reference to a swap chain's buffer is a render-target-view.

Resources