/*
   Form2.cpp  -- Child Window Controls And Window Procedures   
   In Form1.cpp we registered a Window Class in WinMain() with the RegisterClassEx() Windows Api
   function, which takes a single argument of a WNDCLASSEX object.  Immediately afterward we 
   instantiated an object of the Class with the CreateWindowEx() function, and that function call
   created our main window.  In Form2.cpp we'll do the same to create our main application window, 
   but we'll make additional CreateWindowEx() calls to illustrate the creation of 'child window 
   controls'.  Specifically, we'll create an "edit" control and a "button" control as childs of
   our main program window.  The user can enter text in the edit control, or not, and when the
   button is pressed, we'll retrieve the text, if any, from the edit control, and display it in a 
   Message Box. 
   Note in the code below the Window Procedure fnWndProc() is very different from the Form1 project.
   Graphical User Interface (GUI) programs for any operating system utilize a 'message driven 
   architecture'.  What that means is that the operating system monitors all user interactions
   with the running program, and 'calls back' into the program's code to inform that code of what
   the user is doing, or of system events which might be of interest to the running program.  It
   can do this because it has a pointer to the function the program's author provided as part of
   the WNDCLASSEX::lpfnWndProc structure/class.  That would be our fnWndProc() function below.
   Note that unlike with Form1 whose if statement tested for a WM_DESTROY message only in it's 
   Window Procedure, in Form2 we are using a switch logic construct to map incomming messages 
   received in the 2nd unsigned int parameter of the WndProc, to the code or 'message handlers' 
   that will handle that specific message.       
   The two additional messages that our Form2 Window Proicedure handles that are not seen in Form1
   are the WM_CREATE message, and the WM_COMMAND message.  The WM_CREATE message is kind of special
   in that it will only ever be received one time at program start up.  It is actually a C based
   object constructor call, and is actually running 'inside' the CreateWindow() call in WinMain()
   that creates the main program window.  We'll prove that in the next version of this program.  In
   this particular program you'll see two more CreateWindow() calls in the WM_CREATE handler code
   whose purpose is to create the two child window controls as described just above, i.e., an 
   'edit' control, and a 'button' control.  Note that unlike our CreateWindow() call in WinMain() 
   that created the main program window, we didn't register any edit or button classes in this app 
   as we did with our Form2 class using RegisterClassEx() in WinMain().  Rather, we're using 
   pre-defined operating system classes that are referred to as 'controls', or, more specifically, 
   as Windows 'Standard Controls'.  Among this group would be edit controls, buttons, combo-boxes, 
   list boxes, and labels.  This is a rather elegant design.  All GUI objects in Windows are windows 
   created by one function call which is the CreateWindow() or CreateWindowEx() call.  The specific 
   type of window or the 'class' of the window is specified by the szClassName parameter of the 
   call.
   The 2nd new message we've encountered here is the WM_COMMAND message.  That is how 'child' window
   controls communicate with their parent.  Count across to the 9th parameter of any of the  
   CreateWindowEx() calls in Form2 - either in WinMain() where we created our main program window,
   or in WM_CREATE handler code where we created the two child window controls, and you'll find
   the 'parent' of that respective window.  The parent of the main program window is specified as
   the desktop, which is in some ways like having no parent at all.  But for the edit and button
   child window controls their parent is specified as being the main program window.  That's where
   Windows the operating system will send WM_COMMAND messages if the user of the running program
   interacts with the child window control in any way, for example, in the case of a button, 
   clicking it.
   All of which brings us to the WPARAM and LPARAM parameters of the Window Procedure.  It is 
   through these two parameters that Windows informs the program of which child window control the 
   message applies to, and what specifically the user did with the control.  These are 'composite'
   parameters, and the information is packed rather tightly inside them.  In x64 code they are 8 
   byte entities, and the lower four bytes of WPARAM is the control identifier of the control, and 
   the upper four bytes is an equate/define in the Windows header files which specifies the specific
   'notification' message of what the user did with the control.  Note that the control identifier 
   is the 10th parameter of the CreateWindowEx() call used to create the control.  In the case of 
   the button below it is the #define IDC_BUTTON 1500 seen right below the program includes.  If you 
   do an MSDN search on BN_CLICKED you'll come up with this....   
https://docs.microsoft.com/en-us/windows/win32/controls/bn-clicked   So in the WM_COMMAND handler code below I'm hoping my explanation above will allow the reader to
   make sense out of my if statement where I'm testing to see if an incomming Windows message 
   contains the Control Id of our button, and if the notificaation is that the user clicked it.  If 
   the user did, the LPARAM will contain the HWND (Window Handle) of the button.  As an aside, it is 
   for reasons such as this that it is never necessary to have global variables in Windows programs.  
   All the information the coder will ever need is contained within the parameters of the various 
   functions which one interacts with in Windows coding.
   As an example of the lack of necessity for global variables in Windows SDK coding, check out what
   code actually executes inside the if statement described above in the WM_COMMAND handler code if
   the user actually did click the button to extract the text from the edit control.  The Windows 
   Api function to extract text from a control (any control) is GetWindowText().  Look it up on 
   MSDN.  To use that function we need the HWND (Window Handle) of the control, a pointer to a 
   memory buffer large enough to copy the text to, and the actual size of that buffer.  When we 
   created the edit control in the WM_CREATE handler code we didn't save or persist the returned 
   handle of the edit control - in fact, I purposly threw it away just to prove this point of not 
   needing global variables.  But we need it here to extract text from the edit control if the user 
   typed any.  How will we get it?  It was lost!  
   The GetDlgItem() Windows Api function returns the HWND of a control given the Control Id of the 
   control, and the HWND of the control's parent - which we both have.  Therefore, while there might 
   be a bit of excessive concision in my code, this line retrieves into szBuffer whatever the user 
   typed into the edit control....
   GetWindowText(GetDlgItem(hWnd,IDC_EDIT),szBuffer,256);  
   Finally, a MessageBox() presents that information to the user.  Pretty simple program really, but 
   it elucidates critically important processes in Windows Api SDK style coding.  Important points 
   the reader should grasp from this simple program is the way the CreateWindow() function call 
   creates objects in tandem with WM_CREATE handler code, the switch construct to map incomming 
   Windows messages to the code which handles that message, and the way child window controls are 
   created and how interactions with them are reported to a program through WM_COMMAND messages.
*/
// cl Form2.cpp /O1 /Os /link Kernel32.lib User32.lib                                // 91,648 Bytes VC19, x64, UNICODE LibCmt.lib
// g++ Form2.cpp -luser32 -lkernel32 -oForm2_gcc.exe -mwindows -m64 -s -Os           // 19,968 Bytes GCC 9.2.0, x64, UNICODE
// cl Form2.cpp /O1 /Os /GS- /Gy /link TCLib.lib user32.lib                          //  4,608 Bytes VC19, x64, UNICODE, TCLib.lib
#ifndef UNICODE
   #define UNICODE
