January 1998
Download Ccode.exe (23KB)
Paul DiLascia is the author of Windows ++: Writing Reusable Code in C++ (Addison-Wesley, 1992) and a freelance consultant and
writer-at-large. He can be reached at askpd@pobox.com
or http://pobox.com/~askpd.
|
Q I am writing an MFC app that is not a doc/view app. To implement the app with MFC, I used a document object that doesn't do anything. It all seems to work fine, but whatever I do, MFC gives my app a title like "untitledDataWiz" (DataWiz is the name of my app). How can I get rid of the "untitled" part so only the name of my app appears?
Chad Frawkin
A Easy. All you have to do is turn off the flag FWS_ADDTOTITLE in your main frame window. The best place to do this is in your frame's PreCreateWindow function. |
|
Normally, MFC turns this flag on in CDocTemplate::CreateNewFrame, where MFC creates the frame. |
|
If FWS_ADDTOTITLE is set, CFrameWnd::OnUpdateFrameTitle combines the name of the current document with the name of the app, which it gets from the resource string, whose ID is IDR_MAINFRAME or whatever ID you use for your document template. OnUpdateFrameTitle adds the title to the document name, as in "DataWizuntitled"; FWS_PREFIXTITLE shows the doc name first, as in "untitledDataWiz". By default, MFC sets FWS_PREFIXTITLE if FWS_ADDTOTITLE is set and the program is running in Windows® 95 or Windows NT® 4.0. |
|
By turning the FWS_ADDTOTITLE style off, you turn off this behavior. It's important to turn off the flag before you call CFrameWnd::PreCreateWindow. If you want to turn the flag on or off after the frame is created, you can use ModifyStyle. |
|
You may wonder if there are other FWS styles. There's only one: FWS_SNAPTOBARS. This style controls the sizing of the frame that encloses a floating control bar. FWS_SNAPTOBARS makes the frame fit the control bar, something you'd never use in a normal frame window unless you want a very tiny frame with no client area. MFC uses FWS_SNAPTOBARS in CMiniDockFrameWnd, which is the miniframe that encloses a floating control bar. You might use FWS_SNAPTOBARS if you're implementing your own custom floating-style control bars.
Q I'm using the Windows 95 File Open and File Save common dialogs in my program, but since I'm using them for things other than opening and saving files (like creating, compacting, and repairing a database), I would like to replace the caption of the IDOK button. First I tried to use templates, but for some reason I couldn't manage to do it; my program kept crashing. So I thought I could get a CMyFileDialog class and use OnInitialUpdate to get the IDOK button and replace its caption. But whenever I try to get the button, MFC returns NULL. This is the last pesky detail left on a huge six-month project. What should I do? Rui Santos
Portugal A You had the right idea, but things are a little different with the new common file dialogs, which have evolved to new levels of sophistication and confusionin Windows 95. But first, a quick historical perspective. Back in the old days, you had to write your own dialogs for opening and closing files using a strange Windows API function called DlgDirList that populated a listbox with file names. Ten thousand sixty-two programmers all wrote their own File Open dialogs using DlgDirList. Then someone in Redmond had a brilliant idea: since almost every app has to open and save files, why not incorporate the open and save dialogs in a DLLaka subroutineeveryone could use? They must have been taking their smart pills! Programmers around the planet celebrated when COMMDLG.DLL came out, and we all rushed to use it in our apps. The COMMDLG functions that do dialogs are GetOpenFileName and GetSaveFileName. Both require an OPENFILENAME structure, which contains an intimidating array of parameters for controlling the dialog. You can specify style flags, filters, and your own title, among other things. You can even specify your own hook procedure in lpfnHook. MFC encapsulates all this in a class called CFileDialog. Somewhere in the bowels of CWinApp (actually, it's in CDocManager), MFC creates a CFileDialog to handle the Open and Save As commands, but you can create an open or save dialog anywhere in your program. |
|
If you want the save dialog, create with FALSE instead of TRUE. The constructor has several other optional parameters with reasonable defaults you can override. For example, if you want a Read Only checkbox in your dialog, you can write: |
|
The last zero replaces the MFC default flag OFN_HIDEREADONLY, which hides the checkbox. In any case, after DoModal returns, you can call any number of functions like dlg.GetPathName to get the name of the file the user chose.
All this should be very simple, straightforward, and familiar. But behind the scenes, MFC does a lot of legwork to make CFileDialog look like any other MFC-style dialog object. In particular, it sets OPENFILENAME::lpfnHook to subclass the dialog in MFC's standard way, so all messages go through MFC's message map mechanism. So you can write ON_COMMAND handlers to handle button clicks or message handlers for messages like WM_SETFOCUS or WM_ ACTIVATE. If you want to change the name of one or more controls in a file dialogor any dialog, for that matterthe simplest thing to do is override the virtual function OnInitDialog. OnInitDialog is different from other message handlers in that it's a virtual function. You don't need a message map entry for WM_INITDIALOG; all you have to do is override OnInitDialog. |
|
It looks perfectly sanebut if you try
it in Windows 95 or Windows NT 4.0,
it won't work! With Windows 95 and Windows NT 4.0, the situation is completely different.
|
Figure 2 Old-style versus Explorer-style Dialog |
So if you try to set the text of a child button with SetDlgItemText(IDOK), it fails because the child dialog has no OK buttonor indeed any controls at all. If you call GetDlgItem(IDOK) from within CMyDialog, Windows/MFC returns NULL. Instead, you have to write this: |
|
This works fine, but the official way to do it is to use a new function designed for just this purpose: CFileDialog::SetControlText. |
|
CFileDialog::SetControlText sends the Explorer dialog (the parent of the CFileDialog) a special common dialog message: CDM_SETCONTROLTEXT. The dialog handles this message by setting the text of the corresponding item. There are other CDM_XXX messages and notifications as well; Figure 3 gives the complete list. MFC encapsulates all this nicely with wrappers that send the messages to the parent dialog and virtual functions you can override to handle notifications. Notice I said virtual; to handle the common dialog notifications, you don't have to add anything to your message mapjust write the function. All message handlers should work this way, but that's another story. |
Figure 4 Old Open Dialog |
Figure 5 New Open Dialog |
I wrote a program, OpenDlg, that shows how to change the names of control buttons in both the old (see Figure 4) and new (see Figure 5) Open dialogs. MFC lets you control which dialog it displays by setting the flag OFN_EXPLORER in OPENFILENAME::Flags. By default, MFC sets this flag if you're running Windows 95 or Windows NT 4.0. |
|
|
|
Now Windows uses the dialog resource IDD_MYOPENDLG for the child dialog. Any controls you define are true children of the child dialog (CMyOpenDlg), not the Explorer dialog, so you can handle notifications from your template controls the normal wayby adding message and ON_COMMAND handlers to your dialog class. Thus, CMyOpenDlg handles the Press me! button with an ON_COMMAND(ID_PRESS_ME) entry in its message map. Figure 9 shows a Spy++ screen with OpenDlg running and the child dialog highlighted. You can see the Explorer dialog with my custom title, "Like, pick a file, dude," all its controls, and my child dialog (with no name) with the Press me! button and edit control. |
Figure 9 Spy++ Screen |
You can customize the old-style file dialogs too, but it's more work. When you specify a different template with lpTemplateName and OFN_ENABLETEMPLATE, Windows uses your template to replace the entire dialog, as opposed to appending it. So you have to create a dialog with all the expected controls and all the expected IDs. The easiest way to find out what the IDs are supposed to be is to run the dialog and look at it with Spy++. Beyond a certain point, though, it's easier to just write your own dialog from scratch. For more poop on customizing Explorer-style dialogs, see "Explorer-Style Hook Procedures" in the Platform SDK docs. Have a question about programming in C or C++? Send it to askpd@pobox.com |
From the January 1998 issue of Microsoft Systems Journal.