Blizzhackers

Return of the Jedi

* Login   * Register    * FAQ    * Search

Join us on IRC: #bh@irc.synirc.net (or Mibbit Web IRC)


MuleFactory


It is currently Mon May 20, 2013 12:49 pm


All times are UTC [ DST ]





Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: [C++] adding objects to win32 window without using WinProc()
PostPosted: Thu Jun 21, 2012 4:40 pm 
 
User
User

Joined: Wed Feb 08, 2012 3:34 pm
Hey all,

I started building a class which shall manage the window and its objects.

Quellcode follows (Well, that was my first try so don't expect it to be perfect :P)
(if you have any suggestions, please let me know!)

I fail at that point where I have to handle the window messages in the WinProc-function.
The problem is, in all tutorials and "help me"-forums I visited, the objects I want to add to the window (e.g. a text or a button) needed to be declared in the WinProc-function.

That means I can't just add a method like .addObject( ) to my window-class.
Or I missed the way to do that. And that's why I ask you, guys.

Do you know any way?


window.h
class WINDOW
{
  public:
   typedef struct s_icons
   {
      HICON Large;
      HICON Small;
      std::string szPathLarge;
      std::string szPathSmall;
   };

   LPCWSTR         Topic;
   WNDCLASSEX      wClass;
   HWND         hWindow;
   MSG            wMessage;
   HINSTANCE      ProcessHandleInstance;
   HINSTANCE      ParentProcessHandleInstance;
   LPSTR         CommandLineParams;
   int            nShowCommand;
   struct s_icons   Icons;

   WINDOW::WINDOW( )
   {
      /* - - - - - - Window - - - - - - */
      ZeroMemory( &this->wClass,   sizeof( WNDCLASSEX ) );
      ZeroMemory( &this->hWindow,  sizeof( HWND ) );
      ZeroMemory( &this->wMessage, sizeof( MSG ) );

      /* - - - - - - Icons - - - - - - */
      this->Icons.Large = NULL;
      this->Icons.Small = NULL;
      this->Icons.szPathLarge = "";
      this->Icons.szPathSmall = "";
   }

   bool Initiate( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd, WNDPROC winproc, std::string topic )
   {
      /* - - - - - - Give Window standard values - - - - - - */
      this->ProcessHandleInstance         = hInst;
      this->ParentProcessHandleInstance   = hPrevInst;
      this->CommandLineParams            = lpCmdLine;
      this->nShowCommand               = nShowCmd;
      this->Topic                     = L"Touhou Invaders";

      /* - - - - - - Give wClass standard values - - - - - - */
      this->wClass.cbClsExtra      = NULL;
      this->wClass.cbSize         = sizeof( WNDCLASSEX );
      this->wClass.cbWndExtra      = NULL;
      this->wClass.hbrBackground   = (HBRUSH)COLOR_WINDOW;
      this->wClass.hCursor      = LoadCursor( NULL, IDC_ARROW );
      this->wClass.hIcon         = NULL;
      this->wClass.hIconSm      = NULL;
      this->wClass.hInstance      = hInst;
      this->wClass.lpfnWndProc   = winproc;
      this->wClass.lpszClassName   = "Window Class";
      this->wClass.lpszMenuName   = NULL;
      this->wClass.style         = CS_HREDRAW|CS_VREDRAW;

      if( !this->RegisterWindow( ) )
         return FAIL;

      return SUCCESS;
   }
   bool RegisterWindow( void )
   {
      if( !RegisterClassEx( &this->wClass ) )
      {
         MessageBox( this->hWindow, "Can't register Window-Class!", "(Error): Register", MB_ICONERROR|MB_OKCANCEL );
         return FAIL;
      }
      return SUCCESS;
   }
   bool CreateWin( void )
   {
      this->hWindow = CreateWindowEx( NULL, this->wClass.lpszClassName, (LPCSTR)this->Topic, WS_OVERLAPPEDWINDOW, 40, 40, 800, 600, NULL, NULL, this->ProcessHandleInstance, NULL );

      if( !this->hWindow )
      {
         MessageBox( NULL, "Can't create main-window!", "(Error): Create Main-Window", MB_ICONERROR|MB_OKCANCEL );
         return FAIL;
      }
      return SUCCESS;
   }
   bool Show( void )
   {
      int x = 0;
      if( this->hWindow )
      {
         ShowWindow( this->hWindow, SW_SHOWNORMAL );
         this->Update( );
      }
      else MessageBox( NULL, "Can't show window!", "(Error): Show", MB_ICONERROR|MB_OKCANCEL );
      return SUCCESS;
   }
   bool Update( void )
   {
      UpdateWindow( this->hWindow );
      return SUCCESS;
   }

   bool AddIcon( std::string path, int which = 0 )
   {
      if( which != 1 )
         this->Icons.szPathLarge = path.c_str( );
      if( which != 2 )
         this->Icons.szPathSmall = path.c_str( );
      return SUCCESS;
   }
   struct s_icons * CreateIcons( )
   {
      this->Icons.Large = (HICON)LoadImage( NULL, this->Icons.szPathLarge.c_str( ), IMAGE_ICON, 32, 32, LR_LOADFROMFILE );
      if( !this->Icons.Large )
         MessageBox( this->hWindow, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR );

      this->Icons.Small = (HICON)LoadImage( NULL, this->Icons.szPathSmall.c_str( ), IMAGE_ICON, 16, 16, LR_LOADFROMFILE );
      if( !this->Icons.Small )
         MessageBox( this->hWindow, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR );
      
      return &this->Icons;
   }
};

WINDOW Window; // global instance to make it easier to use


main.cpp
LRESULT CALLBACK WinProc( HWND, UINT, WPARAM, LPARAM );

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd )
{
   Window.Initiate( hInst, hPrevInst, lpCmdLine, nShowCmd, (WNDPROC)WinProc, "Project" );

   if( Window.CreateWin( ) )
      Window.Show( );

   while( GetMessage( &Window.wMessage, NULL, 0, 0 ) )
   {
      TranslateMessage( &Window.wMessage );
      DispatchMessage( &Window.wMessage );
   }

   return EXIT_SUCCESS;
}


