Create project "Grabby".

git-svn-id: svn://vcs.sdm.2ki.xyz/Grabby/trunk@9 27729192-006e-004d-b9b5-06fbd0ef7001
This commit is contained in:
snow flurry 2024-02-13 21:00:46 +00:00
commit 585e61636a
15 changed files with 1133 additions and 0 deletions

352
Bitmap.c Normal file
View file

@ -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 <pshpack1.h>
typedef struct _FULLBMPHDR {
BITMAPFILEHEADER file;
BITMAPINFOHEADER info;
} FULLBMPHDR, *PFULLBMPHDR;
#include <poppack.h>
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;
}

18
Bitmap.h Normal file
View file

@ -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 *);

94
Grabby.c Normal file
View file

@ -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;
}

5
Grabby.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#include "resource.h"
void Die(LPTSTR);

BIN
Grabby.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

128
Grabby.rc Normal file
View file

@ -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

21
Grabby.sln Normal file
View file

@ -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

172
Grabby.vcproj Normal file
View file

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="shift_jis"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="Grabby"
ProjectGUID="{700E5DD7-DD00-46D9-92DF-2C132940F53D}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"
CompileAs="1"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/Grabby.exe"
LinkIncremental="2"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/Grabby.pdb"
SubSystem="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="4"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/Grabby.exe"
LinkIncremental="1"
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\Bitmap.c">
</File>
<File
RelativePath=".\Grabby.c">
</File>
<File
RelativePath=".\Overlay.c">
</File>
<File
RelativePath=".\stdafx.c">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\Bitmap.h">
</File>
<File
RelativePath=".\Grabby.h">
</File>
<File
RelativePath=".\Resource.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
<File
RelativePath=".\Grabby.ico">
</File>
<File
RelativePath=".\Grabby.rc">
</File>
<File
RelativePath=".\small.ico">
</File>
</Filter>
<File
RelativePath=".\ReadMe.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

225
Overlay.c Normal file
View file

@ -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;
}

9
Overlay.h Normal file
View file

@ -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 *);

53
ReadMe.txt Normal file
View file

@ -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.
/////////////////////////////////////////////////////////////////////////////

29
Resource.h Normal file
View file

@ -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

BIN
small.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

8
stdafx.c Normal file
View file

@ -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

19
stdafx.h Normal file
View file

@ -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 <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here