BitBlt not working for Office 2013 - c++

I'm using BitBlt to get screenshots of windows on a user's desktop. I've found that all works well for windows from most programs. However, BitBlt returns blank pixels for any Office 2013 windows (Word, Powerpoint, etc).
PrintWindow does work for these Office 2013 windows, but it has higher processor overhead. I'd rather use BitBlt if possible.
Any ideas why BitBlt would not work with Office 2013 windows?
Code snippet below.
Thanks
UPDATE: BitBlt(...) returns true. Changing code to capture entire desktop instead of appWin captures the Office 2013 window correctly, see this post. I can capture the whole desktop and extract the desired window. However, this loses one cool thing with the new DWM that allows the software to capture images from windows that are not in the foreground.
Is there a better way to do this that will allow the system to both capture Office 2013 type windows AND capture images from windows not in the foreground?
UPDATE 2: When doing the BitBlt on the appWin, it looks like the first BitBlt gives valid pixel data, but subsequent BitBlts give blank pixels. Not sure why but may be an important data point.
INT texUSize = 1024;
INT texVSize = 1024;
RECT rect;
GetClientRect(appWin, &rect);
INT appW = rect.right - rect.left;
INT appH = rect.bottom - rect.top;
// create BITMAP in memory, write to texture pixels from BITMAP
HDC hdc = GetDC(appWin);
HDC hdc_App = CreateCompatibleDC(hdc);
HDC hdc_Tex = CreateCompatibleDC(hdc);
HBITMAP hbmp_App = CreateCompatibleBitmap(hdc, appW, appH);
HBITMAP hbmp_Tex = CreateCompatibleBitmap(hdc, texUSize, texVSize);
HBITMAP hbmp_AppOld = (HBITMAP)SelectObject(hdc_App, hbmp_App);
HBITMAP hbmp_TexOld = (HBITMAP)SelectObject(hdc_Tex, hbmp_Tex);
// Due to the new Desktop Window Manager, Windows Vista and Windows 7 can simply BitBlt the app window
// Windows XP has issues with BitBlt if app window is covered by a different window
if (false)//bVista7 || (GetForegroundWindow() == appWin))
{
appOutputDebugStringf(TEXT("-- bitblting"));
BitBlt(hdc_App, 0, 0, appW, appH, hdc, 0, 0, SRCCOPY);
}
else
{
appOutputDebugStringf(TEXT("-- printwindow"));
PrintWindow(appWin, hdc_App, NULL);
}

Related

How to get the "display stream" of a MS Windows window?

