There's mountains of guides for learning C++ and they all cover from hello world to pointers, but I never see any of them make a peep about making an actual window. They all stay in consoles and that's that.

Why is this? Do most people never mess with API and such? Are people satisfied with just the console?

I'm desperately trying to learn how to make a program look like an actual program, not a black console window. Guides are lacking, creating a default win32 Project in MVS2008 generates 200 lines of code for something so simple.

Do you guys seriously remember all these codes by heart? How can you even learn this stuff with the lack of guides?

On top of that, there's tons of libraries out there to help programming but no one seems to agree on what should be used.

I'm so lost.

C++ has nothing to do with making Windows. It barely knows about the console and keyboard. All that windowing stuff is system dependent and C++ simply taps into that system substructure either via API calls, add-on Windowing systems like MFC, OWL, FLTK, and others.

So you need to research the GUI techniques and choose a GUI System to learn. I hear FLTK is good, and fairly easy.

Comments
Nice

So would it be in my best interest not to really get into win32 Projects, but to use a completely different thing?

Didn't say that. I said it's not C++. It's an advanced form of coding, well worth researching. MFC may be part of Visual C, I'm just not certain never having used it. FLTK may be easier and it will teach you concepts needed, then you can advance to another platform closer to industry standards.

MFC is Microsoft Foundation Classes, and is a Visual C++ thing. It's good if you want to develop Windows apps like Word or Excel, or dialog based utility apps, but it's only for Windows. I always found it kind of fun to develop with, but it's occasionally looked at as being a pain to use.

It would be good to look at to broaden your horizons, but I wouldn't dive exclusively into using it when there are a lot of other options out there to try.

I've worked with MFC pretty extensively, and I can say for certain that it's at times a pain in the ass. I have not worked with it since VC++ 2005. If you're just getting started with GUI then I'd suggest you learn a more portable GUI package which works with several different platforms. wxWidgets is one, and QT is another. If you want 2d modeling such as for games then try out OpenGL. All of these require a firrm understanding of C and C++.

It is windows games programming books and articles that probably have the cleanest explanations of what you want to know.

There are ways to short cut building a window, depending on the version of visual studio you use. but it is worth knowing how to construct a window without any class wizard.

Once you have built the window the rest of the interface is fairly intuitive. A generic system like ancient dragon mentions maybe best in the long term. But for now, when you look for books on game programming they give you the information for using the windows api's and will give the code for constructing a window.

The code for building the window will stay almost the same for your windows applications.

The code gets messy when you see it without explanation and just to build a window that does nothing other than show takes code that looks a bit like this:

#include <windows.h>
BOOL Initialize(int iCmdShow)
{
  WNDCLASSEX    wndclass;

  // Create the window class for the main window
  wndclass.cbSize         = sizeof(wndclass);
  wndclass.style          = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc    = WndProc;
  wndclass.cbClsExtra     = 0;
  wndclass.cbWndExtra     = 0;
  wndclass.hInstance      = m_hInstance;
  wndclass.hIcon          = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetIcon()));
  wndclass.hIconSm        = LoadIcon(m_hInstance,
    MAKEINTRESOURCE(GetSmallIcon()));
  wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  wndclass.lpszMenuName   = NULL;
  wndclass.lpszClassName  = m_szWindowClass;

  // Register the window class
  if (!RegisterClassEx(&wndclass))
    return FALSE;

  // Calculate the window size and position based upon the game size
  int iWindowWidth = (m_iWidth * 1.5) + GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
      iWindowHeight = (m_iHeight * 1.1) + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 +
        GetSystemMetrics(SM_CYCAPTION);
  if (wndclass.lpszMenuName != NULL)
    iWindowHeight += GetSystemMetrics(SM_CYMENU);
  int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
      iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2;

  // Create the window
  m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
    WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
    iWindowHeight, NULL, NULL, m_hInstance, NULL);
  if (!m_hWindow)
    return FALSE;

  // Show and update the window
  ShowWindow(m_hWindow, iCmdShow);
  UpdateWindow(m_hWindow);

  return TRUE;
}

