ultimatepp/bazaar/SysInfo/screengrab.cpp
koldo 43a54a9648 SysInfo: Handles ported to int64 and documented
git-svn-id: svn://ultimatepp.org/upp/trunk@6030 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2013-05-03 23:58:40 +00:00

460 lines
No EOL
12 KiB
C++

#include "SysInfo_in.h"
NAMESPACE_UPP
#if defined(PLATFORM_WIN32) || defined (PLATFORM_WIN64)
#if defined(__MINGW32__)
#define labs(x) labs((Upp::int64)(x))
#elif defined(_MSC_VER)
#define labs(x) abs(x)
#endif
bool Window_SaveCapture(int64 windowId, String fileName, int left, int top, int width, int height)
{
HWND windowIdH = reinterpret_cast<HWND>(windowId);
if (windowIdH == 0)
windowIdH = GetDesktopWindow();
if (GetFileExt(fileName) != ".bmp")
fileName += ".bmp";
RECT rc;
GetWindowRect (windowIdH, &rc);
if (left == -1)
left = rc.left;
if (top == -1)
top = rc.top;
if (width == -1)
width = rc.right-rc.left;
if (height == -1)
height = rc.bottom-rc.top;
HDC hDC = GetDC(0);
HDC memDC = CreateCompatibleDC (hDC);
HBITMAP hb = CreateCompatibleBitmap (hDC, width, height);
HBITMAP OldBM = (HBITMAP)SelectObject(memDC, hb);
BitBlt(memDC, 0, 0, width, height , hDC, left, top , SRCCOPY);
FILE *file = NULL;
BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hDC, hb, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
if(bmpInfo.bmiHeader.biSizeImage <= 0)
bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth*labs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
char *cbuf = new char[bmpInfo.bmiHeader.biSizeImage];
LPVOID buf = cbuf;
bmpInfo.bmiHeader.biCompression = BI_RGB;
GetDIBits(hDC, hb, 0, bmpInfo.bmiHeader.biHeight, buf, &bmpInfo, DIB_RGB_COLORS);
if((file = _wfopen(fileName.ToWString(),L"wb")) == NULL)
return false;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType = 19778;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, file);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER), 1, file);
fwrite(buf,bmpInfo.bmiHeader.biSizeImage, 1, file);
delete[] cbuf;
fclose(file);
SelectObject(hDC, OldBM);
DeleteObject(hb);
DeleteDC(memDC);
ReleaseDC(0, hDC);
return true;
}
class ScreenGrab {
private:
enum {GRAB_MODE_DESKTOP, GRAB_MODE_WINDOW, GRAB_MODE_RECT};
static HDC lDCDest;
static HGDIOBJ lDib;
static void *lDibPtr;
static HGDIOBJ lBmpOld;
static BITMAPINFO tBmpInfo;
static PAVIFILE lAVIPtrFile;
static PAVISTREAM lAVIPtrStrm;
static AVISTREAMINFO tAVIHdr;
static AVIFILEINFO tAVIFile;
long lAVICnt;
double frameRate;
long numFrames; // number of frames in video stream
long firstFrame; // position of the first video frame
String fileName;
bool viewMouse;
bool opened;
int grabMode;
uint64 hwnd;
int left;
int top;
int width;
int height;
bool AVIOpen(bool create = true);
bool AVIWrite();
void AVIClose();
HICON GetCursorHandle();
bool DIBCreate(HWND lHandleSource, long lWidth, long lHeight, long lPosX, long lPosY);
void DIBClean();
bool ScreenshotMemory();
public:
ScreenGrab(String fileName, double secsFrame = 1, bool viewMouse = true);
~ScreenGrab();
bool IniGrabDesktop();
bool IniGrabWindow(uint64 handle);
bool IniGrabDesktopRectangle(int left, int top, int width, int height);
bool Grab(unsigned duration);
bool GrabSnapshot();
void Close();
};
bool Record_Desktop(String fileName, int duration, double secsFrame, bool viewMouse)
{
ScreenGrab grab(fileName, secsFrame, viewMouse);
if (!grab.IniGrabDesktop())
return false;
if (!grab.Grab(duration))
return false;
grab.Close();
return true;
}
bool Record_DesktopRectangle(String fileName, int duration, int left, int top, int width, int height, double secsFrame, bool viewMouse)
{
ScreenGrab grab(fileName, secsFrame, viewMouse);
if (!grab.IniGrabDesktopRectangle(left, top, width, height))
return false;
if (!grab.Grab(duration))
return false;
grab.Close();
return true;
}
bool Record_Window(String fileName, int duration, int64 handle, double secsFrame, bool viewMouse)
{
ScreenGrab grab(fileName, secsFrame, viewMouse);
if (!grab.IniGrabWindow(handle))
return false;
if (!grab.Grab(duration))
return false;
grab.Close();
return true;
}
bool ScreenGrab::AVIOpen(bool create)
{
long lRet, mode, res;
AVIFileInit();
if (create)
mode = OF_CREATE | OF_WRITE;
else
mode = OF_SHARE_DENY_WRITE;
lRet = AVIFileOpen(&lAVIPtrFile, fileName, mode, 0);
if (lRet == AVIERR_OK && create) {
tAVIHdr.fccType = streamtypeVIDEO;
tAVIHdr.fccHandler = 0;
tAVIHdr.dwScale = 100;
tAVIHdr.dwRate = (DWORD)(tAVIHdr.dwScale*frameRate);
//tAVIHdr.dwQuality = -1;
tAVIHdr.dwSuggestedBufferSize = tBmpInfo.bmiHeader.biSizeImage;
SetRect(&(tAVIHdr.rcFrame), 0, 0, tBmpInfo.bmiHeader.biWidth, tBmpInfo.bmiHeader.biHeight);
lRet = AVIFileCreateStream(lAVIPtrFile, &lAVIPtrStrm, &tAVIHdr);
if (lRet == AVIERR_OK) {
lRet = AVIStreamSetFormat(lAVIPtrStrm, 0, &(tBmpInfo.bmiHeader), sizeof(tBmpInfo.bmiHeader));
if (lRet == AVIERR_OK)
lAVICnt = 0;
}
} else {
res = AVIFileGetStream(lAVIPtrFile, &lAVIPtrStrm, streamtypeVIDEO, 0);
if (res != AVIERR_OK)
return false;
firstFrame = AVIStreamStart(lAVIPtrStrm);
if (firstFrame != -1)
return false;
numFrames = AVIStreamLength(lAVIPtrStrm);
if (numFrames == -1)
return false;
res = AVIFileInfo(lAVIPtrFile, &tAVIFile, sizeof(tAVIFile));
if (res != AVIERR_OK)
return false;
res = AVIStreamInfo(lAVIPtrStrm, &tAVIHdr, sizeof(tAVIHdr));
if (res != AVIERR_OK)
return false;
}
return true;
}
bool ScreenGrab::AVIWrite()
{
HRESULT lRet;
lRet = AVIStreamWrite(lAVIPtrStrm, lAVICnt, 1, lDibPtr, tBmpInfo.bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL);
if (lRet == AVIERR_OK) {
lAVICnt++;
return true;
} else
return false;
}
void ScreenGrab::AVIClose()
{
if (lAVIPtrStrm != 0)
AVIStreamClose(lAVIPtrStrm);
if (lAVIPtrFile != 0)
AVIFileClose(lAVIPtrFile);
AVIFileExit();
}
HICON ScreenGrab::GetCursorHandle()
{
HWND lHandle;
POINT lpPos;
long lThreadID;
long lCurrentThreadID;
GetCursorPos(&lpPos);
lHandle = WindowFromPoint(lpPos);
lThreadID = GetWindowThreadProcessId(lHandle, 0);
lCurrentThreadID = GetWindowThreadProcessId(reinterpret_cast<HWND>(GetWindowIdFromProcessId(GetProcessId())), 0);
HICON ret;
if (lThreadID != lCurrentThreadID) {
if (AttachThreadInput(lCurrentThreadID, lThreadID, true)) {
ret = GetCursor();
AttachThreadInput(lCurrentThreadID, lThreadID, false);
}
} else
ret = GetCursor();
return ret;
}
bool ScreenGrab::DIBCreate(HWND lHandleSource, long lWidth, long lHeight, long lPosX, long lPosY)
{
HDC lDCSource, lDCSourceDesktop;
POINT lpCursorPos;
lDCSource = GetWindowDC(lHandleSource);
lDCSourceDesktop = GetWindowDC(0);
bool ret = false;
if (lDCSource != 0 && lDCSourceDesktop != 0) {
lDCDest = CreateCompatibleDC(lDCSource);
if (lDCDest != 0) {
tBmpInfo.bmiHeader.biSize = sizeof(tBmpInfo.bmiHeader);
tBmpInfo.bmiHeader.biWidth = lWidth;
tBmpInfo.bmiHeader.biHeight = lHeight;
tBmpInfo.bmiHeader.biPlanes = 1;
tBmpInfo.bmiHeader.biBitCount = 24;
tBmpInfo.bmiHeader.biCompression = 0;
tBmpInfo.bmiHeader.biSizeImage = ((tBmpInfo.bmiHeader.biWidth * 3 + 3) & 0xFFFFFFFC) * tBmpInfo.bmiHeader.biHeight;
lDib = CreateDIBSection(lDCDest, &tBmpInfo, 0, &lDibPtr, 0, 0);
if (lDib != 0) {
lBmpOld = SelectObject(lDCDest, lDib);
BitBlt(lDCDest, 0, 0, lWidth, lHeight, lDCSourceDesktop, lPosX, lPosY, 0xCC0020);
if (viewMouse) {
GetCursorPos(&lpCursorPos);
DrawIcon(lDCDest, lpCursorPos.x - lPosX, lpCursorPos.y - lPosY, GetCursorHandle());
}
ret = true;
}
}
}
ReleaseDC(lHandleSource, lDCSource);
ReleaseDC(0, lDCSourceDesktop);
return ret;
}
void ScreenGrab::DIBClean()
{
SelectObject(lDCDest, lBmpOld);
DeleteDC(lDCDest);
DeleteObject(lDib);
}
bool ScreenGrab::ScreenshotMemory()
{
HWND lHandle;
RECT lpRect;
long lWidth, lHeight;
long lPosX, lPosY;
switch (grabMode) {
case GRAB_MODE_DESKTOP:
lHandle = GetDesktopWindow();
GetWindowRect(lHandle, &lpRect);
lWidth = lpRect.right - lpRect.left;
lHeight = lpRect.bottom - lpRect.top;
lPosX = lpRect.left;
lPosY = lpRect.top;
break;
case GRAB_MODE_WINDOW:
lHandle = reinterpret_cast<HWND>(hwnd);
GetWindowRect(lHandle, &lpRect);
lWidth = lpRect.right - lpRect.left;
lHeight = lpRect.bottom - lpRect.top;
lPosX = lpRect.left;
lPosY = lpRect.top;
break;
case GRAB_MODE_RECT:
lHandle = GetDesktopWindow();
GetWindowRect(lHandle, &lpRect);
lWidth = width;
lHeight = height;
lPosX = left;
lPosY = top;
break;
default:
throw Exc(t_("Unknown grab mode"));
return false;
}
if (DIBCreate(lHandle, lWidth, lHeight, lPosX, lPosY))
return true;
else
return false;
}
HDC ScreenGrab::lDCDest;
HGDIOBJ ScreenGrab::lDib;
void *ScreenGrab::lDibPtr;
HGDIOBJ ScreenGrab::lBmpOld;
PAVIFILE ScreenGrab::lAVIPtrFile;
PAVISTREAM ScreenGrab::lAVIPtrStrm;
BITMAPINFO ScreenGrab::tBmpInfo;
AVISTREAMINFO ScreenGrab::tAVIHdr;
AVIFILEINFO ScreenGrab::tAVIFile;
ScreenGrab::ScreenGrab(String _fileName, double secsFrame, bool _viewMouse)
{
opened = false;
fileName = _fileName;
viewMouse = _viewMouse;
frameRate = 1./secsFrame;
}
ScreenGrab::~ScreenGrab()
{
Close();
}
void ScreenGrab::Close()
{
if (!opened)
return;
AVIClose();
DIBClean();
opened = false;
}
bool ScreenGrab::IniGrabDesktop()
{
opened = true;
grabMode = GRAB_MODE_DESKTOP;
if (!ScreenshotMemory())
return false;
if (!AVIOpen())
return false;
return true;
}
bool ScreenGrab::IniGrabWindow(uint64 handle)
{
opened = true;
grabMode = GRAB_MODE_WINDOW;
hwnd = handle;
if (!ScreenshotMemory())
return false;
if (!AVIOpen())
return false;
return true;
}
bool ScreenGrab::IniGrabDesktopRectangle(int _left, int _top, int _width, int _height)
{
opened = true;
grabMode = GRAB_MODE_RECT;
left = _left;
top = _top;
width = _width;
height = _height;
if (!ScreenshotMemory())
return false;
if (!AVIOpen())
return false;
return true;
}
bool ScreenGrab::Grab(unsigned duration)
{
if (!opened)
return false;
TimeStop timer;
timer.Reset();
while (timer.Elapsed() < duration*1000) {
if (!ScreenshotMemory())
return false;
if (!AVIWrite())
return false;
while (timer.Elapsed() < (lAVICnt*1000.)/frameRate)
Sleep(10);//DoEvents();
}
return true;
}
bool ScreenGrab::GrabSnapshot()
{
if (!opened)
return false;
if (!ScreenshotMemory())
return false;
if (!AVIWrite())
return false;
return true;
}
#endif
#ifdef PLATFORM_POSIX
bool Window_SaveCapture(int64 windowId, String fileName, int left, int top, int width, int height)
{
if (GetFileExt(fileName) != ".xwd")
fileName += ".xwd";
String command;
if (windowId == 0)
command = "xwd -root -silent -out \"" + fileName + "\"";
else
command = "xwd -id " + FormatLong(windowId) + " -silent -out \"" + fileName + "\"";
String strret;
return Sys(command, strret) >= 0;
}
#endif
bool Snap_Desktop(String fileName)
{
return Window_SaveCapture(0, fileName);
}
bool Snap_DesktopRectangle(String fileName, int left, int top, int width, int height)
{
return Window_SaveCapture(0, fileName, left, top, width, height);
}
bool Snap_Window(String fileName, int64 handle)
{
return Window_SaveCapture(handle, fileName);
}
END_UPP_NAMESPACE