LRESULT CALLBACK WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
   switch( msg )
   {
      case WM_DESTROY:
         PostQuitMessage( 0 );
         break;
      case WM_CLOSE:
         DestroyWindow( hWnd );
         break;
      case WM_COMMAND:
         // Handle messages here
         // Handle messages here
         // Handle messages here
         break;
      case WM_CREATE:
         break;
   }
   return DefWindowProc( hWnd, msg, wParam, lParam );
}

_________________
"I want to see a machine, acting like a human being!"
"Well, I want to see a human, acting like a human being!"

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 22, 2012 8:29 am 
 
Moderator
Moderator
User avatar

Joined: Thu Apr 30, 2009 12:31 pm
Location: %scrdir%
for adding objects, you only need the HWND of that target, so it doesn't need to be done in the WndProc, but generally anything you want to add should be handled in WM_CREATE.
to make it easier to pass around your class object in a WndProc, you can actually attach a pointer to it to the HWND, via SetWindowLongPtr(hWnd,GWLP_USERDATA,this), and retrieve it via GetWindowLongPtr,
this way to can not only verify if an HWND is yours, but you can also have multiple HWND's/Windows, so now you can also handle any object specific messages inside the WndProc

_________________
Learn C++, not Crap++ http://tinyurl.com/so-cxxbooks
Hackito Ergo Sum
Cthulhon: No, I am a dancer. I am in charge of popping and locking.

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 22, 2012 10:52 am 
 
User
User

