How do I? - Part 8
by Eric Slaats
Hello Again. My column two months ago generated a lot of mail. Not my "How Do I?" column, but my article about hardware wrestling. I guess a lot of people are experiencing the same troubles as I am. I also found that hostile hardware is not an exclusive OS/2 problem. All platforms I have tried have given me the same problems, so I guess there's hope after all.
A lot of the replies I received were about using Delphi in OS/2. I tried to answer them all, but some mail messages bounced back. So here's a reply to all those people asked about it.
- Q -
- Where did you get the patch to use Delphi under OS/2?
- A -
- I guess I wasn't specific enough. I found something that can recompile Delphi programs to OS/2 PM programs (which is far more exiting than creating WIN/95 programs under OS/2). The disadvantage of this approach is that the code still has to be built under Win/95 or Win/NT. I haven't been able to get it running due to lack of time, but here's what I found:
One of my students has a subscription to a German c't magazine (Computertechnik). Besides the fact that all the articles are written in German (no problem for Dutch people, but I guess native English speakers might have a problem) it's a very good magazine that regularly runs OS/2 stories.
One of the writers there is Matthias Withopf. He's a real genius in meddling with EXE formats and compilers. He's the one that patched Borland Pascal 6.0 for DOS to produce OS/2 EXE's. He'd written an article in CT (Oct/96) about a way to convert the Borland C++ 2.0 compiler for OS/2 (and the freeware GNU compiler) in such a way it will compile Delphi code to OS/2 PM programs. I don't know if his article is available in English but it's called "Delphi meets Wunderkind". The file in which the Delphi patch can be found is CT9610.zip (this file contains more stuff from that issue of c't) and I got it from a German FTP server at ftp://ftp.heise.de/pub/ct/listings/.
Enough about my last column, back to business. It's getting harder and harder not to make this column too difficult but I still aim at the beginning PM programmer. So if you're starting to have problems reading or understanding this column, please let me know.
Time for something new! As I promised last time, we will take a look at something different than the frame control. This month, we will begin a small series about how to create and use dialogs. The dialog is a very important and flexible way for PM programs to obtain input. Also, dialogs can be created with drag and drop tools.
The PM has a number of default dialogs like the file open dialog, the font dialog and the message boxes. This series will also be used as a stepping stone for future columns in which exciting controls like notebooks, containers, etc. will be handled. What will be handled this month:
- Parent/owner concepts for windows
- Modeless dialogs
- Modal dialogs
- WinMessageBox API call.
A dialog box / WinMessageBox
What exactly is a dialog? A dialog box is a child window of the main application window in which user interaction is obtained that can not be handled through menus. I know this definition isn't exactly watertight; the sub-windows in a MDI (Multi Document Interface) could also be viewed as dialogs with this definition. So to make things clearer, here are some examples of typical dialog-boxes:
- The find/replace dialog of the e.exe editor.
- The message boxes that appear to tell you an error or some other event has occurred.
- The OS/2 file open/save dialog.
- The OS/2 font change dialog.
- In general, the about boxes of applications.
Very often a dialog is used to tell the user something, display an error, ask the user if the current action must be continued or cancelled, etc. It would be time, space and performance consuming if we had to make a dialog for every one of these simple tasks an application has to perform. This is why there are two default dialogs built into the OS/2 API, WinMessageBox and WinMessageBox2. The second of these is a more sophisticated version of the message dialog that can be modified in a large number of ways (check it out, it's fun).
For this article we'll use WinMessageBox to show the behaviour of dialogs. The API call for WinMessageBox looks like this:
HWND hwndParent; // Parent-window handle HWND hwndOwner; // Owner-window handle PSZ pszText; // Message PSZ pszCaption; // Titlebar text ULONG idWindow; // Window ID ULONG flStyle; // Window style. ULONG usResponse; // User-response value. usResponse = WinMessageBox(hwndParent, hwndOwner,pszText, pszCaption, idWindow, flStyle);
To create a message box, we first have to know which windows will be parent and owner of the dialog. We delve into that in a moment. The message we pass to the user must be specified in pszText which will contain the text that is shown in the window body of the message text. The way WinMessageBox handles this text is really done very well. If this text needs several lines to be displayed, OS/2 simply splits the text at the most convenient point and resizes the height of the box to accommodate the text. This is very convenient since in systems with different resolutions, the text length may vary. OS/2 will make sure the text in the message box is displayed correctly.
The pszCaption string defines the text in the title bar. I usually use one or two words to describe the dialog's purpose. Something like "ERROR!" or "Warning" will do fine. Note that if the title bar text is too long, it will simply be clipped.
The idWindow isn't that important for what we are doing this month. It's an ID that is passed to the help system if the help button (if we defined it that way) is pressed on the message box. Since we won't use it here, we simply fill in a 0.
The flStyle is next. Here's a parameter I like; with this one we can completely control the way the message box works. The way this works is much like the way we define the FCF flags for a frame window. We simple or (|) together a number of flags and the result is put into one integer which is dissected by the system to display the box in the way we want.
WinMessageBox knows the following identifiers to define the buttons on the message box:
MB_OK OK button. MB_OKCANCEL OK and CANCEL buttons. MB_CANCEL CANCEL button. MB_ENTER ENTER button. MB_ENTERCANCEL ENTER and CANCEL buttons. MB_RETRYCANCEL RETRY and CANCEL buttons. MB_ABORTRETRYIGNORE ABORT, RETRY, and IGNORE buttons. MB_YESNO YES and NO buttons. MB_YESNOCANCEL YES, NO, and CANCEL buttons. MB_HELP HELP button.
As a regular user of OS/2 you may have noticed that some message boxes contain bitmaps to identify the sort of message box that is displayed. The following identifiers are used to display an icon on the message box. Note that only one of these identifiers can be used. If more are used, the result may be unpredictable. You'll also note that there are several ways to display the same icon. The deeper reason for this is unknown to me.
MB_ERROR Red circle with a red line across it. MB_ICONASTERISK Information (i) icon. MB_ICONEXCLAMATION Exclamation point (!) icon. MB_ICONHAND Red circle with a red line across it. MB_ICONQUESTION Question mark (?) icon. MB_INFORMATION Information (i) icon. MB_NOICON Message box is not to contain an icon. MB_QUERY Question mark (?) icon. MB_WARNING Exclamation point (!) icon.
The next group is the so-called modality indicator. What modal and modeless means will be explained later on.
MB_APPLMODAL Message box is application modal. MB_SYSTEMMODAL Message box is system modal.
Finally we have the Mobility indicator. We can define a message box so that it can't be moved. This results in a message box that has no title bar. If we want the user to be able to move the message box, we need to define the MB_MOVEABLE ID.
So, if we want to create an error box, we could do the following:
WinMessageBox(hwndParent, hwndOwner, "An error occurred!", "ERROR!" MB_OK | MB_ORROR);
Modal and Modeless dialogs
Dialog boxes can be used in a number of ways. In fact that's the core of this month's column. If you regularly use an OS/2 application, you know that there are dialogs that pop up and have to be closed before you can access any other window of the main application. Examples of this are most "about" boxes and the file open dialogs in the e.exe and the Smalled editors. There are also dialogs that stay on top of the application, but let you use anything the application has to offer. Examples of this are the find/replace dialogs in most editors. Dialogs with these behaviours are referred to as Modeless and Modal dialogs, respectively.
A Modal dialog will restrict the user's interaction to the current (dialog) window. The user can not interact with other windows of the application. With message boxes, we can go one step further and make the box system modal. This means the user can't interact with anything else on the system besides the box. An example of this is a system error message.
Modeless dialogs, on the other hand, will let the user interact with all the other windows on the system/application. Depending on the parent (see next section), the window will stay on top of the application, even if it isn't active. (Check out this month's sample for a display of this behaviour.) In the sample this month (ZIP, 16k) we don't check if a dialog is already active. Because we can interact with the main window, we are able to start numerous instances of one dialog. In my opinion this is a common error. We'll see how this can be fixed somewhere along this series about dialogs.
Owned and Parented
It didn't surface before in this column, but every window that we create will have a parent and an owner. For example the Client window in the small applets we build until now has the Frame window as parent as well as owner. These concepts are important because, to a large extent, they define the way windows behave.
What's a parent?
The most obvious task a parent has is to control where a child window will be visible. Child windows will be 'clipped' to the parent window. This means if you want to move a child window beyond the borders of the parent, the part that will 'stick out' of the window won't be visible. (Check the sample this month for an example of this behaviour.) This also means if we want to be able to move the dialog all over the Desktop, the parent can't be the current application's Frame window. We need to use the Desktop window as the Parent. For this, OS/2 has the default HWND_DESKTOP constant that can be used as the hwndParent.
A child window will also inherit all the styles a parent has. This means that if a parent is visible, the child will be visible. This can easily be checked by hiding the Sample8 applet. If a dialog is open, it will also be made invisible along with the parent (frame) window. A child will also move with the parent if the parent is moved. Again, this can be easily checked by moving sample8 when a dialog is open. Finally, a child will always be on top of the parent window.
The existence of a child window also depends on the existence of the parent. If a parent is destroyed, all the children are also destroyed. Of course this is logical, since if there is no parent, the child has no place to present itself.
What's an owner?
The "duties" of an owner window are much the same as the duties of a parent window. The owned windows are destroyed, hidden, or minimized with the owner. The most important difference is that owned windows aren't clipped to their owner. This means owned windows can move beyond the borders of the owner.
Another notable difference is that there is communication between owner and owned windows. The owner will get a WM_CONTROL message with the mp parameters telling the owner which dialog sent the message and what happened. We will delve into this in a future article.
The sample for this month contains a very simple program that shows the behaviour of dialogs in several settings. For this, WinMessageBoxes are used. Next month we'll dive into dialogs more deeply. At that point we will create our own dialogs and take a first look at dialog handling procedures. And, of course, Modal and Modeless dialogs will reappear.