Getting Properties of a Running Program - c++

I would like to develop a program which ID's a card as it is played in another running program such as a poker or hearts game or whatever. I'm starting by trying to get the information I need on that game program which is already running, and I'm having problems right from the start. I'm running MSVC++ 2013 and developing an MFC application. Right now I'm playing with the Hearts game and here's the code:
HWND hwnd = FindWindowA(NULL, "Hearts");
if (hwnd == NULL)
{ /* window not found*/
}
else
{ /* window was found */
RECT rect;
GetWindowRect(hwnd, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
}
So I get hwnd just fine and the code works depending on whether I have Hearts open or not. But the line GetWindowRect(hwnd, &rect); won't compile saying
"error C2660: 'CWnd::GetWindowRect' : function does not take 2 arguments".
There is a GetWindowRect function which only has the rect argument, but gets the properties of the program window I'm working on. There is lot's of documentation on GetWindowRect which shows the two arguments as above, but how do I invoke that subroutine?

As you are inside an MFC window class, you are calling the CWnd::GetWindowRect function - you want to call the one in the Win32 API, so:
::GetWindowRect(hwnd, &rect);
where the :: scope resolution operator (without a namespace or class name on the left-hand side) says to call the function in the global scope.

Related

C++ changing image on user input in WinAPI

I am having issues in getting my .bmp image displayed to change to another one on user input. The image can be successfully printed at the start (title.bmp), but is supposed to change when pressing 1 or 2 followed by enter (to introduction.bmp & start.bmp). I must be missing something!
Where this happens is around the bottom of the code from while (running == 1) { so skip down to there.
I am using loadImage("title.bmp"); to print my images (I change the filename appropriately of course), and cin >> menuSelection; to pause the program and wait until the user presses one or two followed by enter.
I've searched many, many pages on how to print and change images in WinAPI, and this is the closest I can get. If there is any other information I have missed please tell me and I will comment it. Thanks in advance for helping!
//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection = 0;
int userInput;
int userInputDummy;
int intPointer;
//Starter variables used in creating a window and printing images. These are global.
HDC imageDC; // the DC to hold our image
HBITMAP imageBmp; // the actual bitmap which contains the image (will be put in the DC)
HBITMAP imageBmpOld; // the DC's old bitmap (for cleanup)
const int screenSize_X = 640;
const int screenSize_Y = 480;
//Functions! Sections of code to re-used in the program
// Function to load the image into our DC so we can draw it to the screen
void loadImage(const char* pathname)
{
imageDC = CreateCompatibleDC(NULL); // create an offscreen DC
imageBmp = (HBITMAP)LoadImageA( // load the bitmap from a file
NULL, // not loading from a module, so this is NULL
pathname, // the path we're loading from
IMAGE_BITMAP, // we are loading a bitmap
0, 0, // don't need to specify width/height
LR_DEFAULTSIZE | LR_LOADFROMFILE// use the default bitmap size (whatever the file is), and load it from a file
);
imageBmpOld = (HBITMAP)SelectObject(imageDC, imageBmp); // put the loaded image into our DC
}
// Function to clean up
void cleanUpImage()
{
SelectObject(imageDC, imageBmpOld); // put the old bmp back in our DC
DeleteObject(imageBmp); // delete the bmp we loaded
DeleteDC(imageDC); // delete the DC we created
}
// The function to draw our image to the display (the given DC is the screen DC)
void drawImage(HDC screen)
{
BitBlt(
screen, // tell it we want to draw to the screen
0, 0, // as position 0,0 (upper-left corner)
screenSize_X, // width of the rect to draw
screenSize_Y, // height of the rect
imageDC, // the DC to get the rect from (our image DC)
0, 0, // take it from position 0,0 in the image DC
SRCCOPY // tell it to do a pixel-by-pixel copy
);
}
// A callback to handle Windows messages as they happen
LRESULT CALLBACK wndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l)
{
// what kind of message is this?
switch (msg)
{
// we are interested in WM_PAINT, as that is how we draw
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC screen = BeginPaint(wnd, &ps); // Get the screen DC
drawImage(screen); // draw our image to our screen DC
EndPaint(wnd, &ps); // clean up
}break;
// we are also interested in the WM_DESTROY message, as that lets us know when to close the window
case WM_DESTROY:
PostQuitMessage(0);
break;
}
// for everything else, let the default window message handler do its thing
return DefWindowProc(wnd, msg, w, l);
}
// A function to create the window and get it set up
HWND createWindow(HINSTANCE inst)
{
WNDCLASSEX wc = { 0 }; // create a WNDCLASSEX struct and zero it
wc.cbSize = sizeof(WNDCLASSEX); // tell windows the size of this struct
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); // tell it to use the normal arrow cursor for this window
wc.hInstance = inst; // give it our program instance
wc.lpfnWndProc = wndProc; // tell it to use our wndProc function to handle messages
wc.lpszClassName = TEXT("DisplayImage"); // give this window class a name.
RegisterClassEx(&wc); // register our window class with Windows
// the style of the window we want... we want a normal window but do not want it resizable.
int style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; // normal overlapped window with a caption and a system menu (the X to close)
// Figure out how big we need to make the window so that the CLIENT area (the part we will be drawing to) is
// the desired size
RECT rc = { 0,0,screenSize_X,screenSize_Y }; // desired rect
AdjustWindowRect(&rc, style, FALSE); // adjust the rect with the given style, FALSE because there is no menu
return CreateWindow( // create the window
TEXT("DisplayImage"), // the name of the window class to use for this window (the one we just registered)
TEXT("Display an Image"), // the text to appear on the title of the window
style | WS_VISIBLE, // the style of this window (OR it with WS_VISIBLE so it actually becomes visible immediately)
100, 100, // create it at position 100,100
rc.right - rc.left, // width of the window we want
rc.bottom - rc.top, // height of the window
NULL, NULL, // no parent window, no menu
inst, // our program instance
NULL); // no extra parameter
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// _________________________________________________________________________________________
// The actual entry point for the program!
// This is Windows' version of the 'main' function:
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int show)
{
// load our image
loadImage("title.bmp");
// create our window
HWND wnd = createWindow(inst);
// Do the message pump! keep polling for messages (and respond to them)
// until the user closes the window.
MSG msg;
while (GetMessage(&msg, wnd, 0, 0)) // while we are getting non-WM_QUIT messages...
TranslateMessage(&msg); // translate them
DispatchMessage(&msg); // and dispatch them (our wndProc will process them)
{
while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
cin >> menuSelection;
//Selecting the introduction option
if (menuSelection == 1) {
loadImage("introduction.bmp");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the start option
else if (menuSelection == 2) {
loadImage("start");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the exit option
else if (menuSelection == 3) {
menuSelection = 0;
running = 0;
}
}
// once the user quits....
cleanUpImage();
return 0;
return EXIT_SUCCESS;
}
}
you cannot use cin in win32 use an editbox then get the user's input from it as character string then if you want convert it to an integer value otherwise use the API:
GetDlgItemInt(...);
you are also handling only GetMessage in while-loop while you only handle dispatchmessage outside the loop which means you handle it only once, when getmessage fails (the end of program) so the result is a freezing windows as long as there's no one who takes messages from getmessage to the target windo.
the solution: make DispatchMessage inside while loop:
another thing: you pass hwnd to getmessage the result destroying the window won't make the application exit.
take a look at GetMessage() when passing a non-null value:
link text
the correct thing in your case:
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
* don't load image inside loop just load at the time wanted:
make an edit box with style ES_NUMBER and another button names for example change image so when clicked take the content of edit box convert it to integer, check whether it is 1 or 2 then load imaged depending the value.
you may ask "why I can't use iostream input and output streams in win32" because I ask you "where is console windows?" and if it is here what is the role of while-loop (blocking waiting for messages)?

C++ Win32 GDI double buffering

Could you give the simplest way to achieve double buffering for this example code (to prevent flickering):
HWND hwnd = FindWindow(0, "Untitled - Notepad");
HDC hDC_Desktop = GetDC(hwnd);
...
while( )
{
RECT rect = { 10, 10, 10 + 50, 10 + 50 };
FillRect(hDC_Desktop, &rect, ColorBrush);
InvalidateRect (hwnd, NULL, TRUE);
}
The reason it's "flickering" is because the target window is getting invalidated and it is being redrawn. Since it's not your window - you don't necessarily have control over that.
If this was your own window there is a simple strategy to speed up your drawing speed and reduce flicker: Use a Memory DC to draw on and capture WM_ERASEBKGND to suppress background redraws.
In depth explanation and strategy for fixing it (in your application's window): http://www.catch22.net/tuts/win32/flicker-free-drawing
If your intent is to draw on another application, might I suggest creating a window on top of that application and draw on that.

Windows api get client dc bitmap size

I use the following code to get the size of the bitmap bound with Windows MFC View window's client area DC:
void CView::OnDraw(CDC* )
{
CDC *pDc = GetDC();
BITMAP bmpHeader;
memset( &bmpHeader, 0, sizeof(BITMAP));
HGDIOBJ hbmp = GetCurrentObject(pDc->m_hDC, OBJ_BITMAP);
GetObject(hbmp,sizeof(BITMAP), &bmpHeader);
int bmpWidth = bmpHeader.bmWidth;
int bmpHeight = bmpHeader.bmHeight;
...
}
According to MSDN GetDC() gets the client area dc:
Retrieves a pointer to a common, class, or private device context for the client area depending on the class style specified for the CWnd
So I suppose the bmpWidth and bmpHeight should be the same size as client area rect. But it isn't. It appears to be the size of entire window including toolbar area and menu area. Am I doing something wrong here?
Use GetClientRect to find with and height of client area. This is the area which does not include the titlebar and borders. Instead of calling GetDC(), use the CDC* parameter which is already provided, or else use CClientDC dc(this) which has automatic cleanup. In this case drawing should be something like this:
void CMyView::OnDraw(CDC* dc)
{
CRect rc;
GetClientRect(&rc);
dc->FillSolidRect(rc, RGB(0, 0, 255));
}
Use Window Functions to get information about Windows.
Most Window functions have equivalent in MFC. For example,
In WinApi: GetClientRect(HWND hwnd, LPRECT rc);
In MFC: CWnd::GetClientRect(LPRECT rc);

How do you create a button outside the WM_CREATE message in win32?

I'm using c++ with win32 and gdi+ for graphics.
When I initialize a button outside WM_CREATE, specifically in a WM_TIMER message, I can't draw anything else, after that one frame is drawn.
Here's a snippet of the code:
case WM_TIMER:
RECT client;
GetClientRect(hWnd, &client);
client.bottom-=100; //The bottom hundred pixels are static after I draw the first frame, so I never update them
if(starting==true)
{
starting=false;
hdc = GetDC(hWnd);
hdcBuf = CreateCompatibleDC(hdc);
hdcMem = CreateCompatibleDC(hdcBuf);
hbmBackBM = CreateCompatibleBitmap(hdc, client.right, client.bottom );
hbmOldBackBM = (HBITMAP)SelectObject(hdcBuf, hbmBackBM);
Graphics temp(hdc);
SolidBrush yelloworange(Color(250,225,65));
temp.FillRectangle(&yelloworange,0,client.bottom,client.right,100); //Fill the bottom with yellow
buttons[0]=CreateWindow("button","makereg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 630, 60, 20, hWnd, HMENU(IDB_MAKEREG), NULL, NULL);
//buttons[1]=CreateWindow("button","destroyreg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 670, 80, 20, hWnd, HMENU(IDB_MAKEREG+1), NULL, NULL);
}
Graphics g(hdcBuf);
The first part is for double buffering, and the variables that I instantiate are global. I delete the HDCs and HBITMAPs in WM_DESTROY. starting is a global boolean that is instantiated as true.
I do all of my drawing in this WM_TIMER message. If I comment out just the two lines where the buttons are created, everything runs normally. With them, it only draws out what is left in this WM_TIMER, and does not draw in the next one. All of the other drawing code is done to hdcBuf or g, and hdcBuf is then BitBlt'd onto hdc.
I tried creating the button in WM_CREATE, and then showing it in WM_TIMER, but that caused the same problem. I can't create and show the window in WM_CREATE, because otherwise it gets drawn over when I fill the bottom 100 pixels with a yellow color.
Is there a way to create and show a button outside WM_CREATE and outside WM_PAINT without crashing the rest of the code?
EDIT: Here is some of the code that stops working, in WM_TIMER:
if(mousex!=uptomousex && mousey!=uptomousey && lbuttondown==true) // this code draws a rectangle between the point where the user begins holding the left mousebutton, and where the mouse is right now.
{
if(uptomousex-mousex>0 && uptomousey-mousey>0)
g.DrawRectangle(&(p[0]), mousex, mousey, uptomousex-mousex, uptomousey-mousey);
else if(uptomousex-mousex<0 && uptomousey-mousey>0)
g.DrawRectangle((&p[0]), uptomousex, mousey, mousex-uptomousex, uptomousey-mousey);
else if(uptomousex-mousex>0 && uptomousey-mousey<0)
g.DrawRectangle((&p[0]), mousex, uptomousey, uptomousex-mousex, mousey-uptomousey);
else if(uptomousex-mousex<0 && uptomousey-mousey<0)
g.DrawRectangle(&(p[0]), uptomousex, uptomousey, mousex-uptomousex, mousey-uptomousey);
}
Some global variables:
bool lbuttondown=false;
float mousex=0;
float mousey=0;
float uptomousex=0;
float uptomousey=0;
Elsewhere in WndProc...
case WM_LBUTTONDOWN:
lbuttondown=true;
mousex=(float)GET_X_LPARAM(lParam);
mousey=(float)GET_Y_LPARAM(lParam);
uptomousex=mousex;
uptomousey=mousey;
break;
case WM_MOUSEMOVE:
if(mousex!=GET_X_LPARAM(lParam) && mousey!=GET_Y_LPARAM(lParam))
{
uptomousex=(float)GET_X_LPARAM(lParam);
uptomousey=(float)GET_Y_LPARAM(lParam);
}
break;
You are creating/getting at least 3 Device Context instances on each timer call, and you never delete/release them (at least in the sample that you posted), so no surprise that you are ending by crushing the whole GDI system.
For each GetDC() call, ReleaseDC() should be called,
for each CreateCompatibleDC() call, DeleteObject() should be called.
I have not figured out why this happens, but I have created a simple patch: my own button class, which I'll share here:
class button
{
public:
int x;
int y;
int width;
int height;
string text;
void (*func)(short);
button(int px, int py, int w, int h, string txt, void (*f)(short))
{
x=px;
y=py;
width=w;
height=h;
text=txt;
func=*f;
}
};
Then, there is a global vector of buttons, allbuttons, and in the WM_LBUTTONUP message I loop through allbuttons and check if the click was in the button, and if so I call func.
Its simple, more flexible, and it actually works. However, the graphics are worse, and I would still like to find out why the windows button is dysfunctional, just out of curiosity.

Lightbox style dialogs in MFC App

Has anyone implemented Lightbox style background dimming on a modal dialog box in a MFC/non .net app.
I think the procedure would have to be something like:
steps:
Get dialog parent HWND or CWnd*
Get the rect of the parent window and draw an overlay with a translucency over that window
allow the dialog to do it's modal draw routine, e.g DoModal()
Are there any existing libraries/frameworks to do this, or what's the best way to drop a translucent overlay in MFC?
edit Here's a mockup of what i'm trying to achieve if you don't know what 'lightbox style' means
Some App:
with a lightbox dialog box
Here's what I did* based on Brian's links
First create a dialog resource with the properties:
border FALSE
3D look FALSE
client edge FALSE
Popup style
static edge FALSE
Transparent TRUE
Title bar FALSE
and you should end up with a dialog window with no frame or anything, just a grey box.
override the Create function to look like this:
BOOL LightBoxDlg::Create(UINT nIDTemplate, CWnd* pParentWnd)
{
if(!CDialog::Create(nIDTemplate, pParentWnd))
return false;
RECT rect;
RECT size;
GetParent()->GetWindowRect(&rect);
size.top = 0;
size.left = 0;
size.right = rect.right - rect.left;
size.bottom = rect.bottom - rect.top;
SetWindowPos(m_pParentWnd,rect.left,rect.top,size.right,size.bottom,NULL);
HWND hWnd=m_hWnd;
SetWindowLong (hWnd , GWL_EXSTYLE ,GetWindowLong (hWnd , GWL_EXSTYLE ) | WS_EX_LAYERED ) ;
typedef DWORD (WINAPI *PSLWA)(HWND, DWORD, BYTE, DWORD);
PSLWA pSetLayeredWindowAttributes;
HMODULE hDLL = LoadLibrary (_T("user32"));
pSetLayeredWindowAttributes =
(PSLWA) GetProcAddress(hDLL,"SetLayeredWindowAttributes");
if (pSetLayeredWindowAttributes != NULL)
{
/*
* Second parameter RGB(255,255,255) sets the colorkey
* to white LWA_COLORKEY flag indicates that color key
* is valid LWA_ALPHA indicates that ALphablend parameter
* is valid - here 100 is used
*/
pSetLayeredWindowAttributes (hWnd,
RGB(255,255,255), 100, LWA_COLORKEY|LWA_ALPHA);
}
return true;
}
then create a small black bitmap in an image editor (say 48x48) and import it as a bitmap resource (in this example IDB_BITMAP1)
override the WM_ERASEBKGND message with:
BOOL LightBoxDlg::OnEraseBkgnd(CDC* pDC)
{
BOOL bRet = CDialog::OnEraseBkgnd(pDC);
RECT rect;
RECT size;
m_pParentWnd->GetWindowRect(&rect);
size.top = 0;
size.left = 0;
size.right = rect.right - rect.left;
size.bottom = rect.bottom - rect.top;
CBitmap cbmp;
cbmp.LoadBitmapW(IDB_BITMAP1);
BITMAP bmp;
cbmp.GetBitmap(&bmp);
CDC memDc;
memDc.CreateCompatibleDC(pDC);
memDc.SelectObject(&cbmp);
pDC->StretchBlt(0,0,size.right,size.bottom,&memDc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
return bRet;
}
Instantiate it in the DoModal of the desired dialog, Create it like a Modal Dialog i.e. on the stack(or heap if desired), call it's Create manually, show it then create your actual modal dialog over the top of it:
INT_PTR CAboutDlg::DoModal()
{
LightBoxDlg Dlg(m_pParentWnd);//make sure to pass in the parent of the new dialog
Dlg.Create(LightBoxDlg::IDD);
Dlg.ShowWindow(SW_SHOW);
BOOL ret = CDialog::DoModal();
Dlg.ShowWindow(SW_HIDE);
return ret;
}
and this results in something exactly like my mock up above
*there are still places for improvment, like doing it without making a dialog box to begin with and some other general tidyups.
I think you just need to create a window and set the transparency. There is an MFC CGlassDialog sample on CodeProject that might help you. There is also an article on how to do this with the Win32 APIs.