_C PROGRAMMING COLUMN_ by Al Stevens Listing One // ------ dfwrap.h #ifndef DFWRAP_H #define DFWRAP_H typedef int bool; const int true = 1; const int false = 0; #include extern "C" { #include "dflat.h" } #include "dfrect.h" #include "dfwnd.h" #include "dfappl.h" #include "dfdial.h" #endif Listing Two // -------- dfrect.h #ifndef DFRECT_H #define DFRECT_H class Rect { RECT m_rect; public: Rect(RECT rc) : m_rect(rc) { /* ... */ } Rect(int x=0, int y=0, int ht=1, int wd=1) { m_rect.lf = x; m_rect.tp = y; m_rect.rt = x+wd-1; m_rect.bt = y+ht-1; } operator RECT() { return m_rect; } int Left() const { return m_rect.lf; } int Top() const { return m_rect.tp; } int Height() const { return m_rect.bt - m_rect.tp + 1; } int Width() const { return m_rect.rt - m_rect.lf + 1; } int Right() const { return m_rect.rt; } int Bottom() const { return m_rect.bt; } int Area() const { return Height() * Width(); } }; #endif Listing Three // ------- dfwnd.h #ifndef DFWND_H #define DFWND_H #include // ------------------------------------------------------------- #define MAPDEF(base) \ virtual bool DispatchDFMessage(MESSAGE msg); \ bool DispatchBaseDFMessage(MESSAGE msg) \ { \ MESSAGE sm=m_msg;PARAM s1=p1,s2=p2; \ bool rtn = base::DispatchDFMessage(msg); \ if (rtn&&msg==CLOSE_WINDOW)m_Wnd=0; \ m_msg=sm;p1=s1;p2=s2; \ return rtn; \ } // ------------------------------------------------------------- #define MSGMAP(ap) \ bool ap::DispatchDFMessage(MESSAGE msg) \ {MESSAGE sm=m_msg;PARAM s1=p1,s2=p2;bool rtn=true;switch(msg){ // ------------------------------------------------------------- #define MSG(id,fn) case id:rtn=fn();break; // ------------------------------------------------------------- #define ENDMAP default:break;} \ m_msg=sm;p1=s1;p2=s2; \ return rtn?DispatchBaseDFMessage(msg):false; \ } // ------------------------------------------------------------- class dfWindow { protected: static dfWindow *mp_cwindow; WINDOW m_Wnd; MESSAGE m_msg; PARAM p1, p2; dfWindow(); dfWindow(CLASS cl, const string& ttl, const Rect& rc = Rect(0,0,-1,-1), void *ext = 0, int attrib = 0); void CommonConstructor(); virtual ~dfWindow() { } static bool mf_WndProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2); virtual bool DispatchDFMessage(MESSAGE) { return DefaultWndProc(m_Wnd, m_msg, p1, p2); } public: void Show() { SendMessage(SHOW_WINDOW);} void Hide() { SendMessage(HIDE_WINDOW); } void CloseWindow() { SendMessage(CLOSE_WINDOW); } void Paint() { SendMessage(PAINT); } void Move(int x, int y) { SendMessage(MOVE, x, y); } void Size(int h, int w) { SendMessage(SIZE, GetTop(m_Wnd)+h-1, GetRight(m_Wnd)+w-1); } bool isAttributeSet(int attrib) { return TestAttribute(m_Wnd, attrib); } void SetAttribute(int attrib) { AddAttribute(m_Wnd, attrib); } void ResetAttribute(int attrib) { ClearAttribute(m_Wnd, attrib); } int SendMessage(MESSAGE msg, PARAM p1 = 0, PARAM p2 = 0) { return ::SendMessage(m_Wnd, msg, p1, p2); } void PostMessage(MESSAGE msg, PARAM p1 = 0, PARAM p2 = 0) { ::PostMessage(m_Wnd, msg, p1, p2); } int SendCommand(PARAM cmd, PARAM p2 = 0) { return ::SendMessage(m_Wnd, COMMAND, cmd, p2); } void PostCommand(PARAM cmd, PARAM p2 = 0) { ::PostMessage(m_Wnd, COMMAND, cmd, p2); } int Top() { return GetTop(m_Wnd); } int Bottom() { return GetBottom(m_Wnd); } int Left() { return GetLeft(m_Wnd); } int Right() { return GetRight(m_Wnd); } int Height() { return WindowHeight(m_Wnd); } int Width() { return WindowWidth(m_Wnd); } int ClientTop() { return GetClientTop(m_Wnd); } int ClientBottom() { return GetClientBottom(m_Wnd); } int ClientLeft() { return GetClientLeft(m_Wnd); } int ClientRight() { return GetClientRight(m_Wnd); } int ClHeight() { return ClientHeight(m_Wnd); } int ClWidth() { return ClientWidth(m_Wnd); } #ifdef INCLUDE_MINIMIZE void Minimize() { SendMessage(MINIMIZE); } bool isMinimized() { return m_Wnd->condition == ISMINIMIZED; } #endif #ifdef INCLUDE_MAXIMIZE void Maximize() { SendMessage(MAXIMIZE); } bool isMaximized() { return m_Wnd->condition == ISMAXIMIZED; } #endif #ifdef INCLUDE_RESTORE void Restore() { SendMessage(RESTORE); } bool isRestored() { return m_Wnd->condition == ISRESTORED; } Rect RestoredRect() { return m_Wnd->RestoredRC; } void SetRestoredRect(Rect rc) { m_Wnd->RestoredRC = rc; } #endif Rect WndRectangle() { return WindowRect(m_Wnd); } void SetWndRectangle(Rect rc); void SetWndCondition(Condition cnd) { m_Wnd->condition = cnd; } Rect ClientRectangle() { return Rect(ClientLeft(), ClientTop(), ClHeight(), ClWidth()); } void SetForeground(char fg) { WndForeground(m_Wnd) = fg; } void SetBackground(char bg) { WndBackground(m_Wnd) = bg; } void ShowCursor() { ::SendMessage(0, SHOW_CURSOR, 0, 0); } void HideCursor() { ::SendMessage(0, HIDE_CURSOR, 0, 0); } void SetCursor() { cursor(ClientLeft()+Column(), ClientTop()+Row()); } void CursorHome() { m_Wnd->CurrCol = 0; SetCursor(); } void CursorUp(int ct = 1); void CursorDown(int ct = 1); void CursorRight(int ct = 1); void CursorLeft(int ct = 1); void WriteChar(int ch); int Row() { return m_Wnd->WndRow; } int Column() { return m_Wnd->CurrCol; } void SetRow(int y) { m_Wnd->WndRow = y; } void SetColumn(int x) { m_Wnd->CurrCol = x; } void PositionCursor(int x, int y); void ScrollUp() { scroll_window(m_Wnd, ClientRectangle(), TRUE); } void ClearScreen(); void ClearToEOL(); void SetFocus() { SendMessage(SETFOCUS, true); } void SetRestoredAttrib(int attr) { m_Wnd->restored_attrib = attr; } int GetRestoredAttrib() const { return m_Wnd->restored_attrib; } }; #endif Listing Four // ---------- dfwnd.cpp #include "dfwrap.h" dfWindow *dfWindow::mp_cwindow; void dfWindow::CommonConstructor() { m_Wnd = 0; p1 = 0; p2 = 0; } dfWindow::dfWindow() { CommonConstructor(); } dfWindow::dfWindow(CLASS cl, const string& ttl, const Rect& rc, void *ext, int attrib) { CommonConstructor(); if (cl == APPLICATION) init_messages(); mp_cwindow = this; CreateWindow(cl,ttl.c_str(), rc.Left(),rc.Top(),rc.Height(),rc.Width(), ext,0,&dfWindow::mf_WndProc,attrib); assert(m_Wnd != 0); } bool dfWindow::mf_WndProc(WINDOW wnd, MESSAGE msg, PARAM pr1, PARAM pr2) { bool rtn = false; dfWindow *This; if (wnd->wrapper == 0) { assert(mp_cwindow != 0); wnd->wrapper = mp_cwindow; mp_cwindow->m_Wnd = wnd; mp_cwindow = 0; } This = (dfWindow*)(wnd->wrapper); This->p1 = pr1; This->p2 = pr2; This->m_msg = msg; if (msg == COMMAND && (pr2 == 0 || pr2 == LB_CHOOSE || pr2 ==LB_SELECTION)) rtn = This->DispatchDFMessage((MESSAGE)pr1); else rtn = This->DispatchDFMessage(msg); // --- done again because of reentrant calls This->p1 = pr1; This->p2 = pr2; This->m_msg = msg; if (rtn && msg == CLOSE_WINDOW) This->m_Wnd = 0; return rtn; } void dfWindow::SetWndRectangle(Rect rc) { m_Wnd->rc = rc; m_Wnd->ht = rc.Height(); m_Wnd->wd = rc.Width(); } void dfWindow::WriteChar(int ch) { SetStandardColor(m_Wnd); PutWindowChar(m_Wnd, ch, m_Wnd->CurrCol, m_Wnd->WndRow); } void dfWindow::PositionCursor(int x, int y) { SetColumn(x); SetRow(y); SetCursor(); } void dfWindow::CursorUp(int ct) { while (ct-- && m_Wnd->WndRow) { m_Wnd->WndRow--; SetCursor(); } } void dfWindow::CursorDown(int ct) { while (ct-- && m_Wnd->WndRow < ClHeight()) { m_Wnd->WndRow++; SetCursor(); } } void dfWindow::CursorRight(int ct) { while (ct-- && m_Wnd->CurrCol < ClWidth()) { m_Wnd->CurrCol++; SetCursor(); } } void dfWindow::CursorLeft(int ct) { while (ct-- && m_Wnd->CurrCol) { m_Wnd->CurrCol--; SetCursor(); } } void dfWindow::ClearScreen() { SendMessage(CLEARTEXT); Paint(); PositionCursor(0, 0); } void dfWindow::ClearToEOL() { int col = m_Wnd->CurrCol; SetStandardColor(m_Wnd); while (col < ClWidth()) PutWindowChar(m_Wnd, ' ', col++, m_Wnd->WndRow); } Listing Five // --------- dfappl.h #ifndef DFAPPL_H #define DFAPPL_H #include class dfApplication : public dfWindow { int m_currx, m_curry; MBAR& menu; protected: MAPDEF(dfWindow) virtual bool LoadConfig() { return ::LoadConfig(); } virtual void SaveConfig() { ::SaveConfig(); } bool OnOpen(); bool OnClose(); public: dfApplication(const string& ttl, MBAR& mnu, const Rect& rc = Rect(0,0,-1,-1)); virtual ~dfApplication(); void Run(); void WriteStatus(const string& tx); void ClearStatus(); bool GetCommandToggle(commands id) { return (bool) ::GetCommandToggle(&menu, id); } void SetCommandToggle(commands id) { ::SetCommandToggle(&menu, id); } void ClearCommandToggle(commands id) { ::ClearCommandToggle(&menu, id); } }; #endif Listing Six // ------- dfappl.cpp #include "dfwrap.h" MSGMAP(dfApplication) MSG(OPEN_WINDOW, OnOpen) MSG(CLOSE_WINDOW, OnClose) ENDMAP dfApplication::dfApplication(const string& ttl, MBAR& mnu, const Rect& rc) : dfWindow(APPLICATION, ttl, rc, &mnu, HASSTATUSBAR), menu(mnu) { curr_cursor(&m_currx, &m_curry); LoadHelpFile(DFlatApplication); ResetAttribute(CONTROLBOX); m_Wnd->condition = ISMAXIMIZED; } dfApplication::~dfApplication() { cursor(m_currx, m_curry); } bool dfApplication::OnOpen() { if (!LoadConfig()) cfg.ScreenLines = SCREENHEIGHT; return true; } bool dfApplication::OnClose() { DispatchBaseDFMessage(CLOSE_WINDOW); SaveConfig(); return false; } void dfApplication::Run() { SendMessage(SETFOCUS, TRUE, 0); while (dispatch_message()) ; } void dfApplication::WriteStatus(const string& tx) { ::SendMessage(m_Wnd->StatusBar, SETTEXT, (PARAM) tx.c_str(), 0); ::SendMessage(m_Wnd->StatusBar, PAINT, 0, 0); } void dfApplication::ClearStatus() { ::SendMessage(m_Wnd->StatusBar, CLEARTEXT, 0, 0); ::SendMessage(m_Wnd->StatusBar, PAINT, 0, 0); } Listing Seven // ---------- dfdial.h #ifndef DFDIAL_H #define DFDIAL_H #include #include "icmds.h" class dfDialog : public dfWindow { DBOX m_dbox; bool OnClose(); bool OnSize(); bool OnMove(); bool OnLBChoose(); protected: MAPDEF(dfWindow) bool KeepLBSelectionInView(cmds id); bool m_isrunning; public: dfDialog(DBOX& db) : m_dbox(db), m_isrunning(false) { } virtual ~dfDialog() { } bool doModal(); void doModeless(); bool isRunning() const { return m_isrunning; } void SetTitle(const char *title); void SetControlFocus(cmds id); void SetControlText(cmds id, const char *t, CLASS cl = (CLASS)-1); const char *GetControlText(cmds id, CLASS cl = (CLASS)-1); int SendCtlMessage(cmds id, MESSAGE msg, PARAM pr1=0, PARAM pr2=0); void SetWindowText(cmds id, const char *t) { SendCtlMessage(id, SETTEXT, (PARAM) t); } char *GetWindowText(cmds id) const; void AddWindowText(cmds id, const char *t) { SendCtlMessage(id, ADDTEXT, (PARAM) t); } bool TextChanged(cmds id); void ClearWindowText(cmds id) { SendCtlMessage(id, CLEARTEXT); } int GetLineCount(cmds id); int GetLBSelection(cmds id) { return SendCtlMessage(id, LB_CURRENTSELECTION); } void SetLBSelection(cmds id, int sel) { SendCtlMessage(id, LB_SETSELECTION, sel); } void GetLBTextLine(cmds id, int lno, char *t) { SendCtlMessage(id, LB_GETTEXT, (PARAM) t, lno); } void GetSelectedLBText(cmds id, char *t); int DeleteSelectedLBLine(cmds id, char *prompt = 0); void InsertTextLine(cmds id, int lno, char *t) { SendCtlMessage(id, INSERTTEXT, (PARAM) t, lno); } void DeleteTextLine(cmds id, int lno) { SendCtlMessage(id, DELETETEXT, lno); } void PaintControl(cmds id) { SendCtlMessage(id, PAINT); } void MoveControl(cmds id, int x, int y); void SizeControl(cmds id, int h, int w); void SetControlOn(cmds id); void SetControlOff(cmds id); bool GetControlSetting(cmds id); void EnableCommandButton(cmds id) { EnableButton(&m_dbox, (commands) id); } void DisableCommandButton(cmds id) { DisableButton(&m_dbox, (commands) id); } void SetProtection(cmds id); void SetControlWindowAttribute(cmds id, int attrib); void ResetControlWindowAttribute(cmds id, int attrib); bool isEmpty(cmds id) const; const DBOX& DBox() const { return m_dbox; } void DialogTextCopy(char *s1, cmds id, int len); }; class DialogConfig { bool max; // true if DB was maximized Rect rc; // DB position, size Rect rrc; // DB restored configuration Rect ctls[MAXCONTROLS]; // control positions, sizes int restattrib; // restored attribute public: DialogConfig() : max(false) { } void SaveDialog(dfDialog& db); void RestoreDialog(dfDialog& db); }; #endif Listing Eight // ----- dfdial.cpp #include "dfwrap.h" MSGMAP(dfDialog) MSG(LB_CHOOSE, OnLBChoose) MSG(SIZE, OnSize) MSG(MOVE, OnMove) MSG(CLOSE_WINDOW, OnClose) ENDMAP bool dfDialog::OnLBChoose() { PostCommand(ID_OK); return true; } bool dfDialog::OnClose() { m_isrunning = false; return true; } bool dfDialog::doModal() { mp_cwindow = this; m_isrunning = true; return DialogBox(0, &m_dbox, TRUE, mf_WndProc); } void dfDialog::doModeless() { mp_cwindow = this; m_isrunning = true; DialogBox(0, &m_dbox, FALSE, mf_WndProc); } void dfDialog::SetTitle(const char *title) { m_dbox.dwnd.title = (char *) title; if (m_isrunning) SendMessage(BORDER); } bool dfDialog::OnMove() { m_dbox.dwnd.x = (int) p1; m_dbox.dwnd.y = (int) p2; return true; } bool dfDialog::OnSize() { m_dbox.dwnd.x = Left(); m_dbox.dwnd.y = Top(); m_dbox.dwnd.w = p1-Left()+1; m_dbox.dwnd.h = p2-Top()+1; return true; } void dfDialog::SetControlText(cmds id, const char *t, CLASS cl) { SetDlgTextString(&m_dbox, (commands) id, (char*) t, cl); } const char* dfDialog::GetControlText(cmds id, CLASS cl) { return GetDlgTextString(&m_dbox, (commands) id, cl); } void dfDialog::SetControlFocus(cmds id) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) ::SendMessage(cwnd, SETFOCUS, TRUE, 0); } int dfDialog::SendCtlMessage(cmds id, MESSAGE msg, PARAM pr1, PARAM pr2) { int rtn = -1; WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) { MESSAGE svmsg = m_msg; PARAM svp1 = p1; PARAM svp2 = p2; rtn = ::SendMessage(cwnd, msg, pr1, pr2); p1 = svp1; p2 = svp2; m_msg = svmsg; } return rtn; } char* dfDialog::GetWindowText(cmds id) const { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) return GetText(cwnd); return 0; } bool dfDialog::TextChanged(cmds id) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) return (bool) (cwnd->TextChanged); return false; } int dfDialog::GetLineCount(cmds id) { int ct = 0; WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) ct = GetTextLines(cwnd); return ct; } void dfDialog::GetSelectedLBText(cmds id, char *t) { int sel = GetLBSelection(id); if (sel != -1) GetLBTextLine(id, sel, t); else *t = '\0'; } int dfDialog::DeleteSelectedLBLine(cmds id, char *prompt) { int count = GetLineCount(id); if (count > 0) { int sel = GetLBSelection(id); if (sel != -1) { if (prompt == 0 || YesNoBox(prompt)) { DeleteTextLine(id, sel); if (sel == count-1) SetLBSelection(id, sel-1); KeepLBSelectionInView(id); PaintControl(id); SetControlFocus(id); return sel; } } } return -1; } void dfDialog::MoveControl(cmds id, int x, int y) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) { int oldx = FindCommand(&m_dbox, (commands) id, -1)->dwnd.x; int oldy = FindCommand(&m_dbox, (commands) id, -1)->dwnd.y; x = x == -1 ? oldx : x; y = y == -1 ? oldy : y; int difx = x - oldx; int dify = y - oldy; if (difx || dify) { FindCommand(&m_dbox, (commands) id, -1)->dwnd.x = x; FindCommand(&m_dbox, (commands) id, -1)->dwnd.y = y; SendCtlMessage(id, MOVE, GetLeft(cwnd)+difx, GetTop(cwnd)+dify); } } } void dfDialog::SizeControl(cmds id, int h, int w) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) { FindCommand(&m_dbox, (commands) id, -1)->dwnd.h = h; FindCommand(&m_dbox, (commands) id, -1)->dwnd.w = w; SendCtlMessage(id, SIZE, GetLeft(cwnd)+w-1, GetTop(cwnd)+h-1); } } void dfDialog::SetControlOn(cmds id) { CTLWINDOW *ct = FindCommand(&m_dbox, (commands) id, RADIOBUTTON); if (ct != 0) PushRadioButton(&m_dbox, (commands) id); else SetCheckBox(&m_dbox, (commands) id); PaintControl(id); } void dfDialog::SetControlOff(cmds id) { ClearCheckBox(&m_dbox, (commands) id); PaintControl(id); } bool dfDialog::GetControlSetting(cmds id) { CTLWINDOW *ct = FindCommand(&m_dbox, (commands) id, RADIOBUTTON); if (ct != 0) return RadioButtonSetting(&m_dbox, (commands) id); return CheckBoxSetting(&m_dbox, (commands) id); } void dfDialog::SetProtection(cmds id) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) SetProtected(cwnd); } bool dfDialog::KeepLBSelectionInView(cmds id) { bool rtn = false; int sel = SendCtlMessage(id, LB_CURRENTSELECTION); if (sel != -1) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); int top = cwnd->wtop; int ht = ClientHeight(cwnd) - 1; int bottom = top + ht; if ((rtn = (sel < top)) == true) cwnd->wtop = sel; else if ((rtn = (sel > bottom)) == true) cwnd->wtop = sel - ht; } return rtn; } void dfDialog::SetControlWindowAttribute(cmds id, int attrib) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) AddAttribute(cwnd, attrib); } void dfDialog::ResetControlWindowAttribute(cmds id, int attrib) { WINDOW cwnd = ControlWindow(&m_dbox, (commands) id); if (cwnd != 0) ClearAttribute(cwnd, attrib); } bool dfDialog::isEmpty(cmds id) const { const char *p_txt = GetWindowText(id); if (p_txt) while (*p_txt) { if (*p_txt != ' ' && *p_txt != '\n') return false; p_txt++; } return true; } void dfDialog::DialogTextCopy(char *s1, cmds id, int len) { const char *s2 = GetWindowText(id); if (s1 != 0 && s2 != 0) while (*s2 && *s2 != '\n' && --len) *s1++ = *s2++; *s1 = '\0'; } void DialogConfig::RestoreDialog(dfDialog& db) { if (rc.Width() > 1) { db.SetWndRectangle(rc); db.SetRestoredRect(rrc); db.SetRestoredAttrib(restattrib); DBOX& dbox = const_cast(db.DBox()); dbox.dwnd.x = rc.Left(); dbox.dwnd.y = rc.Top(); dbox.dwnd.h = rc.Height(); dbox.dwnd.w = rc.Width(); if (max) // --- DB was maximized when last used db.SetWndCondition(ISMAXIMIZED); for (int i = 0; i < MAXCONTROLS; i++) { dbox.ctl[i].dwnd.x = ctls[i].Left(); dbox.ctl[i].dwnd.y = ctls[i].Top(); dbox.ctl[i].dwnd.h = ctls[i].Height(); dbox.ctl[i].dwnd.w = ctls[i].Width(); } } } void DialogConfig::SaveDialog(dfDialog& db) { rc = db.WndRectangle(); rrc = db.RestoredRect(); max = db.isMaximized(); restattrib = db.GetRestoredAttrib(); for (int i = 0; i < MAXCONTROLS; i++) { const DIALOGWINDOW& dwnd = db.DBox().ctl[i].dwnd; ctls[i] = Rect(dwnd.x, dwnd.y, dwnd.h, dwnd.w); } } Example 1: (a) class MailAppl : public dfApplication { bool OnFile(); // menu command bool OnClose(); // " " protected: MAPDEF(dfApplication) public: MailAppl(); virtual ~MailAppl(); }; (b) MSGMAP(MailAppl) MSG(ID_FILE, OnAbout) MSG(CLOSE_WINDOW, OnClose) ENDMAP (c) bool MailAppl::OnFile() { // ... return false; } Example 2: (a) MailAppl *mailappl; int main() { mailappl = new MailAppl; mailappl->Run(); delete mailappl; return 0; } (b) extern DBOX AddrBookDB; class AddrBook : public dfDialog { bool OnOK(); protected: MAPDEF(dfDialog) public: AddrBook() : dfDialog(AddrBookDB) { } }; Example 3: (a) DIALOGBOX( AddrBookDB ) DB_TITLE( "Address Book", -1, -1, 15, 60 ) CONTROL(TEXT, "~Addresses:", 1, 0, 1,10, ID_ADDRESS) CONTROL(LISTBOX, NULL, 1, 1,12,45, ID_ADDRESS) CONTROL(BUTTON, " ~Select ", 48, 1, 1, 8, ID_OK) ENDDB MSGMAP(AddrBook) MSG(ID_ADDRESS, OnAddress) MSG(ID_OK, OnOK) ENDMAP bool AddrBook::OnAddress() { // ... return true; } bool AddrBook::OnOK() { // ... return new; } (b) AddrBook *p_addrbook = new AddrBook; p_addrbook->doModal(); // or doModeless() delete p_addrbook;