Jump to content
  • Advertisement
Sign in to follow this  
gothicly

(C++) WinMain, WNDPROC, and Classes

This topic is 2755 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a "working" directx engine. And it's in quotes because I constantly break it trying to get new stuff to work.

Anyway, I have a question about how I can get a WNDPROC to work...

Currently I was not using a WNDPROC function that I explicitly defined it was "(WNDPROC)::DefWindowProc" but (after learning how wrong that was) am deciding to use one.

I initialize my WNDCLASS in another class,which defines my engine structure and I'm just having TONS of trouble getting the WNDPROC to work...

I understand that this might seem a bit confusing. Because I cannot describe what is happening very well at all. So I hope that by throwing some code at you, you might understand what's going on.

I'm going to super simplify some of it to shorten the post...

These are all in one file:
class ENGINE
{
public:
HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
LRESULT CALLBACK winproc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
};


ENGINE::Init(HINSTANCE hInstance, int width, int height, bool windowed)
{
//Create the windows class
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = ENGINE::winproc; //HERE IS THE PROOOOOOOBLEM
wc.hInstance = hInstance;
wc.lpszClassName = "EngineWND";
}


LRESULT CALLBACK ENGINE::winproc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
return 0;
}


This is in another file, that does the main:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
ENGINE engine;

if(FAILED(engine.Init(hInstance, 1024, 768, true)))
return 0;
//ETC ETC ETC
}


So, I'm just posting ONE example of what I have tried just to get you an idea of what I'm trying to do... Hopefully someone has any idea of what to do...

Thanks if you have any input...

Share this post


Link to post
Share on other sites
Advertisement
The problem is that you have to declare the window procedure static in order to have it as part of the class. This will introduce a whole slew of other issues, like not having access to the non-static class variables and members. There are many articles on how to solve these problems, several of which are hosted on this site (or at least were on the old site).

Share this post


Link to post
Share on other sites
optionally you can make your WndProc function a 'friend' of your Engine class. That way WndProc will lose the 'this' pointer and still be able to access variables of your Engine class.

Share this post


Link to post
Share on other sites

c++ style is garbage. Scrap classes and go with c style design... just make a ton of functions. =D


Its really too bad that they took away downvotes dry.gif

Share this post


Link to post
Share on other sites

optionally you can make your WndProc function a 'friend' of your Engine class. That way WndProc will lose the 'this' pointer and still be able to access variables of your Engine class.



Alright, I was looking at class inheritance before and I didn't really mess with it. So I'll read more about the friend thing... See what I can figure out!

Thanks!

Share this post


Link to post
Share on other sites
I created a semi C++ windows wrapper, I am not sure if this is the "correct" way of doing this, but it works.

WindowsWrapper.h

//Contains all of our windows stuff
#ifndef _INC_PREWINDOWS //if we have not run it
#define _INC_PREWINDOWS //define it as if we have run it and run it


#define WIN32_LEAN_AND_MEAN
#define INIT_GUID


#include <windows.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#include <io.h>
#include <fstream>
#include <conio.h>
#include <fcntl.h>
#include <string.h>
#include <memory.h>



class WindowsWrapper
{
private:
HINSTANCE hInstMain;//main application handle
HINSTANCE hPrevInst;//previous application handle
HWND hWndMain;//handle to our main window
LPCTSTR lpClassName; //this is our classname
WNDCLASSEX wcx; //our windows class

public:

bool KeyPressed; //true if a key was pressed
string LastKeyPress;

//mouse
bool RightClick; //mouse was right clicked
bool LeftClick; //mouse was left clicked

bool SetupMyWindow(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd,UINT Style,LPCTSTR lpszClassName); //setup our windows class
bool WindowsWrapper::CreateMyWindow(DWORD dwStyle,LPCTSTR lpWindowName,int xSize,int ySize); //create our window

HWND GethWnd(); //get the hwnd
static LRESULT CALLBACK MyWindowProc(HWND hWndMain,UINT uMsg,WPARAM wParam,LPARAM lParam); //windows message proc

WindowsWrapper()//Constructor
{



}
~WindowsWrapper() //Destructor
{

}


};




#endif



WindowsWrapper.cpp

#include "WindowsWrapper.h"

WindowsWrapper * MyWindowsWrapper = NULL; //our "static" member

