I have solved the saving, but my problem now is that the image file does not contain the picture of the window. Can you help to fix it?
Code: Select all
// CODE 81 and 82 de facto no difference
#define CODE 85 // 81
#define WINDOW_MIN_HEIGHT 200
#define WINDOW_MAX_HEIGHT 700
#define WINSTYLE 0x14FF0000
#define ROTATION_ANGLE 45
#define M_PI 3.14159265358979323846
// #define IS_CHILD TRUE // [TRUE | FALSE | 0] ... 0 - deactivates this detection
// GetWindowLong: GWL_HWNDPARENT
#include <windows.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
#include <tchar.h>
#include <conio.h>
#include <gdiplus.h>
#include <stdlib.h> // abs
#include <math.h> // cos
using namespace std;
using namespace Gdiplus;
int GetEncoderClsid (const WCHAR* format, CLSID* pClsid)
{
UINT num = 0;//number of image encoders
UINT size = 0;//size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize (&num, &size);
if (size == 0)
return-1;//Failure
pImageCodecInfo = (ImageCodecInfo *) (malloc (size));
if (pImageCodecInfo == NULL)
return-1;//Failure
GetImageEncoders (num, size, pImageCodecInfo);
for (UINT j = 0; j <num; ++ j)
{
if (wcscmp (pImageCodecInfo [j].MimeType, format) == 0)
{
*pClsid = pImageCodecInfo [j].Clsid;
free (pImageCodecInfo);
return j;//Success
}
}
free (pImageCodecInfo);
return-1;//Failure
}
// Old way to save file
int FileWriteSaveImage(BYTE* memory, LONG dx, LONG dy, int fudgex)
{
char *buffer = new char[50];
sprintf(buffer, "capture%d%d.bmp", dx, dy);
ofstream file(buffer, ios::binary);
if (!file) return 1;
// initialize bitmap file headers
BITMAPFILEHEADER fileHeader = {0};
BITMAPINFOHEADER infoHeader = {0};
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
infoHeader.biSize = sizeof(infoHeader);
infoHeader.biWidth = dx + fudgex;
infoHeader.biHeight = dy;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biCompression = BI_RGB;
// save file headers
file.write((char*)&fileHeader, sizeof(fileHeader));
file.write((char*)&infoHeader, sizeof(infoHeader));
// save 24-bit bitmap data
int wbytes = (((24 * (dx) + 31) & (~31)) / 8);
int tbytes = wbytes * dy;
file.write((char*)(memory), tbytes);
file.close();
return 0;
}
const int maxstr = 200;
// const char wndtitle[] = "AOK";
RECT rect, wrect;
int fudgex, fudgey;
struct windata {
static const string titles[]; // only static const integral data members can be initialized within a class
static const string default;
string choose;
HWND hfnd; // Found destination window handler
};
const string windata::titles[] = {"learn", "dialog", "aok", "map" };
const string windata::default = "learn"; // windata.default = ... will produce syntax error : missing ';' before '.'
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lparam)
{
char title[maxstr + 1];
char *ch = title;
GetWindowRect(hwnd, &wrect); // Calculate window height
int winHeight = wrect.bottom-wrect.top;
if ( (WINDOW_MIN_HEIGHT && winHeight<WINDOW_MIN_HEIGHT) ||
(WINDOW_MAX_HEIGHT && winHeight>WINDOW_MAX_HEIGHT))
return TRUE; // skip window
if ( GetWindowLong(hwnd, GWL_STYLE) & WINSTYLE != TRUE )
return TRUE;
/* GetWindowTextA - copies the text of the specified window's
title bar (if it has one) into a buffer. If the specified window is a
control, the text of the control is copied. However, it
can't retrieve the text of a control in another application. */
if (GetWindowTextA(hwnd, title, maxstr)) {
for (char *ch = title; *ch; ++ch) // was ch++)
*ch = (char)tolower(*ch);
// strstr - finds the first occurrence of a substring within a string. The comparison is case-sensitive.
// c_str - converts the contents of a string as a C-style, null-terminated string.
if (strstr(title, ((windata*)lparam)->choose.c_str())) {
((windata*)lparam)->hfnd = hwnd;
SetLastError(ERROR_NO_MATCH);
cout << "Found matching window - " << title << endl;
return FALSE;
}
}
return TRUE;
} // Press F5 to continue debug, not F10. Otherwise "error" occurs.
int main()
{
// HWND HCapture = GetForegroundWindow();
/* HWND HCapture = FindWindow(NULL, _T("Learning WInAPI")); // get window handle
*/
windata wd;
cout << "Partial window title: ";
getline(cin, wd.choose);
wd.choose.erase(wd.choose.find_last_not_of(" \n\r\t")+1); // trim string
if ( wd.choose == "" ) // select default window
wd.choose = wd.default;
/* EnumWindows(in,in) - Enumerates all top-level windows on the
screen by passing the handle to each window, in turn, to
callback function. EnumWindows continues until the last top-level
window is enumerated or the callback function returns FALSE.
The EnumWindows function does not enumerate child windows.
*/
if (EnumWindows(EnumWindowsProc, (LPARAM)&wd) || (GetLastError() != ERROR_NO_MATCH)) {
cout << "Cannot find window\n";
_getch();
return 1;
}
HWND HCapture = wd.hfnd;
if (!IsWindow(HCapture)) {
cout << "Bad find! Cannot find window\n";_getch();return 2;
}
#if CODE<85
fudgey = (GetMenu(HCapture)?GetSystemMetrics(SM_CYMENU):0)
+ GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYSIZEFRAME);
fudgex = 0;
#endif
GetClientRect(HCapture, &rect);
LONG dx = rect.right - rect.left;
LONG dy = rect.bottom - rect.top;
if (CODE>82) {
/*
const int fudgey = (GetMenu(HCapture)?GetSystemMetrics(SM_CYMENU):0)
+ GetSystemMetrics(SM_CYSIZE) + GetSystemMetrics(SM_CYSIZEFRAME);
*/
// Height should be 26 not 22
fudgey = (wrect.bottom - wrect.top) - dy +4 - 2 * GetSystemMetrics(SM_CYSIZEFRAME);
fudgex = 0;
}
/*
int test = GetSystemMetrics(SM_CYSIZEFRAME); // 4
int test2 = GetSystemMetrics(SM_CYMENU); // 24
int test3 = wrect.bottom - wrect.top;
*/
// create BITMAPINFO structure
// used by CreateDIBSection
BITMAPINFO info = {0};
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = dx + fudgex;
info.bmiHeader.biHeight = dy + fudgey;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 24;
info.bmiHeader.biCompression = BI_RGB;
HDC HDevice = CreateCompatibleDC(NULL);
//HDC HDevice = GetDC(HCapture);
BYTE* memory = 0;
HBITMAP HBitmap = CreateDIBSection(HDevice, &info, DIB_RGB_COLORS, (void**)&memory, NULL, NULL);
SelectObject(HDevice, HBitmap);
//SendMessage(HCapture, WM_PRINTCLIENT, 0, 0);
// SendMessage(HCapture, WM_PRINTCLIENT,(WPARAM) HDevice, 0);
if (!PrintWindow(HCapture, HDevice, /*PW_CLIENTONLY*/0))
return 2;
// SendMessage(HCapture, WM_PRINTCLIENT, 0, 0);
ReleaseDC(HCapture, HDevice);
// INIT GDI
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
if (!gdiplusToken) return 3;
// Gdip_GetRotatedDimensions:
GpBitmap* pBitmap;
int result = Gdiplus::DllExports::GdipCreateBitmapFromHBITMAP(HBitmap, 0, &pBitmap);
// SelectObject(HDevice, obm); DeleteObject(hbm); DeleteDC(hdc)
unsigned int w; unsigned int h;
//GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
Gdiplus::DllExports::GdipGetImageWidth(pBitmap, &w);
Gdiplus::DllExports::GdipGetImageHeight(pBitmap, &h);
REAL TAngle = ROTATION_ANGLE*(M_PI/180);
if ( !w && !h )
return -1;
REAL RWidth = ceil(abs(w*cos(TAngle))+abs(h*sin(TAngle)));
REAL RHeight = ceil(abs(w*sin(TAngle))+abs(h*cos(TAngle)));
// gdip_getrotatedtranslation:
REAL xTranslation, yTranslation;
REAL bound = (ROTATION_ANGLE >= 0) ? ROTATION_ANGLE%360 : 360-(-ROTATION_ANGLE%-360);
if ((bound >= 0) && (bound <= 90))
{ xTranslation = h*sin(TAngle); yTranslation = 0; }
else if ((bound > 90) && (bound <= 180))
{ xTranslation = (h*sin(TAngle))-(w*cos(TAngle)); yTranslation = -1*h*cos(TAngle); }
else if ((bound > 180) && (bound <= 270))
{ xTranslation = -(w*cos(TAngle)); yTranslation = -(h*cos(TAngle))-(w*sin(TAngle)); }
else if ((bound > 270) && (bound <= 360))
{ xTranslation = 0; yTranslation = -1*w*sin(TAngle); }
// Gdip_GraphicsFromImage:
// GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics)
GpGraphics * pG;
result = Gdiplus::DllExports::GdipGetImageGraphicsContext(pBitmap, &pG);
// GpStatus WINGDIPAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode)
// smooth = 4; See http://msdn.microsoft.com/en-us/library/windows/desktop/ms534173%28v=vs.85%29.aspx
Gdiplus::SmoothingMode smooth = SmoothingModeHighQuality;
result = Gdiplus::DllExports::GdipSetSmoothingMode(pG, smooth);
// ; Best interpolation is 5 - it's like no antialias
// Gdip_SetInterpolationMode(G, 7)
// Gdip_SetInterpolationMode(pGraphics, InterpolationMode)
// GpStatus WINGDIPAPI GdipSetInterpolationMode(GpGraphics *graphics, InterpolationMode interpolationMode)
// Gdiplus::InterpolationMode interpolation = 7; // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms534141%28v=vs.85%29.aspx
Gdiplus::InterpolationMode interpolation = InterpolationModeNearestNeighbor;
result = Gdiplus::DllExports::GdipSetInterpolationMode(pG, interpolation);
// Gdip_TranslateWorldTransform(pGraphics, x, y, MatrixOrder=0)
// GpStatus WINGDIPAPI GdipTranslateWorldTransform(GpGraphics *graphics, REAL dx, REAL dy, GpMatrixOrder order)
/*
enum MatrixOrder
{
MatrixOrderPrepend = 0,
MatrixOrderAppend = 1
};
*/
MatrixOrder MatrixOrder_ = MatrixOrderPrepend;
result = Gdiplus::DllExports::GdipTranslateWorldTransform(pG, xTranslation, yTranslation, MatrixOrder_);
// Gdip_RotateWorldTransform(G, Angle)
// Gdip_RotateWorldTransform(pGraphics, Angle, MatrixOrder=0)
// GpStatus WINGDIPAPI GdipRotateWorldTransform(GpGraphics *graphics, REAL angle, GpMatrixOrder order)
MatrixOrder_ = MatrixOrderPrepend;
result = Gdiplus::DllExports::GdipRotateWorldTransform(pG, ROTATION_ANGLE, MatrixOrder_);
// GpStatus WINGDIPAPI GdipCreateImageAttributes(GpImageAttributes **imageattr)
GpImageAttributes * ImgAttributes;
// from 'Gdiplus::GpImageAttributes' to 'Gdiplus::GpImageAttributes **'
result = Gdiplus::DllExports::GdipCreateImageAttributes(&ImgAttributes); // create an ImageAttribute object
int sx(0), sy(0);
// Gdip_DrawImage
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms536044%28v=vs.85%29.aspx
// GpStatus WINGDIPAPI GdipDrawImageRectRect(
// GpGraphics *graphics, GpImage *image, REAL dstx, REAL dsty, REAL dstwidth, REAL dstheight, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
// GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, DrawImageAbort callback, VOID * callbackData)
result = Gdiplus::DllExports::GdipDrawImageRectRect(pG,pBitmap,0,0,w,h,0,0,w,h,UnitPixel,ImgAttributes,0,0); // Draw the original image onto the new bitmap
result = Gdiplus::DllExports::GdipDisposeImageAttributes(ImgAttributes);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
// GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height, GpGraphics* target, GpBitmap** bitmap)
result = Gdiplus::DllExports::GdipCreateBitmapFromGraphics(w, h, pG, &pBitmap);
result = Gdiplus::DllExports::GdipSaveImageToFile(pBitmap, L"justest.png", &pngClsid, NULL); // last voluntary? GDIPCONST EncoderParameters* encoderParams
DeleteObject(HBitmap);
// FileWriteSaveImage(memory, dx, dy, fudgex);
return 0;
}
And it fails to get the picture to the file. In the png just created, there are no pixels (I see black image only). Tested on several windows.