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   {
277     pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
278                                             0,
279                                             sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits));
280   }
281   else
282   {
283     pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
284                                             0,
285                                             sizeof(BITMAPINFOHEADER));
286   }
287 
288 	if (!pScrSht->lpbi)
289 	{
290 		GetError();
291 		return FALSE;
292 	}
293 
294 	pScrSht->lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
295 	pScrSht->lpbi->bmiHeader.biWidth = bitmap.bmWidth;
296 	pScrSht->lpbi->bmiHeader.biHeight = bitmap.bmHeight;
297 	pScrSht->lpbi->bmiHeader.biPlanes = bitmap.bmPlanes;
298 	pScrSht->lpbi->bmiHeader.biBitCount = bitmap.bmBitsPixel;
299 
300 	if (cClrBits < 24)
301 		pScrSht->lpbi->bmiHeader.biClrUsed = (1 << cClrBits);
302 
303 	pScrSht->lpbi->bmiHeader.biCompression = BI_RGB;
304 	pScrSht->lpbi->bmiHeader.biSizeImage = ((pScrSht->lpbi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
305                                            * pScrSht->lpbi->bmiHeader.biHeight;
306 
307 	pScrSht->lpbi->bmiHeader.biClrImportant = 0;
308 
309 //////////////////////////////////////////////////////
310 
311     /* reserve memory to hold the screen bitmap */
312     pScrSht->lpvBits = HeapAlloc(GetProcessHeap(),
313                                  0,
314                                  pScrSht->lpbi->bmiHeader.biSizeImage);
315     if (pScrSht->lpvBits == NULL)
316     {
317         GetError();
318         return FALSE;
319     }
320 
321     /* convert the DDB to a DIB */
322     Ret = GetDIBits(pScrSht->hDC,
323                     pScrSht->hBitmap,
324                     0,
325                     pScrSht->Height,
326                     pScrSht->lpvBits,
327                     pScrSht->lpbi,
328                     DIB_RGB_COLORS);
329     if (Ret == 0)
330     {
331         GetError();
332         return FALSE;
333     }
334 
335     return TRUE;
336 
337 }
338 
339 
340 // INT WINAPI GetScreenshot(BOOL bFullScreen)
341 int WINAPI _tWinMain(HINSTANCE hInstance,
342                    HINSTANCE hPrevInstance,
343                    LPTSTR szCmdLine,
344                    int iCmdShow)
345 {
346     PSCREENSHOT pScrSht;
347     TCHAR szFileName[MAX_PATH] = _T("");
348 
349     BOOL bFullScreen = TRUE;
350 
351     pScrSht = HeapAlloc(GetProcessHeap(),
352                         0,
353                         sizeof(SCREENSHOT));
354     if (pScrSht == NULL)
355         return -1;
356 
357     if (bFullScreen)
358     {
359         pScrSht->hSelf = GetDesktopWindow();
360     }
361     else
362     {
363         pScrSht->hSelf = GetForegroundWindow();
364     }
365 
366     if (pScrSht->hSelf == NULL)
367     {
368         HeapFree(GetProcessHeap(),
369                  0,
370                  pScrSht);
371 
372         return -1;
373     }
374 
375     if (CaptureScreen(pScrSht))
376     {
377         /* convert the DDB image to DIB */
378         if(ConvertDDBtoDIB(pScrSht))
379         {
380             /* Get filename from user */
381             if(DoSaveFile(pScrSht->hSelf, szFileName))
382             {
383                 /* build the headers and write to file */
384                 DoWriteFile(pScrSht, szFileName);
385             }
386         }
387     }
388 
389     /* cleanup */
390     if (pScrSht->hSelf != NULL)
391         ReleaseDC(pScrSht->hSelf, pScrSht->hDC);
392     if (pScrSht->hBitmap != NULL)
393         DeleteObject(pScrSht->hBitmap);
394     if (pScrSht->lpbi != NULL)
395         HeapFree(GetProcessHeap(),
396                  0,
397                  pScrSht->lpbi);
398     if (pScrSht->lpvBits != NULL)
399         HeapFree(GetProcessHeap(),
400                  0,
401                  pScrSht->lpvBits);
402     if (pScrSht != NULL)
403         HeapFree(GetProcessHeap(),
404                  0,
405                  pScrSht);
406 
407     return 0;
408 }
409