How it Works

 

Home
Overview
How it Works
Downloads
Tutorials

Examples

Links
Contact

 

 

Win32++ Classes

The classes which define the library itself are contained within the Win32xx namespace. These classes are as follows:

  • CAnimation:  A class used to create an animation control.
  • CArchive:  A class used to archive objects to a file.
  • CAXHost:  A class used to implement a COM container used by CWebBrowser.
  • CBitmap:  A class used to create a bitmap resource.
  • CBitmapInfoPtr:  A class used to create the BITMAPINFO structure.
  • CBrush:  A class used to create a brush resource.
  • CButton:  A class used to create a button control.
  • CClientDC:  The class used to device contect for the client area of the window.
  • CColorDialog:  A class used to display the Color common dialog box.
  • CComboBox:  A class used to create a combo box control.
  • CComboBoxEx:  A class used to create a ComboBoxEx control.
  • CCommonDialog:  The base class for the common dialogs.
  • CCriticalSection:  This class provides for thread synchronization for multi-threaded applications.
  • CDataExchange:  This class is used to provide support for Dialog Data eXchange(DDX) and Dialog Data Validation(DDV).
  • CDateTime:  This class is used to create a date and time picker control.
  • CDC:  A class which represents a Device Context. It simplifies working the windows GDI.
  • CDialog:  The class responsible for creating modal and modeless dialogs. It is used by CFrame, and can also be used to create dialog applications.
  • CDockContainer:  The class is used to create docking containers.
  • CDocker:  The class used for a docking window. Docking windows can also be used as splitter windows.
  • CDockFrame:  This class combines a normal CFrame with docking.
  • CEdit:  A class used to create an edit control.
  • CEnhMetaFile:  A class used to manage a HENHMETAFILE.
  • CEnhMetaTileDC:  A class used to create an enhanced metafile device context.
  • CEvent:  A class used to create an event object.
  • CException:  This is the base class for the exceptions used in Win32++.
  • CFile:  A class used to read from and write to files.
  • CFileDialog:  A class used to display the FileOpen and FileSave common dialogs.
  • CFileException:  This exception is thrown by CArchive and CFile.
  • CFileFind:  A class used to find one or more files matching the specified string.
  • CFindReplaceDialog:  A class used to display the FindText and ReplaceText common dialogs.
  • CFolderDialog:  A class used to display a dialog to choose a folder.
  • CFont:  A class used to create a font resource.
  • CFontDialog:  A class used to display the Font common dialog.
  • CFrame:  This class produces a frame window which has a rebar, menubar, toolbar, and a status bar. The client area of the frame window should be occupied by a separate CWnd object.
  • CFrameT:  A class template used by CFrame, CDockFrame, CMDIFrame, CRibbonFrame etc.
  • CGDIObject:  The base class for GDI objects including CBitmap, CBrush, CFont, CPalette, CPen, and CRgn.
  • CGlobalLock:  A template class used for global memory, used by CDevMode amd CDevNames.
  • CHeader:  A class used to create a header control.
  • CHGlobal:  A class used to manage global memory acquired by GlobalAlloc.
  • CHotKey:  A class used to create a hot key control.
  • CImageList:  A class used to create and manage Image Lists.
  • CIPAddress:  The class used to create an IP address control.
  • CListBox:  A class used to create a list-box control.
  • CListView:  A class that is used to create a List-View control.
  • CMDIChild:  This is the class to be used for MDI children. Each MDI child should be inherited from this class.
  • CMDIDockFrame:  This class combines a normal CMDIFrame with docking.
  • CMDIFrame:This class is responsible for creating the MDI frame window.
  • CMDIFrameT:  A template class used by CMDIDockFrame, CMDIFrame, CMDIRibbonFrame and CRibbonMDIDockFrame.
  • CMemDC:  The class used to create memory device context.
  • CMenu:  The class used to create and modify menus.
  • CMenuBar: This class is responsible for creating the menubar.  A menubar is a menu housed inside a rebar control.
  • CMenuMetrics:  A classed used by CFrameT to retrieve the size of menu components.
  • CMessagePump:  A classed used provide a message pump for CWinApp and CWinThread.
  • CMetaFile:  A class used to manage a HMETAFILE.
  • CMetaFileDC:  A class used to create metafile device context.
  • CMonthCalendar:  A class used to create a month calendar control.
  • CMutex:  A class used to create a mutex object.
  • CNotSupportedException: This exception is thrown when Win32++ can't be started.
  • CPageSetupDialog:  A class used to display the Page Setup common dialog.
  • CPaintDC:  A class used to create device context for the WM_PAINT message.
  • CPalette:  A class used to create a palette resource.
  • CPen:  A class used to create a pen resource.
  • CPoint:  A class that can be used in place of a POINT structure.
  • CPrintDialog:  A class used to display the print common dialog.
  • CPrintDialogEx:  A class used to display the  extended print common dialog.
  • CPrintPrintPreview:  A class template used to provide a print preview.
  • CProgressBar:  A class used to create a progress bar control.
  • CPropertyPage:  The class used to create a property page. A property sheet has one or more property pages.
  • CPropertySheet:  This class represents a property page. It is used by CPropertySheet.
  • CReBar:  This class is responsible for creating the rebar. It is used by CFrame.
  • CRect:  A class that can be used in place of a RECT structure.
  • CRegKey:  A class used to manage acces to the system registry.
  • CResizer:  A class used to automatically rearrange child windows when the parent window is resized.
  • CResourceException:  This exception is thrown when a GDI resource can't be created.
  • CRgn:  A class used to create a region.
  • CRibbon:  The class used to add a Window 7 ribbon framework to a window.
  • CRibbonDockFrame:  The class used to add a frame which supports docking and the Window 7 ribbon framework. A menu and toolbar will be used if the operating system doesn't support the ribbon framework.
  • CRibbonFrame:  The class used to create a frame window with a Window 7 ribbon framework A menu and toolbar will be used if the operating system doesn't support the ribbon framework.
  • CRibbonFrameT:  A classtemplate used by CRibbonFrame, CRibbonDockFrame, CRibbonMDIFrame and CRibbonMDIDockFrame.
  • CRichEdit:  A class used to create a rich edit control.
  • CScrollBar:  A class used to create a scroll bar control.
  • CScrollView:  A class used to add scroll bars to a view window.
  • CSemaphore:  A class used to create a semaphore object.
  • CSize:  A class that can be used in place of a SIZE structure.
  • CSlider:  The class used to create a slider control (sometimes referred to as a track bar control).
  • CSocket:  This class adds network support to Win32++.
  • CSpinButton:  The class used to create a spin button control (sometimes referred to as an up down control).
  • CStatic:  The class used to create a static control.
  • CStatusBar:  The class responsible for creating the status bar. It is used by CFrame.
  • CString:  The class used to create and modify character strings.
  • CStringT:  A class template used by CStringA and CStringW.
  • CTab:  The class used to create a Tab control.
  • CTabbedMDI:  The class used for Tabbed MDI window.
  • CTaskDialog:  The class used for to create a Task Dialog.
  • CThreadLock:  This class provides a convenient RAII-style mechanism for owning a CCriticalSection.
  • CThreadT:  A class template used by CWinThread and CWorkThread.
  • CTime:  This class represents an absolute date and time.
  • CTimeSpan:  This class provides the difference between two CTime values.
  • CToolBar:  The class responsible for creating the tool bar. It is used by CFrame.
  • CToolTip:  The class used to create a tool tip control.
  • CTreeView:  A class used to create a Tree-View control.
  • CUserException:  This exception is thrown and caught by CDataExchange when validation fails.
  • CWebBrowser:  The class used to create a web browser in a window.
  • CWinApp:  The class responsible for initializing Win32++, and also provides our message loop. You should inherit from this class to start the application.
  • CWindowDC:  The class used to create a device context for the entire window, including the non-client area.
  • CWinException:  A class which handles exceptions.
  • CWinThread:  The class used to to create GUI threads. A window can run in a GUI thread.
  • CWnd:  The class responsible for the window objects. It is the base class for the more specialized window objects such as CDialog, CFrame, CToolbar etc.
  • CWorkThread:  The class used to to create worker threads.
  • Shared_Ptr:  A smart pointer that can be used in a STL container such as a vector.

 

