Thread: Help with WinApi ?

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    8

    Angry Help with WinApi ?

    Even tough this is only a c++ forum, I hope some one can help me with my C WinApi problem. I have posted this question on CodeGuru Forums but no helpfull reply at all.
    I have homework for school and we were instructed to write a game in plain c with conio2.h for graphical output. But I hvae decided to make it in WinApi.

    Now here is my problem I have a function CheckStatus() which verifies if the game is over and if it is it asks the user play again or quit. If I put this function in WM_KEYDOWN it works ok, but if I move the function to the end of WM_PAINT, the window won't repaint on a new game unless you completley resize it or move arround the blank screen a few times. Does any 1 know what that could be?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <windows.h>
    #include <commctrl.h>
    
    #define WIDTH 1378
    #define HEIGHT 820
    #define WM_START 0x1337
    #define IDM_FILE_NEW 1
    #define IDM_FILE_REPLAY 2
    #define IDM_FILE_DIFFICULTY 3
    #define IDM_FILE_OPTIONS 4
    #define IDM_FILE_QUIT 5
    
    HINSTANCE Instance;
    int GameOver = 0;
    int GameDevelopment = 1;
    int Misek;
    int Resizing = 0;
    int Tezavnost = 2;
    int Vertical = 0;
    
    struct Cat{
    	int X, Y;
    	int prevX, prevY;
    }Cat;
    struct Mice{
    	char status;
    	int X, Y;
    }Mouse[50];
    struct Dogs{
    	int X, Y;
    }Dog[200];
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    void LoadAndBlitCat(HDC hWinDC);
    void LoadAndBlitMice(HDC hWinDC);
    void LoadAndBlitDogs(HDC hWinDC);
    void InitializeAnimals(HWND hwnd);
    void CheckStatus(HWND hwnd);
    void AddMenus(HWND hwnd);
    
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
    			LPSTR lpCmdLine, int nCmdShow )
    {
      MSG  msg ;    
      WNDCLASS wc = {0};
      wc.lpszClassName = TEXT( "Windows" );
      wc.hInstance     = hInstance ;
      wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
      wc.lpfnWndProc   = WndProc ;
      wc.hCursor       = LoadCursor(0,IDC_ARROW);
      
      RegisterClass(&wc);
      CreateWindow(wc.lpszClassName, TEXT("Windows"),
                    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
                        WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE,
                    GetSystemMetrics(SM_CXSCREEN)/9, 
    				GetSystemMetrics(SM_CYSCREEN)/12,
    				WIDTH, HEIGHT, 0, 0, hInstance, 0);  
    
      while( GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      return (int) msg.wParam;
    }
    
    LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ){
      HDC hdc;
      PAINTSTRUCT ps;
      switch(msg)  
      {
        case WM_START:{
    		GameOver = 0;
    		Misek = Tezavnost*5;
    		GameDevelopment = 1;
    		InitializeAnimals(hwnd);
    	    InvalidateRect(hwnd, NULL, TRUE);
    		break;
    	}
        case WM_CREATE:{
    		AddMenus(hwnd);
    		SendMessage(hwnd, WM_START, 0, 0);
    	    break;
        }
    	case WM_KEYDOWN:{
    
    		if(!Vertical){
    		    Cat.prevX = Cat.X;
    		    Cat.prevY = Cat.Y;
    		}
    
            if(wParam == 0x57){
    		    if(Cat.Y-34 <= 0)
    				Beep(500,500);
    		    else
    			    Cat.Y -= 34;
    	    }
    		if(wParam == 0x41){
    		    if(Cat.X-34 <= 0)
    				Beep(500,500);
    		    else
    			    Cat.X -= 34;
    	    }
    		if(wParam == 0x53){
    		    if(Cat.Y+34 >= HEIGHT-150)
    				Beep(500,500);
    		    else
    			    Cat.Y += 34;
    	    }
    		if(wParam == 0x44){
    		    if(Cat.X+34 >= WIDTH-34)
    				Beep(500,500);
    		    else
    			    Cat.X += 34;
    	    }
    		CheckStatus(hwnd);
    		Vertical = 1;
    		InvalidateRect(hwnd, NULL, FALSE);
    	    break;
    	}
    	case WM_PAINT:{
    		 
    		Vertical = 0;
    		hdc = BeginPaint(hwnd, &ps);
    		
    		HBRUSH hFillBrush = GetSysColorBrush(COLOR_3DFACE);
    		HBRUSH hBrushOld = (HBRUSH)SelectObject(hdc, hFillBrush);
    		HPEN hLinePen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
    	    HPEN hPenOld = (HPEN)SelectObject(hdc, hLinePen);
    
    		Rectangle(hdc, Cat.prevX, Cat.prevY, Cat.prevX+34, Cat.prevY+34);
    
            hLinePen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
    	    hPenOld = (HPEN)SelectObject(hdc, hLinePen);
    
    		if(GameDevelopment){
    			for(int i = 1;i<=WIDTH;i=i+34){
    			    MoveToEx(hdc, i, 0, NULL);
    				LineTo(hdc, i, HEIGHT-139);
    			}
    			for(int i = 1;i<=HEIGHT-139;i=i+34){
    			    MoveToEx(hdc, 0, i, NULL);
    				LineTo(hdc, WIDTH-17, i);
    			}
    
    			if(GameDevelopment == 1 || Resizing == 1){
    			    LoadAndBlitMice(hdc);
    				Resizing = 0;
    		    }
    			LoadAndBlitCat(hdc);
    			if(GameDevelopment == 1 || Resizing == 1){
    			    LoadAndBlitDogs(hdc);
    				Resizing = 0;
    		    }
    		}
    
    		SelectObject(hdc, hPenOld);
    	    DeleteObject(hLinePen);
    		SelectObject(hdc, hBrushOld);
    		DeleteObject(hFillBrush);
    		 
    		EndPaint(hwnd, &ps);
    
            break;
    	}
    	case WM_SIZE:{
    	    Resizing = 1;
    		break;
    	}
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            break; 
        }
      }
      return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    
    void AddMenus(HWND hwnd){
      HMENU hMenubar;
      HMENU hMenu;
    
      hMenubar = CreateMenu();
      hMenu = CreateMenu();
    
      AppendMenu(hMenu, MF_STRING, IDM_FILE_NEW, TEXT("&New"));
      AppendMenu(hMenu, MF_STRING, IDM_FILE_REPLAY, TEXT("&Replay"));
      AppendMenu(hMenu, MF_STRING, IDM_FILE_DIFFICULTY, TEXT("&Difficutly"));
      AppendMenu(hMenu, MF_STRING, IDM_FILE_OPTIONS, TEXT("&Options"));
      AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
      AppendMenu(hMenu, MF_STRING, IDM_FILE_QUIT, TEXT("&Quit"));
    
      AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hMenu, TEXT("&File"));
      SetMenu(hwnd, hMenubar);
    }
    
    void LoadAndBlitCat(HDC hWinDC){
    	HBITMAP hBitmap;
        BITMAP qBitmap;
        HDC hLocalDC;
    
        hBitmap = (HBITMAP)LoadImage(NULL, TEXT("Cat.bmp"), IMAGE_BITMAP, 0, 0, 
                    LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
        hLocalDC = CreateCompatibleDC(hWinDC);
    
        GetObject((HGDIOBJ) hBitmap, sizeof(BITMAP), (LPVOID) &qBitmap);
    
        HBITMAP hOldBmp = (HBITMAP) SelectObject(hLocalDC, hBitmap);
    
    
        BitBlt(hWinDC, Cat.X, Cat.Y, qBitmap.bmWidth, qBitmap.bmHeight, hLocalDC, 0, 0, SRCCOPY);
        SelectObject(hLocalDC, hOldBmp);
    
    	DeleteDC(hLocalDC);
    	DeleteObject(hBitmap);
    }
    void LoadAndBlitMice(HDC hWinDC){
    	HBITMAP hBitmap;
        BITMAP qBitmap;
        HDC hLocalDC;
        
        hBitmap = (HBITMAP)LoadImage(NULL, TEXT("Mouse.bmp"), IMAGE_BITMAP, 0, 0, 
                    LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
        hLocalDC = CreateCompatibleDC(hWinDC);
    
        GetObject((HGDIOBJ) hBitmap, sizeof(BITMAP), (LPVOID) &qBitmap);
    
        HBITMAP hOldBmp = (HBITMAP) SelectObject(hLocalDC, hBitmap);
    
        for(int i=0;i<Tezavnost*5;i++)
    		if(Mouse[i].status != 'D')
                BitBlt(hWinDC, Mouse[i].X, Mouse[i].Y, qBitmap.bmWidth, qBitmap.bmHeight, hLocalDC, 0, 0, SRCCOPY);
    		
    
        SelectObject(hLocalDC, hOldBmp);
    
    	DeleteDC(hLocalDC);
    	DeleteObject(hBitmap);
    }
    void LoadAndBlitDogs(HDC hWinDC){
    	HBITMAP hBitmap;
        BITMAP qBitmap;
        HDC hLocalDC;
        
        hBitmap = (HBITMAP)LoadImage(NULL, TEXT("Batman.bmp"), IMAGE_BITMAP, 0, 0, 
                    LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
        hLocalDC = CreateCompatibleDC(hWinDC);
    
        GetObject((HGDIOBJ) hBitmap, sizeof(BITMAP), (LPVOID) &qBitmap);
    
        HBITMAP hOldBmp = (HBITMAP) SelectObject(hLocalDC, hBitmap);
    
        for(int i=0;i<Tezavnost*50;i++)
            BitBlt(hWinDC, Dog[i].X, Dog[i].Y, qBitmap.bmWidth, qBitmap.bmHeight, hLocalDC, 0, 0, SRCCOPY);
    	
        SelectObject(hLocalDC, hOldBmp);
    
    	DeleteDC(hLocalDC);
    	DeleteObject(hBitmap);
    }
    
    void InitializeAnimals(HWND hwnd){
    	int i, j, si;
    	Cat.X =2;
    	Cat.Y=2;
    
    	srand(time(NULL));
    
    	for(i=0;i<Tezavnost*5;i++)
    		Mouse[i].status = 'A';
    
    	for(i=0;i<Tezavnost*5;i++){//Misi XY
    	    do{
    		    si=0;
    		    Mouse[i].X = (rand()%40*34)+2;
    		    Mouse[i].Y = (rand()%20*34)+2;
    	        for(j=0;i>j;j++)
    			    if((Mouse[i].Y == Mouse[j].Y && Mouse[i].X == Mouse[i].X) || 
                                    (Mouse[i].Y == Cat.Y && Mouse[i].X == Cat.X))
    				    si=1;
    		}while(si);
    	}
    
    	for(i=0;i<Tezavnost*50;i++){//Psi XY
    	    do{
    		    si=0;
    		    Dog[i].X = (rand()%40*34)+2;
    		    Dog[i].Y = (rand()%20*34)+2;
    			for(j=0;i>j;j++)
    			    if((Dog[i].X == Cat.X && Dog[i].Y == Cat.Y) || (
                                    Dog[i].X == Dog[j].X && Dog[i].Y == Dog[j].Y) || 
                                    (Dog[i].X == Mouse[j].X && Dog[i].Y == Mouse[j].Y))
    				    si=1;
    			if(Dog[i].X == Mouse[j].X && Dog[i].Y == Mouse[j].Y)
    				si=1;
    		}while(si);
    	}
    }
    
    void CheckStatus(HWND hwnd){
    	int i;
        for(i=0;i<Tezavnost*5;i++){
    	    if(Mouse[i].Y == Cat.Y && Mouse[i].X == Cat.X){
    		    Mouse[i].status = 'D';
    			    if(--Misek == 0){
    				    if(MessageBox(hwnd, TEXT("YOU WIN"), TEXT("MessageBox"), MB_YESNO) == IDYES)
    					    SendMessage(hwnd, WM_START, 0, 0);
    					else
    					    SendMessage(hwnd, WM_CLOSE, 0, 0);
    				}
    				i=1000;
    	        }
    	}
    	for(i=0;i<Tezavnost*50;i++){
    	    if(Dog[i].Y == Cat.Y && Dog[i].X == Cat.X){
    			if(MessageBox(hwnd, TEXT("YOU LOST"), TEXT("MessageBox"), MB_YESNO) == IDYES)
    			    SendMessage(hwnd, WM_START, 0, 0);
    		    else
    				SendMessage(hwnd, WM_CLOSE, 0, 0);
    			i=1000;
    			}
    	}
    }
    This is the code the works but if I would put CheckStatus at the end of WM_PAINT it doesn't restart properly.
    Last edited by Sevko; 01-01-2011 at 06:51 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Moved to windows forum.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    I'm pretty sure paint is NOT where you want to check for status changes / actions from the user. Why do you want it to be in the paint code?
    Mainframe assembler programmer by trade. C coder when I can.

  4. #4
    Registered User
    Join Date
    Jan 2011
    Posts
    8
    Because i you press W+A it sends 2 WM_KEYDOWN messages so first it goes up and the coordinates change by -34 then it goes left and it changes by -34 and if you hit something with the upward movment you loose. But if i were to check this in paint the coordinates are already - - so if nothing is there you don't loose. But for now I just disabled moving vertically.
    Last edited by Sevko; 01-01-2011 at 09:55 AM.

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Sevko View Post
    Because i you press W+A it sends 2 WM_KEYDOWN messages so first it goes up and the coordinates change by -34 then it goes left and it changes by -34 and if you hit something with the upward movment you loose. But if i were to check this in paint the coordinates are already - - so if nothing is there you don't loose. But for now I just disabled moving vertically.
    I don't really follow what you're saying here. All paint should do is draw what you want to draw. No checking for win/loss, no actual moving things, just drawing things.

    If what you're saying is "if they press W+A fast enough I want them to move northwest without worrying if they ran into something", then the answer is to make a different key for northwest.

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Sevko View Post
    I have homework for school and we were instructed to write a game in plain c with conio2.h for graphical output. But I hvae decided to make it in WinApi.
    I would think your instructor gave you the assignment for a reason... like maybe he wants you to have a given programming experience...

    The game is not going to work proplerly with your status check in WM_PAINT because that's not what the WM_PAINT message is about... it is sent when a portion of a window is changed or occluded and needs to be re-drawn. You need to devise another way to know when your game is over... like sending a "Game Over" message and processing it in your windproc.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    As has been said Paint or OnPaint() is the wrong place to change the status of the game. If you follow a simple model-view-controller paradigm you will have a much better chance of success.

    The view or the painting in your case should never change the status of the application. If you are looking to make a game loop in Win32 the best way I know how is to use the WM_IDLE message in your WndProc and then do your updating and rendering/drawing in the block of code that intercepts the message. The view only renders the data it has been given access to. If the view changes you get a different view of the same data. If the data changes you get the same view but with different data.

  8. #8
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    A few observations.....

    Your paint will be very slow, with over 100 BitBlt() calls + LoadImage() + CreateDC() each time the screen is redrawn.
    I would consider double buffering (I have posted plenty of examples) as only the 'cat' moves, the 'mice' and 'dogs' could be drawn once to a mem DC when a game starts and this whole mem DC blitted once as a backgraound (instead of the 110 possible blits) each time the 'cat' moves [2 blits total; background and then cat].

    Your paint should ONLY call one BitBlt() using the PAINTSTRUCT's HDC and RECT. WM_PAINT is often generated outside your app and so should be as quick as possible (and never modify the 'state' as pointed out).

    To call for a quicker paint, use InvalidateRect() followed by an UpdateWindow().
    This bypasses the OS msg queue and posts the paint directly to the callback. [WM_PAINT msgs are also generated outside your app and are the lowest priority in the OS msg queue. Multiple WM_PAINT msgs are concatinated in the msg queue, which may cause issues ie jerky updates, shearing, flicker etc).

    You have a GDI leak in your paint.
    The hLinePen is allocated memory and selected into the DC (the default is in hPenOld).
    A new GDI object is allocated over hLinePen and selected into the DC (probably the original hLinePen is now in hPenOld and the original / default pen is lost).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Draw a semi-transparent icon in winapi.
    By diskdisk in forum Windows Programming
    Replies: 4
    Last Post: 07-18-2009, 12:08 PM
  2. do i still need winAPI
    By datainjector in forum Windows Programming
    Replies: 8
    Last Post: 07-12-2003, 01:43 AM
  3. references for the winapi
    By stallion in forum Windows Programming
    Replies: 9
    Last Post: 01-28-2003, 02:56 AM
  4. WINAPI: Meaning of HDC ?
    By Mecnels in forum Windows Programming
    Replies: 1
    Last Post: 01-21-2002, 10:06 AM
  5. C++ and WinAPI?
    By Matt2u in forum C++ Programming
    Replies: 9
    Last Post: 01-09-2002, 12:57 AM