(this is pretty much the code that was from a games book I had, but it is several easy chapters of material to get the window to be useful.

The one caveat about using windows with your c++ code is the strings, converting to and from std::string s can be a nightmare as there are 4 types of string objects used.

But once you have got past the initial difficulties it is just like the rest of c++ with inheriting classes and you can reuse your existing code on one platform anyway:)

So would it be in my best interest not to really get into win32 Projects, but to use a completely different thing?

thanks for all the advice everyone.
btw, you guys wouldn't have any book recommendations would you?

btw, you guys wouldn't have any book recommendations would you?

No... We don't recommend books. Oh, and ignore that post at the top of the forum titled "Read Me: C++ Books" :)

Comments

I most definitely have a book recommendation for you and that is Charles Petzold's "Programming Windows" books. I most imagine all the book links at the top are about C++ specific issues. Creating GUI Windows programs is not a C++ specific issue as others have said.

Even if you choose some class framework to create GUI code, learning just a bit about the lower level Apis is a good idea in both the Windows world and the Linux world.

Comments
Good book suggestion, I've used it myself and agree with you.

Here is a sample Win32 program for you with directions for setting it up in Visual Studio...

1) Start Visual Studio;
2) Click Create New Project;
3) Highlight C++, Win32 Project;
4) I put mine here >>>> C:\Code\VStudio\VC++9\txtInput;
5) When the Win32 Project – Application Wizard opens choose ‘Windows Application’ and ‘Empty Project’. This is very important! Don’t let Visual Studio write your code for you!!! This is found under ‘Application Settings on the left part of the pane;
6) Click ‘Finish’;
7) Create a file name Form1.h from this…

//Form1.h
#define  IDC_EDIT      2000
#define  IDC_BUTTON    2005

typedef struct         WindowsEventArguments
{
 HWND                  hWnd;
 WPARAM                wParam;
 LPARAM                lParam;
 HINSTANCE             hIns;
}WndEventArgs,         *lpWndEventArgs;


struct EVENTHANDLER
{
 unsigned int          Code;
 long                  (*fnPtr)(lpWndEventArgs);
};

…and Main.cpp from this, and put them in the Visual Studio txtInput project directory…

//Main.cpp
#include <windows.h>
#include <tchar.h>
#include "Form1.h"
EVENTHANDLER  EventHandler[3];

/*    ******  long fnWndProc_OnCreate(lpWndEventArgs)  ******

  The WM_CREATE message is only received one time for each window
  creation.  The lParam parameter to the message contains a pointer
  to the CREATESTRUCT struct Windows filled out with the data in
  the CreateWindow() call that created the window (in this program
  down in WinMain()).  Just below are two more CreateWindow() calls,
  but these don't create main top level program windows, but rather
  two child window controls, i.e., the edit control and button you
  see when the program run.  The processing in fnWndProc_OnCreate()
  will occur before the CreateWindow() call in WinMain() returns.
  If you return a -1 from this procedure window creation will halt.
*/
long fnWndProc_OnCreate(lpWndEventArgs Wea)
{
 HWND hCtrl;

 Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance;
 hCtrl=
 CreateWindowEx
 (
  WS_EX_CLIENTEDGE,    //will give edit control 3D appearence
  _T("edit"),          //class name of window to create
  _T(""),              //caption (for edit control contents)
  WS_CHILD|WS_VISIBLE, //non-extended window styles
  10,30,270,30,        //location & size of window/control
  Wea->hWnd,           //parent of window being created
  (HMENU)IDC_EDIT,     //control id to associate with new window
  Wea->hIns,           //program instance handle
  0                    //creation parameters (here none)
 );

 hCtrl=
 CreateWindow          //adding extended styles to button controls
 (                     //doesn't do much for me, so i usually just
  _T("button"),        //use CreateWindow() calls instead of
  _T("Click Me"),      //CreateWindowEx() calls, which just macro
  WS_CHILD|WS_VISIBLE, //i believe to CreateWindowEx() with a null
  70,80,150,30,        //1st parameter.
  Wea->hWnd,
  (HMENU)IDC_BUTTON,
  Wea->hIns,
  0
 );

 return 0;
}