Joined: Sat Mar 17, 2012 5:39 pm
I think what he means is, he is having problems using an object reference (i.e. HANDLE_MSG(hwnd, WM_CREATE, /*object->*/OnCreate)). There are two solutions. The first is to scrap your managed code, and the second is to do as TUS said. Here is some pseudo code from a Splash window program.

class CObject
{
private:
   HWND m_hwnd;
private:
   typedef struct tagCREATEPARAMS
   {
      LPVOID pthis;
      UINT uElapse;
      BOOL bAnimate;
      DWORD dwFlags;
   } CREATEPARAMS, *LPCREATEPARAMS;

private:
   BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct);

private:
   static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
   LRESULT CALLBACK WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
};

BOOL CObject::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
   UINT uElapse;
   BOOL bAnimate;
   DWORD dwFlags;

   uElapse = ((LPCREATEPARAMS)lpCreateStruct->lpCreateParams)->uElapse;

   SetTimer(hwnd, 0, uElapse, NULL);

   bAnimate = ((LPCREATEPARAMS)lpCreateStruct->lpCreateParams)->bAnimate;

   if(bAnimate)
   {
      dwFlags = ((LPCREATEPARAMS)lpCreateStruct->lpCreateParams)->dwFlags;
      AnimateWindow(hwnd, (DWORD)uElapse, dwFlags);
   }

   return TRUE;
}

LRESULT CALLBACK CObject::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   CObject *pObject;

   switch(uMsg)
   {
   case WM_CREATE:
      pObject = (CObject *)((LPCREATEPARAMS)((LPCREATESTRUCT)lParam)->lpCreateParams)->pthis;
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG)pObject);
      break;
   default:
      pObject = (CObject *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
      if(pObject == NULL)
      {
         return DefWindowProc(hwnd, uMsg, wParam, lParam);
      }
      break;
   }

   pObject->m_hwnd = hwnd;

   return pObject->WindowProc(uMsg, wParam, lParam);
}

LRESULT CALLBACK CObject::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
   HANDLE_MSG(m_hwnd, WM_CREATE, OnCreate);
   default:
      return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
   }

   return 0;
}


I hope this helps you understand better, but it's pretty advanced, so don't hesitate to ask about specific sections of code.

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 22, 2012 6:06 pm 
 
User
User

Joined: Wed Feb 08, 2012 3:34 pm
Thanks for the fast an informative answers!

If I get all this right, then every object has its own WinProc() function.
And the static WindowProc() function is the one, I append to the main window.
/*static*/ LRESULT CALLBACK CObject::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   CObject *pObject;

   switch(uMsg)
   {
      /////.....

Does this code affect ALL objects of the type CObject?
Well, of course it does, because of "static". What I mean is, will the call of WindowProc() bind all CObject's to the main window?
I never used static members/methods, so forgive me my maybe silly question.

If my thoughts are correct, I could fap to this :D
With that it should be possible to add some kind of "event handler"-class which consists of On[Action]() functions like OnClick(), OnDoubleClick() and so on!



Well, that would be my next question: "How can I build event-functions like OnClick without using the WM_COMMAND way?"

My first idea was some kind of that:
LRESULT CALLBACK CObject::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
      HANDLE_MSG(m_hwnd, WM_CREATE, OnCreate);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnClick, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnDoubleClick, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnMouseOver, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnMouseDown, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnMouseUp, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnFocus, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      HANDLE_MSG(m_hwnd, WM_COMMAND, OnI_DONT_KNOW_MORE, /*maybe some other parameter. e.g. the constant "id" of the object*/);
      default:
         return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
   }

   return 0;


I really pray for that this will be so easy!

_________________
"I want to see a machine, acting like a human being!"
"Well, I want to see a human, acting like a human being!"

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 22, 2012 8:33 pm 
 
User
User

Joined: Sat Mar 17, 2012 5:39 pm
In the switch statement, you will specify WM_COMMAND, and then handle those notifications in the OnCommand callback. You can take a look at the WindowsX header--type it in to your compiler and open the document--in the Windows SDK.