Using Win32++

The code which forms the basis of Win32++ is located in the include  directory.  You shouldn't need to modify these files, but rather inherit from the Win32++ classes and add any additional code in your derived classes.  To create a SDI frame window, for example, you would typically derive your own class from CFrame and place any modifications to the standard frame there.  You can override the WndProc member function to include any additional messages you would like to handle.

The tutorials which ship with Win32++ provide step by step instructions for using Win32++.

The documentation for Win32++ is available here.

 

Object oriented approach

The key to bringing an object oriented approach to programming directly with the Windows API is to have a C++ class that can create a window and which includes its own window procedure as a member function. Once we have this class, we can inherit from it and override the window procedure member function to handle messages the way we want for each derived window type.

Creating a class like this is not trivial, and I suspect that's one of the reasons why MFC was created in the first place. The problem stems from the way a "window class" is registered before the window can be created. (The term "class" here refers to the Windows API "window class", which is not the same thing as a C++ class.) The following code snippet shows how a window class might be registered using the API:

WNDCLASSEX wc;
memset((WNDCLASSEX*)&wc, 0, sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
//The name of the window procedure
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = "TEST";
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

//Register the window class
::RegisterClassEx(&wc);

Note that we need to supply the function name of our window procedure. The window procedure is where we control what is to be done when a window message is received. This function must conform precisely to the predefined standards required by the Windows API. A typical declaration of the callback function looks like this:

LRESULT CALLBACK WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam);