bool WindowsWrapper::SetupMyWindow(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd,UINT Style,LPCTSTR lpszClassName)//setup our windows class
{
hInstMain=NULL;
hPrevInst=NULL;
hWndMain=NULL;
hInstMain=hInstance;
hPrevInst=hPrevInstance;
RightClick = false;
LeftClick = false;
wcx.cbSize=sizeof(WNDCLASSEX);
wcx.style=Style;
wcx.lpfnWndProc=MyWindowProc;
wcx.cbClsExtra=0;
wcx.cbWndExtra=0;//window extra
wcx.hInstance=hInstMain;//application handle
wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);//icon
wcx.hCursor=LoadCursor(NULL,IDC_ARROW);//cursor
wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//background color
wcx.lpszMenuName=NULL;//menu
wcx.lpszClassName="WINXCLASS";//class name
WindowsWrapper::lpClassName="WINXCLASS";
wcx.hIconSm=NULL;//small icon
//register the window class, return 0 if not successful
if(!RegisterClassEx(&wcx)) return(false);

MyWindowsWrapper = this;
return true;
}

///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///

bool WindowsWrapper::CreateMyWindow(DWORD dwStyle,LPCTSTR lpWindowName,int xSize,int ySize) //create our window
{
WindowsWrapper::hWndMain=CreateWindowEx(NULL,
WindowsWrapper::lpClassName,
lpWindowName,
dwStyle,
0,0,xSize,ySize,
NULL,
NULL,
hInstMain,
NULL);

if(!WindowsWrapper::hWndMain) return false;

return true;
}

///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///
HWND WindowsWrapper::GethWnd() //get the hwnd
{
return WindowsWrapper::hWndMain;
}
///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///
///-----------------------------------------------------------------------------------------------------------------------------------///
LRESULT CALLBACK WindowsWrapper::MyWindowProc(HWND hWndMain,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_LBUTTONUP:
{
MyWindowsWrapper->LeftClick = true;
}break;

//case WM_RBUTTONDOWN:
//{
// MyWindowsWrapper->RightClick = true;
//}break;

case WM_RBUTTONUP:
{
MyWindowsWrapper->RightClick = true;
}break;


case WM_CHAR:
{

MyWindowsWrapper->LastKeyPress = wParam;
MyWindowsWrapper->KeyPressed = true;

}break;


case WM_KEYDOWN:
{

}break;

case WM_DESTROY://the window is being destroyed
{
PostQuitMessage(0);//tell the application we are quitting
}break;

case WM_PAINT://the window needs repainting
{

PAINTSTRUCT ps;//a variable needed for painting information
HDC hdc=BeginPaint(hWndMain,&ps);//start painting
EndPaint(hWndMain,&ps);//end painting

}break;

}

return(DefWindowProc(hWndMain,uMsg,wParam,lParam));
}





And to init your windows just call


WindowsWrapper Windows; //this is your class


//Setup our window
if (!Windows.SetupMyWindow(hInstance, hPrevInstance, lpCmdLine, nShowCmd,CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, "WINXCLASS"))
{
return(0);//something failed
}

//Now Create our window
int ResX = 800;
int ResY = 600;
if (!Windows.CreateMyWindow(WS_VISIBLE | WS_SYSMENU| WS_MINIMIZEBOX | WS_CAPTION, "Test", ResX, ResY))
{
return(0);//something failed
}

Share this post


Link to post
Share on other sites
That would likely suffice if you just have one class, but having the global instance is kind of bad form.

Typically, most Win32 wrappers will employ the use of MSDN - SetWindowLongPtr and MSDN - GetWindowLongPtr to associate the instance pointer of the class in the GWLP_USERDATA with the window handle. It would be typically stored while handling the WM_CREATE or WM_NCCREATE message by making the pointer through lpVoid when calling MSDN - CreateWindowEx. Note this can get fairly complicated if you try to support more than just your single window.


Also, are you planning to do something with your WM_PAINT message? Because it looks like you are drawing the window and then passing it to DefWindowProc, which is effectively going to do this again. Many times when you handle a message yourself, you will return a 0 (see MSDN about what individual messages should return). You typically pass things to DefWindowProc that you don't want to handle.

[edit]
Also, you don't really need to keep a copy of WNDCLASSEX around. You just need to to call RegisterClassEx and the ATOM returned by it or just the classname you used to call CreateWindowEx. You are done with WNDCLASSEX at that point. If you need to find anything you used during it, you can usually get it from a GetClassInfo call.

Share this post


Link to post
Share on other sites
Thanks for the tips rattrap I will try to incorporate them!
I tend to not follow form when programming as I am mostly self taught and I have picked up some bad habits...
For my games I tend to have a base class that holds all of my other classes.

Share this post


Link to post
Share on other sites

For my games I tend to have a base class that holds all of my other classes.


If you just have 1 window, this isn't so bad. But if you are handling multiple (win32 buttons, menus, text boxes, etc), this style may get ugly real fast.

Share this post


Link to post
Share on other sites

If you just have 1 window, this isn't so bad. But if you are handling multiple (win32 buttons, menus, text boxes, etc), this style may get ugly real fast.


I try to stay as far away from win32 as possible =p

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!