Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / ATL
Article

Simple ATL dialog based exe

Rate me:
Please Sign up or sign in to vote.
4.36/5 (12 votes)
28 Apr 20045 min read 107.8K   1.7K   36   19
How to create a simple program based on a dialog box using nothing but ATL

Introduction

Did you ever have to write a simple light dialog based exe to do simple stuff? Great then, because I can tell you how to do it in a brief, using nothing but ATL.

Background

ATL is great to develop light COM components with a minimum of dependencies, those can be contained on a DLL or an EXE, also ATL wizard has an option to create an ATL Object based on CAxDialogImpl<> template, so why not to use these options to create an standalone exe? No reason, isn't it? So, let's do it.

The recipe

  • Start a new project.
  • Select ATL COM AppWizard
  • Choose a name for your project, I'll use DlgTest
  • Click Next
  • On the Server Type, choose the "Executable (EXE)" option
  • Finish and OK. On the ClassView tab of the workspace, right click on the tree root and select from the menu "New ATL Object..." From the ATL Object Wizard window, change to the Miscellaneous category
  • No many options there, so select Dialog and then click "Next >"
  • Choose a name, I'll use MainDlg, so my class will actually be CMainDlg, and the click OK. Hung on, almost there.

Let's now create an instance of our dialog class.

Expand the Global folder on the ClassView's tree and double click on _tWinMain function, it will open the DlgTest.cpp file and show the code for that function scroll down almost to the end until you see these lines

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
  DispatchMessage(&msg);

Create an instance of the CMainDlg (remember this is the name I chose) just before the loop, and show the dialog.

CMainDlg dlg;          //Create an istance of this class
dlg.Create(NULL);        //Create the main window,
                //the NULL parameter means the desktop
                //will be the parent window
dlg.ShowWindow(SW_SHOWNORMAL); //Show it,
       //acording with the SDK, the first time a window is showed
       //the parameter should be SW_SHOWNORMAL instead of SW_SHOW
Let's not forget to add the
#include "MainDlg.h"        //the dialog's header file
at the beginning of this file.

I know, you want to taste it, ok, go a head compile it and run it. But is not ready yet...

So, it ran, it showed the dialog box with the 2 default buttons, but when you click either of them you got an assertion, told ya wasn't ready.

But is ok, so we can learn something while cooking this. What happened is, the dialog was created as a modeless using the member function Create(), but the default implementation from the wizard assumes it would be a modal one, so when the OnOK or OnCancel function are called, the default is just call EndDialog, which is not what a modeless is expecting. To fix this, let's replace the EndDialog for DestroyWindow which is the appropriated way to destroy a modeless dialog. Another little thing, this is our only window, so if it is destroyed the whole application should shutdown, so let do that also, will do it calling PostQuitMessage. Going back to our recipe.

Open the MainDlg.h file, look for
LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
 EndDialog(wID);
 return 0;
}

LRESULT OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
 EndDialog(wID);
 return 0;
}
and let's replace EndDialog by DestroyWindow and also add the PostQuitMessage, so, they should look like this
LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
 DestroyWindow();   //Destroy this window
 PostQuitMessage(0);
   //Tell's the main loop to stop and exit returning then code 0
 return 0;
}

LRESULT OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
 DestroyWindow();   //Destroy this window
 PostQuitMessage(0);   //Tell's the main loop to
     //stop and exit returning then code 0
 return 0;
}
Done. Now it should run and shutdown gracefully.

Nice, but... not very useful, ok, I know, we forgot the seasoning. Let's put some spices and see what we get.

A form window?

Yes, this dialog based application can look and feel like a form based window application, let me show how to do it.

First, let's get rid of the button. From the dialog template, delete the two buttons. But now we need another way to end the program. Let's add a menu, on the resources tree, right click and choose "Insert...", select menu and click New. Let add 4 items on the menu, &File as a top menu, then type &New, a separator and then E&xit. Open the items' properties and choose IDNEW as the id for &New and IDCLOSE for E&xit.

We'll use this clean up and to shutdown the application respectively. Go back to the dialog box template, open its properties and in the General tab select the menu id from the Menu combo box. Go to the Styles tab and change the Border to Resizing, you can also add the Minimize and Maximize boxes. Let's add also a text box, so it'll do something. Change the properties of the text box to Multiline, Vertical and Horizontal scroll and Auto HScroll and AutoVScroll. We are done with the template, let's go back to our class and add some code.

Open the class' header file, we don't need to process the IDOK and IDCANCEL handlers any more, remember we deleted the buttons, so delete these two lines from the message map section.

BEGIN_MSG_MAP(CMainDlg)
 MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
//DEL COMMAND_ID_HANDLER(IDOK, OnOK)
//DEL COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()

and also the functions definitions

//DEL LRESULT OnOK(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
//DEL {
//DEL  DestroyWindow();   //Destroy this window
//DEL  PostQuitMessage(0);   //Tell's the main loop to
//DEL          // stop and exit returning then code 0
//DEL  return 0;
//DEL }

//DEL LRESULT OnCancel(WORD wNotifyCode, 
//DEL      WORD wID, HWND hWndCtl, BOOL& bHandled)
//DEL {
//DEL  DestroyWindow();   //Destroy this window
//DEL  PostQuitMessage(0);   
//DEL //Tell's the main loop to stop and exit returning then code 0
//DEL  return 0;
//DEL }
Now we want to process the messages from the menu, so let's add the the handler on the message map section

BEGIN_MSG_MAP(CMainDlg)
 MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
 MESSAGE_HANDLER(WM_COMMAND, OnMenu)