We might be tempted to set the WindowProc function as a member of the class. Unfortunately, each class member function has an implicit this pointer as one of its arguments, and therefore cannot be used as the callback function for a window. If we did this, our WindowProc function would no longer conform to the predefined standards and the program would fail to compile.

We can make the WindowProc function a static member function of the class. There is no implicit this in a static function, and this will compile correctly. Unfortunately, a static member function doesn't have access to the class object (i.e., it doesn't have a this pointer), and it cannot access other members of the class. It is this which prevents the static member function from being used in an object oriented way. The following code demonstrates the limitations of a static member function approach:

class TestStatic
{
public:
  int member;

  void NormalFunction()
  {
    //We can access member variables in a normal
    //member function
    member = 5;

    //The following line is equivalent to the one above
    this->member = 5;
  }

  void static StaticFunction()
  {
    //We cannot access member variables
    //in a static member function
    //The following line will give a compile error
    member = 5;

    //This will give an error too
    this->member = 5;
  }
};

A static member function for the window procedure would be useful if we could just get our hands on a pointer to the window class object (our this pointer). There are a number of techniques that we can use to get access to our pointer as the window is being created. The one I have chosen takes advantage of Thread Local Storage to store our pointer, which is later inserted into an STL map. This is how it's done:

Step 1: Set up the Thread Local Storage to store our this pointer. This is done in the CWinApp class:

CWinApp::CWinApp(HINSTANCE instance) : m_instance(instance)
{
  if (GetApp() == 0)
  {
    st_dwTlsIndex = ::TlsAlloc();

    //snip

    }
}

Step 2: Store our this pointer in the Thread Local Storage when we use CreateEx to create the window:

// Ensure this thread has the TLS index set
TLSData* pTLSData = GetApp()->SetTlsIndex();

// Store the CWnd pointer in thread local storage
pTLSData->pCWnd = this;

Step 3: Extract the pointer from Thread Local Storage and add it to the STL map during the initial creation of the window:

// Retrieve the pointer to the TLS Data
TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());

// Retrieve pointer to CWnd object from Thread Local Storage TLS
w = pTLSData->pCWnd;

// Store the CWnd pointer in the HWND map
GetApp()->AddToMap(hwnd, w);

return w->WndProc(msg, wparam, lparam);

Step 4: For each subsequent window message, we extract the pointer from the STL map and use it to redirect the message handling to the appropriate WndProc function:

CWnd* w = GetApp()->GetCWndFromMap(hwnd);
return w->WndProc(msg, wparam, lparam);

 

Window creation in detail

Now that we've had a look at the window procedure it is time to see how these fit together as we create the window. This is the code which creates the window:

inline HWND CWnd::CreateEx(DWORD exStyle, LPCTSTR pClassName, LPCTSTR pWindowName, 
                             DWORD style, int x, int y, int width, int height, HWND parent, 
                             HMENU idOrHMenu, LPVOID lparam /*= NULL*/)
