Hmmm...  I'm at a loss as to what I should show for an example of the improved DWinLib.  I could redo the Tic-Tac-Toe program, but that doesn't even begin to push the limits of the revised framework (although it would show you how frameworks such as this increase your executable size for a blank window - a minimal window jumped from 85 kb to 138 kb using BCB4).  Let me start by telling a little more about the revisions.

The improvements between the first version and this version deal with improved ease of child control handling.  For instance, in an API program, you have to assign a control a unique ID number to each control, and then handle that control by checking for that control's ID.  This has been very well automated inside DWinLib.

Another nice aspect of DWinLib is that you can easily change the callbacks to the control items.  Even though these callbacks have been implemented as pointers to static functions, they are very powerful, and the function signatures hold enough information to allow you to easily call into instantiated DWinLib objects.

The Boost libraries were not used for binding the member function pointers, although they probably could have been.  This is simply because I was never comfortable with the syntax of boost::bind, nor did I understand how boost::bind worked.  I also wanted to keep third party dependencies to a minimum.  The method I selected was powerful, efficient, and it worked.

This version of the wrapper has a couple dependancies that the first version of the wrapper didn't have.  For instance, just to create a blank window, in addition to the 'WinBaseO' and the 'Application' unit, you must also supply a 'WinMainO'.  Each project will need a custom version of this, as this is the main program window definition. You must also link to 'WinControl', 'WinCallBackList', and a 'WinDC'.  These units are not there because of monstrous dependencies.  The classes are not that poorly designed.  In the case of WinDC, it is simply there because the default WM_PAINT handler is given a WinDC in its signature, in order to simplify the DC management for the programmer.

There is one dependency that I did not like, and it had to do with the WinCallBackList.  I have forgotten the details, but it had to do with the fact that the WinBaseO window is derived from WinControl, and therefore needed WinControl for default message handling.  Because of that, all the control processing logic has to be included, and the programmer was shielded from this processing by placing the core of that logic into WinControl::wCommand().  That processing deals with an application callback list, therefore WinCallBackList must be included.  I can see no way around that dependency.

With that out of the way, let us create the simplest DWinLib project - a blank window.  All the code we need to come up with boils down to the following units:

MainWinO unit
//MainWinO.h
#ifndef WinMainOH #define WinMainOH #include "WinBaseO.h" class WinMainO : public WinBaseO { //Static form initialization stuff public: static TCHAR * winClassNameC; static TCHAR * winCaptionC; static bool winRegClass(); //Other stuff public: WinMainO(char * cmdStr); //WinBaseO overrides public: virtual int wClose(); virtual int wEraseBackground(HDC dc); //If form does erase bkgnd return non-zero //And now for the meat of the class private: public: }; #endif
//MainWinO.cpp
#include "DWinLib.h" #include "ProgramHeaders.h" #pragma hdrstop #pragma package(smart_init) #include "WinMainO.h" //Globals for application #include "Application.h" extern Application * gApp; std::string gHelpFileFullName; WinMainO * gWinMain; //-----------------------------------------------------------------------------------------// // Static stuff first // // --------------------------------------------------------------------------------------- // TCHAR * WinMainO::winCaptionC = "Blank Window"; TCHAR * WinMainO::winClassNameC = "MainWindowClass"; bool WinMainO::winRegClass() { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = gApp->WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = gApp->hinst(); gApp->icon(LoadIcon(gApp->hinst(), "MAINICON")); wc.hIcon = gApp->icon(); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = winClassNameC; if (!RegisterClass(&wc)) return false; return true; } // --------------------------------------------------------------------------------------- // // Next, the general routines // // --------------------------------------------------------------------------------------- // WinMainO::WinMainO(char *) : WinBaseO(NULL, 100, 100, 200, 210) { gApp->setWinBeingCreated(this); hwndC = CreateWindowEx(WS_EX_CONTROLPARENT, winClassNameC, winCaptionC, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, leftC, topC, widthC, heightC, NULL, NULL, gApp->hinst(), NULL); if (!hwndC) throw AppException("Unable to create window"); gWinMain = this; ShowWindow(hwndC, SW_SHOW); } int WinMainO::wClose() { PostQuitMessage(0); return DefWindowProc(hwndC, WM_CLOSE, 0, 0); } int WinMainO::wEraseBackground(HDC dc) { RECT r; GetClientRect(hwndC, &r); HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); FillRect(dc, &r, brush); DeleteObject(brush); //Must not delete this way if 'SelectObject' is used! return 1; //As am erasing background must not return 0 }
The main project file will look like this in BCB4:
//TicTacToeProj.cpp
#include "DWinLib.h" #include "ProgramHeaders.h" #pragma hdrstop #include <condefs.h> #include "Application.h" #include "WinMainO.h" #include "WinHidden.h" USEUNIT("WinMainO.cpp"); USEUNIT("DWinLib\Application.cpp"); USEUNIT("DWinLib\WinBaseO.cpp"); USEUNIT("DWinLib\WinControl.cpp"); USEUNIT("DWinLib\WinCallBackList.cpp"); USEUNIT("DWinLib\WinDC.cpp"); USEUNIT("DWinLib\WinHidden.cpp"); //--------------------------------------------------------------------------- #pragma argsused WINAPI WinMain(HINSTANCE inst1, HINSTANCE inst2, LPSTR str, int show) { Application app(inst1, inst2, str, show); app.addRegFunc(WinHidden::winRegClass); app.addRegFunc(WinMainO::winRegClass); if (!app.init()) return 0; return app.run(); }
END OF CODE

That isn't too bad for usage.  It looks amazingly close to a pure API program.  This method gives you the full power of the API, and shields you from most of the truly painful elements of that same API.

Here is a zip file containing the blank window (72 kb, includes executable).

Now, what should we use to show the power of this method?  Let us make something up.  How about some stupid squares on a window?

All content © 2005-2010, David O'Neil