1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/windows/utils/screenshot.c
Simon Tatham 74150633f1 Add and use cmdline_arg_to_filename().
Converting a CmdlineArg straight to a Filename allows us to make the
filename out of the wide-character version of the string on Windows.
So now filenames specified on the command line should generally be
able to handle pathnames containing Unicode characters not in the
system code page.

This change also involves making some char pointers _into_ Filename
structs where they weren't previously: for example, the
'openssh_config_file' variable in Windows Pageant's WinMain().
2024-09-26 11:30:07 +01:00

127 lines
3.7 KiB
C

#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 */