Use this link as a reference for the control library.

The following is an example of how your switch statement and OnCommand callback will function.

...
switch(uMsg)
{
...
HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
...
}
...

void OnCommand(HWND hwnd, int Id, HWND hwndCtl, UINT codeNotify)
{
   switch(Id)
   {
   case IDC_CONTROL: // Control Id, for example, a button might be IDC_BUTTON1
      switch(codeNotify)
      {
      case BN_CLICKED:
         pButton1->OnClicked();
         break;
      }
      break;
   }
}


As for the static WindowProc, that is what TUS was talking about. You store pObject in the user data associated with the window. See SetWindowLongPtr for more details, under the parameter nIndex. Basically, it's just a more "elegant" solution for managing your code.

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Thu Jun 28, 2012 6:09 pm 
 
User
User

Joined: Wed Feb 08, 2012 3:34 pm
Thanks for that, FireFromTheSky.
Well, I didn't get that right now, but I'm still trying...

I think the most depressing fact is, that I need to declare a constant ID for each object. That is what makes it static.

I read that it is possible to change constant variables with some pointer work like this one. (Something like that)
const int n = 10;
const int * ptr1 = &n;
int ** ptr2 = &ptr1;
ptr2 = 5; // n is now 5


Well, I know constants should stay constant, thats because they were declared as const.

But in that case I think its just Microsofts typical rashness ...


Does anyone know any solution?

_________________
"I want to see a machine, acting like a human being!"
"Well, I want to see a human, acting like a human being!"

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Thu Jun 28, 2012 7:50 pm 
 
Moderator
Moderator
User avatar

Joined: Thu Apr 30, 2009 12:31 pm
Location: %scrdir%
Thanks for that, FireFromTheSky.
Well, I didn't get that right now, but I'm still trying...

I think the most depressing fact is, that I need to declare a constant ID for each object. That is what makes it static.

I read that it is possible to change constant variables with some pointer work like this one. (Something like that)
const int n = 10;
const int * ptr1 = &n;
int ** ptr2 = &ptr1;
ptr2 = 5; // n is now 5


Well, I know constants should stay constant, thats because they were declared as const.

But in that case I think its just Microsofts typical rashness ...


Does anyone know any solution?
Your code same violates aliasing rules and conversion rules (loss of qualifier), it should even compiler. plus ontop of that, most compilers do constant propagation, removing the link to the variable and substituting its value instead.

As for your problem, why do you need it to be static? use an enum for runtime tagging or template meta-programming for RTTI style compile time tagging

_________________
Learn C++, not Crap++ http://tinyurl.com/so-cxxbooks
Hackito Ergo Sum
Cthulhon: No, I am a dancer. I am in charge of popping and locking.

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Thu Jun 28, 2012 8:22 pm 
 
User
User

Joined: Wed Feb 08, 2012 3:34 pm
Your code same violates aliasing rules and conversion rules (loss of qualifier), it should even compiler. plus ontop of that, most compilers do constant propagation, removing the link to the variable and substituting its value instead.

As for your problem, why do you need it to be static? use an enum for runtime tagging or template meta-programming for RTTI style compile time tagging

It's the opposite. I need it to be non-static, non-constant.

The problem is, that the WindowProcedure() works with constant IDs, mostly defined like
#define IDC_BUTTON_01 0x012345


And that is static. E.g. I can't run a for()-loop that adds 20 buttons to the window, because giving buttons OnEvent message handler will require a constant ID

_________________
"I want to see a machine, acting like a human being!"
"Well, I want to see a human, acting like a human being!"

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Thu Jun 28, 2012 8:47 pm 
 
User
User

Joined: Wed Feb 08, 2012 3:34 pm
Maybe, to make that clear, I should tell you the way I want my window class working
/*class*/ WINDOW Window;

