- Move NCI generated files to arch-specific directories
[reactos.git] / rosapps / screenshot / screenshot.c
1 #include "screenshot.h"
2
3 /*
4 * Save a screenshot to file until the clipboard
5 * is ready to accept images.
6 */
7
8
9 static VOID
10 GetError(VOID)
11 {
12 LPVOID lpMsgBuf;
13
14 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
15 FORMAT_MESSAGE_FROM_SYSTEM |
16 FORMAT_MESSAGE_IGNORE_INSERTS,
17 NULL,
18 GetLastError(),
19 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
20 (LPTSTR) &lpMsgBuf,
21 0,
22 NULL );
23
24 MessageBox(NULL,
25 lpMsgBuf,
26 _T("Error!"),
27 MB_OK | MB_ICONERROR);
28
29 LocalFree(lpMsgBuf);
30 }
31
32
33 static BOOL
34 DoWriteFile(PSCREENSHOT pScrSht,
35 LPTSTR pstrFileName)
36 {
37 BITMAPFILEHEADER bmfh;
38 BOOL bSuccess;
39 DWORD dwBytesWritten;
40 HANDLE hFile;
41 //INT PalEntries;
42
43 hFile = CreateFile(pstrFileName,
44 GENERIC_WRITE,
45 0,
46 NULL,
47 CREATE_ALWAYS,
48 FILE_ATTRIBUTE_NORMAL,
49 NULL);
50
51 if (hFile == INVALID_HANDLE_VALUE)
52 return FALSE;
53
54 /* write the BITMAPFILEHEADER to file */
55 bmfh.bfType = *(WORD *)"BM"; // 0x4D 0x42
56 bmfh.bfReserved1 = 0;
57 bmfh.bfReserved2 = 0;
58 bSuccess = WriteFile(hFile,
59 &bmfh,
60 sizeof(bmfh),
61 &dwBytesWritten,
62 NULL);
63 if ((!bSuccess) || (dwBytesWritten < sizeof(bmfh)))
64 goto fail;
65
66 /* write the BITMAPINFOHEADER to file */
67 bSuccess = WriteFile(hFile,
68 &pScrSht->lpbi->bmiHeader,
69 sizeof(BITMAPINFOHEADER),
70 &dwBytesWritten,
71 NULL);
72 if ((!bSuccess) || (dwBytesWritten < sizeof(BITMAPINFOHEADER)))
73 goto fail;
74
75 /* calculate the size of the pallete * /
76 if (pScrSht->lpbi->bmiHeader.biCompression == BI_BITFIELDS)
77 PalEntries = 3;
78 else
79 {
80 if (pScrSht->lpbi->bmiHeader.biBitCount <= 8)
81 PalEntries = (INT)(1 << pScrSht->lpbi->bmiHeader.biBitCount);
82 else
83 PalEntries = 0;
84 }
85 if (pScrSht->lpbi->bmiHeader.biClrUsed)
86 PalEntries = pScrSht->lpbi->bmiHeader.biClrUsed;
87
88 / * write pallete to file * /
89 if (PalEntries != 0)
90 {
91 bSuccess = WriteFile(hFile,
92 &pScrSht->lpbi->bmiColors,
93 PalEntries * sizeof(RGBQUAD),
94 &dwBytesWritten,
95 NULL);
96 if ((!bSuccess) || (dwBytesWritten < PalEntries * sizeof(RGBQUAD)))
97 goto fail;
98 }
99 */
100 /* save the current file position at the bginning of the bitmap bits */
101 bmfh.bfOffBits = SetFilePointer(hFile, 0, 0, FILE_CURRENT);
102
103 /* write the bitmap bits to file */
104 bSuccess = WriteFile(hFile,
105 pScrSht->lpvBits,
106 pScrSht->lpbi->bmiHeader.biSizeImage,
107 &dwBytesWritten,
108 NULL);
109 if ((!bSuccess) || (dwBytesWritten < pScrSht->lpbi->bmiHeader.biSizeImage))
110 goto fail;
111
112 /* save the current file position at the final file size */
113 bmfh.bfSize = SetFilePointer(hFile, 0, 0, FILE_CURRENT);
114
115 /* rewrite the updated file headers */
116 SetFilePointer(hFile, 0, 0, FILE_BEGIN);
117 bSuccess = WriteFile(hFile,
118 &bmfh,
119 sizeof(bmfh),
120 &dwBytesWritten,
121 NULL);
122 if ((!bSuccess) || (dwBytesWritten < sizeof(bmfh)))
123 goto fail;
124
125 return TRUE;
126
127 fail:
128 GetError();
129 if (hFile) CloseHandle(hFile);
130 DeleteFile(pstrFileName);
131 return FALSE;
132
133 }
134
135
136 static BOOL
137 DoSaveFile(HWND hwnd, LPTSTR szFileName)
138 {
139 OPENFILENAME ofn;
140
141 static TCHAR Filter[] = _T("24 bit Bitmap (*.bmp,*.dib)\0*.bmp\0");
142
143 ZeroMemory(&ofn, sizeof(ofn));
144 ofn.lStructSize = sizeof(OPENFILENAME);
145 ofn.hwndOwner = hwnd;
146 ofn.nMaxFile = MAX_PATH;
147 ofn.nMaxFileTitle = MAX_PATH;
148 ofn.lpstrDefExt = _T("bmp");
149 ofn.lpstrFilter = Filter;
150 ofn.lpstrFile = szFileName;
151 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
152
153 if (GetSaveFileName(&ofn))
154 return TRUE;
155
156 if (CommDlgExtendedError() != CDERR_GENERALCODES)
157 MessageBox(NULL, _T("Save to file failed"), NULL, 0);
158
159 return FALSE;
160 }
161
162
163 static BOOL
164 CaptureScreen(PSCREENSHOT pScrSht)
165 {
166 HDC ScreenDC;
167 RECT rect;
168
169 /* get window resolution */
170 //pScrSht->Width = GetSystemMetrics(SM_CXSCREEN);
171 //pScrSht->Height = GetSystemMetrics(SM_CYSCREEN);
172
173 GetWindowRect(pScrSht->hSelf, &rect);
174 pScrSht->Width = rect.right - rect.left;
175 pScrSht->Height = rect.bottom - rect.top;
176
177 /* get a DC for the screen */
178 if (!(ScreenDC = GetDC(pScrSht->hSelf)))
179 return FALSE;
180
181 /* get a bitmap handle for the screen
182 * needed to convert to a DIB */
183 pScrSht->hBitmap = CreateCompatibleBitmap(ScreenDC,
184 pScrSht->Width,
185 pScrSht->Height);
186 if (pScrSht->hBitmap == NULL)
187 {
188 GetError();
189 ReleaseDC(pScrSht->hSelf, ScreenDC);
190 return FALSE;
191 }
192
193 /* get a DC compatable with the screen DC */
194 if (!(pScrSht->hDC = CreateCompatibleDC(ScreenDC)))
195 {
196 GetError();
197 ReleaseDC(pScrSht->hSelf, ScreenDC);
198 return FALSE;
199 }
200
201 /* select the bitmap into the DC */
202 SelectObject(pScrSht->hDC,
203 pScrSht->hBitmap);
204
205 /* copy the screen DC to the bitmap */
206 BitBlt(pScrSht->hDC,
207 0,
208 0,
209 pScrSht->Width,
210 pScrSht->Height,
211 ScreenDC,
212 0,
213 0,
214 SRCCOPY);
215
216 /* we're finished with the screen DC */
217 ReleaseDC(pScrSht->hSelf, ScreenDC);
218
219 return TRUE;
220 }
221
222
223 static BOOL
224 ConvertDDBtoDIB(PSCREENSHOT pScrSht)
225 {
226 INT Ret;
227 BITMAP bitmap;
228 WORD cClrBits;
229
230
231 /*
232 / * can't call GetDIBits with hBitmap selected * /
233 //SelectObject(hDC, hOldBitmap);
234
235 / * let GetDIBits fill the lpbi structure by passing NULL pointer * /
236 Ret = GetDIBits(hDC,
237 hBitmap,
238 0,
239 Height,
240 NULL,
241 lpbi,
242 DIB_RGB_COLORS);
243 if (Ret == 0)
244 {
245 GetError();
246 ReleaseDC(hwnd, hDC);
247 HeapFree(GetProcessHeap(), 0, lpbi);
248 return -1;
249 }
250 */
251
252 ////////////////////////////////////////////////////
253
254 if (!GetObjectW(pScrSht->hBitmap,
255 sizeof(BITMAP),
256 (LPTSTR)&bitmap))
257 {
258 GetError();
259 return FALSE;
260 }
261
262 cClrBits = (WORD)(bitmap.bmPlanes * bitmap.bmBitsPixel);
263 if (cClrBits == 1)
264 cClrBits = 1;
265 else if (cClrBits <= 4)
266 cClrBits = 4;
267 else if (cClrBits <= 8)
268 cClrBits = 8;
269 else if (cClrBits <= 16)
270 cClrBits = 16;
271 else if (cClrBits <= 24)
272 cClrBits = 24;
273 else cClrBits = 32;
274
275 if (cClrBits != 24)
276 pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
277 0,
278 sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits));
279 else
280 pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
281 0,
282 sizeof(BITMAPINFOHEADER));
283
284 if (!pScrSht->lpbi)
285 {
286 GetError();
287 return FALSE;
288 }
289
290 pScrSht->lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
291 pScrSht->lpbi->bmiHeader.biWidth = bitmap.bmWidth;
292 pScrSht->lpbi->bmiHeader.biHeight = bitmap.bmHeight;
293 pScrSht->lpbi->bmiHeader.biPlanes = bitmap.bmPlanes;
294 pScrSht->lpbi->bmiHeader.biBitCount = bitmap.bmBitsPixel;
295
296 if (cClrBits < 24)
297 pScrSht->lpbi->bmiHeader.biClrUsed = (1 << cClrBits);
298
299 pScrSht->lpbi->bmiHeader.biCompression = BI_RGB;
300 pScrSht->lpbi->bmiHeader.biSizeImage = ((pScrSht->lpbi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
301 * pScrSht->lpbi->bmiHeader.biHeight;
302
303 pScrSht->lpbi->bmiHeader.biClrImportant = 0;
304
305 //////////////////////////////////////////////////////
306
307 /* reserve memory to hold the screen bitmap */
308 pScrSht->lpvBits = HeapAlloc(GetProcessHeap(),
309 0,
310 pScrSht->lpbi->bmiHeader.biSizeImage);
311 if (pScrSht->lpvBits == NULL)
312 {
313 GetError();
314 return FALSE;
315 }
316
317 /* convert the DDB to a DIB */
318 Ret = GetDIBits(pScrSht->hDC,
319 pScrSht->hBitmap,
320 0,
321 pScrSht->Height,
322 pScrSht->lpvBits,
323 pScrSht->lpbi,
324 DIB_RGB_COLORS);
325 if (Ret == 0)
326 {
327 GetError();
328 return FALSE;
329 }
330
331 return TRUE;
332
333 }
334
335
336 // INT WINAPI GetScreenshot(BOOL bFullScreen)
337 int WINAPI WinMain(HINSTANCE hInstance,
338 HINSTANCE hPrevInstance,
339 PSTR szCmdLine,
340 int iCmdShow)
341 {
342 PSCREENSHOT pScrSht;
343 TCHAR szFileName[MAX_PATH] = _T("");
344
345 BOOL bFullScreen = TRUE;
346
347 pScrSht = HeapAlloc(GetProcessHeap(),
348 0,
349 sizeof(SCREENSHOT));
350 if (pScrSht == NULL)
351 return -1;
352
353 if (bFullScreen)
354 {
355 pScrSht->hSelf = GetDesktopWindow();
356 }
357 else
358 {
359 pScrSht->hSelf = GetForegroundWindow();
360 }
361
362 if (pScrSht->hSelf == NULL)
363 {
364 HeapFree(GetProcessHeap(),
365 0,
366 pScrSht);
367
368 return -1;
369 }
370
371 if (CaptureScreen(pScrSht))
372 {
373 /* convert the DDB image to DIB */
374 if(ConvertDDBtoDIB(pScrSht))
375 {
376 /* Get filename from user */
377 if(DoSaveFile(pScrSht->hSelf, szFileName))
378 {
379 /* build the headers and write to file */
380 DoWriteFile(pScrSht, szFileName);
381 }
382 }
383 }
384
385 /* cleanup */
386 if (pScrSht->hSelf != NULL)
387 ReleaseDC(pScrSht->hSelf, pScrSht->hDC);
388 if (pScrSht->hBitmap != NULL)
389 DeleteObject(pScrSht->hBitmap);
390 if (pScrSht->lpbi != NULL)
391 HeapFree(GetProcessHeap(),
392 0,
393 pScrSht->lpbi);
394 if (pScrSht->lpvBits != NULL)
395 HeapFree(GetProcessHeap(),
396 0,
397 pScrSht->lpvBits);
398 if (pScrSht != NULL)
399 HeapFree(GetProcessHeap(),
400 0,
401 pScrSht);
402
403 return 0;
404 }