commit 585e61636aaa2c69849a399b602c361745a22de8 Author: snow flurry Date: Tue Feb 13 21:00:46 2024 +0000 Create project "Grabby". git-svn-id: svn://vcs.sdm.2ki.xyz/Grabby/trunk@9 27729192-006e-004d-b9b5-06fbd0ef7001 diff --git a/Bitmap.c b/Bitmap.c new file mode 100644 index 0000000..d2c9996 --- /dev/null +++ b/Bitmap.c @@ -0,0 +1,352 @@ +#include "stdafx.h" +#include "Bitmap.h" + +void DeleteScreen(Screen *); + +Screen * +CreateScreen(void) +{ + Screen *scrn = GlobalAlloc(GPTR, sizeof(Screen)); + RECT rectScreen = { 0 }; + + if (!scrn) { + return NULL; + } + + scrn->hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); + scrn->hdcBitmap = CreateCompatibleDC(scrn->hdcScreen); + + rectScreen.right = GetDeviceCaps(scrn->hdcScreen, HORZRES); + rectScreen.bottom = GetDeviceCaps(scrn->hdcScreen, VERTRES); + + scrn->hScreenRgn = CreateRectRgnIndirect(&rectScreen); + if (!scrn->hScreenRgn) { + // Store the error to be bubbled up + DWORD err = GetLastError(); + DeleteScreen(scrn); + SetLastError(err); + + return NULL; + } + + return scrn; +} + +void +DeleteScreen(Screen *scrn) +{ + if (scrn) { + if (scrn->hScreenRgn) DeleteObject((HGDIOBJ) scrn->hScreenRgn); + if (scrn->hdcBitmap) DeleteDC(scrn->hdcBitmap); + if (scrn->hdcScreen) DeleteDC(scrn->hdcScreen); + + GlobalFree(scrn); + } + + return; +} + +#include +typedef struct _FULLBMPHDR { + BITMAPFILEHEADER file; + BITMAPINFOHEADER info; +} FULLBMPHDR, *PFULLBMPHDR; +#include + +PFULLBMPHDR +GenerateBitmapInfo(Screen *scrn, + BITMAP *bmp) +{ + PFULLBMPHDR pBmpHdr = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(struct _FULLBMPHDR)); + RECT rcScrn = {0}; + WORD cClrBits = (WORD)(bmp->bmPlanes * bmp->bmBitsPixel); + DWORD hdrSize; + + if (!pBmpHdr) return NULL; + + if (!GetRgnBox(scrn->hScreenRgn, &rcScrn)) { + return NULL; + } + + if (cClrBits <= 16) { + cClrBits = 16; + } else { + cClrBits = 32; + } + + pBmpHdr->info.biSize = sizeof(BITMAPINFOHEADER); + pBmpHdr->info.biWidth = bmp->bmWidth; + pBmpHdr->info.biHeight = bmp->bmHeight; + pBmpHdr->info.biPlanes = bmp->bmPlanes; + pBmpHdr->info.biBitCount = cClrBits; + pBmpHdr->info.biCompression = BI_RGB; + // According to MSDN docs, this alignment to WORD boundaries is + // required for Win9x GDI. + pBmpHdr->info.biSizeImage = (((bmp->bmWidth * cClrBits + 31) & ~31) >> 3) + * bmp->bmHeight; + + pBmpHdr->file.bfType = 0x4d42; // "BM" + // actual bits offset: file header + info header + colors used + hdrSize = (DWORD) (sizeof(BITMAPFILEHEADER) + + pBmpHdr->info.biSize + + ((cClrBits >= 16) ? 0 : (pBmpHdr->info.biClrUsed * + sizeof(RGBQUAD)))); + // file size is header size (offset above) + bits size + pBmpHdr->file.bfSize = hdrSize + pBmpHdr->info.biSizeImage; + pBmpHdr->file.bfOffBits = hdrSize; + + return pBmpHdr; +} + +int +SnapScreen(Screen *scrn) +{ + RECT rcScreen = {0}; + int iScrWidth, + iScrHeight; + if (!scrn) return FALSE; + + // Don't make a new hBitmap if we have one + if (scrn->hBitmap) return TRUE; + + GetRgnBox(scrn->hScreenRgn, &rcScreen); + + iScrWidth = rcScreen.right - rcScreen.left; + iScrHeight = rcScreen.bottom - rcScreen.top; + + scrn->hBitmap = CreateCompatibleBitmap(scrn->hdcScreen, + iScrWidth, + iScrHeight); + if (!scrn->hBitmap) return FALSE; + + scrn->hOldObj = SelectObject(scrn->hdcBitmap, scrn->hBitmap); + if (!scrn->hOldObj) { + DWORD err = GetLastError(); + DeleteObject(scrn->hBitmap); + scrn->hBitmap = NULL; + SetLastError(err); + return FALSE; + } + + if (!BitBlt(scrn->hdcBitmap, + 0, 0, + iScrWidth, + iScrHeight, + scrn->hdcScreen, + rcScreen.left, rcScreen.top, + SRCCOPY)) + { + DWORD err = GetLastError(); + SelectObject(scrn->hdcBitmap, scrn->hOldObj); + DeleteObject(scrn->hBitmap); + scrn->hBitmap = NULL; + SetLastError(err); + + return FALSE; + } + + return TRUE; +} + +int +WriteRegionToFile(Screen *scrn, + RECT *rgn, + LPTSTR fname) +{ + BITMAP bmp = {0}; // hBitmap's metadata + HANDLE hOutFile = NULL; // Output .bmp + LPBYTE lpBits = NULL; // Actual bitmap bits + + HDC hdcRgn = NULL; // HDC for defined region + HBITMAP hRgnBitmap = NULL; // Bitmap of defined region + HGDIOBJ hOldObj = NULL; // Old bitmap, if any + PFULLBMPHDR pHdr = NULL; // Full bitmap header + PBITMAPINFO pbmi = NULL; // BMI header, in case bits <= 8 + + WORD cClrBits = 0; // How many bits per pixel + + BOOL hasErr = FALSE; // If something went wrong, set this + DWORD err = 0, // Used to store LastError + dwTmp = 0; // Used for written bytes storage + + if (!scrn || (!rgn || !fname)) { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + if (!RectInRegion(scrn->hScreenRgn, rgn)) { + // TODO: is there a better error we can set here? + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + // Overlay already grabs the screen, so don't trample over it + if (!scrn->hBitmap && !SnapScreen(scrn)) + { + hasErr = TRUE; + goto cleanup; + } + + hdcRgn = CreateCompatibleDC(scrn->hdcScreen); + if (!hdcRgn) { + hasErr = TRUE; + goto cleanup; + } + + // Create a new bitmap for the specific region + hRgnBitmap = CreateCompatibleBitmap(scrn->hdcScreen, + rgn->right - rgn->left, + rgn->bottom - rgn->top); + if (!hRgnBitmap) { + hasErr = TRUE; + goto cleanup; + } + + + if (!GetObject(hRgnBitmap, sizeof(BITMAP), &bmp)) { + hasErr = TRUE; + goto cleanup; + } + + hOldObj = SelectObject(hdcRgn, hRgnBitmap); + if (!hOldObj) { + hasErr = TRUE; + goto cleanup; + } + + if (!BitBlt( + hdcRgn, + 0, 0, + rgn->right - rgn->left, + rgn->bottom - rgn->top, + scrn->hdcBitmap, + rgn->left, rgn->top, + SRCCOPY)) + { + hasErr = TRUE; + goto cleanup; + } + + pHdr = GenerateBitmapInfo(scrn, + &bmp); + if (!pHdr) { + hasErr = TRUE; + goto cleanup; + } + + lpBits = HeapAlloc(GetProcessHeap(), + 0, + pHdr->info.biSizeImage); + if (!lpBits) { + hasErr = TRUE; + goto cleanup; + } + + if (pHdr->info.biBitCount <= 8) { + pbmi = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(BITMAPINFOHEADER) + + (pHdr->info.biClrUsed * sizeof(RGBQUAD))); + if (!pbmi) { + hasErr = TRUE; + goto cleanup; + } + CopyMemory(&pbmi->bmiHeader, &pHdr->info, sizeof(BITMAPINFOHEADER)); + } else { + // For all other bit sizes, we don't care about the color + // table. Just use the info header directly. + // (Yes this is pretty shady. Don't worry about it) + pbmi = (PBITMAPINFO) &pHdr->info; + } + + if (!GetDIBits(scrn->hdcBitmap, + hRgnBitmap, + 0, + (WORD) pHdr->info.biHeight, + lpBits, + pbmi, + DIB_RGB_COLORS)) + { + hasErr = TRUE; + goto cleanup; + } + + // Create and write to the output file + + hOutFile = CreateFile(fname, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hOutFile == INVALID_HANDLE_VALUE) { + hasErr = TRUE; + goto cleanup; + } + + // First, write the header + if (!WriteFile(hOutFile, pHdr, sizeof(FULLBMPHDR), &dwTmp, NULL)) { + hasErr = TRUE; + goto cleanup; + } + + // Assuming we're only using 16- or 32-bit BMPs, we should never + // need to write a color table. But since this could easily be + // modified to support smaller bit widths (i.e., 256 or less), + // let's make sure such cases don't crash. + if (pHdr->info.biBitCount <= 8) { + if (!WriteFile(hOutFile, + pbmi, + pbmi->bmiHeader.biClrUsed * sizeof(RGBQUAD), + &dwTmp, + NULL)) + { + hasErr = TRUE; + goto cleanup; + } + } + + // And last but not least, the pixels + if (!WriteFile(hOutFile, lpBits, pHdr->info.biSizeImage, &dwTmp, NULL)) { + hasErr = TRUE; + goto cleanup; + } + +cleanup: + // make sure to grab the error before we start freeing everything + if (hasErr) { + err = GetLastError(); + } + + if (hOutFile) { + CloseHandle(hOutFile); + if (hasErr) { + // Since it's probably busted, try to delete it too + DeleteFile(fname); + } + } + + if (lpBits) HeapFree(GetProcessHeap(), 0, lpBits); + + // In case our bits are <= 8, pbmi will be an actual heap-alloc'd + // pointer. Let's make sure to handle that. + if (pbmi && pbmi != (PBITMAPINFO) &pHdr->info) HeapFree(GetProcessHeap(), 0, pbmi); + + if (pHdr) HeapFree(GetProcessHeap(), 0, pHdr); + + if (scrn->hOldObj) SelectObject(scrn->hdcBitmap, scrn->hOldObj); + if (hOldObj) SelectObject(hdcRgn, hOldObj); + if (hRgnBitmap) DeleteObject(hRgnBitmap); + if (scrn->hBitmap) DeleteObject(scrn->hBitmap); + + if (hdcRgn) DeleteDC(hdcRgn); + + if (hasErr) { + SetLastError(err); + } + + return hasErr ? -1 : 0; +} \ No newline at end of file diff --git a/Bitmap.h b/Bitmap.h new file mode 100644 index 0000000..99b2ce1 --- /dev/null +++ b/Bitmap.h @@ -0,0 +1,18 @@ +#pragma once + +#include "stdafx.h" + +typedef struct _Screen { + HDC hdcScreen; + HDC hdcBitmap; + HRGN hScreenRgn; + HBITMAP hBitmap; + HGDIOBJ hOldObj; +} Screen; + +// Create a Screen struct. +Screen *CreateScreen(void); +// Write a screen region to the given filename. +int WriteRegionToFile(Screen *, RECT *, LPTSTR); +// Commit a "screenshot" of the screen to scrn->hBitmap +int SnapScreen(Screen *); \ No newline at end of file diff --git a/Grabby.c b/Grabby.c new file mode 100644 index 0000000..003e13e --- /dev/null +++ b/Grabby.c @@ -0,0 +1,94 @@ +// Grabby.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "Bitmap.h" +#include "Overlay.h" +#include "Grabby.h" + +/** + * Print an error with a given context before bailing out + */ +void Die(LPTSTR lpContextMsg) +{ + LPCTSTR lpszFmt = "%s: %s"; + int iFullLen; + LPTSTR lpszError = NULL, + lpszFullMsg = NULL; + + // The whole point of this is to print an actual message, so get the + // actual message + if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + 0, + (LPTSTR) &lpszError, + 0, + NULL)) + { + if (lpszError != NULL) LocalFree(lpszError); + lpszError = _T("unknown error"); + } + + iFullLen = _sctprintf(lpszFmt, lpContextMsg, lpszError); + lpszFullMsg = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR) * (iFullLen + 1)); + + if (lpszFullMsg == NULL) { + // I'm honestly gonna guess if we get here, we're out of memory. + // So let's print what we have and bail + MessageBox(NULL, + lpContextMsg, + _T("Catastrophic Error"), + MB_OK | MB_ICONERROR); + } else { + _sntprintf(lpszFullMsg, iFullLen, lpszFmt, lpContextMsg, lpszError); + MessageBox(NULL, + lpszFullMsg, + _T("Fatal Error"), + MB_OK | MB_ICONERROR); + } + + // TODO: should we still be nice and free memory here? + ExitProcess(1); +} + +int APIENTRY _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + RECT capRegion = {0}; + Screen *scrn = CreateScreen(); + + if (!scrn) { + Die("Couldn't get screen information"); + } + + switch (CreateOverlay(hInstance, scrn)) { + case -1: + Die("Couldn't create overlay window"); + break; + case 0: + /* Do nothing */ + break; + case 1: + // User requested we cancel out, so do that + return 0; + } + + GetChosenRect(&capRegion); + + + if (WriteRegionToFile(scrn, &capRegion, _T("test.bmp")) == -1) { + Die("Couldn't grab region of the screen"); + } + + MessageBox(NULL, + _T("Successfully grabbed a part of the screen!"), + _T("\\o/"), + MB_OK | MB_ICONINFORMATION); + + return 0; +} \ No newline at end of file diff --git a/Grabby.h b/Grabby.h new file mode 100644 index 0000000..99b2cd0 --- /dev/null +++ b/Grabby.h @@ -0,0 +1,5 @@ +#pragma once + +#include "resource.h" + +void Die(LPTSTR); \ No newline at end of file diff --git a/Grabby.ico b/Grabby.ico new file mode 100644 index 0000000..d551aa3 Binary files /dev/null and b/Grabby.ico differ diff --git a/Grabby.rc b/Grabby.rc new file mode 100644 index 0000000..57d852f --- /dev/null +++ b/Grabby.rc @@ -0,0 +1,128 @@ +//Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN) +LANGUAGE 17, 1 +#pragma code_page(932) + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. + +IDI_GRABBY ICON "Grabby.ico" +IDI_SMALL ICON "small.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_GRABBY MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_GRABBY ACCELERATORS +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG 22, 17, 230, 75 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 9, "System" +BEGIN + ICON IDI_GRABBY,IDC_MYICON,14,9,16,16 + LTEXT "Grabby Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2024",IDC_STATIC,49,20,119,8 + DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDC_GRABBY "GRABBY" + IDS_APP_TITLE "Grabby" +END + +#endif +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/Grabby.sln b/Grabby.sln new file mode 100644 index 0000000..3e07894 --- /dev/null +++ b/Grabby.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Grabby", "Grabby.vcproj", "{700E5DD7-DD00-46D9-92DF-2C132940F53D}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {700E5DD7-DD00-46D9-92DF-2C132940F53D}.Debug.ActiveCfg = Debug|Win32 + {700E5DD7-DD00-46D9-92DF-2C132940F53D}.Debug.Build.0 = Debug|Win32 + {700E5DD7-DD00-46D9-92DF-2C132940F53D}.Release.ActiveCfg = Release|Win32 + {700E5DD7-DD00-46D9-92DF-2C132940F53D}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Grabby.vcproj b/Grabby.vcproj new file mode 100644 index 0000000..be2f988 --- /dev/null +++ b/Grabby.vcproj @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Overlay.c b/Overlay.c new file mode 100644 index 0000000..9a60017 --- /dev/null +++ b/Overlay.c @@ -0,0 +1,225 @@ +#include "stdafx.h" +#include "Bitmap.h" + +LRESULT CALLBACK OverlayWndProc(HWND, UINT, WPARAM, LPARAM); + +#define OVERLAY_CLASS _T("GrabbyOverlay") +#define OVERLAY_TITLE _T("Grabby Overlay") + +// Static function to store and retrieve the overlay-chosen rect. +static void +SetGetRect(BOOL set, RECT *r) +{ + static RECT rcMain = {0}; + if (r) { + if (set) { + CopyMemory(&rcMain, r, sizeof(RECT)); + } else { + CopyMemory(r, &rcMain, sizeof(RECT)); + } + } + return; +} + +void +GetChosenRect(RECT *rcOut) +{ + SetGetRect(FALSE, rcOut); + return; +} + +int +CreateOverlay(HINSTANCE hInstance, + Screen *scrn) +{ + HWND hWnd = NULL; + RECT rcScreen = {0}; + MSG msg = {0}; + BOOL bRet; + WNDCLASSEX wcClass = { + sizeof(WNDCLASSEX), + CS_HREDRAW | CS_VREDRAW, + OverlayWndProc, + 0, + 0, + hInstance, + LoadIcon(NULL, IDI_APPLICATION), + LoadCursor(NULL, IDC_CROSS), + (HBRUSH)( COLOR_WINDOW + 1 ), + OVERLAY_TITLE, + OVERLAY_CLASS, + NULL + }; + + if (!RegisterClassEx(&wcClass)) { + return -1; + } + + if (!GetRgnBox(scrn->hScreenRgn, &rcScreen)) { + UnregisterClass(OVERLAY_CLASS, hInstance); + return -1; + } + + hWnd = CreateWindowEx( + WS_EX_TOPMOST, + OVERLAY_CLASS, + OVERLAY_TITLE, + WS_VISIBLE | WS_POPUP, + rcScreen.left, + rcScreen.top, + rcScreen.right - rcScreen.left, + rcScreen.bottom - rcScreen.top, + NULL, + NULL, + hInstance, + scrn); + + if (!hWnd) { + UnregisterClass(OVERLAY_CLASS, hInstance); + return -1; + } + + ShowWindow(hWnd, SW_SHOWNORMAL); + + while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0) { + if (bRet == -1) { + // TODO: error handling + break; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + if (hWnd) DestroyWindow(hWnd); + UnregisterClass(OVERLAY_CLASS, hInstance); + + return (int)msg.wParam; +} + +// Left, Top, Right, Bottom +#define POINT2RECT(a,b) { \ + min(a.x, b.x), \ + min(a.y, b.y), \ + max(a.x, b.x), \ + max(a.y, b.y) \ +} + +LRESULT CALLBACK +OverlayWndProc(HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + HDC hDC = NULL; + PAINTSTRUCT ps = {0}; + static POINTS ptStart = {0}, // Starting drag point + ptCur = {0}; // Current/end drag point + static BOOL isDrag = FALSE; // Are we mid-drag? + static Screen *scrn = NULL; // Screen data + static RECT rcScreen = {0}; + static HGDIOBJ hOldObj = NULL; + + switch (uMsg) { + case WM_CREATE: + { + HDC dcWnd = GetDC(hWnd); + // Get the Screen object passed in from CreateWindowEx + HBITMAP hOldBmp = NULL; + LPCREATESTRUCT csCreate = (LPCREATESTRUCT)lParam; + if (csCreate && csCreate->lpCreateParams) { + scrn = (Screen *)csCreate->lpCreateParams; + if (!scrn) { + // uhhhhhhhhh + MessageBox(hWnd, + _T("Couldn't get screen info for mysterious reasons !?"), + _T("Fatal Error"), + MB_OK | MB_ICONERROR); + PostQuitMessage(1); + return 1; + } + + GetRgnBox(scrn->hScreenRgn, &rcScreen); + + if (!SnapScreen(scrn)) { + MessageBox(hWnd, + _T("Couldn't store screen data !!"), + _T("Fatal Error"), + MB_OK | MB_ICONERROR); + PostQuitMessage(1); + return 1; + } + } + } + /* PASSTHRU */ + case WM_PAINT: + hDC = BeginPaint(hWnd, &ps); + + if (scrn->hBitmap) { + // Draw the "background" + if (!BitBlt(hDC, + ps.rcPaint.left, + ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + scrn->hdcBitmap, + rcScreen.left + ps.rcPaint.left, + rcScreen.top + ps.rcPaint.top, + SRCCOPY)) + { + // walk it off, I guess... + OutputDebugString(_T("Failed to blit background to DC...")); + } + } + + if (isDrag && hDC) { + RECT rcOuter = POINT2RECT(ptStart, ptCur); + DrawFocusRect(hDC, &rcOuter); + } + + EndPaint(hWnd, &ps); + break; + case WM_MOUSEMOVE: + if (isDrag && (wParam & MK_LBUTTON)) { + POINTS ptPrev = ptCur; + ptCur = MAKEPOINTS(lParam); + if ((ptCur.x != ptStart.x) && + (ptCur.y != ptStart.y)) + { + RECT rcPrevDmg = POINT2RECT(ptStart, ptPrev); + // InvalidateRect(hWnd, &rcCurDmg, TRUE); + InvalidateRect(hWnd, &rcPrevDmg, TRUE); + } + + } + break; + case WM_LBUTTONDOWN: + if (!isDrag) { + // Start the drag operation and set the origin + ptStart = ptCur = MAKEPOINTS(lParam); + isDrag = TRUE; + } + break; + case WM_LBUTTONUP: + if (isDrag) { + // Done dragging, store the rect and get out of here + RECT rcFinal = POINT2RECT(ptStart, ptCur); + + SetGetRect(TRUE, &rcFinal); + isDrag = FALSE; + PostQuitMessage(0); + } + break; + case WM_KEYUP: + // TODO: Escape + break; + case WM_RBUTTONUP: + // We treat right click as Escape + PostQuitMessage(1); + break; + default: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + + return 0; +} \ No newline at end of file diff --git a/Overlay.h b/Overlay.h new file mode 100644 index 0000000..02ef611 --- /dev/null +++ b/Overlay.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Bitmap.h" + +// Gets a RECT representing the screen region the user wants. +void GetChosenRect(RECT *); + +// Creates the overlay window. +int CreateOverlay(HINSTANCE, Screen *); \ No newline at end of file diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..0ea70af --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,53 @@ +======================================================================== + WIN32 APPLICATION : Grabby Project Overview +======================================================================== + +AppWizard has created this Grabby application for you. +This file contains a summary of what you will find in each of the files that +make up your Grabby application. + + +Grabby.vcproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +Grabby.cpp + This is the main application source file. + +///////////////////////////////////////////////////////////////////////////// +AppWizard has created the following resources: + +Grabby.rc + This is a listing of all of the Microsoft Windows resources that the + program uses. It includes the icons, bitmaps, and cursors that are stored + in the RES subdirectory. This file can be directly edited in Microsoft + Visual C++. + +Resource.h + This is the standard header file, which defines new resource IDs. + Microsoft Visual C++ reads and updates this file. +Grabby.ico + This is an icon file, which is used as the application's icon (32x32). + This icon is included by the main resource file Grabby.rc. + +small.ico + This is an icon file, which contains a smaller version (16x16) + of the application's icon. This icon is included by the main resource + file Grabby.rc. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named Grabby.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/Resource.h b/Resource.h new file mode 100644 index 0000000..6bcd5f7 --- /dev/null +++ b/Resource.h @@ -0,0 +1,29 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Grabby.rc +// + +#define IDS_APP_TITLE 103 + +#define IDR_MAINFRAME 128 +#define IDD_GRABBY_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_GRABBY 107 +#define IDI_SMALL 108 +#define IDC_GRABBY 109 +#define IDC_MYICON 2 +#define IDC_STATIC -1 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/small.ico b/small.ico new file mode 100644 index 0000000..d551aa3 Binary files /dev/null and b/small.ico differ diff --git a/stdafx.c b/stdafx.c new file mode 100644 index 0000000..33bf825 --- /dev/null +++ b/stdafx.c @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// Grabby.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..8ee51eb --- /dev/null +++ b/stdafx.h @@ -0,0 +1,19 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +// C RunTime Header Files +#include +#include +#include +#include +#include + +// TODO: reference additional headers your program requires here