/*  ****  long fnWndProc_OnCommand(lpWndEventArgs Wea)  ****

  Child window controls such as text boxes and buttons communicate with
  their parent by sending WM_COMMAND messages.  Contained within the
  wParam and lParam parameters associated with the message are message
  specific details such as the control id of the control that generated
  the message, its hWnd, and other good stuff specific to the control
  and what the user did to trigger the message.  The only action this
  program takes is to display the text from a textbox when the user
  clicks the single button on the Form.  In that case the lower 16 bits
  of the wParam will contain the control id of the button window
  assigned during its CreateWindow() call; the high 16 bits (not used
  here) will contain the notification code BN_CLICKED; and the lParam
  will contain the hWnd (Window handle) of the clicked button.

  In the below piece of code I used the GetDlgItem() Api function to
  retrieve the window handle of the text box because the window handle
  is needed by the GetWindowText() call to retrieve the text out of the
  text box.  Note that you can always retrieve the window handle of a
  control from Windows if you know the control's parent and its control
  id.  Therefore, its NEVER necessary to make global variables out of
  window handles.
*/
long fnWndProc_OnCommand(lpWndEventArgs Wea)
{
 switch(LOWORD(Wea->wParam))
 {
   case IDC_BUTTON:
   {
     TCHAR szBuffer[256];
     GetWindowText(GetDlgItem(Wea->hWnd,IDC_EDIT),szBuffer,256);
     MessageBox
     (
      Wea->hWnd,
      szBuffer,
      _T("Here Is The Text You Entered"),
      MB_OK
     );
   }
 }

 return 0;
}

/*  ****  long fnWndProc_OnClose(lpWndEventArgs Wea)  ****

  When you click the little [x] button in a window's title bar,
  Windows sends the window a WM_CLOSE message.  Here I handled that
  message by doing a DestroyWindow() call to destroy the window,
  and by calling PostQuitMessage(0) which causes the program to drop
  out of the message processing loop (message pump) down in
  WunMain().  The program will then return (close).

*/
long fnWndProc_OnClose(lpWndEventArgs Wea)
{
 DestroyWindow(Wea->hWnd);
 PostQuitMessage(0);

 return 0;
}


/*  ****  void AttachEventHandlers(void)  ****

  This procedure is called one time down in WinMain() and it associates
  Windows messages such as WM_CREATE, WM_COMMAND, etc., with the address
  of the procedure which handles the message.  The EVENTHANDLER struct
  contains just two integer members, i.e., 'Code' - which is the message
  such as WM_CREATE, and 'fnPtr' - which is the address of the function
  to call when some particular message is received in the program's
  Window Procedure.
*/
void AttachEventHandlers(void)             //This program only handles
{                                          //three messages, i.e.,
 EventHandler[0].Code=WM_CREATE;           //WM_CREATE, WM_COMMAND and
 EventHandler[0].fnPtr=fnWndProc_OnCreate; //WM_CLOSE.  All others will
 EventHandler[1].Code=WM_COMMAND;          //be passed to DefWindowProc().
 EventHandler[1].fnPtr=fnWndProc_OnCommand;
 EventHandler[2].Code=WM_CLOSE;
 EventHandler[2].fnPtr=fnWndProc_OnClose;
}


