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