reactos/modules/rosapps/applications/sysutils/screenshot/screenshot.c
2019-11-07 22:32:15 +03:00

409 lines
10 KiB
C

#include "screenshot.h"
/*
* Save a screenshot to file until the clipboard
* is ready to accept images.
*/
static VOID
GetError(VOID)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL );
MessageBox(NULL,
lpMsgBuf,
_T("Error!"),
MB_OK | MB_ICONERROR);
LocalFree(lpMsgBuf);
}
static BOOL
DoWriteFile(PSCREENSHOT pScrSht,
LPTSTR pstrFileName)
{
BITMAPFILEHEADER bmfh;
BOOL bSuccess;
DWORD dwBytesWritten;
HANDLE hFile;
//INT PalEntries;
hFile = CreateFile(pstrFileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
/* write the BITMAPFILEHEADER to file */
bmfh.bfType = *(WORD *)"BM"; // 0x4D 0x42
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bSuccess = WriteFile(hFile,
&bmfh,
sizeof(bmfh),
&dwBytesWritten,
NULL);
if ((!bSuccess) || (dwBytesWritten < sizeof(bmfh)))
goto fail;
/* write the BITMAPINFOHEADER to file */
bSuccess = WriteFile(hFile,
&pScrSht->lpbi->bmiHeader,
sizeof(BITMAPINFOHEADER),
&dwBytesWritten,
NULL);
if ((!bSuccess) || (dwBytesWritten < sizeof(BITMAPINFOHEADER)))
goto fail;
/* calculate the size of the pallete * /
if (pScrSht->lpbi->bmiHeader.biCompression == BI_BITFIELDS)
PalEntries = 3;
else
{
if (pScrSht->lpbi->bmiHeader.biBitCount <= 8)
PalEntries = (INT)(1 << pScrSht->lpbi->bmiHeader.biBitCount);
else
PalEntries = 0;
}
if (pScrSht->lpbi->bmiHeader.biClrUsed)
PalEntries = pScrSht->lpbi->bmiHeader.biClrUsed;
/ * write pallete to file * /
if (PalEntries != 0)
{
bSuccess = WriteFile(hFile,
&pScrSht->lpbi->bmiColors,
PalEntries * sizeof(RGBQUAD),
&dwBytesWritten,
NULL);
if ((!bSuccess) || (dwBytesWritten < PalEntries * sizeof(RGBQUAD)))
goto fail;
}
*/
/* save the current file position at the bginning of the bitmap bits */
bmfh.bfOffBits = SetFilePointer(hFile, 0, 0, FILE_CURRENT);
/* write the bitmap bits to file */
bSuccess = WriteFile(hFile,
pScrSht->lpvBits,
pScrSht->lpbi->bmiHeader.biSizeImage,
&dwBytesWritten,
NULL);
if ((!bSuccess) || (dwBytesWritten < pScrSht->lpbi->bmiHeader.biSizeImage))
goto fail;
/* save the current file position at the final file size */
bmfh.bfSize = SetFilePointer(hFile, 0, 0, FILE_CURRENT);
/* rewrite the updated file headers */
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
bSuccess = WriteFile(hFile,
&bmfh,
sizeof(bmfh),
&dwBytesWritten,
NULL);
if ((!bSuccess) || (dwBytesWritten < sizeof(bmfh)))
goto fail;
return TRUE;
fail:
GetError();
if (hFile) CloseHandle(hFile);
DeleteFile(pstrFileName);
return FALSE;
}
static BOOL
DoSaveFile(HWND hwnd, LPTSTR szFileName)
{
OPENFILENAME ofn;
static TCHAR Filter[] = _T("24 bit Bitmap (*.bmp,*.dib)\0*.bmp\0");
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrDefExt = _T("bmp");
ofn.lpstrFilter = Filter;
ofn.lpstrFile = szFileName;
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if (GetSaveFileName(&ofn))
return TRUE;
if (CommDlgExtendedError() != CDERR_GENERALCODES)
MessageBox(NULL, _T("Save to file failed"), NULL, 0);
return FALSE;
}
static BOOL
CaptureScreen(PSCREENSHOT pScrSht)
{
HDC ScreenDC;
RECT rect;
/* get window resolution */
//pScrSht->Width = GetSystemMetrics(SM_CXSCREEN);
//pScrSht->Height = GetSystemMetrics(SM_CYSCREEN);
GetWindowRect(pScrSht->hSelf, &rect);
pScrSht->Width = rect.right - rect.left;
pScrSht->Height = rect.bottom - rect.top;
/* get a DC for the screen */
if (!(ScreenDC = GetDC(pScrSht->hSelf)))
return FALSE;
/* get a bitmap handle for the screen
* needed to convert to a DIB */
pScrSht->hBitmap = CreateCompatibleBitmap(ScreenDC,
pScrSht->Width,
pScrSht->Height);
if (pScrSht->hBitmap == NULL)
{
GetError();
ReleaseDC(pScrSht->hSelf, ScreenDC);
return FALSE;
}
/* get a DC compatable with the screen DC */
if (!(pScrSht->hDC = CreateCompatibleDC(ScreenDC)))
{
GetError();
ReleaseDC(pScrSht->hSelf, ScreenDC);
return FALSE;
}
/* select the bitmap into the DC */
SelectObject(pScrSht->hDC,
pScrSht->hBitmap);
/* copy the screen DC to the bitmap */
BitBlt(pScrSht->hDC,
0,
0,
pScrSht->Width,
pScrSht->Height,
ScreenDC,
0,
0,
SRCCOPY);
/* we're finished with the screen DC */
ReleaseDC(pScrSht->hSelf, ScreenDC);
return TRUE;
}
static BOOL
ConvertDDBtoDIB(PSCREENSHOT pScrSht)
{
INT Ret;
BITMAP bitmap;
WORD cClrBits;
/*
/ * can't call GetDIBits with hBitmap selected * /
//SelectObject(hDC, hOldBitmap);
/ * let GetDIBits fill the lpbi structure by passing NULL pointer * /
Ret = GetDIBits(hDC,
hBitmap,
0,
Height,
NULL,
lpbi,
DIB_RGB_COLORS);
if (Ret == 0)
{
GetError();
ReleaseDC(hwnd, hDC);
HeapFree(GetProcessHeap(), 0, lpbi);
return -1;
}
*/
////////////////////////////////////////////////////
if (!GetObjectW(pScrSht->hBitmap,
sizeof(BITMAP),
(LPTSTR)&bitmap))
{
GetError();
return FALSE;
}
cClrBits = (WORD)(bitmap.bmPlanes * bitmap.bmBitsPixel);
if (cClrBits == 1)
cClrBits = 1;
else if (cClrBits <= 4)
cClrBits = 4;
else if (cClrBits <= 8)
cClrBits = 8;
else if (cClrBits <= 16)
cClrBits = 16;
else if (cClrBits <= 24)
cClrBits = 24;
else cClrBits = 32;
if (cClrBits != 24)
{
pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
0,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << cClrBits));
}
else
{
pScrSht->lpbi = (PBITMAPINFO) HeapAlloc(GetProcessHeap(),
0,
sizeof(BITMAPINFOHEADER));
}
if (!pScrSht->lpbi)
{
GetError();
return FALSE;
}
pScrSht->lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pScrSht->lpbi->bmiHeader.biWidth = bitmap.bmWidth;
pScrSht->lpbi->bmiHeader.biHeight = bitmap.bmHeight;
pScrSht->lpbi->bmiHeader.biPlanes = bitmap.bmPlanes;
pScrSht->lpbi->bmiHeader.biBitCount = bitmap.bmBitsPixel;
if (cClrBits < 24)
pScrSht->lpbi->bmiHeader.biClrUsed = (1 << cClrBits);
pScrSht->lpbi->bmiHeader.biCompression = BI_RGB;
pScrSht->lpbi->bmiHeader.biSizeImage = ((pScrSht->lpbi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
* pScrSht->lpbi->bmiHeader.biHeight;
pScrSht->lpbi->bmiHeader.biClrImportant = 0;
//////////////////////////////////////////////////////
/* reserve memory to hold the screen bitmap */
pScrSht->lpvBits = HeapAlloc(GetProcessHeap(),
0,
pScrSht->lpbi->bmiHeader.biSizeImage);
if (pScrSht->lpvBits == NULL)
{
GetError();
return FALSE;
}
/* convert the DDB to a DIB */
Ret = GetDIBits(pScrSht->hDC,
pScrSht->hBitmap,
0,
pScrSht->Height,
pScrSht->lpvBits,
pScrSht->lpbi,
DIB_RGB_COLORS);
if (Ret == 0)
{
GetError();
return FALSE;
}
return TRUE;
}
// INT WINAPI GetScreenshot(BOOL bFullScreen)
int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR szCmdLine,
int iCmdShow)
{
PSCREENSHOT pScrSht;
TCHAR szFileName[MAX_PATH] = _T("");
BOOL bFullScreen = TRUE;
pScrSht = HeapAlloc(GetProcessHeap(),
0,
sizeof(SCREENSHOT));
if (pScrSht == NULL)
return -1;
if (bFullScreen)
{
pScrSht->hSelf = GetDesktopWindow();
}
else
{
pScrSht->hSelf = GetForegroundWindow();
}
if (pScrSht->hSelf == NULL)
{
HeapFree(GetProcessHeap(),
0,
pScrSht);
return -1;
}
if (CaptureScreen(pScrSht))
{
/* convert the DDB image to DIB */
if(ConvertDDBtoDIB(pScrSht))
{
/* Get filename from user */
if(DoSaveFile(pScrSht->hSelf, szFileName))
{
/* build the headers and write to file */
DoWriteFile(pScrSht, szFileName);
}
}
}
/* cleanup */
if (pScrSht->hSelf != NULL)
ReleaseDC(pScrSht->hSelf, pScrSht->hDC);
if (pScrSht->hBitmap != NULL)
DeleteObject(pScrSht->hBitmap);
if (pScrSht->lpbi != NULL)
HeapFree(GetProcessHeap(),
0,
pScrSht->lpbi);
if (pScrSht->lpvBits != NULL)
HeapFree(GetProcessHeap(),
0,
pScrSht->lpvBits);
if (pScrSht != NULL)
HeapFree(GetProcessHeap(),
0,
pScrSht);
return 0;
}