locked
Black Screen or Image on screen capture of Windows Applications RRS feed

  • Question

  • Hi,

    i am developing a desktop application in java to capture an image of selected application. For applications, other then Microsoft Applications, i am able to capture an image. but for microsoft products, the same code returns black image.

    Please provide some solution.

    Wednesday, August 30, 2017 12:30 PM

All replies

  • Hi,

    Thank you for posting here.

    Did you try to debug your current project and get other error message?

    Did you try to use the windows API to capture the image as file.

    To store an image temporarily, your application must call CreateCompatibleDC to create a DC that is compatible with the current window DC. After you create a compatible DC, you create a bitmap with the appropriate dimensions by calling the CreateCompatibleBitmap function and then select it into this device context by calling the SelectObject function.

    For more information, please see the document as reference.

    If you want to use the C# language, please see the link that has captured image.

    C# Capture Image

    Best  Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, August 31, 2017 2:57 AM
  • Hi Hart,

    I used the same method by you. It results into black screen for MicroSoft products and applications like Settings in Windows 8 onwards.

    i have used User32, GDI32 and WinGI functions, same as mentioned in the document link shared by you.

    Foolowing is the code snippet

    private BufferedImage capture(final WinDef.HWND hWnd) {
    final WinDef.HDC hdcWindow = User32.INSTANCE.GetDC(hWnd);
    final WinDef.HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(hdcWindow);
    final WinDef.RECT bounds = new WinDef.RECT();

    User32Extra.INSTANCE.GetClientRect(hWnd, bounds);

    final int width = bounds.right - bounds.left;
    final int height = bounds.bottom - bounds.top;
    final WinDef.HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcWindow, width, height);
    final WinNT.HANDLE hOld = GDI32.INSTANCE.SelectObject(hdcMemDC, hBitmap);

    GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, WinGDIExtra.SRCCOPY);
    GDI32.INSTANCE.SelectObject(hdcMemDC, hOld);
    GDI32.INSTANCE.DeleteDC(hdcMemDC);

    final WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();

    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = -height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = WinGDI.BI_RGB;

    BufferedImage image = null;
    if (width > 0 && height > 0) {
    final Memory buffer = new Memory(width * height * 4);
    GDI32.INSTANCE.GetDIBits(hdcWindow, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);

    image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    image.setRGB(0, 0, width, height, buffer.getIntArray(0, width * height), 0, width);
    }

    GDI32.INSTANCE.DeleteObject(hBitmap);
    User32.INSTANCE.ReleaseDC(hWnd, hdcWindow);
    return image;
    }

    Thursday, August 31, 2017 10:06 AM
  • Hi,

    Do you test the current code on other operating system( windows 7 or 10 )?

    if the situation doesn't occur on other operating system, you can post the situation on connect website, which will handle the issue.

    I hope that you can upload a reproducing demo on one drive.

    I want to test the issue.

    Best Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, September 4, 2017 7:53 AM
  • For UWP applications, you can use DWM APIs, like DwmRegisterThumbnail() and so on

    I just tested  in C++ on Windows 10 with "Settings" window and the window is correctly copied


    • Edited by Castorix31 Monday, September 4, 2017 9:31 AM
    Monday, September 4, 2017 8:43 AM
  • I tested another method : D3DXSaveSurfaceToFile() which works on Windows 10 too

    Monday, September 4, 2017 9:19 AM
  • Hi,

    I had tested on windows 7, 8, 8.1 and 10.

    Please share the link of connect website.

    below is the code and link of the video. Please go through them.

    Video link : https://1drv.ms/f/s!ApEl74YK5mxhbE3lRyPmxtWXQjk

    Java Application : https://1drv.ms/u/s!ApEl74YK5mxhaQGrl4T9b3N5GuY

    The above link of Jar file requires Windows 7 or above, Java Runtime 1.8

    Monday, September 4, 2017 12:33 PM
  • Hi,

    >>" Please share the link of connect website. "

    https://connect.microsoft.com/ 

    Best Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, September 5, 2017 2:21 AM
  • hi

    "I tested another method : D3DXSaveSurfaceToFile() which works on Windows 10 too"

    On which application you have tested on?

    Can you capture screen of MicroSoft Excel 2016 in Windows 10?

    Also How can we get the list of open applications, as we get in task manager, under apps tab, with their HWND?


    • Edited by GauravG.2692 Tuesday, September 5, 2017 11:23 AM
    Tuesday, September 5, 2017 11:23 AM
  • hi

    "I tested another method : D3DXSaveSurfaceToFile() which works on Windows 10 too"

    On which application you have tested on?

    Can you capture screen of MicroSoft Excel 2016 in Windows 10?

    Also How can we get the list of open applications, as we get in task manager, under apps tab, with their HWND?


    Yes, I tested in C++ D3DXSaveSurfaceToFile() with "Settings" window (command : ms-settings:settings) or Excel 2016 (I set them to foreground with SwitchToThisWindow, then I call the D3DX API)

    List of applications/windows can be got with EnumWindows or EnumDesktopWindows



    • Edited by Castorix31 Tuesday, September 5, 2017 1:39 PM
    Tuesday, September 5, 2017 12:59 PM
  • Hi Hart,

    Can you share the code of C++ that you used to capture the window of Application? Also the code to get list of applications/windows?

    Thanks

    Wednesday, September 6, 2017 4:37 AM
  • Hi Hart,

    Can you share the code of C++ that you used to capture the window of Application? Also the code to get list of applications/windows?

    Thanks

    I'm not Hart :-)

    But I can post the test I did in C++ :

    In an empty Win32 window, on right click,  I search Excel and if it is found, I set the window to foreground and I call D3DXSaveSurfaceToFile() to save it into a jpg file.

    I added a test for Fullscreen because coordinates are weird (negative) in this case (maybe this part can be improved...)

    =>

    #define _CRT_SECURE_NO_WARNINGS 
    #define _CRT_NON_CONFORMING_SWPRINTFS
    
    #include <windows.h>
    #include <tchar.h>
    
    #include <d3d9.h>
    #include <d3dx9.h>
    
    #pragma comment(lib, "d3d9")
    #pragma comment(lib, "d3dx9")
    
    #include <DxErr.h>
    #pragma comment(lib, "legacy_stdio_definitions.lib")
    #pragma comment(lib, "dxerr.lib")
    
    #define	ErrorMessage(x)		MessageBox(NULL, x, L"Error", MB_OK | MB_ICONERROR)
    #define	InfoMessage(x)		MessageBox(NULL, x, L"Information", MB_OK | MB_ICONINFORMATION)
    HINSTANCE hInst;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    BOOL WINAPI EnumWindowsProc(HWND hWnd, LPARAM lParam);
    BOOL IsFullScreen(HWND hWnd);
    
    IDirect3D9*			g_pD3D = NULL;
    IDirect3DDevice9*	g_pd3dDevice = NULL;
    IDirect3DSurface9*	g_pSurface = NULL;
    
    #define	WINDOW_MODE			TRUE
    HRESULT	InitD3D(HWND hWnd);
    void CleanupD3D();
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
    	HINSTANCE hPrevInstance,
    	LPTSTR    lpCmdLine,
    	int       nCmdShow)
    {
    	hInst = hInstance;
    	WNDCLASSEX wcex =
    	{
    		sizeof(WNDCLASSEX), 0, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
    		LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, L"D3DX", NULL
    	};
    	if (!RegisterClassEx(&wcex))
    		return ErrorMessage(L"Cannot register class !");
    	int nX = (GetSystemMetrics(SM_CXSCREEN) - 300) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - 200) / 2;
    	HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, L"D3DX Screen Capture", WS_OVERLAPPEDWINDOW, nX, nY, 300, 200, NULL, NULL, hInst, NULL);
    	if (!hWnd)
    		return ErrorMessage(L"Cannot create window !");
    	ShowWindow(hWnd, SW_SHOWNORMAL);
    	UpdateWindow(hWnd);
    	MSG msg;
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return (int)msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	PAINTSTRUCT ps;
    	HDC hdc;	
    
    	switch (message)
    	{
    	case WM_CREATE:
    	{
    		if (FAILED(InitD3D(hWnd)))
    			return -1;
    	}
    	break;
    	case WM_RBUTTONDOWN:
    	{
    		HRESULT hr = E_UNEXPECTED;
    		HWND hWndTarget = NULL;
    		//hWndTarget = FindWindow(L"XLMAIN", NULL);
    		EnumDesktopWindows(NULL, EnumWindowsProc, (LPARAM)&hWndTarget);
    		if (hWndTarget)
    		{
    			RECT rect;
    			if (IsFullScreen(hWndTarget))
    			{
    				GetClientRect(GetDesktopWindow(), &rect);
    				HWND hWndTaskbar = FindWindow(L"Shell_TrayWnd", NULL);
    				if (hWndTaskbar)
    				{
    					APPBARDATA abd;
    					abd.cbSize = sizeof(APPBARDATA);
    					abd.hWnd = hWndTaskbar;
    					SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
    					DWORD dwState = (DWORD)SHAppBarMessage(ABM_GETSTATE, &abd);
    					if (!dwState)
    					{
    						if (abd.uEdge == ABE_BOTTOM)
    						{
    							rect.bottom -= abd.rc.bottom - abd.rc.top;
    						}
    						else if (abd.uEdge == ABE_TOP)
    						{
    							rect.top += abd.rc.bottom - abd.rc.top;
    						}
    						else if (abd.uEdge == ABE_LEFT)
    						{
    							rect.left += abd.rc.right - abd.rc.left;
    						}
    						else if (abd.uEdge == ABE_RIGHT)
    						{
    							rect.right -= abd.rc.right - abd.rc.left;
    						}						
    					}
    				}				
    			}
    			else
    				GetWindowRect(hWndTarget, &rect);
    			void (FAR STDAPICALLTYPE * pSTTW)(HWND hWnd, BOOL bAltTab);
    			HINSTANCE hInst = LoadLibrary(L"USER32.DLL");
    			if (hInst)
    			{
    				(FARPROC&)pSTTW = GetProcAddress(hInst, "SwitchToThisWindow");
    				if (pSTTW != NULL)
    					pSTTW(hWndTarget, TRUE);
    				Sleep(200);
    
    				hr = g_pd3dDevice->GetFrontBufferData(0, g_pSurface);
    				if (SUCCEEDED(hr))
    				{
    					WCHAR wszFileName[MAX_PATH] = L"C:\\test.jpg";
    					hr = D3DXSaveSurfaceToFile(wszFileName, D3DXIFF_JPG, g_pSurface, NULL, &rect);
    					pSTTW(hWnd, TRUE);
    					if (SUCCEEDED(hr))
    					{
    						WCHAR wsMessage[MAX_PATH] = L"";
    						wsprintf(wsMessage, L"Screenshot saved as : \n%s", wszFileName);
    						InfoMessage(wsMessage);
    					}
    					else
    					{
    						WCHAR wsError[255] = L"", wsErrorMessage[255] = L"";
    						swprintf(wsErrorMessage, L"Error: %s - Error description : %s", DXGetErrorString(hr), DXGetErrorDescription(hr));
    						swprintf(wsError, L"Error saving front buffer to file (%s)\n", wsErrorMessage);
    						ErrorMessage(wsError);
    					}
    				}
    				pSTTW(hWnd, TRUE);
    				FreeLibrary(hInst);
    			}			
    		}
    		else
    			ErrorMessage(L"Window not found !");
    	}
    	break;
    	
    	case WM_PAINT:
    		hdc = BeginPaint(hWnd, &ps);
    		EndPaint(hWnd, &ps);
    		break;
    	case WM_DESTROY:
    		CleanupD3D();
    		PostQuitMessage(0);
    		break;
    	default:
    		return DefWindowProc(hWnd, message, wParam, lParam);
    	}
    	return 0;
    }
    
    BOOL WINAPI EnumWindowsProc(HWND hWnd, LPARAM lParam)
    {
    	WCHAR szClass[32];
    	GetClassName(hWnd, szClass, ARRAYSIZE(szClass));
    	HWND *phWnd = (HWND*)lParam;
    	if (wcscmp(szClass, L"XLMAIN") == 0)
    	{
    		if (phWnd)
    			*phWnd = hWnd;
    		return FALSE;
    	}
    	return TRUE;
    }
    
    HRESULT	InitD3D(HWND hWnd)
    {
    	D3DDISPLAYMODE	ddm;
    	D3DPRESENT_PARAMETERS	d3dpp;
    
    	if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
    	{
    		ErrorMessage(L"Unable to Create Direct3D ");
    		return E_FAIL;
    	}
    
    	if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ddm)))
    	{
    		ErrorMessage(L"Unable to Get Adapter Display Mode");
    		return E_FAIL;
    	}
    
    	ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));
    
    	d3dpp.Windowed = WINDOW_MODE;
    	d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    	d3dpp.BackBufferFormat = ddm.Format;
    	d3dpp.BackBufferHeight = ddm.Height;
    	d3dpp.BackBufferWidth = ddm.Width;
    	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    	d3dpp.hDeviceWindow = hWnd;
    	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
    	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
    
    	if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice)))
    	{
    		ErrorMessage(L"Unable to Create Device");
    		return E_FAIL;
    	}
    
    	if (FAILED(g_pd3dDevice->CreateOffscreenPlainSurface(ddm.Width, ddm.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &g_pSurface, NULL)))
    	{
    		ErrorMessage(L"Unable to Create Surface");
    		return E_FAIL;
    	}
    
    	return S_OK;
    }
    
    BOOL IsFullScreen(HWND hWnd)
    {
    	RECT rc;
    	GetWindowRect(hWnd, &rc);
    	if ((rc.left <= 0 || rc.top <= 0) && (rc.right >= GetSystemMetrics(SM_CXFULLSCREEN)) && (rc.bottom >= GetSystemMetrics(SM_CYFULLSCREEN)))
    		return TRUE;
    	return FALSE;
    }
    
    void CleanupD3D()
    {
    	if (g_pSurface)
    	{
    		g_pSurface->Release();
    		g_pSurface = NULL;
    	}
    	if (g_pd3dDevice)
    	{
    		g_pd3dDevice->Release();
    		g_pd3dDevice = NULL;
    	}
    	if (g_pD3D)
    	{
    		g_pD3D->Release();
    		g_pD3D = NULL;
    	}
    }

    • Edited by Castorix31 Wednesday, September 6, 2017 11:41 AM
    Wednesday, September 6, 2017 11:35 AM
  • Hi,

    Were you able to figure out what went wrong or why the code mentioned in the link below, shared by Hart, is not getting the desired output? As you are bringing the window to foreground and then saving it to an image.

    The need of the our is to get images of all the open application, even if any or all of them is in minimised state.

    Link :

    https://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

    Thanks

    • Edited by GauravG.2692 Thursday, September 7, 2017 10:34 AM
    Thursday, September 7, 2017 10:31 AM
  • Were you able to figure out what went wrong or why the code mentioned in the link below, shared by Hart, is not getting the desired output? As you are bringing the window to foreground and then saving it to an image.

    The need of the our is to get images of all the open application, even if any or all of them is in minimised state.

    Link :https://msdn.microsoft.com/en-us/library/windows/desktop/dd183402(v=vs.85).aspx

    This won't work with UWP applications

    To get images (in a window) of all applications without setting them to foreground, the first method works (DwmRegisterThumbnail(), DwmQueryThumbnailSourceSize(), DwmUpdateThumbnailProperties())

    Thursday, September 7, 2017 11:33 AM
  • Hi,

    I am facing some issue with the code shared by you, using DirectX, as it couldn't find some header files while working in Windows 10. I am still working on it to find a way out.

    Out of curiosity, i would like to ask you if this code will be functional on all Windows OS i.e. Windows 7, Windows 8, Windows 8.1, Windows 10 and other upcoming releases? Have you tested it on all these Windows OS?

    Thursday, September 14, 2017 11:43 AM
  • The headers I use are from the Microsoft DirectX SDK (June 2010)
    I used D3DXSaveSurfaceToFile() in a freeware to capture a game screenshots, from XP to Windows 10.
    Thursday, September 14, 2017 12:23 PM