mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
409 lines
10 KiB
C
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;
|
|
}
|