screenshot.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include "putty.h"
  2. #if HAVE_DWMAPI_H
  3. #include <dwmapi.h>
  4. char *save_screenshot(HWND hwnd, Filename *outfile)
  5. {
  6. HDC dcWindow = NULL, dcSave = NULL;
  7. HBITMAP bmSave = NULL;
  8. uint8_t *buffer = NULL;
  9. char *err = NULL;
  10. static HMODULE dwmapi_module;
  11. DECL_WINDOWS_FUNCTION(static, HRESULT, DwmGetWindowAttribute,
  12. (HWND, DWORD, PVOID, DWORD));
  13. if (!dwmapi_module) {
  14. dwmapi_module = load_system32_dll("dwmapi.dll");
  15. GET_WINDOWS_FUNCTION(dwmapi_module, DwmGetWindowAttribute);
  16. }
  17. dcWindow = GetDC(NULL);
  18. if (!dcWindow) {
  19. err = dupprintf("GetDC(window): %s", win_strerror(GetLastError()));
  20. goto out;
  21. }
  22. int x, y, w, h;
  23. RECT wr;
  24. /* Use DwmGetWindowAttribute in place of GetWindowRect to exclude
  25. * drop shadow, otherwise we get a load of unwanted desktop
  26. * background under the shadow */
  27. if (p_DwmGetWindowAttribute &&
  28. 0 <= p_DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS,
  29. &wr, sizeof(wr))) {
  30. x = wr.left;
  31. y = wr.top;
  32. w = wr.right - wr.left;
  33. h = wr.bottom - wr.top;
  34. } else {
  35. BITMAP bmhdr;
  36. memset(&bmhdr, 0, sizeof(bmhdr));
  37. GetObject(GetCurrentObject(dcWindow, OBJ_BITMAP),
  38. sizeof(bmhdr), &bmhdr);
  39. x = y = 0;
  40. w = bmhdr.bmWidth;
  41. h = bmhdr.bmHeight;
  42. }
  43. dcSave = CreateCompatibleDC(dcWindow);
  44. if (!dcSave) {
  45. err = dupprintf("CreateCompatibleDC(desktop window dc): %s",
  46. win_strerror(GetLastError()));
  47. goto out;
  48. }
  49. bmSave = CreateCompatibleBitmap(dcWindow, w, h);
  50. if (!bmSave) {
  51. err = dupprintf("CreateCompatibleBitmap: %s",
  52. win_strerror(GetLastError()));
  53. goto out;
  54. }
  55. if (!SelectObject(dcSave, bmSave)) {
  56. err = dupprintf("SelectObject: %s", win_strerror(GetLastError()));
  57. goto out;
  58. }
  59. if (!BitBlt(dcSave, 0, 0, w, h, dcWindow, x, y, SRCCOPY)) {
  60. err = dupprintf("BitBlt: %s", win_strerror(GetLastError()));
  61. goto out;
  62. }
  63. BITMAPINFO bmInfo;
  64. memset(&bmInfo, 0, sizeof(bmInfo));
  65. bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
  66. bmInfo.bmiHeader.biWidth = w;
  67. bmInfo.bmiHeader.biHeight = h;
  68. bmInfo.bmiHeader.biPlanes = 1;
  69. bmInfo.bmiHeader.biBitCount = 32;
  70. bmInfo.bmiHeader.biCompression = BI_RGB;
  71. size_t bmPixels = (size_t)w*h, bmBytes = bmPixels * 4;
  72. buffer = snewn(bmBytes, uint8_t);
  73. if (!GetDIBits(dcWindow, bmSave, 0, h, buffer, &bmInfo, DIB_RGB_COLORS))
  74. err = dupprintf("GetDIBits (get data): %s",
  75. win_strerror(GetLastError()));
  76. FILE *fp = f_open(outfile, "wb", false);
  77. if (!fp) {
  78. err = dupprintf("'%s': unable to open file", filename_to_str(outfile));
  79. goto out;
  80. }
  81. BITMAPFILEHEADER bmFileHdr;
  82. bmFileHdr.bfType = 'B' | ('M' << 8);
  83. bmFileHdr.bfSize = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader) + bmBytes;
  84. bmFileHdr.bfOffBits = sizeof(bmFileHdr) + sizeof(bmInfo.bmiHeader);
  85. fwrite((void *)&bmFileHdr, 1, sizeof(bmFileHdr), fp);
  86. fwrite((void *)&bmInfo.bmiHeader, 1, sizeof(bmInfo.bmiHeader), fp);
  87. fwrite((void *)buffer, 1, bmBytes, fp);
  88. fclose(fp);
  89. out:
  90. if (dcWindow)
  91. ReleaseDC(NULL, dcWindow);
  92. if (bmSave)
  93. DeleteObject(bmSave);
  94. if (dcSave)
  95. DeleteObject(dcSave);
  96. sfree(buffer);
  97. return err;
  98. }
  99. #else /* HAVE_DWMAPI_H */
  100. /* Without <dwmapi.h> we can't get the right window rectangle */
  101. char *save_screenshot(HWND hwnd, Filename *outfile)
  102. {
  103. return dupstr("Demo screenshots not compiled in to this build");
  104. }
  105. #endif /* HAVE_DWMAPI_H */