/*  long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)

  When Windows intercepts some hardware related event such as a keystroke,
  mouse movement, COM port activity, etc., which it believes a window might
  be interested in, it packages up a message and sends it to the program's
  Window Procedure.  Most programmers seem to like to use a switch construct
  to map messages to the code that handles the message, but I prefer to use
  for loop/if logic and my function pointer setup to do the mapping.  This
  has the effect of making highly modular code and a minimalist Window
  Procedure.

*/
long __stdcall fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam,LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<3; i++)
 {
     if(EventHandler[i].Code==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(&Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


/*   ***** WinMain()  *****

  Program entry point.  Below event handlers are attached, a WNDCLASSEX struct
  is filled out, and a CreateWindow() call is made to create an instance of
  the Form1 class.  After that the program drops into a message loop which
  monitors the program's message quene for messages from the system pertaining
  to its one window.
*/
int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("Form1");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 AttachEventHandlers();
 wc.lpszClassName=szClassName;
 wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);
 wc.style=CS_DBLCLKS;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
 wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);
 wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;
 wc.cbWndExtra=0;
 wc.cbClsExtra=0;
 wc.lpszMenuName=NULL;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,_T("Enter Text In Text Box"),WS_OVERLAPPEDWINDOW,100,100,300,160,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}

If you want to understand better how it works do a search for Forger's Win32 Tutorial or check mine out here...

http://www.jose.it-berater.org/smfforum/index.php?board=380.0

And of course best is Charles Petzold's books.

thanks for all the replies and the book/site suggestions!

Just thought I would mention the other direction. You have asked and talked about moving from the console onto GUI programming but there is another direction and that is leaving the user interface behind entirely or having a completely platform dependent interface.

C++ (and C) are used on a vast array of platforms and the console/GUI platforms you have talked about are typical of PCs (of all makes and OSes) but these actually make up the minority of platforms using C++/C code because every piece of electronic equipment you use has a processor in it running code and a lot of the time that code is compiled from C/C++. Myself I have worked on digital television receivers, 3G modems and remote data acquisition units and without exception none of them had a console let alone a GUI.

Personally I like that sort of platform. Not having to deal with the mess that generally occurs from having to have direct contact with an actual user leaves you free to concentrate on the purity of the logic required to perform the task at hand.

I'm not saying don't learn a GUI I am just trying to complete the picture of available interfaces in which none is actually rather a common one.


I would advise you to stick clear of MFC which is a bit long in the tooth, not terribly well documented, buggy and in my experience a nightmare to debug.

@Frederick2:
I don't know much about Windows programming (I once started reading the theForger tutorial, but I stopped somewhere at the very beginning).
However, I could remember something about the Message Loop:

IMPORTANT: GetMessage() will return -1 if it encounters an error. Make sure you remember this, or it will catch you out at some point... even though GetMessage() is defined as returning a BOOL, it can return values other than TRUE or FALSE, since BOOL is defined as UINT (unsigned int). The following are examples of code that may seem to work, but will not process certian conditions correctly: while(GetMessage(&Msg, NULL, 0, 0)) while(GetMessage(&Msg, NULL, 0, 0) != 0) while(GetMessage(&Msg, NULL, 0, 0) == TRUE) The above are all wrong! It may be of note that I used to use the first of these throughout the tutorial, since as I just mentioned, it works fine as long as GetMessage() never fails, which when your code is correct it won't. However I failed to take into consideration that if you're reading this, your code probably won't be correct a lot of the time, and GetMessage() will fail at some point :) I've gone through and corrected this, but forgive me if I've missed a few spots. while(GetMessage(&Msg, NULL, 0, 0) > 0) This, or code that has the same effect should always be used.

I noticed that you also used an "incorrect" version (at least: according to this text).

Comments
Nice :)

Good point Tux4Life! I never picked up on that, even though I've been doing this for about 12 years! That point is even described right in the GetMessage documentation. I do believe I may modify my code from now on, but truthfully, I can't say I've ever had a problem with this.

Amazingly, Charles Petzold's books right from Microsoft Press show it the way I have it in my program above. Same with Rector & Newcommer's "Win32 Programming", which is the other major reference on the topic.

This article has been dead for over six months. Start a new discussion instead.