#endif
#ifndef _UNICODE
   #define _UNICODE
#endif   
#include <windows.h> 
#define  IDC_BUTTON 1500   // Constant Numeric Identifier For Child Window "Retrieve Text" Button
#define  IDC_EDIT   1505   // Constant Numeric Identifier For Child Window Edit Control
LRESULT CALLBACK fnWndProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 switch(msg)                                                
 {                                                          
   case WM_CREATE: // WM_CREATE Message Received One Time and Is A C Based Object Constructor Call.  This code Actually Runs
    {              // 'Inside' The CreateWindowEx() Call Down In WinMain() Which Creates The Main App Window.  When Zero Is                                                       
        HINSTANCE hIns = NULL;                     // Returned Just Below, The CreateWindowEx() Call In WinMain() terminates,
        hIns=((LPCREATESTRUCT)lParam)->hInstance;  // and Execution Of ShowWindow() Occurs.
        CreateWindowEx(WS_EX_CLIENTEDGE,L"edit",L"",WS_CHILD|WS_VISIBLE,50,40,200,25,hWnd,(HMENU)IDC_EDIT,hIns,0);
        CreateWindowEx(0,L"button",L"Retrieve Text",WS_CHILD|WS_VISIBLE,95,90,120,30,hWnd,(HMENU)IDC_BUTTON,hIns,0);
        return 0;
    }   
   case WM_COMMAND:  // Child Windows (edit and button control in this app) Communicate With Their Parent (Main App Window) By                                      
    {                // Sending WM_COMMAND Messages To Their Parent.  Message Specifics (What The User Did With The Control)
        wchar_t szBuffer[256];   // Are Packaged Within The WPARAM And LPARAM Parameters Of The Window Procedure.                                       
        if(LOWORD(wParam)==IDC_BUTTON && HIWORD(wParam)==BN_CLICKED)  
        {                                                             
           GetWindowText(GetDlgItem(hWnd,IDC_EDIT),szBuffer,256); // GetDlgItem() Retrieves The HWND Of A Child Window Control
           MessageBox(hWnd,szBuffer,L"Button Click",MB_OK);       // Given Its Parent And Constant Numeric Define.  GetWindowText()   
        }                                                         // Retrieves The Text From A Control.   
        return 0;	  
    } 
   case WM_DESTROY:                                         
    {                          // When PostQuitMessage() Just Left Executes, The Message Pump Down In WinMain()
        PostQuitMessage(0);    // Terminates And The App Ends.                                                    
        return 0;   	
    }
 }                                                            
 return (DefWindowProc(hWnd, msg, wParam, lParam)); // Default Processing For Messages Not Handled Here.
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 wchar_t szClassName[] = L"Form2";              
 HWND hWnd             = NULL;                              
 WNDCLASSEX wc;                                 
 MSG messages;                                  
                                                
 memset(&wc,0,sizeof(wc));                                          
 wc.lpszClassName = szClassName;                
 wc.lpfnWndProc   = fnWndProc;                  
 wc.cbSize        = sizeof(WNDCLASSEX);         
 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);    
 wc.hInstance     = hInstance;                  
 RegisterClassEx(&wc);                          
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,200,175,320,200,HWND_DESKTOP,0,hInstance,0);
 ShowWindow(hWnd,iShow);                        
 while(GetMessage(&messages,NULL,0,0))          
 {                                       
    TranslateMessage(&messages);         
    DispatchMessage(&messages);          
 }
                                         
 return (int)messages.wParam;
}