int WinMain( /*params*/ )
{
   Window.Initiate( /*params*/ );

   WINDOW::Add( std::string szType, std::string szName, std::string szTitle, RECT sRctRectangle, FUNCPTR fnOnEvent );
   Window.Add( "Button", "Button1", "Click Me 1", RECT( /*x*/ 10, /*y*/ 10, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button1 );
   Window.Add( "Button", "Button2", "Click Me 2", RECT( /*x*/ 10, /*y*/ 50, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button2 );
   Window.Add( "Button", "Button3", "Click Me 3", RECT( /*x*/ 10, /*y*/ 90, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button3 );
   Window.Add( "Button", "Button4", "Click Me 4", RECT( /*x*/ 10, /*y*/ 130, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button4 );
   Window.Add( "Button", "Button5", "Click Me 5", RECT( /*x*/ 10, /*y*/ 170, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button5 );
   Window.Add( "Button", "Button6", "Click Me 6", RECT( /*x*/ 10, /*y*/ 210, /*width*/ 110, /*height*/ 30 ), (FUNCPTR)OnClick_Button6 );

   Window.Add( "Text", "Text1", "Hallo Welt", RECT( /*********/ ), NULL );

   if( Window.CreateWin( ) )
      Window.Show( );
}


That way I want to build a GUI.

long __stdcall WindowProcedure( struct HWND__ * hWnd, unsigned int uiMsg, unsigned int __w64 wParam, long __w64 lParam )
{
   switch( msg )
   {
      case WM_CREATE:
         //
         //
         //
         // NOTHING HERE! ALL IN WinMain()!
         //
         //
         //
         break;
      case WM_COMMAND:
         //
         // JUST CALLING MY OWN "WindowProcedure()"
         Window.Events( hWnd, uiMsg, wParam, lParam );
         //
         //
         break;
      case WM_DESTROY:
         PostQuitMessage( 0 );
         break;
      case WM_CLOSE:
         DestroyWindow( hWnd );
         break;
   }
   return DefWindowProc( hWnd, msg, wParam, lParam );
}


In the method WINDOW::ObjectEvents( HWND, UINT, WPARAM, LPARAM ) the OnEvent functions should be assigned to the buttons.

_________________
"I want to see a machine, acting like a human being!"
"Well, I want to see a human, acting like a human being!"

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 29, 2012 3:46 am 
 
User
User

Joined: Sat Mar 17, 2012 5:39 pm
I don't understand. How do you plan on accessing controls if their ID isn't defined somewhere? You code doesn't make sense.

Top
 Profile  
 Post subject: Re: [C++] adding objects to win32 window without using WinPr
PostPosted: Fri Jun 29, 2012 8:37 am 
 
Moderator
Moderator
User avatar

Joined: Thu Apr 30, 2009 12:31 pm
Location: %scrdir%
And that is static. E.g. I can't run a for()-loop that adds 20 buttons to the window, because giving buttons OnEvent message handler will require a constant ID

class XYZ
{
private:
     unsigned long dwLastElementID;

public:
    unsigned long GenGUID()
    {
        return dwLastElement++;
    }
};

XYZ::dwLastElementID = 0x1000; //or whatever


then whenever you create an element, you assign it Window.GenGUID();, so when you receive a message, you walk your list looking for the matching ID (the lParam is also the HWND of the control, so you don't even need to scroll by ID, and in fact, you can use the same method I pointed out above to attach your Window Manager to its HWND, to attach the objects for each control to their respective HWND's, which means you don't even need to look them up, you just do ((Object*)GetWindowLongPtr((HWND)lParam,GWLP_USERDATA))->HandleMessage(...).

_________________
Learn C++, not Crap++ http://tinyurl.com/so-cxxbooks
Hackito Ergo Sum
Cthulhon: No, I am a dancer. I am in charge of popping and locking.

Top
 Profile  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
cron