1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 18:07:59 +00:00
putty-source/windows/utils/screenshot.c
Simon Tatham bc7e06c494 Windows tools: assorted '-demo' options.
Using a new screenshot-taking module I just added in windows/utils,
these new options allow me to start up one of the tools with
demonstration window contents and automatically save a .BMP screenshot
to disk. This will allow me to keep essentially the same set of demo
images and update them easily to keep pace with the current appearance
of the real tools as PuTTY - and Windows itself - both evolve.
2022-04-02 17:23:34 +01:00

127 lines
3.6 KiB
C

#include "putty.h"
#if HAVE_DWMAPI_H
#include <dwmapi.h>
char *save_screenshot(HWND hwnd, const char *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 = fopen(outfile, "wb");
if (!fp) {
err = dupprintf("'%s': unable to open file", 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, const char *outfile)
{
return dupstr("Demo screenshots not compiled in to this build");
}
#endif /* HAVE_DWMAPI_H */