I need to load a bmp image from file and load image data into buffer and then create new image from it. (I have a reason for doing this way). I wrote a sample program to mimic my project scenario.
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static BITMAP bm;
static HBITMAP bmpSource = NULL;
static HBITMAP hbmp=NULL;
static HDC hdcSource = NULL;
static HDC hdcDestination= NULL;
static PAINTSTRUCT ps;
BITMAPINFO bitmap_info[2] = {0};
if (Msg == WM_CREATE) {
bmpSource = (HBITMAP)LoadImage(NULL, L"bmp00004.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
GetObject(bmpSource, sizeof(BITMAP), &bm);
bitmap_info->bmiHeader.biSize = sizeof(bitmap_info->bmiHeader);
int ret = GetDIBits(hdcSource, bmpSource, 0, bm.bmHeight, NULL, bitmap_info,DIB_RGB_COLORS);
LPVOID *lpvBits = (LPVOID*) malloc(3*(bm.bmWidth * bm.bmHeight * sizeof(DWORD)));
int gotData = GetDIBits(hdcSource, bmpSource, 0,bm.bmHeight,lpvBits, bitmap_info, DIB_RGB_COLORS);
hbmp = (HBITMAP) CreateBitmap(bm.bmWidth, bm.bmHeight, bm.bmPlanes, bm.bmBitsPixel ,lpvBits);
hdcSource = CreateCompatibleDC(GetDC(0));
SelectObject(hdcSource, hbmp);
return 0;
}else if (Msg == WM_PAINT) {
hdcDestination = BeginPaint(hWnd, &ps);
BitBlt(hdcDestination, 0, 0,bm.bmWidth , bm.bmHeight, hdcSource, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
return 0;
}else if (Msg == WM_DESTROY) {
DeleteDC(hdcSource);
EndPaint(hWnd, &ps);
DeleteObject(bmpSource);
DeleteObject(hbmp);
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
I am expecting program to print the image on the window.
Now the newly created image is not displayed on window. All I can see is a gray box.
Your code can be considerably simplified. There is no need to call GetDIBits (which you are doing before you set up hdcSource anyway), and you should clean up properly and minimise the use of static variables. Something like the following (error checking omitted for clarity):
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP bmpSource;
if (Msg == WM_CREATE) {
bmpSource = (HBITMAP)LoadImage(NULL, L"bmp00004.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
return 0;
}
if (Msg == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdcDestination = BeginPaint(hWnd, &ps);
BITMAP bm;
GetObject(bmpSource, sizeof(bm), &bm);
HDC hdcSource = CreateCompatibleDC(hdcDestination);
HGDIOBJ hOldBmp = SelectObject(hdcSource, bmpSource);
BitBlt(hdcDestination, 0, 0,bm.bmWidth , bm.bmHeight, hdcSource, 0, 0, SRCCOPY);
SelectObject(hdcSource, hOldBmp);
DeleteDC(hdcSource);
EndPaint(hWnd, &ps);
return 0;
}
if (Msg == WM_DESTROY)
DeleteObject(bmpSource);
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
It seems you are attempting to read a bitmap file and write to another HBITMAP handle, for whatever reason...
LoadImage returns a compatible bitmap (unless you specify LR_CREATEDIBSECTION), therefore you need CreateCompatibleBitmap followed by SetDIBits to duplicate that source bitmap.
For some reason you have declared BITMAPINFO bminfo[2] But you only need one bminfo object. You need new or malloc to allocate enough memory for one object. Note that you cannot randomly swap arrays for pointers and vice-versa. If you used a debugger you would notice the functions failed and bminfo was not properly filled.
It's easier if you setup BITMAPINFOHEADER yourself, rather than let GetDIBits fill that parameter:
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc_memory;
static HBITMAP hbmp_src;
static HBITMAP hbmp_dst;
static BITMAP bm;
if(Msg == WM_CREATE)
{
hbmp_src = (HBITMAP)LoadImage(NULL, L"file.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC(0);
hdc_memory = CreateCompatibleDC(hdc);
GetObject(hbmp_src, sizeof(bm), &bm);
int w = bm.bmWidth;
int h = bm.bmHeight;
if(h < 0) h = -h;
int size = ((w * bm.bmBitsPixel + 31) / 32) * 4 * h;
BITMAPINFOHEADER bi = { sizeof(bi), w, h, bm.bmPlanes, bm.bmBitsPixel };
BYTE* bits = new BYTE[size];
GetDIBits(hdc, hbmp_src, 0, h, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
//change the pixel data in bits if that's your goal ...
hbmp_dst = CreateCompatibleBitmap(hdc, w, h);
SetDIBits(hdc, hbmp_dst, 0, h, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
SelectObject(hdc_memory, hbmp_dst);
delete[] bits;
ReleaseDC(0, hdc);
return 0;
}
else if(Msg == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdc_memory, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
return 0;
}
else if(Msg == WM_DESTROY)
{
DeleteDC(hdc_memory);
DeleteObject(hbmp_src);
DeleteObject(hbmp_dst);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
Related
I am writing the WinAPI Application, and I tried to write a function, that would automate for me creating Rectangles for text input (with Font, BkMode, TextColor), that then is called by DrawContent function called by WM_PAINT. The text does not appear, after I call ELW::AddTextControl.
LRESULT CALLBACK ELW::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
ELW::DrawContent(hWnd, hInst, hdc);
}
break;
case WM_CLOSE:
{
DestroyWindow(hWnd);
UnregisterClass(CLASS_NAME, hInst);
}
break;
case WM_SYSCOMMAND:
{
if (wParam == SC_CLOSE);
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// Content drawing
void ELW::DrawContent(HWND hWnd, HINSTANCE hInst, HDC hdc)
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
RECT testowyRectangle = { 0, 1 , 20 , 30 };
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_GRAYTEXT + 1));
ELW::AddTextControl("Testowy test", 80, 80, 100, 100, CUSTOM_COLOR_YELLOW_COLORREF, 10, "Euroscope", hdc);
EndPaint(hWnd, &ps);
};
void ELW::AddTextControl(const char* text, int xPos, int yPos, int xSize, int ySize, COLORREF rgb, int fontSize, const char* fontName, HDC hdc)
{
RECT TextRectangle = { xPos, yPos, ( xPos + xSize ) , ( yPos + ySize ) }; // Left, Top, Right, Bottom
if (rgb == NULL)
rgb = RGB(0, 0, 0);
if (fontSize == NULL)
fontSize = 10;
if (fontName == NULL)
fontName = "Euroscope";
HFONT hFont = CreateFont(fontSize, 8, 0, 0, 600, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT(fontName));
SelectObject(hdc, hFont);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, rgb);
DrawText(hdc, TEXT(text), strlen(text), &TextRectangle, DT_CENTER | DT_NOCLIP);
}
Found an error:
strlen(text)
should be
strlen(TEXT(text))
I am trying to load some bitmaps when starting up the application. I am trying to load them in WM_CREATE but only the last bitmap i load will stay loaded.
I can load the pictures in WM_PAINT but i have been told it's better to load them in WM_CREATE.
//before switch statement
static HBITMAP bitmap1, bitmap2;
case WM_CREATE: {
HINSTANCE hInstance = GetModuleHandle(NULL);
bitmap1 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
bitmap2 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
if (!bitmap1 || !bitmap2) MessageBox(NULL, _T("Error while loading images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
case WM_PAINT:{
//Draw bitmap...
}
I expected that both bitmaps got loaded as they do when loaded inside WM_PAINT
EDIT:
The problem weren't were i thought. The problem is it draws behind the filled area i had made. I still don't know how to fix.
//Draw bitmap function
bool DrawBitmap(HBITMAP hBitmap, int posX, int posY, int sizeX, int sizeY)
{
BITMAP bmp;
HWND hWnd = FindWindow(windowClassName, NULL);
if (!hWnd) return false;
HDC hdc = GetDC(hWnd);
if (!hdc) return false;
HDC hBitmapDC = CreateCompatibleDC(hdc);
if (!hBitmapDC) return false;
GetObject(hBitmap, sizeof(bmp), &bmp);
SelectObject(hBitmapDC, hBitmap);
BitBlt(hdc, posX, posY, sizeX, sizeY, hBitmapDC, 0, 0, SRCCOPY);
DeleteObject(hBitmap);
ReleaseDC(hWnd, hBitmapDC);
ReleaseDC(hWnd, hdc);
return true;
}
//Before switch
RECT recRect;
STATIC HBITMAP bitmap1;
//case WM_CREATE:
case WM_CREATE: {
HINSTANCE hInstance = GetModuleHandle(NULL);
bitmap1 = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
if (!bitmap) MessageBox(NULL, _T("Error while loading images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
return 0;
break;
//case WM_PAINT
case WM_PAINT:
DefWindowProc(hwnd, msg, wParam, lParam);
hdc = GetWindowDC(hwnd);
recRect = { -1, -1, 50 + 1, 30 + 1 };
FillRect(hdc, &recRect, (HBRUSH)CreateSolidBrush(RGB(30, 30, 30)));
if (DrawBitmap(bitmap1, 5, 5, 10, 10) == false) MessageBox(NULL, _T("Error while drawing images"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
return DefWindowProc(hwnd, msg, wParam, lParam);
return 0;
break;
The problem does not occur when i declare the bitmap in WM_PAINT
GetWindowDC returns the dc for the whole window, including the non-client area. You usually need GetDC instead.
Always use BeginPaint/EndPaint when responding to WM_PAINT and return 0.
CreateSolidBrush is a GDI resource leak. After creating brush or other GDI objects, you have to destroy those objects, otherwise you have resource leak, the program will crash after 10,000 GDI leaks.
In your draw function you have DeleteObject(hBitmap) This will destroy the bitmap immediately. But you probably want to keep the bitmap handle and destroy it only after the program is finished.
Suggestion:
bool DrawBitmap(HDC hdc, HBITMAP hBitmap, int posX, int posY, int sizeX, int sizeY)
{
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbmp = SelectObject(memdc, hBitmap);
BitBlt(hdc, posX, posY, sizeX, sizeY, memdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
return true;
}
...
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HBRUSH hbrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &ps.rcPaint, hbrush);
DeleteObject(hbrush);
BITMAP bm1;
GetObject(bitmap1, sizeof(bm1), &bm1);
DrawBitmap(hdc, bitmap1, 0, 0, bm1.bmWidth, bm1.bmHeight);
int x = bm1.bmWidth;
int y = bm1.bmHeight;
BITMAP bm2;
GetObject(bitmap2, sizeof(bm2), &bm2);
DrawBitmap(hdc, bitmap2, x, y, bm2.bmWidth, bm2.bmHeight);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
DeleteObject(bitmap1);
DeleteObject(bitmap2);
PostQuitMessage(0);
return 0;
using Visual Studio 2017, vc141, the following code should got a screenshot from front game window but now it return a black and blank image.
only issue with games(tried OpenGL and Vulkan, ogl return black, vulkan return white)
before upgrade to windows 10 1703, it works on windows 10 1607 and windows 7 sp1
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
code:
BOOL ScreenShot(cv::Mat *img, HWND hWnd = NULL) {
HBITMAP hBitmap;
HDC hdcSys = GetDC(hWnd);
HDC hdcMem = CreateCompatibleDC(hdcSys);
void *ptrBitmapPixels;
BITMAPINFO bi;
HDC hdc;
RECT rect;
if (!GetWindowRect(hWnd, &rect) || (hWnd == NULL)) {
return FALSE;
}
ZeroMemory(&bi, sizeof(BITMAPINFO));
LONG lWidth = rect.right - rect.left;
LONG lHeight = rect.bottom - rect.top;
bi.bmiHeader.biSize = sizeof(BITMAPINFO);
bi.bmiHeader.biWidth = lWidth;
bi.bmiHeader.biHeight = -lHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
hdc = GetDC(hWnd);
hBitmap = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &ptrBitmapPixels, NULL, 0);
SelectObject(hdcMem, hBitmap);
*img = cv::Mat(lHeight, lWidth, CV_8UC4, ptrBitmapPixels, 0);
BitBlt(hdcMem, 0, 0, lWidth, lHeight, hdcSys, 0, 0, SRCCOPY);
//DeleteObject(hBitmap);
DeleteDC(hdcMem);
ReleaseDC(hWnd, hdcSys);
ReleaseDC(hWnd, hdc);
return TRUE;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
/*...*/
HotKeyId = GlobalAddAtom(L"DBKGNDSCREENSHOT");
RegisterHotKey(hWnd, HotKeyId, NULL, VK_F10);
/*...*/
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
/*...*/
case WM_HOTKEY:
if (wParam == HotKeyId) {
cv::Mat t;
HWND MainHWND;
MainHWND = GetForegroundWindow();
ScreenShot(&t, MainHWND);
cv::imshow("1", t);
}
break;
/*...*/
}
and still black even PrintWindow(at least we got a titlebar)
PrintWindow(hWnd, hdcMem, 0);
//BitBlt(hdcMem, 0, 0, lWidth, lHeight, hdcSys, 0, 0, SRCCOPY);
I send this program to my friend (without any modify, his OS=win7 x64), but he got the correct result.
so what should I do?
GDI is a very old technology and is slowly getting deprecated. The more reliable method to capture desktop on Windows 10 would be through Desktop Duplication API.
How can I stop displaying the bitmap in my Win32 Project. I have a method that I'm calling in WM_PAINT called LoadBitmap. It's code looks like this:
bool LoadBitmap(LPTSTR szfilename, HDC winhdc, int x, int y) {
HBITMAP bitmap;
bitmap = (HBITMAP)LoadImage(NULL, szfilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (bitmap == NULL) {
::MessageBox(NULL, _T("Bitmap failed"), NULL, MB_OK);
return false;
}
HDC hdc;
hdc = ::CreateCompatibleDC(winhdc);
if (hdc == NULL)
{
::MessageBox(NULL, _T("HDC FAILED"), NULL, MB_OK);
return false;
}
BITMAP qbitmap;
int ireturn = GetObject(reinterpret_cast<HGDIOBJ>(bitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qbitmap));
if (!ireturn) {
::MessageBox(NULL, _T("RETURN FAILED"), NULL, MB_OK);
return false;
}
HBITMAP holdbitmap = (HBITMAP)::SelectObject(hdc, bitmap);
if (holdbitmap == NULL) {
::MessageBox(NULL, _T("HOLD FAILED"), NULL, MB_OK);
return false;
}
BOOL qRetBlit = ::BitBlt(winhdc, x, y, qbitmap.bmWidth, qbitmap.bmHeight, hdc, 0, 0, SRCCOPY);
if (!qRetBlit)
{
::MessageBox(NULL, _T("BLIT FAILED"), NULL, MB_OK);
return false;
}
::SelectObject(hdc, holdbitmap);
::DeleteDC(hdc);
::DeleteObject(bitmap);
return true;
}
NOTE x and y change continuously.
When x and y change however, the previous instance of them stays behind.
How can I stop displaying a bitmap once it has been painted in a new position?
If there is background brush then the old bitmap is erased with each paint call. If there is no background then erase it manually for example with FillRect Here is example with double buffering, assumes there is no background brush.
case WM_PAINT:
{
...
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
LoadBitmap(filename, memdc, x, y);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
Edit *************
It will be faster to load the bitmap file only once. For each paint request, we need only to draw the bitmap, instead of LoadImage every time + draw.
You can declare HBITMAP handles as static values in window's procedure. Set it up once in WM_CREATE, and clean it up in WM_NCDESTROY. Now we can use them anywhere in side window procedure:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
static HBITMAP hbitmap_background = NULL;
static HBITMAP hbitmap_sprite = NULL;
switch (msg)
{
case WM_CREATE:
{
hbitmap_background = (HBITMAP)LoadImage(NULL,
L"background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_background)
OutputDebugStringW(L"!hbitmap_background\n");
hbitmap_sprite = (HBITMAP)LoadImage(NULL,
L"sprite.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbitmap_sprite)
OutputDebugStringW(L"!hbitmap_sprite\n");
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
//setup double-buffering:
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);
//double-buffer ready, do custom paintings here:
FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
DrawBitmap(hbitmap_background, memdc, 0, 0);
DrawBitmap(hbitmap_sprite, memdc, 0, 0);
//BitBlt to hdc
BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(hdc, oldbitmap);
DeleteObject(membitmap);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_NCDESTROY:
{
//cleapup bitmap handles
if (hbitmap_background)
DeleteObject(hbitmap_background);
if (hbitmap_sprite)
DeleteObject(hbitmap_sprite);
}
}
return DefWindowProc(hwnd, msg, wp, lp);
}
We can change DrawBitmap so it only needs HBITMAP handle
void DrawBitmap(HBITMAP hbitmap, HDC hdc, int x, int y)
{
if (!hbitmap)
{
OutputDebugStringW(L"error\n");
return;
}
BITMAP bm;
GetObject(hbitmap, sizeof(BITMAP), &bm);
HDC memdc = CreateCompatibleDC(hdc);
HGDIOBJ oldbitmap = SelectObject(memdc, hbitmap);
BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbitmap);
DeleteDC(memdc);
}
Note, in this example I assume background.bmp is very large, and sprite.bmp is very small. If it is painted the other way around then background will hide the sprite.
I need to get a screen view of a specific window as .bmp format. In other words I need to have the functionality of alt+printscreen and it needs to work even the window is at back or minimized. So I wrote a function below which returns a HBITMAP type in order to save the view as .bmp file with another function later.
HBITMAP CaptureWindowBitmap(HWND MyHWND)
{
HDC hWindowDC = GetWindowDC(MyHWND);
HDC hMemoryDC = CreateCompatibleDC(hWindowDC);
int x = GetDeviceCaps(hWindowDC, HORZRES);
int y = GetDeviceCaps(hWindowDC, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hWindowDC, x, y);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
BitBlt(hMemoryDC, 0, 0, x, y, hWindowDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmapOld);
DeleteDC(hMemoryDC);
DeleteDC(hWindowDC);
return hBitmap;
}
However my function gets the image of the whole screen. How can I fix this?
Here is the solution i found from elsewhere:
HBITMAP CaptureWindowBitmap(HWND MyHWND)
{
RECT rc;
GetClientRect(MyHWND, &rc);
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);
PrintWindow(MyHWND, hdc, PW_CLIENTONLY);
DeleteDC(hdc);
ReleaseDC(NULL, hdcScreen);
return hbmp;
}
Window is captured by the function below:
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char buffer[128];
int written = GetWindowTextA(hwnd, buffer, 128);
if (written && strstr(buffer,WindowName) ) {
*(HWND*)lParam = hwnd;
return FALSE;
}
return TRUE;
}
HWND GetHwnd()
{
HWND hWnd = NULL;
EnumWindows(EnumWindowsProc, (LPARAM)&hWnd);
return hWnd;
}
where LPCTSTR WindowName is a global variable containing the name or partial name of the window.