make sure GetDIBits() failures are reported
[imager-screenshot.git] / scwin32.c
CommitLineData
0ddb7051
TC
1#include "imext.h"
2#include <windows.h>
3#include <string.h>
87cd516f 4#include "imss.h"
0ddb7051
TC
5
6i_img *
87cd516f 7imss_win32(unsigned hwnd_u, int include_decor, int left, int top,
4e6ce56a 8 int right, int bottom, int display) {
0ddb7051 9 HWND hwnd = (HWND)hwnd_u;
4e6ce56a 10 HDC cdc = 0, wdc, bmdc;
0ddb7051 11 HBITMAP work_bmp, old_dc_bmp;
4e6ce56a
TC
12 int orig_x = 0;
13 int orig_y = 0;
87cd516f 14 int window_width, window_height;
0ddb7051
TC
15 BITMAPINFO bmi;
16 unsigned char *di_bits;
17 i_img *result = NULL;
87cd516f 18 int width, height;
0ddb7051
TC
19
20 i_clear_error();
21
4e6ce56a
TC
22 if (hwnd) {
23 RECT rect;
24 if (include_decor) {
25 wdc = GetWindowDC(hwnd);
26 GetWindowRect(hwnd, &rect);
27 }
28 else {
29 wdc = GetDC(hwnd);
30 GetClientRect(hwnd, &rect);
31 }
32 if (!wdc) {
33 i_push_error(0, "Cannot get window DC - invalid hwnd?");
34 return NULL;
35 }
0ddb7051 36
4e6ce56a
TC
37 window_width = rect.right - rect.left;
38 window_height = rect.bottom - rect.top;
0ddb7051
TC
39 }
40 else {
4e6ce56a 41 if (display == -1) {
4e6ce56a
TC
42 cdc = CreateDC("DISPLAY", NULL, NULL, NULL);
43 orig_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
44 orig_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
45 window_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
46 window_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
47 }
48 else {
49 DISPLAY_DEVICE dd;
50 dd.cb = sizeof(dd);
0ddb7051 51
4e6ce56a 52 if (EnumDisplayDevices(NULL, display, &dd, 0)) {
f7119376
TC
53 if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) {
54 cdc = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
55 }
56 else {
57 i_push_errorf(0, "Display device %d not active", display);
58 return NULL;
59 }
4e6ce56a
TC
60 }
61 else {
62 i_push_errorf(0, "Cannot enumerate device %d: %ld", display, (long)GetLastError());
63 return NULL;
64 }
65
66 window_width = GetDeviceCaps(cdc, HORZRES);
67 window_height = GetDeviceCaps(cdc, VERTRES);
68 }
69
70 wdc = cdc;
71 }
87cd516f
TC
72
73 /* adjust negative/zero values to window size */
74 if (left < 0)
75 left += window_width;
76 if (top < 0)
77 top += window_height;
78 if (right <= 0)
79 right += window_width;
80 if (bottom <= 0)
81 bottom += window_height;
82
83 /* clamp */
84 if (left < 0)
85 left = 0;
86 if (right > window_width)
87 right = window_width;
88 if (top < 0)
89 top = 0;
90 if (bottom > window_height)
91 bottom = window_height;
92
93 /* validate */
94 if (right <= left || bottom <= top) {
95 i_push_error(0, "image would be empty");
f7119376
TC
96 if (cdc)
97 DeleteDC(cdc);
98 else
99 ReleaseDC(hwnd, wdc);
87cd516f
TC
100 return NULL;
101 }
102 width = right - left;
103 height = bottom - top;
104
0ddb7051
TC
105 work_bmp = CreateCompatibleBitmap(wdc, width, height);
106 bmdc = CreateCompatibleDC(wdc);
107 old_dc_bmp = SelectObject(bmdc, work_bmp);
4e6ce56a 108 BitBlt(bmdc, 0, 0, width, height, wdc, orig_x + left, orig_y + top, SRCCOPY);
0ddb7051
TC
109
110 /* make a dib */
111 memset(&bmi, 0, sizeof(bmi));
112 bmi.bmiHeader.biSize = sizeof(bmi);
113 bmi.bmiHeader.biWidth = width;
114 bmi.bmiHeader.biHeight = -height;
115 bmi.bmiHeader.biPlanes = 1;
116 bmi.bmiHeader.biBitCount = 32;
117 bmi.bmiHeader.biCompression = BI_RGB;
118
119 di_bits = mymalloc(4 * width * height);
120 if (GetDIBits(bmdc, work_bmp, 0, height, di_bits, &bmi, DIB_RGB_COLORS)) {
0ddb7051
TC
121 result = i_img_8_new(width, height, 3);
122
f7119376
TC
123 if (result) {
124 i_color *line = mymalloc(sizeof(i_color) * width);
125 i_color *cp;
126 int x, y;
127 unsigned char *ch_pp = di_bits;
128 for (y = 0; y < height; ++y) {
129 cp = line;
130 for (x = 0; x < width; ++x) {
131 cp->rgb.b = *ch_pp++;
132 cp->rgb.g = *ch_pp++;
133 cp->rgb.r = *ch_pp++;
134 ch_pp++;
135 cp++;
136 }
137 i_plin(result, 0, width, y, line);
0ddb7051 138 }
f7119376 139 myfree(line);
0ddb7051 140 }
0ddb7051 141 }
925cac26
TC
142 else {
143 i_push_errorf(0, "GetDIBits() failure %d", (long)GetLastError());
144 }
0ddb7051 145
62b84c46
TC
146 i_tags_setn(&result->tags, "ss_window_width", window_width);
147 i_tags_setn(&result->tags, "ss_window_height", window_height);
148 i_tags_set(&result->tags, "ss_type", "Win32", 5);
149 i_tags_setn(&result->tags, "ss_left", left);
150 i_tags_setn(&result->tags, "ss_top", top);
151
0ddb7051
TC
152 /* clean up */
153 myfree(di_bits);
154 SelectObject(bmdc, old_dc_bmp);
155 DeleteDC(bmdc);
156 DeleteObject(work_bmp);
4e6ce56a
TC
157
158 if (cdc) {
159 DeleteDC(cdc);
160 }
161 else {
162 ReleaseDC(hwnd, wdc);
163 }
0ddb7051
TC
164
165 return result;
166}