END_MSG_MAP()

and the implementation

 LRESULT OnMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
 {
  WORD itemId = (WORD)(wParam & 0xFFFF); 
  //The low-order word specifies the identifier of the menu item, control, or 
//accelerator. 
  switch(itemId)
  {
  case IDNEW:
   //Process here the New menu item
   break;
   
  case IDCANCEL: //Process here the close window box on the Title bar
  case IDCLOSE: //Process here the Exit menu item
   {
    DestroyWindow();
    PostQuitMessage(0);
    break;
   }
  default:
   bHandled = FALSE;
  }
  return 0;
 }

Let's now clean the text box when the New menu item is selected

case IDNEW:
 {
  //Process here the New menu item
  //Let's clean up the text box

  //Get the HWND of the text box
  HWND hWnd = GetDlgItem(IDC_EDIT1);

  //Set an empty string into it
  ::SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)_T(""));
  break;
 }
Also we want to have the text box to resized when the window change its size, so let process the WM_SIZE message to.

BEGIN_MSG_MAP(CMainDlg)
 MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
 MESSAGE_HANDLER(WM_COMMAND, OnMenu)
 MESSAGE_HANDLER(WM_SIZE, OnSize)
END_MSG_MAP()

and the implementation

LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
 //Get the size of the client rect and resize the text box
 RECT rect;
 GetClientRect(&rect); //The RECT structure receives the client coordinates.
   //The left and top members are zero.
   //The right and bottom members contain the width and height of the window.

 //Get the HWND of the text box
 HWND hWnd = GetDlgItem(IDC_EDIT1);

 //Resize it
 ::MoveWindow(hWnd, 0, 0, rect.right, rect.bottom, TRUE);
 return 0;
}

And last but not least, a very tricky line. But before I tell you, just for the fun of it, compile and run it. The resize is working, and also the Exit menu is working, but is not possible to input any text to the text box.

Why? Because the message loop is not translating the virtual key for our dialog to understand the WM_KEYDOWN and the WM_KEYUP, so it is not getting the WM_CHAR.

So remember this?

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
  DispatchMessage(&msg);

ok, we have to change to this

MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
  TranslateMessage(&msg);   //TranslateMessage function translates
       //virtual-key messages into character messages.
  DispatchMessage(&msg);
}

and voilà. Now we have a little mini tiny notepad.

Points of Interest

I think the whole point here is not what the application is about, but how to put together a functional exe with minimum dependencies in a record time using only ATL. If this is not useful by itself at least I believe is a good exercise to see beyond what could be the standard use of ATL.

Note: I have done no error control what so ever, in a real application the code should have plenty of error controls, never forget that.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
f64
Web Developer
United States United States
Not a programmer, but a ChemE, self-taught basic (started with a Z80, am I that old?), qbasic, DBase, Fox, FoxPro, Pascal, Turbo Basic, Turbo Pascal, some Prolog, some Lisp, VB (since version 1.x?), SQL, HTML, and finally VC++, MFC, ATL and COM. No, I never did neither Fortran nor Cobol, thank God.

Comments and Discussions

 
GeneralSome comments Pin
peterchen7-May-10 3:53
peterchen7-May-10 3:53 
GeneralRe: Some comments Pin
ehaerim4-Sep-10 12:11
ehaerim4-Sep-10 12:11 
Questionhow to add TranslateMessage in CAxDialogImpl based dialog? Pin
joyjjjz17-Feb-09 0:44
joyjjjz17-Feb-09 0:44 
GeneralSystem Tray Menu not working Pin
navinkaus22-Jul-07 18:30
navinkaus22-Jul-07 18:30 
GeneralRe: System Tray Menu not working Pin
f6426-Jul-07 9:47
f6426-Jul-07 9:47 
GeneralRe: System Tray Menu not working Pin
ehaerim14-Feb-10 23:16
ehaerim14-Feb-10 23:16 
General_tWinMain Pin
Freudi_t26-Feb-07 22:25
Freudi_t26-Feb-07 22:25 
GeneralRe: _tWinMain Pin
f6428-Feb-07 9:21
f6428-Feb-07 9:21 
QuestionRe: _tWinMain Pin
Freudi_t28-Feb-07 22:10
Freudi_t28-Feb-07 22:10 
Questionhow to add toolbar? Pin
ckwat19-Oct-06 1:56
ckwat19-Oct-06 1:56 
GeneralTab does not work. Pin
mail4johnv19-Jul-06 20:11
mail4johnv19-Jul-06 20:11 
GeneralDialog cannot be created if the dialog contans some control types Pin
platohe17-Mar-06 9:28
platohe17-Mar-06 9:28 
GeneralRe: Dialog cannot be created if the dialog contans some control types Pin
f6417-Mar-06 9:41
f6417-Mar-06 9:41 
GeneralRe: Dialog cannot be created if the dialog contans some control types Pin
Michael Dunn17-Mar-06 11:23
sitebuilderMichael Dunn17-Mar-06 11:23 
GeneralRe: Dialog cannot be created if the dialog contans some control types Pin
platohe20-Mar-06 3:52
platohe20-Mar-06 3:52 
Generalgood article and... Pin
dSolariuM11-Dec-04 19:16
dSolariuM11-Dec-04 19:16 
GeneralRe: good article and... Pin
f6414-Dec-04 9:53
f6414-Dec-04 9:53 
GeneralWTL Pin
Gilad Novik29-Apr-04 2:21
Gilad Novik29-Apr-04 2:21 
GeneralRe: WTL Pin
MyBlindy6-May-04 15:46
MyBlindy6-May-04 15:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.