• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1631
  • Last Modified:

Screen capture with Directx makes transparent Windows to disappear

Hi experts,

I am facing trouble when capturing the desktop screen with both DirectX 8 and 9. Some windows dissappear at the very moment of capturing the screen, which is very annoying to users.

The hint I can give you is that those dissappearing windows are transparent. The method I am using is basically GetFrontBuffer, and I can not use GDI. I don't care if the content of the transparent window is not included in the screenshot, I just want that users don't complaint.

Thanks in advance
0
parnasso
Asked:
parnasso
  • 13
  • 11
1 Solution
 
satsumoSoftware DeveloperCommented:
I've never seen this happen.  It may be that D3D is grabbing the data directly from the the display and holds up the system in a way that prevents the transparent window redrawing.  It could be holding up the GDI or preventing WM_PAINT messages getting to those windows.

Transparent windows get their WM_PAINT message after the windows beneath have updated.  If GetFrontBufferData() is causing the app window to update and then grabbing the data, there would be a pause before the transparent windows redraw.  Grabbing the data is slow and WM_PAINT messages are given low priority.

I have display grabbing code, except I'm using a lockable back buffer.  Grabing the display is done by locking the back buffer and copying data out of it.  This is still slow, but faster than GetFrontBufferData and won't interfere with the display.  It still works if the app window is off the edge of the screen or on a second monitor. GetFrontBufferData converts to D3DFMT_A8R8G8B8 if the display is 16 bit, that conversion slows things down.  Locking the surface does not convert, the program chooses a back buffer format.
0
 
parnassoAuthor Commented:
Satsumo:

When you say "Grabing the display is done by locking the back buffer and copying data out of it".
How do you do it? I ask you because every time I try something like that I get all black bytes.
I think it is because my application does not use Present neither does put something into the back buffer, Maybe I am wrong and you can guide me getting to know how to use the back buffer instead.

Thanks by the way
0
 
satsumoSoftware DeveloperCommented:
You're using Direct 3D only to grab the display, not to render anything?
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
parnassoAuthor Commented:
Yes, I'm using Direct 3D just to grab the display. I am not allowed to use GDI and it seemed the only way i have to grab.
0
 
satsumoSoftware DeveloperCommented:
In that case locking the back buffer isn't going to help.  If this idea is to grab one window, I was going to suggest sending a WM_PRINTCLIENT message.  Except that requires creating a memory device context, which uses GDI.

How about simulating the PrintScreen key to copy an image of the active window onto the clipboard?  On the clipboard it's just DIB data, not a GDI device.  Maybe use SendKeys() to simulate pressing the PrintScreen key, not exactly sure what you would send it to, possibly the Desktop object.  You may get the same result from sending a WM_KEYDOWN message to the desktop window.

I looked at the possibility of using Still Image, Windows Image Aquisition and Video for Windows but they all appear to be concerned with capturing from external devices.

The not using GDI thing is a real sticker.  Using D3D is an inventive way around it, though I can't see how that's going to cause less trouble than using the GDI.  It means the program depends on Direct X being installed, and Direct X uses more system resource than GDI.
0
 
parnassoAuthor Commented:
satsumo:

I'm grateful for your help and for taking your time to answer the question. In spite of the problem itself has not been solved, because as you posted it can't be solved, your comments have been really great.
0
 
parnassoAuthor Commented:
The solution isn't really a solution but rather a thorough explanation of why it is not going to work in the way I've planned.
0
 
satsumoSoftware DeveloperCommented:
Thanks for awarding me the answer.  I would have preferred to solve the problem too.  Though I think the problem is part of Windows and Direct X.
0
 
satsumoSoftware DeveloperCommented:
Actually, that started me wondering about the grabbing procedure.  How does it work exactly?  Does the program update the window then call GetFrontBuferData immediately after?  I'm wondering what would happen if it updated, then waited for a short time before calling GetFrontBufferData.  Maybe that would allow Windows enough time to send the WM_PAINT messages to the transparent windows.  Perhaps it dosen't need to update the display at all.
0
 
parnassoAuthor Commented:
Looks interesting. The transparent window is not actually my window; it is another program that happens to be running when I take the screenshot with GetFrontBufferData.