I have a program (we will call it the "virtual screen") that create a full screen window and start arbitrary programs, and with the help of hooks (CBTProc) get handles to windows that started programs create. From those handles I retrieve the content of the windows (using GetDIBits) and displays it in the "virtual screen" window.
Currently, this "virtual screen" copy content of windows and then redraw them, which make it work, sort of like a mirroring software.
Here is how I get the content of a window:
struct WindowContent {
void *pixel;
int width;
int height;
};
WindowContent getWindowContent(HWND hWnd, int height, int width)
{
WindowContent content;
WINDOWINFO windowInfo;
GetWindowInfo(hWnd, &windowInfo);
content.height = windowInfo.rcClient.right - windowInfo.rcClient.left;
content.width = windowInfo.rcClient.bottom - windowInfo.rcClient.top;
HDC hdc = GetDC(hWnd);
HDC captureHdc = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, content.width, content.height);
HGDIOBJ oldHdc = SelectObject(captureHdc, hBitmap);
BitBlt(captureHdc, 0, 0, content.width, content.height, hdc, 0, 0, SRCCOPY|CAPTUREBLT);
SelectObject(captureHdc, oldHdc);
DeleteDC(captureHdc);
BITMAPINFO outputBitmapInfo = {};
outputBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hdc, hBitmap, 0, 0, NULL, &outputBitmapInfo, DIB_RGB_COLORS);
content.pixel = (BYTE *)malloc(outputBitmapInfo.bmiHeader.biSizeImage);
outputBitmapInfo.bmiHeader.biCompression = BI_RGB;
outputBitmapInfo.bmiHeader.biBitCount = 32;
GetDIBits(hdc, hBitmap, 0, outputBitmapInfo.bmiHeader.biHeight, content.pixel, &outputBitmapInfo, DIB_RGB_COLORS);
return content;
}
My question is, how do I remove the copying part, how can I make an area on my "virtual screen" the window output for those programs ?
Emphasis on the fact that I'm trying to make created windows be the area on the "virtual screen", I don't want an additional window hidden or living on the desktop.
In my research, I've looked into Windows DWM DLLs and found some undocumented function (SignalRedirectionStartComplete or MilConnection_CreateChannel) which names look linked to what I want to do, but I don't think I should use them, as they are undocumented.
Also, the code is using Win32 API but I don't mind using another Windows API or another language (C#, DX* ...).
Forgot to mention, I have already thought about using the DWM thumbnail stuff, but it's not that reliable enough for what I'm trying to do.
As far as I understand Windows 10 uses DX under the hood for all display output, for GDI, and even for Vulkan / OpenGL programs, and someone used it to make a lib that
gets DX 10 texture from a window (). Is it possible to make something similar, that, for a specific HWND, set its "output" to a texture or some region in
memory (swapchain redirection ?) instead of the screen and then display the output in another program (in my case, on the "virtual screen" window) ?
The DWM was a reasonable place to look. It has some documented functions to get you at least a little closer to what you want.
You can register your window as a "thumbnail" viewer using DwmRegisterThumbnail. Then you (probably) call DwmUpdateThumbnailProperties to tell it how to draw to your window (e.g., set opacity, rectangle to draw to, and whether to draw the whole source window, or just its client area). When you're done, you call DwmUnregisterThumbnail to unhook from displaying it.
This is only a little closer to what you want though--it eliminates your having to copy bitmaps from the source into your own window--but that's about all it does. The target application will still have its own window running elsewhere.
If you want to do more to hide the application, you could create another desktop, and display the application in that desktop. If you don't provide a way to switch desktops, that can keep it pretty well hidden. On the other hand, there are external tools that will let the user change desktops, which would let them see the application directly.
One other avenue to consider (for a subset of applications) would be COM. Part of what COM supports is having a COM server that displays its output inside the frame of some COM client's window. That's no longer nearly the big thing it once was, but (I believe) all the code to support it is still available. But, it only works for applications that are specifically written to support it (which, honestly, isn't a huge number). The code for this isn't exactly trivial either.

How to capture screen window content of Metro/UWP app in Windows 8.1/Windows 10?

I'm developing a software which capture hidden screen window content of Metro/UWP app in Windows 8.1/Windows 10.
It look very much like below:
Target overlapped window to capture
Currently, I used the code of GetWindowDC(hwnd) as below. I can capture overlapped window in Win32 app.
DC hDC = GetWindowDC(hwnd);
BitBlt(BitmapDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY /* |CAPTUREBLT */);
ReleaseDC(hDC, hDC);
But I cannot capture overlapped window on UWP application on Windows 10:
Capture result
I already tried to solve this problem by using GDI/GDI+ and DirectX but unsuccessfully.
Could you please support me to solve this touch problem?
Best regards,
Le Le

Cannot capture IE11, MS Word 2013 with single window on Win 8.1

I have a issue related to capture a specific window. I used getWindowDC(hwnd) on window 7. Almost of them are OK.
But I captured IE11, MS Word 2013 on window 8.1, content of images are white images. I think because IE11, MS Office 2013 on Windows 8.1 is using non-GDI technology, the capture cannot get correctly, is that right?
I would like to capture a specific window on Windows 8.1 or Windows 10, but I cannot find other API can replace getWindowDC(hwnd).
I used the code of GetWindowDC(hwnd) as below:
DC hDC = GetWindowDC(hwnd);
BitBlt(BitmapDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY /* |CAPTUREBLT */);
ReleaseDC(hDC, hDC);
image captured:

How can i copy the visual content of a window and put it on a new window in win32 c++?

I've read something about GetDIBits or BitBlt but i do not understand them.
That could be because i don't understand how Windows actually handles graphics on windows. It would be perfect if someone could refer me to a page where i could learn about these things! :)
I solved the problem using this code in the windows WM_PAINT. It now shows the exact same content as the target window.
PAINTSTRUCT ps;
HDC hdc = BeginPaint(MainWindow, &ps);
HDC TargetDC = GetDC(TargetWindow);
RECT rect;
GetWindowRect(TargetWindow, &rect);
BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,TargetDC,0,0,SRCCOPY);
EndPaint(MainWindow, &ps);
You might have some luck with sending the window a WM_PRINTCLIENT message. This may not work well for windows that use DirectX or OpenGL.
You may have some issues using WM_PRINTCLIENT on systems that have Aero enabled (i.e. when the DWM is active). If the system DOES have DWM active then it may offer ways of getting at the window backing store but I have not looked into doing that in any great depth before.
What you want is to:
Get a HWND to the window of which you want the pixels.
Create a memory DC of the correct size (check this out).
Send a WM_PRINTCLIENT or WM_PAINT to the window whilst supplying your memory DC (not all controls/windows implement this though)
Copy the contents of your memory DC to screen
Alternatively for step 3 you can use the DWM or get hacky using the clipboard:
void CopyWndToClipboard(CWnd *pWnd)
{
CBitmap bitmap;
CClientDC dc(pWnd);
CDC memDC;
CRect rect;
memDC.CreateCompatibleDC(&dc);
pWnd->GetWindowRect(rect);
bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height());
CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);
pWnd->OpenClipboard() ;
EmptyClipboard() ;
SetClipboardData(CF_BITMAP, bitmap.GetSafeHandle()) ;
CloseClipboard() ;
memDC.SelectObject(pOldBitmap);
bitmap.Detach();
}

