I'm facing quite a dilemma. I've injected my DLL into other process as well as hooked few
WinAPI calls from there, ExtTextOutW#GDI32, DrawTextExW#GDI32 and AlphaBlend#Msimg32 to be specific. Now, the problem is that when the other application writes something with those two GDI32 functions, i don't know the exact location where it comes up. This is because the DC which contains the text gets processed with AlphaBlend, which also eventually puts it to the window's DC.
So, how can I track certain HDC? In pseudo code, here's how the other application draws
text to the screen:
HDC h = DrawTextW("STRING")
Do something with h. The "STRING" gets new HDC, say h2.
Pass h2 to AlphaBlend, which draws it to the screen.
Like I said, I loose track with the original h as the string gets new DC before AlphaBlend.
Any idea, how I can make a connection from h > h2 with certain string in it?
I don't know if I was able to explain the problem properly, please ask if you've got any questions...
static BOOL (WINAPI *AlphaBlend_t)(
HDC hdcDest,
int nXOriginDest,
int nYOriginDest,
int nWidthDest,
int nHeightDest,
HDC hdcSrc,
int nXOriginSrc,
int nYOriginSrc,
int nWidthSrc,
int nHeightSrc,
BLENDFUNCTION blendFunction
) = AlphaBlend;
BOOL MyAlphaBlend(
HDC hdcDest,
int nXOriginDest,
int nYOriginDest,
int nWidthDest,
int nHeightDest,
HDC hdcSrc,
int nXOriginSrc,
int nYOriginSrc,
int nWidthSrc,
int nHeightSrc,
BLENDFUNCTION blendFunction
)
{
// modify hdcDest to hdcDest2
return AlphaBlend_t(hdcDest2, ...);
}
That should do the trick. Put in any code to modify the HDC in the latter function.
Related
I am unable to manage memory for Bitmap and CLSID objects I have created in a screenshot object class. Both of these are from the GDI+ library. The header lists the following private variables in Screenshot.h
#include <gdiplus.h>
#include <iostream>
#include <fstream>
#include <string>
#include "windows.h"
#pragma once
#pragma comment(lib, "gdiplus.lib")
using namespace std;
using namespace Gdiplus;
class Screenshot
{
private:
HDC dc, memdc, fontdc;
HBITMAP membit;
Bitmap* bmpPtr;
CLSID clsid;
ULONG_PTR gdiplusToken;
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
public:
Screenshot();
~Screenshot();
void TakeScreenshot(string userAction, string winName, long xMousePos, long yMousePos, long long tStamp);
void SaveScreenshot(string filename);
void memoryManagement();
};
Then when my main program takes a screenshot, the values are filled in with TakeScreenshot(), but not yet saved to disk
void Screenshot::TakeScreenshot(//redacted for readibility) {
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hwnd = GetDesktopWindow();
dc = ::GetDC(0);
int scaleHeight, scaleWidth = 0;
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
scaleHeight = Height + (0.1 * Height);
memdc = CreateCompatibleDC(dc);
membit = CreateCompatibleBitmap(dc, Width, scaleHeight);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);
//Other code that adds fonts, etc. Does not invoke bmpPtr
bmpPtr = new Bitmap(membit, NULL);
GetEncoderClsid(L"image/jpeg", &clsid);
If the screenshot is saved, another function SaveScreenshot() uses bmpPtr->Save() and Gdiplus shutdown is called inside of it. However, some of the screenshots get popped off from a queue (STL queue) and out of memory instead of saved, as follows:
void ManageQueue(Screenshot& ssObj)
{
//If queue contains 30 screenshots, pop off first element and push new object
//Else just push new object
if (screenshotQueue.size() == MAX_SCREENSHOTS)
{
screenshotQueue.front().memoryManagement();
screenshotQueue.pop();
screenshotQueue.push(ssObj);
}
else
{
screenshotQueue.push(ssObj);
}
}
I wrote a MemoryManagement() function to perform the necessary releases and deletes before the Screenshot is popped off. This function is not called if the screenshot has been saved:
void Screenshot::memoryManagement()
{
delete bmpPtr;
delete &clsid;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
}
When either the delete on bmpPtr or clsid is called, whether it is from this function or in the deconstructor, the program is crashing. I am experiencing significant memory leaks with the program now and without running a windows equivalent of Valgrind I'm assuming it's coming from here. How can I successfully delete these objects? I will credit any answer in my source code as a contributing programmer. Please leave any suggestions for improving my question if needed.
scaleHeight = Height + (0.1 * Height);
This seems to be an attempt to fix the problem with DPI scaling. It will work if DPI settings is at 10%, but that's usually not the case. You have to make your program DPI aware through the manifest file. Use SetProcessDPIAware for a quick fix.
Don't declare dc, memdc, etc. as class members. These are GDI handles (not GDI+) which you can hold for a short time, usually during the duration of the function. You have to release them as soon as possible.
Also other variables like clsid don't need to be declared as class members. You can declare them as class member if you wish, but there is nothing to gain.
If you have a multi-monitor setup you also need SM_XVIRTUALSCREEN/Y to get the top-left corner of the monitor setup.
//call this once on start up
SetProcessDPIAware();
HDC dc = ::GetDC(0);
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
HDC memdc = CreateCompatibleDC(dc);
HBITMAP membit = CreateCompatibleBitmap(dc, Width, Height);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, x, y, SRCCOPY);
Bitmap* bmpPtr = new Bitmap(membit, NULL);
// or just Bitmap bmp(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bmpPtr->Save(L"output.jpg", &clsid);
//cleanup:
delete bmpPtr;
SelectObject(memdc, bmpContainer);
DeleteObject(membit);
DeleteDC(memdc);
ReleaseDC(0, dc);
The solution for this problem was to use the namespace delete instead of regular delete. Switching to this prevented the break point trigger during debug and has sealed the memory leak.
void Screenshot::memoryManagement()
{
::delete bmpPtr;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
GdiplusShutdown(gdiplusToken);
}
So my teacher gave us a chunk of code to use for double buffering.
He said "here, use this code so you don't have to sit there for hours finding out how"
Except his code does not function.
His initial usage of hdc is undefined. I tried putting it in the parameter list but that is a no go.
This is the code he gave us:
// Create a backbufer bmp bufer to draw to in memory.
RECT rcClient;
::GetClientRect(hwnd, &rcClient);
int left = rcClient.left;
int top = rcClient.top;
int width = rcClient.right - rcClient.left;
int height = rcClient.bottom - rcClient.top;
HDC hdcMem = ::CreateCompatibleDC(hdc);
const int nMemDC = ::SaveDC(hdcMem);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hdc, width, height);
::SelectObject(hdcMem, hBitmap);
Graphics graphics(hdcMem);
SolidBrush back(Color(255,255,255));
graphics.FillRectangle(&back, left, top, width, height);
// Draw to backbufer bitmap here.
// End draw to backbufer bitmap bufer.
// Swap bufers ie. push memory backbufer to the screen frontbufer
RECT rcClip;
::GetClipBox(hdc, &rcClip);
left = rcClip.left;
top = rcClip.top;
width = rcClip.right - rcClip.left;
height = rcClip.bottom - rcClip.top;
::BitBlt(hdc, left, top, width, height, hdcMem, left, top, SRCCOPY);
::RestoreDC(hdcMem, nMemDC);
::DeleteObject(hBitmap);
Right here is where I run into the errors: HDC hdcMem = ::CreateCompatibleDC(hdc);
I attempted declaring an HDC like so
HDC hdc = (HDC)BeginPaint((LPPAINTSTRUCT)AfxGetApp()->m_pMainWnd->GetSafeHwnd());
But that doesn't compile. What do I do with this hdc?
The HDC is returned by BeginPaint, which presumably is called immediately before this code. BeginPaint takes two parameters and you are trying to call it with only one parameter. Do you have earlier exercises where you handled BeginPaint?
So thanks to the various answers here. My knowledge of this is still fairly new, however with the help of my class mates I was able to come to a solution. Sadly I still do not know what to do with the HDC and this was the first of my problems,
HDC hdcMem = ::CreateCompatibleDC(hdc); was able to be replaced by
HDC hdcMem = ::CreateCompatibleDC(dc);
and a lot of the other code that produced warnings such as the hwnd was simply removed and it worked fine.
I have some problem with my designs for function, and I do not find a proper solution (I am quite a beginner in C++).
Some days ago, I ask another question which is linked to this one.
So, I have a function that makes a screen capture. It works perfectly.
The fact is that I want this function to return an Image object from a class I implemented.
Basically, it is:
class Image {
public:
BYTE *bitPointer;
int width;
int height;
};
And my function is like this one:
Image screenCapture(int width, int height) {
HDC hdcTemp, hdc;
BYTE* bitPointer;
hdc = GetDC(HWND_DESKTOP);
hdcTemp = CreateCompatibleDC(hdc);
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = width;
bitmap.bmiHeader.biHeight = -height;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 24;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = 0;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
SelectObject(hdcTemp, hBitmap);
BitBlt(hdcTemp, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
ReleaseDC(HWND_DESKTOP, hdc);
DeleteDC(hdcTemp);
Image screen;
screen.bitPointer = bitPointer;
screen.width = width;
screen.height = height;
return screen;
}
The bitPointer created using CreateDIBSection is actually a pointer to the value of my first pixel (if I understood well).
Then, I can use a simple loop:
for (int i = 0; i >= 0; i++) {
cout << i << ": " << (int)screenCapture(1366, 768).bitPointer[0] << endl;
}
Here is my issue.
I have to free up the hBitmap by calling DeleteObject(hBitmap) otherwise I would have no more memory space (and the loop finally crash).
However, I do not know where to do it.
I would like to do it within my function but if I call DeleteObject(), then it will destroy my bitPointer too and therefore I will not be able to access pixels from my Image object returned.
In fact, I am a little confused with the fact that my bitPointer variable is a pointer. It means that I can not copy it to prevent it being destroyed after. I can not find the solution.
Two solutions I have tried:
Create a destructor calling DeleteObject() for my class Image.
It did not work because the destructor is call from the function and not only from inside my loop.
Add an attribute HBITMAP hBitmap to my class Image, and call DeleteObject() from inside my loop.
It is not really convenient, moreover I have to declare a new Image object, I can not do it anonymously like in the loop I writed.
So, I am stuck, could anyone help me please?
You can pass hBitmap as an argument to screenCapture function.
screenCapture(int width, int height, HBITMAP& hBitmap)
This way you get to destroy it when you want without interfering with Image members. You declare an "empty" hBitmap outside screenCapture function and pass it as argument. The function will use the reference to create the object and you will be able to destroy it outside of screenCapture after you are done with using bitPointer values.
If you need storing all screenshots, you need to implement a working buffer as you have finite amount of memory.
Trying to run a for loop through physical monitors but the handles are really confusing me, I have pseudo code that runs along the lines of:
int tempCounter=0
for(counter = number of monitors;counter > 0;counter--){
RECT tempRECT;
HDC tempHDC;
Get resolution of DC handle (counter) -> tempRECT;
arrayList[tempCounter] = tempRECT;
Get virtual work area of DC handle (counter) -> tempRECT;
arrayList[tempCounter++] = tempRECT;
tempCounter++;
}
GetSystemMetrics(80) for the count of monitors, is this reliable enough to use, or any exceptions it might fail?
I know there is not much there, but looking on the MSDN just kept me going around in circles, that and I am not very competent at programming.
It can be as simple as this:
#include <Windows.h>
#include <stdio.h>
BOOL CALLBACK MonitorEnumProc(
HMONITOR hMonitor,
HDC hdcMonitor,
LPRECT lprcMonitor,
LPARAM dwData
)
{
printf("%dx%d\n", lprcMonitor->right, lprcMonitor->bottom);
}
int main(int argc, char*argv[]) {
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
}
I would like to get the RGB values of a pixel at different x, y coordinates on the screen.
How would I go about this in C++?
I'm trying to create my own gaussian blur effect.
This would be in Windows 7.
Edit
What libraries need to be included for this to run?
What I have going:
#include <iostream>
using namespace std ;
int main(){
HDC dc = GetDC(NULL);
COLORREF color = GetPixel(dc, 0, 0);
ReleaseDC(NULL, dc);
cout << color;
}
You can use GetDC on the NULL window to get a device context for the whole screen, and can follow that up with a call to GetPixel:
HDC dc = GetDC(NULL);
COLORREF color = GetPixel(dc, x, y);
ReleaseDC(NULL, dc);
Of course, you'd want to only acquire and release the device context once while doing all the pixel-reading for efficiency.
As mentioned in a previous post, you want the GetPixel function from the Win32 API.
GetPixel sits inside gdi32.dll, so if you have a proper environment setup, you should be able to include windows.h (which includes wingdi.h) and you should be golden.
If you have a minimal environment setup for whatever reason, you could also use LoadLibrary on gdi32.dll directly.
The first parameter to GetPixel is a handle to the device context, which can be retrieved by calling the GetDC function(which is also available via <windows.h>).
A basic example that loads GetPixel from the dll and prints out the color of the pixel at your current cursor position is as follows.
#include<windows.h>
#include<stdio.h>
typedef WINAPI COLORREF (*GETPIXEL)(HDC, int, int);
int main(int argc, char** argv)
{
HINSTANCE _hGDI = LoadLibrary("gdi32.dll");
if(_hGDI)
{
while(true) {
GETPIXEL pGetPixel = (GETPIXEL)GetProcAddress(_hGDI, "GetPixel");
HDC _hdc = GetDC(NULL);
if(_hdc)
{
POINT _cursor;
GetCursorPos(&_cursor);
COLORREF _color = (*pGetPixel) (_hdc, _cursor.x, _cursor.y);
int _red = GetRValue(_color);
int _green = GetGValue(_color);
int _blue = GetBValue(_color);
printf("Red: 0x%02x\n", _red);
printf("Green: 0x%02x\n", _green);
printf("Blue: 0x%02x\n", _blue);
}
FreeLibrary(_hGDI);
}
}
return 0;
}