1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
putty-source/windows/utils/screenshot.c

127 lines
3.7 KiB
C
Raw Normal View History

#include "putty.h"
#if HAVE_DWMAPI_H
#include <dwmapi.h>
char *save_screenshot(HWND hwnd, Filename *outfile)
{
HDC dcWindow = NULL, dcSave = NULL;
HBITMAP bmSave = NULL;
uint8_t *buffer = NULL;
char *err = NULL;
static HMODULE dwmapi_module;
DECL_WINDOWS_FUNCTION(static, HRESULT, DwmGetWindowAttribute,
(HWND, DWORD, PVOID, DWORD));
if (!dwmapi_module) {
dwmapi_module = load_system32_dll("dwmapi.dll");
GET_WINDOWS_FUNCTION(dwmapi_module, DwmGetWindowAttribute);
}
dcWindow = GetDC(NULL);
if (!dcWindow) {
err = dupprintf("GetDC(window): %s", win_strerror(GetLastError()));
goto out;
}
int x, y, w, h;
RECT wr;
/* Use DwmGetWindowAttribute in place of GetWindowRect to exclude
* drop shadow, otherwise we get a load of unwanted desktop
* background under the shadow */
if (p_DwmGetWindowAttribute &&
0 <= p_DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
&wr, sizeof(wr))) {
x = wr.left;
y = wr.top;
w = wr.right - wr.left;
h = wr.bottom - wr.top;
} else {
BITMAP bmhdr;
memset(&bmhdr, 0, sizeof(bmhdr));
GetObject(GetCurrentObject(dcWindow, OBJ_BITMAP),
sizeof(bmhdr), &bmhdr);
x = y = 0;
w = bmhdr.bmWidth;
h = bmhdr.bmHeight;
}
dcSave = CreateCompatibleDC(dcWindow);
if (!dcSave) {
err = dupprintf("CreateCompatibleDC(desktop window dc): %s",
win_strerror(GetLastError()));
goto out;
}
bmSave = CreateCompatibleBitmap(dcWindow, w, h);
if (!bmSave) {
err = dupprintf("CreateCompatibleBitmap: %s",
win_strerror(GetLastError()));
goto out;
}
if (!SelectObject(dcSave, bmSave)) {
err = dupprintf("SelectObject: %s", win_strerror(GetLastError()));
goto out;
}
if (!BitBlt(dcSave, 0, 0, w, h, dcWindow, x, y, SRCCOPY)) {
err = dupprintf("BitBlt: %s", win_strerror(GetLastError()));
goto out;
}
BITMAPINFO bmInfo;
memset(&bmInfo, 0, sizeof(bmInfo));
bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
bmInfo.bmiHeader.biWidth = w;
bmInfo.bmiHeader.biHeight = h;
bmInfo.bmiHeader.biPlanes = 1;
bmInfo.bmiHeader.biBitCount = 32;
bmInfo.bmiHeader.biCompression = BI_RGB;
size_t bmPixels = (size_t)w*h, bmBytes = bmPixels * 4;
buffer = snewn(bmBytes, uint8_t);
if (!GetDIBits(dcWindow, bmSave, 0, h, buffer, &bmInfo, DIB_RGB_COLORS))
err = dupprintf("GetDIBits (get data): %s",
win_strerror(GetLastError()));
FILE *fp = f_open(outfile, "wb", false);
if (!fp) {
err = dupprintf("'%s': unable to open file", filename_to_str(outfile));
goto out;
}
BITMAPFILEHEADER bmFileHdr;
bmFileHdr.bfType = 'B' | ('M' << 8);
bmFileHdr.bfSize = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader) + bmBytes;
bmFileHdr.bfOffBits = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader);
fwrite((void *)&bmFileHdr, 1, sizeof(bmFileHdr), fp);
fwrite((void *)&bmInfo.bmiHeader, 1, sizeof(bmInfo.bmiHeader), fp);
fwrite((void *)buffer, 1, bmBytes, fp);
fclose(fp);
out:
if (dcWindow)
ReleaseDC(NULL, dcWindow);
if (bmSave)
DeleteObject(bmSave);
if (dcSave)
DeleteObject(dcSave);
sfree(buffer);
return err;
}
#else /* HAVE_DWMAPI_H */
/* Without <dwmapi.h> we can't get the right window rectangle */
char *save_screenshot(HWND hwnd, Filename *outfile)
{
return dupstr("Demo screenshots not compiled in to this build");
}
#endif /* HAVE_DWMAPI_H */