CreateCompatibleBitmap failing on Windows mobile 6

I'm porting an application from Windows Mobile 2003 to Windows Mobile 6, under Visual Studio 2008. The target device has a VGA resolution screen, and I was surprised to find that the following code fails;
CClientDC ClientDC(this);
CRect Rect;
GetClientRect(&Rect);
int nWidth = Rect.Width(),nHeight = Rect.Height();
CBitmap Temp;
if (!Temp.CreateCompatibleBitmap(&ClientDC,nWidth,nHeight))
{
LogError(elvl_Debug,_T("Error creating bitmap (%s)"),LastSysError());
} else
{
BITMAP bmpinfo;
Temp.GetBitmap(&bmpinfo);
}
The return code from CreateCompatibleBitmap is 8, which translates to 'Not enough memory to process command. nWidth is 350, nHeight is 400, and the display is 16 bits per pixel, so my bitmap is a whopping 280K. The device I'm using has 256mb of program memory, and I've told the linker to reserve 4mb of stack and 64mb of heap. Any ideas what I'm doing wrong, and more importantly a solution? I've been using code similar to the above on Windows CE since CE 2.1 with no problems.
Edit: As per Josh Kelly's post, I moved to device independent bitmaps which works fine on the device. Code is now something like this
CClientDC ClientDC(this);
CRect Rect;
GetClientRect(&Rect);
int nWidth = Rect.Width(),nHeight = Rect.Height();
BITMAPINFOHEADER bmi = { sizeof(bmi) };
bmi.biWidth = nWidth;
bmi.biHeight = nHeight;
bmi.biPlanes = 1;
bmi.biBitCount = 8;
HDC hdc = CreateCompatibleDC(NULL);
BYTE* pbData = 0;
HBITMAP DIB = CreateDIBSection(hdc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&pbData, NULL, 0);
CBitmap *pTempBitmap = CBitmap::FromHandle(DIB);
I haven't done any Windows CE / Windows Mobile programming, but I have dealt with a similar problem (CreateCompatibleBitmap failing with ERROR_NOT_ENOUGH_MEMORY) in desktop Windows. Apparently, from what I've been able to tell from looking around online, Windows may enforce global limitations on the available memory for device dependent bitmaps. (For example, some video drivers may choose to store device dependent bitmaps in video RAM, in which case you're limited by how much RAM is on your video card.) See, for example, this thread. From what I can tell, these limits are determined by the individual video cards or drivers; some computers' storage may be effectively unlimited, others may have strict limits.
One solution is to use device independent bitmaps instead, even though they have a slight performance penalty.