Listing 5: Implementation of a dynamic dialog box

// a pseudo SimpleDB class that handles dialog box creation
const int ROW_HEIGHT=20;
class DlgDB : public SimpleDB {
   HWND parent;
   int row;
   map<string, HWND> wndMap;
public:
   DlgDB(HWND parentDlg) : parent(parentDlg), row(0) {}
   // this function will create the controls and set 
   // them to the values in the param block
   virtual void Write(const char *section, const char *key, 
                      const char *valStr) {
      CreateWindow("STATIC", key, WS_VISIBLE|WS_CHILD, 10, 
         ROW_HEIGHT*row, 300, ROW_HEIGHT-4,parent, 0, 0, 0);
      wndMap[key] = CreateWindow("EDIT", valStr, 
         WS_VISIBLE|WS_CHILD|WS_BORDER, 310, ROW_HEIGHT*row,
         200, ROW_HEIGHT-4, parent, 0, 0, 0);
      row++;
   }
   // this function will read back the values in the controls
   virtual void Read(const char *section, const char *key, 
                     char *valStr, int maxBufLen) {
      HWND editWnd = wndMap[key];
      if (editWnd)
         GetWindowText(editWnd, valStr, maxBufLen);
   }
};

// DialogProc that handles the dynamic dialog
BOOL CALLBACK MyDlgProc(HWND hwndDlg, UINT uMsg, 
                        WPARAM wParam, LPARAM lParam) {
   IOParamBlock *paramBlock;
   DlgDB *dlgDB;
   typedef pair<DlgDB*,IOParamBlock*> DlgProcCBRef;
   DlgProcCBRef *callBackRef;
   switch (uMsg)
   {
      case WM_INITDIALOG:   {
         paramBlock = (IOParamBlock *)lParam;
         int numWnds = paramBlock->ioVars.size();
         SetWindowText(hwndDlg, "DynBox");
         SetWindowPos(hwndDlg,NULL,0,0,500,
            (numWnds+4)*ROW_HEIGHT,SWP_NOZORDER);
         dlgDB = new DlgDB(hwndDlg);
         // create Ok button and store pointer to DlgDB and
         // IOParamBlock in the user data of the OK button
         HWND okWnd = CreateWindow("BUTTON", "Ok", 
            WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 10, 
         ROW_HEIGHT*numWnds+ROW_HEIGHT, 60, 20, 
            hwndDlg, (HMENU)IDOK, 0, 0);
         callBackRef = new DlgProcCBRef(dlgDB,paramBlock);
         SetWindowLong(okWnd, GWL_USERDATA, (long)callBackRef);
         CreateWindow("BUTTON", "Cancel", 
            WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON, 100, 
            ROW_HEIGHT*numWnds+ROW_HEIGHT,
            60, 20, hwndDlg, (HMENU)IDCANCEL, 0, 0);
         paramBlock->WriteAll(*dlgDB, "dummy");
         return 1;
         }
         break;
      case WM_CLOSE:
         EndDialog(hwndDlg, 0);
         break;
      case WM_COMMAND:
         switch (LOWORD(wParam)) {
            case IDOK:
               callBackRef= (DlgProcCBRef*)GetWindowLong (
                   (HWND)lParam, GWL_USERDATA);
               dlgDB      = callBackRef->first;
               paramBlock = callBackRef->second;
               paramBlock->ReadAll(*dlgDB, "dummy");
            case IDCANCEL:
               EndDialog(hwndDlg, LOWORD(wParam));
               break;
         }
         break;
   }
   return 0;
}
 
class TestBlock : public IOParamBlock , public Subject
{
public:
   DECL_NAMED_VAL(int, autoInt);
   DECL_NAMED_VAL(double, autoFloat);
   TestBlock() : 
      CONSTRUCT_AUTOIO_VAL(autoInt, 22),
      CONSTRUCT_AUTOIO_VAL(autoFloat, 1122.33) {}
};

TestBlock tstBlock;

class DummyObserver : public Observer {
public:
   void Update(Subject *subject) {
      MessageBox(NULL, "TestBlock changed!!", "Obs.", MB_OK); }
};

void Test() {
   char *dlgTmpl = new char [sizeof DLGTEMPLATE + 6];
   DLGTEMPLATE *header = (DLGTEMPLATE *)dlgTmpl;
   memset(header,0,sizeof DLGTEMPLATE+6);
   header->style = WS_SYSMENU|WS_CAPTION|WS_VISIBLE;
   DummyObserver dummy;
   tstBlock.Attach(&dummy);
   int dlgRet = DialogBoxIndirectParam(NULL, header, m_hWnd, 
          MyDlgProc, (LPARAM)(IOParamBlock*)&tstBlock);
   if (dlgRet == IDOK)  
      tstBlock.Notify(); // notify observers, tstBlock changed
   tstBlock.Detach(&dummy);
   delete [] dlgTmpl;
}