At the beginning I didn't realize that. It was a client of mine who found that his program disappears and then appears again, when the screenshot is done.

Any further ideas?

 
0
 
satsumoSoftware DeveloperCommented:
How does this work?  Does the screen grabbing code update the display before doing the grab?  Is the client program updating then calling your program.  I'm wondering whether the display repaint is caused by Direct X, your code or the clients program.
0
 
parnassoAuthor Commented:
The whole thing works like this:

1. My client's program X is running on the machine. It has nothing to do with my program.
2. My program Y runs and calls GetFrontBufferData
3. X's window  disappears and then appears
4. My program Y does things with the screenshot data
5. Goto 1.

I'm sorry I didn't clarify how this work before.
0
 
parnassoAuthor Commented:
By the way I never call UpdateData in my program
0
 
satsumoSoftware DeveloperCommented:
Ok, but I guess you create a window.  What do you attach the D3D device to otherwise.  Where is the window?
0
 
parnassoAuthor Commented:
Well, i just put the desktop Window

GetDesktopWindow();
0
 
satsumoSoftware DeveloperCommented:
What else do you do, can you go through the rest of the details of the grabbing code?
0
 
parnassoAuthor Commented:
Sure.

grabbing the code looks like the following example:

3 methods of capturing the screen
0
 
satsumoSoftware DeveloperCommented:
Based on that I'd assume that D3D is updating the display, though I don't see what the purpose of doing that is.  Maybe the transparent windows aren't children of the desktop window so its trying to remove them from.  Do the transparent windows appear in the screen grab?

You could try creating a window that covers the desktop and grabbing from that instead.  Maximise it and  make sure its on top of the window order, set it to have no background brush, no title, no frame etc.  Attach D3D to that and see if you can grab the display.
0
 
parnassoAuthor Commented:
The transparent window does not appear in the grab, which I don't really care. I just want users not to be annoyed.

In the case of creating a window that covers the desktop, on top of the windows order, what would happen to auser that is writing in the word pad? the newly created window will get those keys?

Thanks
0
 
satsumoSoftware DeveloperCommented:
The window would only exist when taking the screenshot, you can destroy it again as soon as your done.  Besides, it dosen't have to take the keyboard focus away from another window.  It would prevent any windows beneath it from changing the display while grabbing the screen, but that happens anyway.
0
 
parnassoAuthor Commented:
I'm going to give it a try. Thanks a lot
0
 
parnassoAuthor Commented:
I've tried creating the topmost window and capture, but still no luck. This is the code i use to create the window:

WNDCLASS wc = {0};
	wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	wc.hbrBackground = 0;
	wc.lpszClassName = MYCLASSNAME;
	wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wc.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
	wc.hInstance = hInstance;
	wc.lpfnWndProc = WinProc;
	wc.lpszMenuName = NULL;

	// Register the windows class
	RegisterClass(&wc);


	// Create the actual window
	HWND hWnd = CreateWindowEx(WS_EX_LAYERED, MYCLASSNAME, NULL, WS_MAXIMIZE | WS_POPUP, 0, 0,
		GetSystemMetrics(SM_CXSCREEN),
		GetSystemMetrics(SM_CYSCREEN),
		NULL, NULL, hInstance, NULL);

	// Show the window
	SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_TOPMOST);
	ShowWindow(hWnd, nShowCmd);
	UpdateWindow(hWnd);

Open in new window


0
 
satsumoSoftware DeveloperCommented:
I would put WS_EX_TOPMOST in the CreateWindow function or call SetWindowPos.  Not sure why you add it in the line below CreateWindow.  That way the style dosen't get applied until you call SetWindowPos, even if you set the style bits.

I wouldn't use WS_EX_LAYERED, WS_POPUP, CS_HREDRAW or CS_VREDRAW either.

Thanks for letting me know whats happening.  Does it manage to grab something?
0
 
parnassoAuthor Commented:
Its does grab the screen, but the application is still disappearing and appearing again each time the grab takes place.

We can reproduce this behavior in some machines, while in others we can't, and the user does not notice anything annoying.

Thanks a lot for your interest, satsumo .
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 13
  • 11
Tackle projects and never again get stuck behind a technical roadblock.
Join Now