// Creates the window by specifying all the window creation parameters
{
    assert( GetApp() );        // Test if Win32++ has been started
    assert( !IsWindow() );     // Only one window per CWnd instance allowed

    // Ensure a window class is registered
    CString className;
    if (pClassName == 0 || pClassName[0] == _T('\0'))
        className = _T("Win32++ Window");
    else
        className = pClassName;

    WNDCLASS wc;
    ZeroMemory(&wc, sizeof(wc));
    wc.lpszClassName = className;
    wc.hbrBackground = reinterpret_cast(::GetStockObject(WHITE_BRUSH));
    wc.hCursor       = ::LoadCursor(NULL, IDC_ARROW);

    // Register the window class (if not already registered)
    if (RegisterClass(wc) == 0)
    {
        TRACE("*** RegisterClass failed ***\n");
        assert( false );
    }

    // Ensure this thread has the TLS index set
    TLSData* pTLSData = GetApp()->SetTlsData();

    // Store the CWnd pointer in thread local storage
    pTLSData->pWnd = this;
    m_wnd = 0;

    // Create window
    HWND wnd = ::CreateWindowEx(exStyle, className, pWindowName, style, x, y, width, height,
                                hWParent, idOrMenu, GetApp()->GetInstanceHandle(), lparam);

    // Tidy up
    pTLSData->pWnd = NULL;

    if (wnd == 0)
    {
        // Throw an exception when window creation fails
        throw CWinException(g_msgWndCreateEx);
    }

    // Automatically subclass predefined window class types
    if (pClassName)
    {
        ::GetClassInfo(GetApp()->GetInstanceHandle(), pClassName, &wc);
        if (wc.lpfnWndProc != GetApp()->m_callback)
        {
            Subclass(wnd);

            // Override this to perform tasks after the window is attached.
            OnAttach();
        }
    }

    // Clear the CWnd pointer from TLS
    pTLSData->pWnd = NULL;

    // Post a message to trigger a call of OnInitialUpdate
    PostMessage(UWM_WINDOWCREATED);

    return wnd;
}

The next code segment is the window procedure which first receives the messages. We extract the pointer to the CWnd object from the map, and use it to redirect the handling of the window messages to the appropriate WndProc function:

inline LRESULT CALLBACK CWnd::StaticWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
// All CWnd windows direct their messages here. This function redirects the message
// to the CWnd's WndProc function.
{
    assert( GetApp() );

    CWnd* w = GetApp()->GetCWndFromMap(wnd);
    if (w == 0)
    {
        // The CWnd pointer wasn't found in the map, so add it now

        // Retrieve the pointer to the TLS Data
        TLSData* pTLSData = GetApp()->GetTlsData();
        assert(pTLSData);

        if (pTLSData)
        {
            // Retrieve pointer to CWnd object from Thread Local Storage TLS
            w = pTLSData->pWnd;
            assert(w);              // pTLSData->pCWnd is assigned in CreateEx
            if (w)
            {
                pTLSData->pWnd = NULL;

                // Store the CWnd pointer in the HWND map
                w->m_wnd = wnd;
                w->AddToMap();
            }
        }
    }

    return w->WndProc(msg, wparam, lparam);

}

Finally, the next code segment shows the function called by StaticWindowProc. Typically, when we derive a new class from CWnd, we would override this function to control the way various window messages are handled:

inline LRESULT CWnd::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
    // Override this function in your class derived from CWnd to handle
    //  window messages. A typical function might look like this:

    //	switch (msg)
    //	{
    //	case MESSAGE1:  return OnMessage1();
    //	case MESSAGE2:  return OnMessage2();
    //	}

    // The message functions should return a value recommended by the Windows API documentation.
    // Alternatively, return FinalWindowProc to continue with default processing.

    // Always pass unhandled messages on to WndProcDefault
    return WndProcDefault(msg, wparam, lparam);
}

 

Conclusion

With technique we are able to forward every window message to the appropriate CWnd object. No messages are discarded, even during window creation. This technique also supports all window types, including dialogs, common controls, MDI frames, and property sheets.