═══ 1. Introduction ═══ This volume, the first of five on OS/2, is not intended to be a guide on how to write Presentation Manager programs, but is a compilation of the solutions to most of the common problems encountered by many in IBM, including myself, whilst writing their own code. Where applicable I have provided code, and a sample program, to show how to overcome the problems. You can use the clipboard to copy and paste the code directly to your program or to a separate file. In addition you will find the complete source and executables for all the sample programs on the diskette on which this volume was supplied. Please note however, that these programs do not have any great function and only serve to confirm that the tips covered in this volume do work. For this reason I have ignored such things as error checking and cleaning up on exit except where relevant. Also, please note that these tips apply to Version 1.2 upwards. In fact all the code I wrote verifying these tips was written using the 1.2 Toolkit on OS/2 Version 1.3. However, you may find that some hints, e.g. WinSetPresParam, do not work completely satisfactorily on Version 1.2. Note: This volume is not yet complete. Further versions will be released at regular intervals. Send any comments to - Bryan Goodyer Personal Systems, Europe IBM UK Mountbatten House Basingstoke Hampshire UK VNET (GOODYER @ WINVMB) ═══ 2. Dialog Boxes and their Controls ═══ This section covers the following topics - Action Bar Disabling Controls Entry Fields Errors Focus Icons Listboxes Main Window Menus Mnemonics Multi-line Entry Fields Position Push Buttons Radio Buttons Size Status Styles Tab Stops Text Window ID Sample Programs ═══ 2.1. Action Bar ═══ ═══ 2.1.1. Action Bar in a Dialog Box ═══ To add an action bar to your dialog box, first define the menu layout and add it to your resource file. You will then need to add a call to WinLoadMenu and send a WM_UPDATEFRAME message to the frame to tell it to update. If you omit to update the frame then the menu will not appear until you minimize and restore the box. You should put this in your WM_INITDLG case statement. ═══ 2.2. Disabling Controls ═══ ═══ 2.2.1. General ═══ To disable a control use WinEnableWindow with the second parameter set to FALSE. To enable the control call it again with TRUE. This is a useful technique to use when you don't want your user to activate a control until he has completed any prerequisites. For example, if you have a delete pushbutton in your dialog you don't want the user pressing it until he has selected an item to delete. Using this technique can save you a lot of validation code. ═══ 2.2.2. Entry Fields ═══ If you need to disable an entry field which is the first control in the dialog box then use WinEnableWindow as usual in your WM_INITDLG case statement but alter the focus to another control. Failure to do this will allow the user to enter data into the field until he tabs out to another control. It will only be now that the entry field will become disabled. It is also important when changing focus in a WM_INITDLG to return TRUE otherwise focus will not be changed. ═══ 2.3. Entry Fields ═══ ═══ 2.3.1. Changing the Default Length ═══ To change the default length of 32 for a text entry field send it an EM_SETTEXTLIMIT message. Alternatively, you can modify your DLG file by adding control data to the control(s) on which you want the length set. The example shows how to set the entry field length to 5 bytes. The format of CTLDATA is CTLDATA size, length, minsel, maxsel where - size = 8 for 8 bytes of control data length = number of characters allowed to be entered minsel = 0 (minsel defines the first char to be initially selected) maxsel = 0 (maxsel defines the last char to be initially selected) Note: If you use this latter approach beware if you use the Dialog Box Editor as you will lose any changes you have made to the DLG file. ═══ 2.3.2. Cursor Not Appearing at Edge of Field ═══ The usual cause of this problem is a static field defined immediately to the left of an entry field so that it overlaps it. This has the effect of the system pointer not changing into the I-beam cursor when it moves into the field, but as it is moved to the right it changes, if and when it reaches the end of the static field. ═══ 2.3.3. Cursor Position ═══ To position the cursor in an entry field send the control an EM_SETSEL message. The third parameter MPFROM2SHORT(m, n) specifies where the cursor is to be positioned and what part of the field needs to be selected, if any. m specifies the offset of the first character in the selection n specifies the offset of the first character after the selection If m = n there is no selection but the cursor is positioned at offset m. If m = 0, n >= text limit the entire text is selected. ═══ 2.3.4. Invisible ═══ To make an entry field invisible so that it can be used for entering passwords use the style ES_UNREADABLE. You must add this style manually to your entry field in your DLG file so be careful if you use the Dialog Box Editor after making this change as it does not support this style. You cannot change this style for an entry field in your program, i.e. the code - hPwd = WinWindowFromID(hwndDlg, ID_PASSWORD); WinSetWindowULong(hPwd, QWL_STYLE, (WinQueryWindowULong(hPwd, QWL_STYLE) | ES_UNREADABLE)); WILL NOT work. The reason is that if changing this style flag meant that the window changed from being unreadable to readable, or vice versa, anyone could write a small program to flip the state of password entry fields and read them making this a very insecure method of password protection. ═══ 2.3.5. Reading Data ═══ To read data from an entry field use WinQueryWindowText or WinQueryDlgItemText for character data, or WinQueryDlgItemShort to convert the text to an integer value. ═══ 2.3.6. Numeric Data Only ═══ To limit an entry field to numeric data you must subclass the entry field window and throw away those keystrokes not required. Don't forget that you will probably need to keep some non-numeric keystrokes, for example - o Backspace o Tab o Minus sign o Enter ═══ 2.3.7. Read-only ═══ If you require a read-only entry field then send the control an EM_SETREADONLY message or add the style ES_READONLY to the control in your DLG file. Alternatively, you can make the control static and use WinSetWindowText or WinSetDlgItemText to change the text. ═══ 2.3.8. Writing Data ═══ To write character data to an entry field use WinSetWindowText or WinSetDlgItemText. Use WinSetDlgItemShort to convert an integer value directly to text. To clear data from an entry field just write null to it. ═══ 2.4. Errors ═══ ═══ 2.4.1. Dialog Box Causes Program to Abend ═══ If a dialog box causes your program to abend try increasing the stack size defined in your DEF file. ═══ 2.5. Focus ═══ ═══ 2.5.1. Setting Focus ═══ The default dialog procedure sets the focus to the first control defined in the dialog box's DLG file. To override this use WinSetFocus in your WM_INITDLG case statement. However, you must return TRUE from WM_INITDLG to tell it that the focus has changed, otherwise the WinSetFocus call will be overridden and the focus will revert to the first control. ═══ 2.6. Icons ═══ ═══ 2.6.1. System Icon in a Dialog Box ═══ To include a system icon in a dialog box just add a CONTROL statement directly into your DLG file. But, be careful if you use the Dialog Box Editor afterwards as it will not handle it correctly and you will lose it. For all the "#n" and SPTR_xxx values see the PMWIN.H include file in the \TOOLKTnn\C\INCLUDE directory. ═══ 2.6.2. User Icon in a Dialog Box ═══ To include your own icon in a dialog box use the Dialog Box Editor to define and position the icon on the window and then add an ICON statement to your resource file specifying which icon filename you want associated with the icon ID, for example - ICON ID_DLGICON hints.ico The associated CONTROL statement generated by the Dialog Box Editor for this is - CONTROL ID_DLGICON, ID_DLGICON, 5, 35, 20, 16, WC_STATIC, SS_ICON | WS_GROUP | WS_VISIBLE ═══ 2.7. Listboxes ═══ ═══ 2.7.1. Columns Using Presentation Parameters ═══ The easiest way to have columns in listboxes is to use presentation parameters to change the font to a non-proportional type, for example, Courier. ═══ 2.7.2. Columns Using Proportional Fonts ═══ If your columns are purely numeric, that also means no leading blanks, then it doesn't matter what font you use. Numbers take up the same space so they will line up even using a non-proportional font. See the MLE/Radio Button program for confirmation of this. However, if you need to display text in columns then you need to use a ownerdraw listbox and do the drawing of items yourself. A very quick and easy way of putting your data into columns is to split your item rectangle into separate rectangles, treating each rectangle as a column. Each time you insert an item a WM_DRAWITEM message is sent so that you can draw the text the way you want it. You must, of course, make sure you have enough room in each column for the data. If you require horizontal scrolling then you will need to change the start positions of the second and successive columns. When an item is selected then you can decode the text in your LN_SELECT case statement. ═══ 2.7.3. Deleting Items ═══ To delete an item from a listbox send it an LM_DELETEITEM message. Remember that the item's index is zero-based. If you need to delete all items then send it an LM_DELETEALL message. ═══ 2.7.4. Deselecting Items ═══ To deselect an item in a listbox send it an LM_SELECTITEM message with the second parameter set to FALSE. Remember that the item's index is zero-based. If you wish to deselect all items in a multiple selection listbox then you must loop through the listbox deselecting each one separately. LIT_NONE for this type of listbox is ignored since what you are saying is, select another item in a multiple selection listbox, and of course this does not deselect any previously selected item. ═══ 2.7.5. Inserting Items ═══ To insert items into a listbox send it an LM_INSERTITEM message. The first parameter of this message indicates where the item is to be inserted. It can either be at the end, in ascending or descending sequence, or at any position. One of the most common uses of listboxes is to display data extracted from a database. In such cases it is often useful to store the key of each item so that you can retrieve any extra data for that item later. A useful technique for doing this is to use the item handle. ═══ 2.7.6. LS_NOADJUSTPOS Style ═══ If this style is included then the listbox control is drawn at the size specified. This can cause parts of an item to be shown at the bottom of the box. This is very evident if you change to a large font in a listbox. If you do not specify this style then the listbox is sized according to whatever font it will be using once initialised so that only complete lines will be drawn. This may make the box considerably smaller than intended. You should therefore bear this in mind if you intend using a different font in a listbox. Furthermore, if you intend allowing the user to change the font at runtime then if this style is not used then the listbox size will vary quite drastically according to what font changes are taking place, so much so that eventually it will be too small to read any items. ═══ 2.7.7. LS_NOVERTSCROLL Style ═══ This style, which causes a listbox not to have a vertical scroll bar, is documented on page 16-1 of the Presentation Manager Programming Reference Manual. However, it was never implemented in the product and so is not available for use. If you do not want a vertical scroll bar in your listbox then see Removing Scroll Bars. ═══ 2.7.8. Non-selectable Items ═══ If you have a requirement to prohibit selection of certain items in a listbox then you must use an ownerdraw listbox and handle the selection yourself. In the ownerdraw code for the listbox sample program you will notice that Finland is not selectable. This is handled in the WM_DRAWITEM case statement where the hilighting is handled. You must still code a trap for it in the LN_SELECT statement, in this case just a warning beep. This can easily be extended to exclude all entries if desired. ═══ 2.7.9. Ownerdraw ═══ This topic has probably caused more problems than any other in Presentation Manager. Briefly, if you want to do anything out of the ordinary with a listbox the chances are you will have to resort to an ownerdraw listbox. What this means is that you are responsible for drawing the items in the box so it gives you complete freedom to do as you please. Probably the most common use of ownerdraw listboxes is to arrange the data in columns, but their use is really unlimited. As a simple introduction we will look at a listbox that centralises the data and uses our own colours for hilighting. Although this is a very simple example it does show the basic steps that can be built on to produce something more complex. So, to start with you must define your listbox with the style LS_OWNERDRAW, this can be done manually or by using the Dialog Box Editor. Now, when you have an ownerdraw listbox your application receives two messages, WM_MEASUREITEM and WM_DRAWITEM. The purpose of the WM_MEASUREITEM message is to establish the height and width of the item to be drawn in the listbox, and the WM_DRAWITEM message is sent whenever the item needs to be drawn. Looking at the WM_MEASUREITEM message first, all we need to do here is query the font metrics to get the maximum vertical distance from one character baseline to the next character baseline, lMaxBaselineExt, for the current logical font. Once we have this value we return it to the system. Since we don't have a horizontal scroll bar we are not interested in the width so just return 0 for its value. However, if you do need to have a horizontal scroll bar then you must return the width of the item. You can get this by using GpiQueryTextBox. One point worth remembering when you have a horizontal scroll bar is that this message is sent every time an item is inserted or deleted for each item in the listbox. This means that when you insert the first 3 items, for example, 6 messages are sent (1+2+3). This is so the system can determine the height and width of every item. For this reason care should be taken not to code lengthy calculations here. We get a WM_DRAWITEM message whenever the listbox needs to be redrawn, for example when an item is inserted or selected. On entry the second parameter, mp2, is a pointer to an OWNERITEM structure which gives us information about the item to be drawn, such as the size of the rectangle it is to be drawn in, its select state, a handle to its presentation space and others, but for this simple example that's all we are interested in. If the state is 0 then the item is not selected so we set the normal colours, in this case yellow on dark green, if it's 1 then it is selected so we reverse the colours. All that needs to be done now is draw the text and exit. The important points to note here though are - 1. Current and old states must be set to 0 else Presentation Manager will take over hilighting and change what we have done. 2. We must return TRUE to prevent Presentation Manager from doing the drawing. If we don't then the text will be left justified and in system colours. This is obviously a trivial example but should be sufficient to get you started in this area. Note: If all you want to do with your listbox is change the font or foreground and background colours then there is no need to resort to an ownerdraw listbox as from OS/2 Version 1.2 onwards you can do this with presentation parameters. However, if you do need to use a different font in an ownerdraw listbox then you can use presentation parameters, but you must put the call to WinSetPresParam in your WM_MEASUREITEM statement otherwise the item height will not be set correctly, so if you use a font larger than the system font, it will be clipped. Not only that, but it must only be executed once otherwise the program will get a trap 000C - SYS1942 A program attempted to reference storage outside the limits of a stack segment. You therefore need a first-time flag to overcome this. Note: This only really applies if you have horizontal scrolling since the WM_MEASUREITEM message is only sent once. ═══ 2.7.10. Processing Multiple Items ═══ To process the selected items in a multiple selection listbox, first send a LM_QUERYSELECTION message with the first parameter set to LIT_FIRST, this will return the index of the first selected item. You can then process this item and then send another LM_QUERYSELECTION message with the first parameter set to the index previously returned. Continue this until LIT_NONE is returned. If this process is going to take some time, and it may well do, since many items are going to be processed, then you should consider putting it in another thread. If you don't want the user interacting with your application whilst this thread is running then you can disable any relevant controls until the thread has completed. Note: To deselect items send each one an LM_SELECTITEM message. ═══ 2.7.11. Removing Scroll Bars ═══ There is no clean method for removing a scroll bar from a listbox. The best that can be done is to get the handle of the scroll bar and use WinDestroyWindow to destroy it. However, this leaves a blank space so looks untidy. Note that removing a vertical scroll bar does not prevent scrolling up and down, whereas removing a horizontal scroll bar does prevent sideways scrolling. ═══ 2.7.12. Retrieving Data Associated with Items ═══ After saving data in an item handle you can retrieve it again by sending the listbox an LM_QUERYITEMHANDLE message. ═══ 2.7.13. Retrieving the Text of a Selected Item ═══ To get the text of a selected item you must first send the listbox an LM_QUERYSELECTION message to get the index of the selected item, the first entry in a listbox having an index of 0. Once you have this value you send it an LM_QUERYITEMTEXT message to get the actual text. Listboxes generate a WM_CONTROL message, so to process it for a listbox check the low word of the mp1 parameter using the SHORT1FROMMP macro and then the high word of the mp1 parameter using the SHORT2FROMMP macro for the LN_ notification code. In this case LN_SELECT. ═══ 2.7.14. Saving Data Associated with Items ═══ When inserting items into a listbox it is often useful to save data associated with each item, for example, the key field to a database row. To do this, after inserting the item send the listbox an LM_SETITEMHANDLE message. At its simplest this could be just the key field, but you may need to store more data in which case you can define the necessary structure and store a pointer to it in the handle. To retrieve the data send the listbox an LM_QUERYITEMHANDLE. Note: Since it is necessary to allocate memory in order to save the data then when deleting items you should free any necessary memory, and when removing the listbox you should free all memory associated with it. Another point worth mentioning is when allocating memory under OS/2 Version 2 the minimum amount allocated will be one page, i.e. 4KB, so you should take this into account when allocating memory for your application if it is to run under this version. ═══ 2.7.15. Selecting Items ═══ To select an item in a listbox send it an LM_SELECTITEM message. Remember that the item's index is zero-based. ═══ 2.8. Main Window ═══ ═══ 2.8.1. Dialog Box as a Main Window ═══ It is sometimes very convenient to use the Dialog Box Editor to create a window and have this window your main, or only, window. The easiest way to do this is to create a modal dialog box in your main routine. You will not need any get/dispatch message loop as this is part of the WinDlgBox call. When this call returns it means your dialog box no longer exists and you can terminate your application. Alternatively, instead of using WinDlgBox you can use WinLoadDlg/WinProcessDlg. ═══ 2.8.2. Starting Minimized ═══ To create a dialog in its minimized state use SWP_MINIMIZE in your WinSetWindowPos call. ═══ 2.9. Menus ═══ ═══ 2.9.1. Pop-up Menus ═══ This is very similar to pop-ups for client windows, but because a dialog box is really just a frame window there are some subtle differences. In your WM_INITDLG processing you still need to do the WinQuerySysValue and WinLoadMenu, but you must be careful where you put it as it is very likely that your dialog box will already have a conventional menu. This means you will have a WinLoadMenu and a WM_UPDATEFRAME for the action bar, so if you place the WinLoadMenu for your pop-up before the WM_UPDATEFRAME then you will find that when the menu pops up so will its action bar. As this is undesirable place it after. The WM_BUTTON2DOWN message processing is identical to that for client windows but what must be added is a case for WM_NEXTMENU to prevent your application hanging if the pop-up menu is displayed and the user presses button 1 in the dialog box area outside the menu. All that's needed is to return FALSE from this message. Unfortunately, another problem exists if you minimize the dialog box. When you restore it the system sends the frame a WM_UPDATEFRAME message causing the pop-up menu's action bar to be displayed and any options on the main action bar to disappear. Now to overcome this you must reload the main menu again when the box is restored. This causes the options to reappear on the action bar and the desired absence of the pop-up menu's action bar. But obviously you must destroy the original action bar, with WinDestroyWindow, when minimizing otherwise each time you minimize/restore an extra action bar will be created. ═══ 2.10. Mnemonics ═══ ═══ 2.10.1. Mnemonics for Controls ═══ If you want to use mnemonics in a dialog box then define a static text field with the DT_MNEMONIC style, either manually or by using the Dialog Box Editor, and place this immediately before the control you want the mnemonic to act upon. This creates a mnemonic based on the position of the static text control in the resource, and underlines the letter with the tilde. CONTROL "~Single Selection", 101, 10, 155, 71, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_MNEMONIC | WS_GROUP | WS_VISIBLE CONTROL "", ID_SLISTBOX, 8, 71, 80, 80, WC_LISTBOX, WS_TABSTOP | WS_VISIBLE In the above example when the user presses Alt-S from anywhere in the dialog, or S from a non-text entry field, it will automatically set the focus to the listbox control. ═══ 2.11. Multi-line Entry Fields ═══ ═══ 2.11.1. Changing Font ═══ The simplest method of changing the font, or colour, of a control is to use presentation parameters. This method works fine for all controls in a dialog box except Multi-line Entry fields (MLE) in which only the following fonts appear to work - 8 point Courier 10 point Courier 12 point Courier 8 point Helvetica 10 point Helvetica 12 point Helvetica 14 point Helvetica 18 point Helvetica 24 point Helvetica To effect this font change use WinSetPresParam. If you need to use a different font in an MLE then you must use the traditional approach, an example of which may be found in the OS/2 Toolkit sample program FONTTEST. Note: The above restriction may change with later levels of OS/2. This is applicable to the initial release of Version 1.3 so if you have a later version then I suggest you try this method first. ═══ 2.11.2. Clearing the MLE ═══ To clear the text from an MLE use WinSetDlgItemText or WinSetWindowText. ═══ 2.11.3. Importing a File ═══ To import a file to an MLE you must first allocate a buffer into which you read the file, or part of the file, and then set this buffer as the current transfer buffer for the MLE. You can then import the file. If you require the file to be inserted at the current cursor position then set the insertion point to -1. The sample code reads in the CONFIG.SYS file and imports it at the current cursor position. ═══ 2.12. Position ═══ ═══ 2.12.1. Positioning a Dialog Box on the Desktop ═══ To position a dialog box on the desktop use WinSetWindowPos without the SWP_SIZE option in your WM_INITDLG code. ═══ 2.13. Push Buttons ═══ ═══ 2.13.1. Default ═══ To determine which push button is the default use WinQueryWindowULong. To remove the default style send the button a BM_SETDEFAULT message set to FALSE and to make it the default again send the same message set to TRUE. Alternatively, to set/remove the default state you can also use WinSetWindowBits, but you must call WinInvalidateRect to force a repaint of the button afterwards to ensure the default border is added/removed as appropriate. Note: From OS/2 Version 1.3 onwards setting another push button to be the default will cause the current default button to lose its default state. ═══ 2.13.2. User Button ═══ If you need to display a bitmap in a push button, for example the system bitmap for a drive, then you must use a push button with the style BS_USERBUTTON. Using this causes a BN_PAINT message to be sent to your window procedure. If you wish to display a non-system bitmap in a push button then you must define it in your resource file and load it in your paint procedure prior to display. The user button code shows both methods. It makes use of the DBM_STRETCH option so that the bitmap is stretched to the full size of the button. ═══ 2.14. Radio Buttons ═══ ═══ 2.14.1. Setting at Initialisation ═══ This is probably the most common problem of all with radio buttons. If you have a group of radio buttons and you want to check one other than the first when starting your dialog, then case WM_INITDLG: WinSendDlgItemMsg(hwnd, BUTTON_ID, BM_SETCHECK, MPFROM2SHORT(TRUE, 0), NULL); will usually work. However, if the group of buttons is the first control in the dialog box then the first button will be checked, irrespective of whatever button ID you specified on the WinSendDlgItemMsg. To overcome this, check the required button as shown above but make sure you return TRUE from the WM_INITDLG. ═══ 2.15. Size ═══ ═══ 2.15.1. Minimizing a Dialog Box ═══ The most common problem encountered when minimizing dialog boxes is the disappearance of your icon. Instead, Presentation Manager paints over the icon with the bottom left corner of your dialog box. To overcome this you must first load your icon using WinLoadPointer and then send a WM_SETICON message to the dialog box. You should do this in your WM_INITDLG code. You must then trap your WM_ADJUSTWINDOWPOS message and if minimizing, hide the control(s) at the bottom left corner of the box. Conversely, when restoring you must show the control(s) again. Finally, pass control back to the default dialog procedure so that it can do any default processing. You should also add a WinDestroyPointer call during your exit processing. ═══ 2.16. Status ═══ ═══ 2.16.1. Status Bar ═══ If you have ever run the AVIOSAMP sample program from the Toolkit you will have noticed that it has a status bar. This bar gives the user the current application status, for example whether he is in insert mode or not. Here are two ways this can be implemented in dialog boxes, the first makes use of the WM_PAINT message and WinDrawText to display the status. But perhaps the easier method is to define a static text field in your dialog box and use WinSetPresParam in your WM_INITDLG to initialise the colours. In this case you use WinSetWindowText to display the status as and when necessary. ═══ 2.17. Styles ═══ ═══ 2.17.1. Changing a Control's Style ═══ To change a control's style, for example, to change an entry field's style of left align to centred, use WinSetWindowULong. ═══ 2.18. Tab Stops ═══ ═══ 2.18.1. Removing and Adding ═══ If you need to remove/add the TABSTOP from a dialog box control, a push button for example, then use WinSetWindowULong. ═══ 2.19. Text ═══ ═══ 2.19.1. Backslash in a Static Text Window ═══ If you require a \ in a static text window then, like C, you must code a double slash, i.e. \\. ═══ 2.19.2. Changing the Dialog Box Title ═══ To change the title of the dialog box use WinSetWindowText with the window handle set to the actual dialog box handle, i.e. the frame handle. Alternatively, use WinSetDlgItemText. ═══ 2.19.3. Changing the Text in a Dialog Box Control ═══ To change the text in a dialog box control use WinSetWindowText with the window handle set to the handle of the control you wish to change. You can use WinWindowFromID to get this value. ═══ 2.19.4. Forcing a Line Break in Static Text Windows ═══ If you have a static text window with word wrap defined in your dialog box and you wish to force a line break, then use \012 at the point you wish to break. For example, in your DLG file - CONTROL "Line one\012Line two\012Line three", ...etc will produce - Line one Line two Line three You can do this either by modifying your DLG file manually or by using WinSetWindowText within your program. Unfortunately, if you use the Dialog Box Editor the \012s are replaced by line breaks in the DLG file and the Resource Compiler fails with a syntax error. ═══ 2.20. Window ID ═══ ═══ 2.20.1. Window ID of a Control ═══ To retrieve the window identity of a control within a dialog box use WinQueryWindowUShort with a value of QWS_ID. ═══ 2.21. Sample Programs ═══ ═══ 2.21.1. General Dialog Box ═══ This sample program does not have any real function but was written to test that most of the tips in this section do work. You will find many areas commented out, this was done to check that any alternative methods also functioned correctly. If you run the program and press OK most of the features described in this section and the section on pop-up menus for dialog boxes are actioned. Pressing button 2 causes the pop-up menu to appear. See the following sample programs for verification of all other tips. Listbox MLE and Radio Buttons HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS.DLG - Dialog template HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 2.21.2. MLE and Radio Buttons ═══ This program was written to verify that the multi-line entry field and radio button tips function correctly. See the following sample programs for verification of all other tips. General Dialog Box Listbox Note: This program also makes use of Presentation Parameters. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS.DLG - Dialog template HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 2.21.3. Listbox ═══ This program was written to verify that the Listbox tips function correctly. See the following sample programs for verification of all other tips. General Dialog Box MLE and Radio Buttons This program displays three listboxes, single and multiple selection, and an ownerdraw, with the first item selected in the single selection box on entry. Items can be deselected from the single and ownerdraw boxes by pressing Deselect, and can be deleted from the single selection box by pressing Delete. If you select items in the multiple selection box and press Process MultSel then each one is processed sequentially and beeps when complete. Notice that this option uses DosSleep to do this which is not recommended. It is done here merely to slow down the process so that you can see what is happening. The ownerdraw box is a simple implementation of columnar data with Finland non-selectable (I've nothing against Finland, I just happened to pick it at random, my apologies to all those Finns using this package). Finally, pressing Alt-S, Alt-M or Alt-O will switch focus to the relevant listbox. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS.DLG - Dialog template HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 3. Fonts ═══ This section covers the following topics - Point Sizes and Face Names ═══ 3.1. Point Sizes and Face Names ═══ The following list represents the point sizes and face names of all the standard fonts in the system. You may use all of them with WinSetPresParam unless you wish to use it for changing the font of a Multi-line Entry field, in which case there are limitations. 8.Courier 10.Courier 12.Courier 8.Helv 10.Helv 12.Helv 14.Helv 18.Helv 24.Helv 10.System Monospaced 12.System Monospaced 12.System Proportional 8.Tms Rmn 10.Tms Rmn 12.Tms Rmn 14.Tms Rmn 18.Tms Rmn 24.Tms Rmn ═══ 4. Menus ═══ This section covers the following topics - Add Items to the System Menu Change a Window's Menu Check Menu Item Delete Items from the System Menu Delete Separator from the System Menu Disable Action Bar Disable Items in an Application Menu Disable Items in the System Menu Dismiss 'MIA_NODISMISS' Menu Pop-up Menus for Client Windows Pop-up Menus for Dialog Boxes Pop-up Sample Program (Dialog Box) Sample Program ═══ 4.1. Add Items to the System Menu ═══ Perhaps one of the most common queries regarding menus is 'How can I alter the system menu?', usually to add an About option, so let's look at how this is done. The first thing to do is get the handle of the system menu by calling WinWindowFromID with the identifier FID_SYSMENU. We then send it an MM_ITEMIDFROMPOSITION to get the ID of the actual menu list. Once we have this we can get the characteristics of the menu by sending it an MM_QUERYITEM message. The important item returned in the SysMenu structure is the actual handle of the submenu. Armed with this we can insert our items into it by sending the submenu an MM_INSERTITEM message. If you look at the declaration of Item you will see that we are adding a separator and some text, the actual text being defined in Text. This code would normally be executed at window creation time, i.e. in your WM_CREATE statement, so don't forget that you cannot use hwndFrame at this point. Clicking on About... will cause a WM_COMMAND message with the low short of mp1 set to ID_ABOUT. On receiving this we display a message box giving details about the program. This information could alternatively be displayed in a dialog box. ═══ 4.2. Change a Window's Menu ═══ There may be times when it is convenient for you to have two or more menus defined in your resource file for a window, and have any one loaded at any given time depending on circumstances. An easy way to do this is to destroy the current menu and use WinLoadMenu to load the next. You must then follow this with a WM_UPDATEFRAME message. ═══ 4.3. Check Menu Item ═══ Whenever a menu is about to be activated the system sends your application a WM_INITMENU message. The purpose being that you can make any changes to the submenu before it is displayed. For example, you may need to add a check mark to an item, or to toggle the item on/off depending on the current state of the application. The sample code shows this by setting up a flag, initially FALSE, and sending an MM_SETITEMATTR message to the menu. Because we are sending the message to the top-level menu rather than the submenu we must specify TRUE to ensure the submenu is searched for the item. Because we want to check an item we use the MIA_CHECKED attribute. The data associated with this is dependent on the flag, and since it is initially FALSE the item is not checked. However, if we now select the item the flag changes state and next time the menu is displayed the item will be checked. Note: This also applies to disabling items using the MIA_DISABLED attribute. ═══ 4.4. Delete Items from the System Menu ═══ To delete items you must first obtain the handle of the system menu and then send it an MM_DELETEITEM message. ═══ 4.5. Delete Separator from the System Menu ═══ If you want to remove Close from the system menu you will also need to remove the separator following it. The problem with deleting menu separators is that their IDs vary. For example, the first separator will have an ID of -2, and the next -3 etc. so you cannot supply a fixed value for a separator ID as you don't know its position. To do this then you must first get the handle of the system menu submenu, i.e. the actual menu displaying the items, and send an MM_ITEMPOSITIONFROMID message to get the position of Close in the menu, you can then add 1 to this to get the position of the separator. Sending an MM_ITEMIDFROMPOSITION message for this value now gives the actual item ID for the separator which can now be used in the MM_DELETEITEM message. The Close option can be deleted in the normal manner, i.e. use (SC_CLOSE, TRUE) with the system menu handle. ═══ 4.6. Disable/Enable Action Bar ═══ To disable the action bar, and thus all its pull-down menus, use WinEnableWindow. ═══ 4.7. Disable/Enable Items in an Application Menu ═══ To disable, or enable, items in your application menu you must first obtain its handle and then send it an MM_SETITEMATTR message to change the attribute of the item. This would normally be done in your WM_INITMENU statement depending on the setting of a flag. See also Check Menu Item. ═══ 4.8. Disable/Enable Items in the System Menu ═══ To disable, or enable, items you must first obtain the handle of the system menu and then send it an MM_SETITEMATTR message to change the attribute of the item. However, you can only disable Close and Switch to... using this method. If you need to disable Move then using WinEnableWindow to disable the title bar will cause Move to be greyed as a result. Note: There are no such restrictions in deleting items from the system menu. ═══ 4.9. Dismiss 'MIA_NODISMISS' Menu ═══ If you have a menu in which one or more items are defined with the MIA_NODISMISS attribute and you select one of these items, then the menu does not disappear. This may be what you need in your application, but, the problem comes when you want to dismiss it, say by pressing a mouse button. You will not be able to do it by sending an MM_DISMISSMENU message as the menu is no longer in menu mode. Instead, you must post MM_STARTMENUMODE and MM_ENDMENUMODE messages. Notice that the MM_ENDMENUMODE message is posted. The documentation states that this message should be sent. However, the MM_STARTMENUMODE message MUST be posted, so if the START was posted, and the END was sent, then the END would be processed first. This is why both must be posted. ═══ 4.10. Pop-up ═══ ═══ 4.10.1. For Client Windows ═══ It can sometimes be useful for your user to be able to pop up a menu by pressing mouse button 2, for example, rather than have to move to the action bar. To do this, first define your menu in the usual way in your resource file, and then trap the WM_CREATE and WM_BUTTON2DOWN messages in your window procedure. In the WM_CREATE case you need to get the handle of the menu by using WinLoadMenu and the action bar height by using WinQuerySysValue with SV_CYMENU, i.e. the height of a single line menu. This is needed so that you can position the pop-up so that the first menu item lines up with the pointer. Without doing this you will find that the menu items are an action bar's height below the pointer. To complete the implementation you need to get the position of the mouse pointer by using the macro MOUSEMSG, making sure you adjust the Y coordinate by adding the action bar height to it. Finally you must POST an MM_STARTMENUMODE message to the menu handle and position the menu using WinSetWindowPos. You can, of course, use a push button or any other method to initiate the pop-up, but pressing button 2 is probably the best method. You must then add the relevant case statements for the menu items in your WM_COMMAND message processing. ═══ 4.10.2. For Dialog Boxes ═══ This is very similar to pop-ups for client windows, but because a dialog box is really just a frame window there are some subtle differences. In your WM_INITDLG processing you still need to do the WinQuerySysValue and WinLoadMenu, but you must be careful where you put it as it is very likely that your dialog box will already have a conventional menu. This means you will have a WinLoadMenu and a WM_UPDATEFRAME for the action bar, so if you place the WinLoadMenu for your pop-up before the WM_UPDATEFRAME then you will find that when the menu pops up so will its action bar. As this is undesirable place it after. The WM_BUTTON2DOWN message processing is identical to that for client windows but what must be added is a case for WM_NEXTMENU to prevent your application hanging if the pop-up menu is displayed and the user presses button 1 in the dialog box area outside the menu. All that's needed is to return FALSE from this message. Unfortunately, another problem exists if you minimize the dialog box. When you restore it the system sends the frame a WM_UPDATEFRAME message causing the pop-up menu's action bar to be displayed and any options on the main action bar to disappear. Now to overcome this you must reload the main menu again when the box is restored. This causes the options to reappear on the action bar and the desired absence of the pop-up menu's action bar. But obviously you must destroy the original action bar, with WinDestroyWindow, when minimizing otherwise each time you minimize/restore an extra action bar will be created. ═══ 4.10.3. Sample Program (Dialog Box) ═══ See General Dialog Box sample program. ═══ 4.11. Sample Program - Menus and Task Manager ═══ This sample program was written to confirm the hints and tips given in the Menus and Task Manager sections and shows the following - Starting in background Adding/removing from the task list Changing the task list Querying the task list Disable 'End Task' button in the task list Disable 'Close' and 'Switch to...' in the system menu Delete 'Size' and 'Move' from the system menu Prohibiting exit from the task list and system menu Adding an 'About...' option to the system menu Disable all menu items Make application system modal Toggle menu item checked/unchecked Force dismissal of MIA_NODISMISS menu Delete 'Close' and its separator from the system menu Changing menus Initially, 'Close' and 'Switch to...' in the system menu and 'End Task' in the task list are greyed out and the action bar is disabled. Pressing button 1 enables the action bar, 'Close' and 'End Task' but doesn't allow closure from these options. Exit is via the action bar only. The title is also changed in the task list. Pressing button 2 removes 'Close' from the system menu. Pressing 'Switch Menus' causes a different menu to be loaded which has two options with two items under 'Option 1'. The first is 'checkable' and and the second is 'NODISMISS', until button 1 is clicked. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 5. Mouse and Pointer Control ═══ This section covers the following topics - Changing the Pointer in a Window Mouse Pointer Position Sample Program ═══ 5.1. Changing the Pointer in a Window ═══ If your application needs to do some lengthy processing in a separate thread, it is a good idea to change the pointer to the hourglass to give the user some visual feedback telling him that he must wait before he is able to continue with the application. It is also a good idea to change the pointer back to the arrow when it is moved outside your window so that he knows he can continue with another application. You will, of course, have to disable all the controls in your application you don't want used whilst the other thread is being processed, as just changing the pointer doesn't stop you using it. So, to do this, trap the WM_CONTROLPOINTER and WM_MOUSEMOVE messages. Whenever the pointer moves into a new window a WM_CONTROLPOINTER message is sent to a control's owner window allowing you to change the pointer. You also need to set the pointer during WM_MOUSEMOVE messages otherwise it will revert to the system arrow pointer. If you have dialog boxes in your application then you may not need to trap both messages, WM_CONTROLPOINTER may suffice, so try this first. If you find that the hourglass reverts to the arrow then you will have to subclass the particular control concerned. For example, in this section's sample program you will find a dialog box with an entry field and listbox. Without subclassing I found that if the entry field was disabled then the hourglass reverted if it moved over it, and moving the pointer to the listbox scrollbar also caused the same reversion. Subclassing the entry field and trapping the WM_MOUSEMOVE messages stopped the reversion for the entry field, and subclassing the listbox and trapping the WM_CONTROLPOINTER messages stopped the scrollbar reverting the pointer. If you use other controls then you may find similar peculiarities so try subclassing and trapping either, or both messages. Note: The above technique also works if you wish to change the pointer to an icon, provided you load it first using WinLoadPointer. ═══ 5.2. Mouse Pointer Position ═══ To retrieve the position of the mouse pointer use WinQueryPointerPos. This will return the co-ordinates in screen units. If you want the co-ordinates relative to your window then use WinMapWindowPoints. ═══ 5.3. Sample Program ═══ This program shows the following - Changing the pointer in a window Mouse pointer position When the program first starts it is in a busy state, i.e. the pointer changes to the hourglass whenever it moves into the window. If you click on the Test DLG button a dialog box is displayed with an entry field and listbox. The purpose of this is to show that the controls must be subclassed to maintain the hourglass. In the case of the entry field this is only necessary if it has been disabled, and in the case of the listbox it is necessary to maintain the hourglass in the scrollbar region. Try changing the program by removing the subclassing to see the effect. If you use other controls, notably MLEs, then you will also have to use subclassing to maintain the hourglass fully. To remove the hourglass, i.e. revert to not busy press the Remove Hourglass button. You will also notice that the mouse position is displayed in screen co-ordinates and window co-ordinates whenever the mouse is moved over the window. If you press, and hold down, button 2 then the mouse will be captured and its position will be displayed wherever it is on the desktop. Releasing the button releases the capture. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS.DLG - Dialog template HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 6. Presentation Parameters ═══ This section covers the following topics - Changing Colour Changing Font Using it on a Frame Window Sample Program ═══ 6.1. Changing Colour ═══ To change a control's colour you can either do it at runtime using WinSetPresParam or by presetting it in the DLG file using the PRESPARAMS statement. Note: If you use the latter approach you must add #define INCL_WINSYS to your resource file otherwise you will get the error message Undefined keyword or name from the Resource Compiler. Also, if you subsequently edit the DLG file by using the Dialog Box Editor the CLR_RED etc will be replaced by their numeric values, i.e. PRESPARAMS PP_BACKGROUNDCOLORINDEX, CLR_RED PRESPARAMS PP_FOREGROUNDCOLORINDEX, CLR_YELLOW becomes PRESPARAMS PP_BACKGROUNDCOLORINDEX, 0x00000002L PRESPARAMS PP_FOREGROUNDCOLORINDEX, 0x00000006L ═══ 6.2. Changing Font ═══ To change the font of a dialog control or window you can either do it at runtime using WinSetPresParam or, for a dialog control, by presetting it in the DLG file using the PRESPARAMS statement. Note: If you use the latter approach you must add #define INCL_WINSYS to your resource file otherwise you will get the error message Undefined keyword or name from the Resource Compiler. Also, if you subsequently edit the DLG file by using the Dialog Box Editor the 10.Courier will be replaced by its meaningless numeric equivalent, i.e. PRESPARAMS PP_FONTNAMESIZE, "10.Courier" becomes PRESPARAMS PP_FONTNAMESIZE, 0x432E3031L, 0x6972756FL, 0x00007265L Although this is a very simple way of changing the font care must be exercised when using this method for Multi-line Entry fields as many fonts cannot be set using WinSetPresParam. Similarly, if you intend to change the font in a listbox at runtime using this method then ensure it has the style LS_NOADJUSTPOS otherwise the listbox will adjust its size according to what font you use and may render the listbox illegible. Also, if you are using an ownerdraw listbox care should be taken where you place the WinSetPresParam call. See the ownerdraw listbox reference for details. Note: You cannot use this method to change the font style, e.g. italic or bold. ═══ 6.3. Using it on a Frame Window ═══ If you use WinSetPresParam on a frame handle then it affects all the controls within that frame, except perhaps the font for any Multi-line Entry fields you may have created. ═══ 6.4. Sample Program ═══ See the MLE/Radio Button program for sample calls to WinSetPresParam. ═══ 7. Task Manager ═══ This section covers the following topics - Add Program Title to the Task List Change Program Title in the Task List Disable 'End Task' Button Prevent Shutdown Query Program Title in the Task List SWL_GRAYED SWL_NONJUMPABLE Sample Program ═══ 7.1. Add Program Title to the Task List ═══ If you use the window style FCF_STANDARD, then your program's name will appear in the task list, and your title bar, concatenated with any text you may have defined for your application's title bar. For example, if your program was called 'XYZ.EXE' and its title was 'Test Program', then in the task list it would appear as 'XYZ.EXETest Program'. To overcome this do not use the style FCF_TASKLIST, which is included in FCF_STANDARD, but manually add it using WinAddSwitchEntry. On exit from the program's message loop use WinRemoveSwitchEntry to remove the entry. Ensure that you declare hwndEntry as static otherwise you will have an invalid handle. Alternatively, use WinQuerySwitchHandle to get the switch list handle first. ═══ 7.2. Change Program Title in the Task List ═══ To change the title of your application in the task list use WinChangeSwitchEntry. Alternatively, for an easier method use WinSetTitle, but beware, this is undocumented and so should be used with caution. ═══ 7.3. Disable 'End Task' Button ═══ WARNING - Undocumented, use with caution. If you have a requirement to disable the End Task button on the task list then use WinNoShutdown. See also Prevent Shutdown. ═══ 7.4. Prevent Shutdown ═══ When the 'End Task' button on the task list is pressed an application receives a WM_QUIT message causing the message loop to end, thus closing the program. However, in this case mp1 contains the frame handle, in all other cases it is NULL. It is therefore possible to use this fact to either ignore shutdown completely, or to put up a message box asking confirmation of closure. This also applies to the Close option on the system menu. To implement this put your message loop in a separate loop and on exit from the message loop test mp1, if not NULL then cancel shutdown. ═══ 7.5. Query Program Title in the Task List ═══ In order to query the task list for an application use WinQuerySwitchHandle to get the switch list handle followed by WinQuerySwitchEntry. ═══ 7.6. Task List Options ═══ ═══ 7.6.1. SWL_GRAYED ═══ Use this value for PgmEntry.uchVisibility when adding your program to the Task List to prohibit switching to it from the Task List. ═══ 7.6.2. SWL_NONJUMPABLE ═══ Use this value for PgmEntry.fbJump when adding your program to the Task List to prohibit switching to it using the Alt_Esc key sequence. ═══ 7.7. Sample Program - Menus and Task Manager ═══ This sample program was written to confirm the hints and tips given in the Menus and Task Manager sections and shows the following - Starting in background Adding/removing from the task list Changing the task list Querying the task list Disable 'End Task' button in the task list Disable 'Close' and 'Switch to...' in the system menu Delete 'Size' and 'Move' from the system menu Prohibiting exit from the task list and system menu Adding an 'About...' option to the system menu Disable all menu items Make application system modal Toggle menu item checked/unchecked Force dismissal of MIA_NODISMISS menu Delete 'Close' and its separator from the system menu Changing menus Initially, 'Close' and 'Switch to...' in the system menu and 'End Task' in the task list are greyed out and the action bar is disabled. Pressing button 1 enables the action bar, 'Close' and 'End Task' but doesn't allow closure from these options. Exit is via the action bar only. The title is also changed in the task list. Pressing button 2 removes 'Close' from the system menu. Pressing 'Switch Menus' causes a different menu to be loaded which has two options with two items under 'Option 1'. The first is 'checkable' and and the second is 'NODISMISS', until button 1 is clicked. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 8. Windows ═══ This section covers the following topics - Active Errors Modality Movement Parent Position Saving State Size Subclassing Title Sample Program ═══ 8.1. Active ═══ ═══ 8.1.1. Active Window and its Process ID ═══ To determine the active window and get its process ID, first call WinQueryActiveWindow which returns the handle of the active window, and then call WinQueryWindowProcess to get the process ID of that window. For a VIO window or full screen icon this will be the process ID of the shell. The sample code gets the active window's process ID and displays it. ═══ 8.2. Errors ═══ ═══ 8.2.1. Don't Use hwndFrame During WM_CREATE ═══ Don't use hwndFrame during WM_CREATE as it is not assigned until WM_CREATE processing is complete. Instead, use WinQueryWindow to get the client's parent, i.e. the frame handle. ═══ 8.2.2. Window Not Being Displayed ═══ Sometimes when you attempt to create a window it does not display and the return code from WinCreateStdWindow is NULL. The most common cause of this problem is the fact that you have used the frame creation flag of FCF_STANDARD which includes a menu, icon and accelerator resource. If you have not defined one of these then your window does not get created. You should also check that all resources belonging to a frame have the same ID, so check your RC file to ensure, for example, that your menu does not have a different ID to your icon, else the create will fail. See the RC file extract. One other area to look at is your WM_CREATE message. If you return TRUE from this then window creation is discontinued. If, however, the create does not fail, i.e. you receive a valid handle, then the most likely cause is that you do not have the WS_VISIBLE style specified for the window. The default is, in fact, NOT visible. It is also possible that if you are not using WinSetWindowPos you may have omitted the frame creation flag FCF_SHELLPOSITION for the window. ═══ 8.3. Modality ═══ ═══ 8.3.1. System Modal Window ═══ A simple way to trap Alt-Esc and Ctrl-Esc is to make your window system modal, i.e. the user can only interact with your application. This renders the hot keys unusable until you remove system modality for that window. To do this use WinSetSysModalWindow in your WM_CREATE statement. Don't forget that you cannot use hwndFrame at this point. ═══ 8.4. Movement ═══ ═══ 8.4.1. Prohibiting Window Movement ═══ There may be occasions when it is required to prohibit the movement of your main window during the course of your normal processing. This could be achieved by subclassing the frame window, but an easier way of doing it is to call WinEnableWindow. This also greys out Move from the window's system menu. To prohibit movement To restore movement ═══ 8.5. Parent ═══ ═══ 8.5.1. Parent Window ═══ To find a window's parent, for example, your client window's parent, i.e. frame window, call WinQueryWindow. ═══ 8.6. Position ═══ ═══ 8.6.1. Centralising your Window ═══ To centralise your window use WinQuerySysValue to get the screen resolution, calculate the appropriate co-ordinates and call WinSetWindowPos. However, be aware of the prerequisites for starting with a predetermined size. ═══ 8.6.2. Keeping your Child Window on Top ═══ If you have a requirement to keep your child window visible whilst you use your main window, maybe in order to keep your application's status in view or for a tool palette, then make the child window's parent HWND_DESKTOP, and then use WinSetOwner to make the child's owner the application's main window. ═══ 8.6.3. Keeping your Main Window on Top ═══ Sometimes it may be necessary to keep your window in view at all times, i.e. on top of all other windows. A very simple way of doing this is to start a timer and in your WM_TIMER message processing for your client window make a call to WinSetWindowPos using the SWP_ZORDER option. Use WinStopTimer to stop the timer when you close down your application, or before if it is no longer required. ═══ 8.6.4. Positioning on Screens with Different Resolution ═══ If you use absolute values when initialising the size of your window and then run your application on a machine which has a screen of different resolution, you may find that your window overlaps the screen, or appears in an otherwise unexpected position. To overcome this you should not use absolute values but ask the system for the screen dimensions first by using WinQuerySysValue. This will give you back the correct number of pels for the screen you are running under. You can then use these values in WinSetWindowPos to set your window's size and position correctly. As an example, if you wanted your window to occupy the entire screen use the sample code, but make sure you include a frame creation flag of FCF_NOBYTEALIGN when you create your window otherwise it will align on eight pel boundaries and not fit the screen exactly. If you do not wish your window to be this large then of course you can set the ScrWidth and ScrHeight variables to any suitable values and, if necessary centralise it. ═══ 8.6.5. Restoring to a Fixed Size or Position ═══ If you always want your window to be set to a particular size and/or position when it is restored then you can use the WinSetWindowUShort function with the relevant QWS_*RESTORE value(s) in your WM_MINMAXFRAME case statement. o QWS_XRESTORE - The X coordinate of the position to which the window is restored o QWS_YRESTORE - The Y coordinate of the position to which the window is restored o QWS_CXRESTORE - The width to which the window is restored o QWS_CYRESTORE - The height to which the window is restored ═══ 8.6.6. Starting in the Background ═══ To start with your window in the background so that it doesn't take the focus away from you use WinSetWindowPos with Behind set to HWND_BOTTOM and SWP_ZORDER as one of the options. ═══ 8.6.7. Starting with a Predetermined Window Size and Position ═══ If you do not wish your window size and position to be set by Presentation Manager then in your WinCreateStdWindow call do not specify the style WS_VISIBLE, and do not specify the frame creation flag FCF_SHELLPOSITION. Instead, follow your WinCreateStdWindow call with a call to WinSetWindowPos. Ensure that you always use SWP_SIZE | SWP_MOVE on the WinSetWindowPos call otherwise your size and start position will not be honoured. Also, use SWP_ACTIVATE to give your window the focus. Note: A common mistake in this area is to use FCF_SHELLPOSITION, which is included with FCF_STANDARD, and trap the WM_CREATE message with the aim of resizing the window. But, Presentation Manager acts on the FCF_SHELLPOSITION after the WM_CREATE message and so your size and position is overwritten. ═══ 8.7. Saving State ═══ ═══ 8.7.1. Saving your Application's Current State ═══ If you have a requirement to save your application's current state of execution then you can make use of the WM_SAVEAPPLICATION message. This message gets dispatched to your client window procedure when the user requests Save... from the Desktop Manager. You may want to save several different types of data but probably the most common is the window's size and position on the desktop. The sample code shows how to save the application's size and position in OS2.INI and restore next time it starts. ═══ 8.8. Size ═══ ═══ 8.8.1. Controlling Window Size ═══ Presentation Manager will not allow the user to size a window smaller than about 3.5 centimetres wide (using 8514/A). If you have a requirement to do this then you must subclass the frame of the standard window and process the WM_QUERYTRACKINFO message. You can, of course, extend this to ensure that your window is always square, or never smaller or greater than a certain size. ═══ 8.8.2. Detecting Minimize/Maximize ═══ To check if your window is about to be minimized or maximized then trap your WM_MINMAXFRAME message. ═══ 8.8.3. Minimizing your Window ═══ If you need to minimize your window automatically from your client's window procedure call WinSetWindowPos. ═══ 8.8.4. Obtaining Window Size ═══ To obtain the size of a window use the WinQueryWindowRect function. For top-level windows this will return the values in screen coordinates. For child windows the coordinates will be in parent coordinates. If you need to query the screen coordinates of child windows, which your client area is (child of FRAME), follow the WinQueryWindowRect call with a call to WinMapWindowPoints. ═══ 8.8.5. Prohibiting Window Minimization/Maximization ═══ To prevent the user from minimizing or maximizing your window, assuming you have FCF_MINMAX defined for the window, use WinEnableWindow with FALSE. To allow it again use TRUE. ═══ 8.8.6. Prohibiting Window Sizing ═══ There may be occasions when it is required to prohibit the sizing of your main window during the course of your normal processing. This can be achieved by changing the window's style from FS_SIZEBORDER to FS_DLGBORDER using WinSetWindowULong. This also greys out Size from the window's system menu. Another way of doing this is to use WinSetWindowBits. You will also need a call to WinInvalidateRect to ensure the frame is updated immediately. To prohibit sizing using WinSetWindowULong To restore sizing using WinSetWindowULong To prohibit sizing using WinSetWindowBits To restore sizing using WinSetWindowBits ═══ 8.8.7. Restoring to a Fixed Size or Position ═══ If you always want your window to be set to a particular size and/or position when it is restored then you can use the WinSetWindowUShort function with the relevant QWS_*RESTORE value(s) in your WM_MINMAXFRAME case statement. o QWS_XRESTORE - The X coordinate of the position to which the window is restored o QWS_YRESTORE - The Y coordinate of the position to which the window is restored o QWS_CXRESTORE - The width to which the window is restored o QWS_CYRESTORE - The height to which the window is restored ═══ 8.8.8. Starting Minimized or Maximized ═══ To create a window in its minimized or maximized state use SWP_MINIMIZE or SWP_MAXIMIZE respectively in your WinSetWindowPos call. ═══ 8.8.9. Starting with a Predetermined Window Size and Position ═══ If you do not wish your window size and position to be set by Presentation Manager then in your WinCreateStdWindow call do not specify the style WS_VISIBLE, and do not specify the frame creation flag FCF_SHELLPOSITION. Instead, follow your WinCreateStdWindow call with a call to WinSetWindowPos. Ensure that you always use SWP_SIZE | SWP_MOVE on the WinSetWindowPos call otherwise your size and start position will not be honoured. Also, use SWP_ACTIVATE to give your window the focus. Note: A common mistake in this area is to use FCF_SHELLPOSITION, which is included with FCF_STANDARD, and trap the WM_CREATE message with the aim of resizing the window. But, Presentation Manager acts on the FCF_SHELLPOSITION after the WM_CREATE message and so your size and position is overwritten. ═══ 8.9. Subclassing ═══ For examples of subclassing see - Controlling Window Size Numeric Data Only ═══ 8.10. Title ═══ ═══ 8.10.1. Changing the Window Title ═══ To change the window title use WinSetWindowText. ═══ 8.10.2. EXE Name Appearing in Title Bar ═══ This happens because you have specified FCF_TASKLIST for your window. See Adding Program Title to the Task List. ═══ 8.11. Sample Programs ═══ ═══ 8.11.1. Skeleton Program ═══ This skeleton program builds a small sizable client window and centralises it on the desktop. It contains an action bar with an Exit option, minimize, maximize and the system menu. I have used this as the base for all the other sample programs. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 8.11.2. Sample Program - Windows ═══ The sample program does not have any real function but was written just to test that all the tips in this section do work. However, as it currently stands it does not incorporate all the tips as some are obviously mutually exclusive. Having said that though, it does open the main client window at the restored position and the child window to its right. The main window displays the process ID of the active window and the child window just displays a text string. If you press button 1 in the main window it becomes fixed, i.e. you cannot move or size it, the minimize and maximize buttons are disabled and the title text is changed. Pressing button 2 returns it to its moveable state. HINTS.C - C source file HINTS.H - Header file HINTS.L - Link control file HINTS.DEF - Module definition file HINTS.RC - Resource file HINTS - Make file Run program (Launch doesn't work in 1.3 yet!) ═══ 9. Sample Programs ═══ The following programs were written purely to verify all the tips given in this volume. The programs themselves do not have any function other than to perform this verification, usually by pressing a mouse button or push button. Skeleton Program General Window Processing General Dialog Box Processing MLE and Radio Buttons Listboxes Menus and Task Manager Mouse and Pointer Control Presentation Parameters ═══ ═══ CONTROL "", ID_ENTRY2, 67, 57, 36, 8, WC_ENTRYFIELD, ES_LEFT | ES_MARGIN | WS_TABSTOP | WS_VISIBLE CTLDATA 8, 5, 0, 0 ═══ ═══ /*---------------------------*/ /* Change focus to ID_ENTRY2 */ /*---------------------------*/ WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, ID_ENTRY2)); /*------------------------------------------------*/ /* Position cursor between 1st and 2nd characters */ /*------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(1, 1), 0L); /*------------------------------------------------*/ /* Position cursor between 1st and 2nd characters */ /* but mark 2nd and 3rd characters only */ /*------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(1, 3), 0L); /*---------------------------------------------------------*/ /* Position cursor at start of field but mark entire field */ /*---------------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(0, 5), 0L); ═══ ═══ CONTROL "", ID_PASSWORD, 77, 37, 45, 8, WC_ENTRYFIELD, ES_LEFT | ES_UNREADABLE | ES_MARGIN | WS_TABSTOP | WS_VISIBLE ═══ ═══ /*-----------------------------------------------*/ /* This code sets the password length to 8 bytes */ /*-----------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_PASSWORD), EM_SETTEXTLIMIT, MRFROMSHORT(8), NULL); ═══ ═══ /*---------------------------------------------*/ /* First define your numeric procedure and a */ /* pointer to the public entry field procedure */ /*---------------------------------------------*/ typedef struct _CHARMSG *PCHARMSG; // Not defined in PMWIN.H MRESULT EXPENTRY NumericProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2); PFNWP EntryFieldProc; // Public Entry Field procedure /*---------------------------------------------*/ /* In your WM_INITDLG case statement save the */ /* address of the public entry field procedure */ /*---------------------------------------------*/ case WM_INITDLG: EntryFieldProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_ENTRY2), NumericProc); /*----------------------------------------------*/ /* The following is the actual window procedure */ /*----------------------------------------------*/ MRESULT EXPENTRY NumericProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 ) { PCHARMSG p; if (msg == WM_CHAR) // If this is a char msg { p = CHARMSG(&msg); // Address char structure if ((p->fs & (KC_KEYUP|KC_CHAR)) == KC_CHAR) // ONLY key down transitions */ { if ((p->chr < 0x30 || p->chr > 0x39) && // Not numeric (p->chr != 8) && // Not backspace (p->chr != 9) && // Not tab (p->chr != 0x2D) && // Not - (p->chr != 13)) // Not enter { WinAlarm(HWND_DESKTOP, WA_WARNING); return (MRESULT)TRUE; } } } // Call public entry field procedure return ((*EntryFieldProc)(hwnd, msg, mp1, mp2)); } ═══ ═══ /*----------------------------------*/ /* Get password and store in szPswd */ /*----------------------------------*/ WinQueryWindowText(WinWindowFromID(hwndDlg, ID_PASSWORD), sizeof(szPswd), szPswd); ═══ ═══ /*----------------------------------*/ /* Get password and store in szPswd */ /*----------------------------------*/ WinQueryDlgItemText(hwndDlg, ID_PASSWORD, sizeof(szPswd), szPswd); ═══ ═══ /*----------------------------------*/ /* Get window ID and store in id */ /* FALSE for unsigned value */ /* TRUE for possible signed value */ /*----------------------------------*/ WinQueryDlgItemShort(hwndDlg, ID_ENTRY1, &id, FALSE); ═══ ═══ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY1), EM_SETREADONLY, (MPARAM)TRUE, NULL); ═══ ═══ CONTROL "", ID_ENTRY1, 77, 25, 100, 16, WC_ENTRYFIELD, ES_CENTER | ES_AUTOSCROLL | ES_MARGIN | ES_READONLY | WS_VISIBLE ═══ ═══ WinSetWindowText(WinWindowFromID(hwndDlg, ID_ENTRY1), "Text"); /*---------------------------------------------------*/ /* To clear an entry field write a null string to it */ /*---------------------------------------------------*/ WinSetWindowText(WinWindowFromID(hwndDlg, ID_ENTRY1), ""); ═══ ═══ WinSetDlgItemText(hwndDlg, ID_ENTRY1, "Text"); /*---------------------------------------------------*/ /* To clear an entry field write a null string to it */ /*---------------------------------------------------*/ WinSetDlgItemText(hwndDlg, ID_ENTRY1, ""); ═══ ═══ WinSetDlgItemShort(hwndDlg, ID_ENTRY1, id, FALSE); ═══ ═══ CHAR *Country, *Capital; case WM_CONTROL: switch(SHORT1FROMMP(mp1)) { case ID_OLISTBOX: switch(SHORT2FROMMP(mp1)) { case LN_SELECT: Oidx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYSELECTION, 0L, 0L); WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Oidx, sizeof(szListBuff)), MPFROMP(szListBuff)); Country = strtok(szListBuff, "\t"); Capital = strtok(NULL, "\t"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, Capital); WinSetDlgItemText(hwndDlg, ID_ENTRY2, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY3, Country); break; default: break; } break; } ═══ ═══ hwndList = WinWindowFromID(hwndDlg, ID_SLISTBOX); WinDestroyWindow(WinWindowFromID(hwndList, 0xC001)); ═══ ═══ case WM_MEASUREITEM: if (first) { strcpy(font, "24.Helv"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_OLISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); first = FALSE; } hps = WinGetPS(WinWindowFromID(hwndDlg, ID_OLISTBOX)); ; ; ; WinReleasePS(hps); return MRFROM2SHORT(cyText, cxText); ═══ ═══ pDB_Data = (PDBDATA)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMHANDLE, MPFROMSHORT(Idx), NULL); DosFreeSeg(SELECTOROF(pDB_Data)); ═══ ═══ /*----------------------------------------------------------*/ /* By default the start position for drawing in the item */ /* rectangle is 1 so if we have been scrolled then xLeft on */ /* input will be some other value depending on how much we */ /* have been scrolled. All we need to do to allow scrolling */ /* is adjust xLeft by the scrolled amount. */ /*----------------------------------------------------------*/ if (pOwner->rclItem.xLeft != 1) rc.xLeft = rc.xRight + pOwner->rclItem.xLeft - 1; else rc.xLeft = rc.xRight; ═══ ═══ ULONG KeyValue; /*------------------------------------------------*/ /* If all we want to do is store the key value... */ /*------------------------------------------------*/ for (Idx = 0; Idx < 26; Idx++) { WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szCountry[Idx])); /*----------------------------------------*/ /* szCountry and KeyValue would normally */ KeyValue = Idx + 1; /* be obtained from a database. */ /* In this case give a key value of 1->26 */ /*----------------------------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SETITEMHANDLE, (MPARAM)Idx, (MPARAM)KeyValue); } /*------------------------------------------------*/ /* If we need to save a pointer to a structure... */ /*------------------------------------------------*/ SEL sel; typedef struct _DBDATA { USHORT Key; CHAR Capital[20]; } DBDATA, FAR *PDBDATA; PDBDATA pDB_Data; for (Idx = 0; Idx < 26; Idx++) { WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szCountry[Idx])); DosAllocSeg(22, &sel, 0); pDB_Data = MAKEP(sel, 0); pDB_Data->Key = Idx + 1; strcpy(pDB_Data->Capital, szCapital[Idx]); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SETITEMHANDLE, (MPARAM)Idx, MPFROMP(pDB_Data)); } ═══ ═══ /*--------------------------------------------*/ /* If we are just retrieving the key value... */ /*--------------------------------------------*/ case LN_SELECT: Idx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYSELECTION, 0L, 0L); /*---------------------------------*/ if (Idx != LIT_NONE) /* If nothing selected then ignore */ { /*---------------------------------*/ KeyValue = (ULONG)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMHANDLE, MPFROMSHORT(Idx), NULL); WinSetDlgItemShort(hwndDlg, ID_ENTRY2, (SHORT)KeyValue, FALSE); ; ; ; } break; /*--------------------------------------------------------------*/ /* Or, to retrieve all data associated with the listbox item... */ /*--------------------------------------------------------------*/ case LN_SELECT: Idx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYSELECTION, 0L, 0L); /*---------------------------------*/ if (Idx != LIT_NONE) /* If nothing selected then ignore */ { /*---------------------------------*/ pDB_Data = (PDBDATA)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMHANDLE, MPFROMSHORT(Idx), NULL); WinSetDlgItemText(hwndDlg, ID_ENTRY1, pDB_Data->Capital); WinSetDlgItemShort(hwndDlg, ID_ENTRY2, (SHORT)pDB_Data->Key, FALSE); ; ; ; } break; ═══ ═══ SHORT Idx; /*----------------------*/ /* Delete selected item */ /*----------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_DELETEITEM, MPFROMSHORT(Idx), NULL); ═══ ═══ /*------------------*/ /* Delete all items */ /*------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_DELETEALL, NULL, NULL); ═══ ═══ /*------------------*/ /* Deselect an item */ /*------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SELECTITEM, MPFROMSHORT(Idx), (MPARAM)FALSE); ═══ ═══ SHORT Idx; static PSZ szCountry[] = {"Austria", "Belgium", "Canada", "Denmark", "Egypt", "Finland", "Greece", "Hungary", "India", "Japan", "Kenya", "Libya", "Morocco", "Nigeria", "Oman", "Peru", "Qatar", "Romania", "Spain", "Turkey", "Uruguay", "Venezuela", "Wales", "Xanxere", "Yemen", "Zambia"}; for (Idx = 0; Idx < 26; Idx++) { WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szCountry[Idx])); } ═══ ═══ SHORT Midx; case ID_PROCMULT: Midx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, //Get first LM_QUERYSELECTION, (MPARAM)LIT_FIRST, 0L); while(Midx != LIT_NONE) { WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_QUERYITEMTEXT, // Get its text MPFROM2SHORT(Midx, sizeof(szCtry)), MPFROMP(szCtry)); WinSetDlgItemText(hwndDlg, ID_ENTRY3, szCtry); // Display it WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_SELECTITEM, // Deselect it MPFROMSHORT(Midx), (MPARAM)FALSE); /*----------------------------------*/ /* Slow down so we can see it happen*/ /* */ DosSleep(1000L); /* DON'T DO THIS IN PM PROGRAMS */ /* AFFECTS PERFORMANCE SEVERELY */ /*----------------------------------*/ Midx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, // Get next LM_QUERYSELECTION, (MPARAM)Midx, 0L); } WinSetDlgItemText(hwndDlg, ID_ENTRY3, "Done"); // All done return FALSE; ═══ ═══ /*-------------------*/ /* Select first item */ /*-------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SELECTITEM, MPFROMSHORT(0), (MPARAM)TRUE); ═══ ═══ SHORT Idx; CHAR szCtry[10]; case WM_CONTROL: switch(SHORT1FROMMP(mp1)) { case ID_SLISTBOX: switch(SHORT2FROMMP(mp1)) { case LN_SELECT: Idx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYSELECTION, 0L, 0L); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Idx, sizeof(szCtry)), MPFROMP(szCtry)); ; ; ; break; default: break; } break; } ═══ ═══ case WM_DRAWITEM: ; ; ; if ((!pOwner->fsState) || // Unselected (pOwner->idItem == 5)) // Don't allow Finland { GpiSetBackColor(pOwner->hps, CLR_DARKGREEN); GpiSetColor(pOwner->hps, CLR_YELLOW); } else // Selected { GpiSetBackColor(pOwner->hps, CLR_YELLOW); GpiSetColor(pOwner->hps, CLR_DARKGREEN); } ; ; ; pOwner->fsStateOld = pOwner->fsState = 0; // Don't let PM hilite return (MRESULT)TRUE; // Don't let PM draw ═══ ═══ /*-----------------------------------------------------------------*/ /* The scroll bar ID for a listbox's vertical scroll bar is 0xC001 */ /* and for a horizontal scroll bar is 0xC002. */ /* This is, however, undocumented so use with caution. */ /*-----------------------------------------------------------------*/ hwndVbar = WinWindowFromID(hwndListbox, 0xC001); hwndHbar = WinWindowFromID(hwndListbox, 0xC002); /*-----------------------------------------------------------------*/ /* Alternatively, enumerate the listbox's windows. This way it */ /* doesn't matter if the scroll bar IDs change in a later release. */ /*-----------------------------------------------------------------*/ hwndListbox = WinWindowFromID(hwndDlg, ID_SLISTBOX); hEnum = WinBeginEnumWindows(hwndListbox); while (hwndChild = WinGetNextWindow(hEnum)) { /*------------------------------*/ /* SBS_VERT = 1L, SBS_HORZ = 0L */ /*------------------------------*/ if (WinQueryWindowULong(hwndChild, QWL_STYLE) & SBS_VERT) hwndVbar = hwndChild; else hwndHbar = hwndChild; } WinEndEnumWindows(hEnum); ═══ ═══ CHAR *Country, *Capital; case WM_INITDLG: ; ; for (Idx = 0; Idx < 26; Idx++) { strcpy(szListBuff, szCountry[Idx]); strcat(szListBuff, "\t"); // Insert a TAB character strcat(szListBuff, szCapital[Idx]); WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szListBuff)); } ; ; break; case WM_DRAWITEM: pOwner = (POWNERITEM)mp2; rc.xRight = pOwner->rclItem.xRight/2; // Split into two and draw rc.xLeft = pOwner->rclItem.xLeft; // item in left rectangle rc.yTop = pOwner->rclItem.yTop; rc.yBottom = pOwner->rclItem.yBottom; GpiSetBackMix(pOwner->hps, BM_OVERPAINT); if (!pOwner->fsState) // Unselected { GpiSetBackColor(pOwner->hps, CLR_DARKGREEN); GpiSetColor(pOwner->hps, CLR_YELLOW); } else // Selected { GpiSetBackColor(pOwner->hps, CLR_YELLOW); GpiSetColor(pOwner->hps, CLR_DARKGREEN); } WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(pOwner->idItem, sizeof(szListBuff)), MPFROMP(szListBuff)); Country = strtok(szListBuff, "\t"); Capital = strtok(NULL, "\t"); WinDrawText(pOwner->hps, strlen(Country), Country, &rc, 0L, 0L, DT_LEFT | DT_TEXTATTRS | DT_ERASERECT); rc.xLeft = rc.xRight; // Draw next item in right rectangle rc.xRight = pOwner->rclItem.xRight; WinDrawText(pOwner->hps, strlen(Capital), Capital, &rc, 0L, 0L, DT_LEFT | DT_TEXTATTRS | DT_ERASERECT); ; ; ; break; ═══ ═══ POINTL points[TXTBOX_COUNT]; case WM_MEASUREITEM: ; ; ; WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Idx, sizeof(szListBuff)), MPFROMP(szListBuff)); GpiQueryTextBox(hps, (LONG)strlen(szListBuff), szListBuff, TXTBOX_COUNT, points); /*-------------------------------------------------*/ /* May need to add on a bit to cxText to ensure */ /* the entire item can be read when fully scrolled */ /*-------------------------------------------------*/ cxText = (USHORT)points[TXTBOX_TOPRIGHT].x + 20; ; ; ; return MRFROM2SHORT(cyText, cxText); ═══ ═══ POWNERITEM pOwner; RECTL rc; case WM_DRAWITEM: pOwner = (POWNERITEM)mp2; rc.xRight = pOwner->rclItem.xRight; rc.xLeft = pOwner->rclItem.xLeft; rc.yTop = pOwner->rclItem.yTop; rc.yBottom = pOwner->rclItem.yBottom; GpiSetBackMix(pOwner->hps, BM_OVERPAINT); if (!pOwner->fsState) // Unselected { GpiSetBackColor(pOwner->hps, CLR_DARKGREEN); GpiSetColor(pOwner->hps, CLR_YELLOW); } else // Selected { GpiSetBackColor(pOwner->hps, CLR_YELLOW); GpiSetColor(pOwner->hps, CLR_DARKGREEN); } WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(pOwner->idItem, sizeof(szListBuff)), MPFROMP(szListBuff)); WinDrawText(pOwner->hps, strlen(szListBuff), szListBuff, &rc, 0L, 0L, DT_CENTER | DT_TEXTATTRS | DT_ERASERECT); pOwner->fsStateOld = pOwner->fsState = 0; // Don't let PM hilite return (MRESULT)TRUE; // Don't let PM draw ═══ ═══ HPS hps; FONTMETRICS fm; SHORT cxText, cyText; case WM_MEASUREITEM: hps = WinGetPS(WinWindowFromID(hwndDlg, ID_OLISTBOX)); GpiQueryFontMetrics(hps, (LONG)sizeof(FONTMETRICS), &fm); cyText = (SHORT)fm.lMaxBaselineExt; cxText = 0; WinReleasePS(hps); return MRFROM2SHORT(cyText, cxText); ═══ ═══ WinSetDlgItemText(hwndDlg, ID_MULTILINE, ""); ═══ ═══ WinSetWindowText(WinWindowFromID(hwndDlg, ID_MULTILINE), ""); ═══ ═══ DosAllocSeg(0, &Selector, SEG_GETTABLE); // Allocate 64K segment Buffer = MAKEP(Selector, 0); // Get pointer to segment DosOpen("C:\\CONFIG.SYS", &hFile, &Action, (ULONG)NULL, (USHORT)NULL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, (ULONG)NULL); DosRead(hFile, Buffer, 65535L, &BytesRead); DosClose(hFile); WinSendMsg(WinWindowFromID(hwndDlg, ID_MULTILINE), MLM_SETIMPORTEXPORT, (MPARAM)Buffer, MPFROMLONG(65535L)); ipt = -1; // Set insertion point for current cursor position WinSendMsg(WinWindowFromID(hwndDlg, ID_MULTILINE), MLM_IMPORT, (MPARAM)&ipt, MPFROMLONG((LONG)BytesRead)); DosFreeSeg(Selector); ═══ ═══ CHAR font[11]; /*-------------------------*/ /* To set 12 point Courier */ /*-------------------------*/ strcpy(font, "12.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); /*--------------------------*/ /* To set 8 point Helvetica */ /*--------------------------*/ strcpy(font, "8.Helv"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); ═══ ═══ BITMAP ID_LOCK lock.bmp ═══ ═══ /*-------------------------------*/ /* Define button paint procedure */ /*-------------------------------*/ VOID Button_Paint(HWND, HPS, USHORT); /*------------------------------------*/ /* Define pointer to button structure */ /*------------------------------------*/ USERBUTTON *ubtn; /*-----------------------------*/ /* Handle the BN_PAINT message */ /*-----------------------------*/ case WM_CONTROL: switch(HIUSHORT(mp1)) { case BN_PAINT: switch(LOUSHORT(mp1)) /* Which Button? */ { case ID_USERBUTTON: ubtn = (USERBUTTON *)mp2; Button_Paint(ubtn->hwnd, ubtn->hps, ubtn->fsState); return (MRESULT)TRUE; default: break; } } break; /*------------------------*/ /* Handle the button push */ /*------------------------*/ case WM_COMMAND: switch(SHORT1FROMMP(mp1)) { ; ; ; case ID_USERBUTTON: DosBeep(500, 100); return FALSE; ; ; ; /*------------------------*/ /* Button paint procedure */ /*------------------------*/ VOID Button_Paint(HWND hwnd, HPS hps, USHORT Status) { RECTL DestPt; HBITMAP hbm; /*------------------------------------------------------------------------*/ /* Display the disk drive bitmap */ /* */ /* hbm = WinGetSysBitmap(HWND_DESKTOP, SBMP_DRIVE); */ /* WinQueryWindowRect(hwnd, &DestPt); */ /* WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&DestPt, CLR_YELLOW, CLR_BLACK, */ /* (Status ? DBM_INVERT : DBM_NORMAL) | DBM_STRETCH); */ /*------------------------------------------------------------------------*/ /*---------------------------------*/ /* Load and display our own bitmap */ /*---------------------------------*/ hbm = GpiLoadBitmap(hps, NULL, ID_LOCK, 0L, 0L); WinQueryWindowRect(hwnd, &DestPt); WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&DestPt, 0L, 0L, (Status ? DBM_INVERT : DBM_NORMAL) | DBM_STRETCH); } ═══ ═══ ULONG lStyle; lStyle = WinQueryWindowULong(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE); if (lStyle & BS_DEFAULT) { /*-----------------------*/ /* Button is the default */ /*-----------------------*/ } ═══ ═══ /*----------------------*/ /* Remove default style */ /*----------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_OK), BM_SETDEFAULT, (MPARAM)FALSE, NULL); /*-------------------*/ /* Set default style */ /*-------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_OK), BM_SETDEFAULT, (MPARAM)TRUE, NULL); ═══ ═══ /*----------------------*/ /* Remove default style */ /*----------------------*/ WinSetWindowBits(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE, 0L, BS_DEFAULT); WinInvalidateRect(WinWindowFromID(hwndDlg, ID_OK), NULL, FALSE); /*-------------------*/ /* Set default style */ /*-------------------*/ WinSetWindowBits(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE, BS_DEFAULT, BS_DEFAULT); WinInvalidateRect(WinWindowFromID(hwndDlg, ID_OK), NULL, FALSE); ═══ ═══ /*-----------------------------*/ /* Change the dialog box title */ /*-----------------------------*/ WinSetWindowText(hwndDlg, "New Title"); ═══ ═══ /*-----------------------------*/ /* Change the dialog box title */ /*-----------------------------*/ WinSetDlgItemText(hwndDlg, FID_TITLEBAR, "New Title"); ═══ ═══ /*----------------------------------------*/ /* Change the text of push button ID_EXIT */ /*----------------------------------------*/ WinSetWindowText(WinWindowFromID(hwndDlg, ID_EXIT), "Quit"); ═══ ═══ /*---------------*/ /* To disable... */ /*---------------*/ WinEnableWindow(WinWindowFromID(hwndDlg, ID_DELETE), FALSE); /*--------------*/ /* To enable... */ /*--------------*/ WinEnableWindow(WinWindowFromID(hwndDlg, ID_DELETE), TRUE); ═══ ═══ USHORT id; /*---------------------------------*/ /* Find ID of the control ID_ENTRY */ /*---------------------------------*/ id = WinQueryWindowUShort(WinWindowFromID(hwndDlg, ID_ENTRY), QWS_ID); ═══ ═══ /*-------------------------------------------------------*/ /* For the information icon (white 'i' in a blue circle) */ /*-------------------------------------------------------*/ CONTROL "#11", SPTR_ICONINFORMATION, 5, 35, 22, 16, WC_STATIC, SS_SYSICON | WS_VISIBLE /*------------------------------------------------------------------*/ /* For the warning icon (black exclamation mark in a yellow circle) */ /*------------------------------------------------------------------*/ CONTROL "#14", SPTR_ICONWARNING, 5, 35, 22, 16, WC_STATIC, SS_SYSICON | WS_VISIBLE ═══ ═══ static HWND hABar; case WM_INITDLG: ; ; ; hABar = WinLoadMenu(hwndDlg, NULL, ID_MENU); WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM)FID_MENU, (MPARAM)NULL); ; return (MRESULT)TRUE; /* Needed if we have changed focus */ break; ═══ ═══ WinSetWindowText(WinWindowFromID(hwndDlg, ID_LBREAK), "Line 1\012Line 2\012Line 3"); ═══ ═══ hDlg = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, DLG_HINTS, NULL); WinProcessDlg(hDlg); ═══ ═══ hab = WinInitialize(NULL); hmq = WinCreateMsgQueue(hab, 0); WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, DLG_HINTS, NULL); WinDestroyMsgQueue(hmq); WinTerminate(hab); ═══ ═══ static HWND hDlgBoxIcon; case WM_INITDLG: hDlgBoxIcon = WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); WinDefDlgProc(hwndDlg, WM_SETICON, (MPARAM)hDlgBoxIcon, (MPARAM)0); ; ; ; return (MRESULT)TRUE; /* Needed if we have changed focus */ break; case WM_ADJUSTWINDOWPOS: if (((PSWP)mp1)->fs & SWP_MINIMIZE) // Being minimized { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), FALSE); } else if (((PSWP)mp1)->fs & SWP_RESTORE) // Being restored { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), TRUE); } return WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; case ID_EXIT: WinDestroyPointer(hDlgBoxIcon); ; ; ; break; ═══ ═══ SHORT X_Left, Y_Bot; LONG ScreenHeight, ScreenWidth; case WM_INITDLG: /*----------------------------------------*/ /* This code will ensure that your dialog */ /* box is centred on the desktop. */ /*----------------------------------------*/ ScreenWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScreenHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); WinQueryWindowRect(hwndDlg, &rc); X_Left = (SHORT)(ScreenWidth - rc.xRight) / 2; Y_Bot = (SHORT)(ScreenHeight - rc.yTop) / 2; WinSetWindowPos(hwndDlg, HWND_TOP, X_Left, Y_Bot, 0, 0, SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); /*---------------------------------------------------------------------*/ /* If you want to start minimized, then use the following */ /* */ /* WinSetWindowPos(hwndDlg, HWND_TOP, X_Left, Y_Bot, 0, 0, */ /* SWP_MOVE | SWP_SHOW | SWP_ACTIVATE | SWP_MINIMIZE); */ /*---------------------------------------------------------------------*/ ; ; return (MRESULT)TRUE; /* Needed if we have changed focus */ break; ═══ ═══ MENU ID_MENU PRELOAD BEGIN SUBMENU "~Options", ID_OPTIONS BEGIN MENUITEM "Test ~1", ID_TEST1 MENUITEM "Test ~2", ID_TEST2 MENUITEM "Test ~3", ID_TEST3 END END ═══ ═══ /*---------------------------------------*/ /* Set the focus to entry field ID_ENTRY */ /*---------------------------------------*/ case WM_INITDLG: WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, ID_ENTRY)); ; ; ; return (MRESULT)TRUE; /* Needed if we have changed focus */ break; ═══ ═══ CONTROL "This is a status line", ID_STATUS, 0, 0, 185, 8, WC_STATIC, SS_TEXT | DT_CENTER | DT_TOP | WS_GROUP | WS_VISIBLE ═══ ═══ WinSetWindowText(WinWindowFromID(hwndDlg, ID_STATUS), szNewStatus); ═══ ═══ HPS hps; RECTL rc; case WM_PAINT: WinDefDlgProc(hwndDlg, msg, mp1, mp2); hps = WinGetPS(hwndDlg); WinQueryWindowRect(hwndDlg, &rc); WinCalcFrameRect(hwndDlg, &rc, TRUE); rc.yTop = rc.yBottom + WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); WinDrawText(hps, -1, "Status = OK", &rc, CLR_YELLOW, CLR_DARKGREEN, DT_CENTER | DT_VCENTER | DT_ERASERECT); WinReleasePS(hps); break; ═══ ═══ ULONG Colour; case WM_INITDLG: Colour = CLR_DARKGREEN; WinSetPresParam(WinWindowFromID( hwndDlg, ID_STATUS ), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); Colour = CLR_YELLOW; WinSetPresParam(WinWindowFromID( hwndDlg, ID_STATUS ), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); ; ; ; return (MRESULT)TRUE; /* If changing focus during initialisation */ break; ═══ ═══ /*---------------------------*/ /* Get handle of entry field */ /*---------------------------*/ hEntry = WinWindowFromID(hwndDlg, ID_ENTRY2); /*-----------------------------*/ /* Change its style to centred */ /*-----------------------------*/ WinSetWindowULong(hEntry, QWL_STYLE, WinQueryWindowULong(hEntry, QWL_STYLE ) | ES_CENTER); ═══ ═══ /*----------------------*/ /* To remove WS_TABSTOP */ /*----------------------*/ hButton = WinWindowFromID(hwndDlg, ID_EXIT); WinSetWindowULong(hButton, QWL_STYLE, WinQueryWindowULong(hButton, QWL_STYLE ) & ~WS_TABSTOP); /*-------------------*/ /* To add WS_TABSTOP */ /*-------------------*/ hButton = WinWindowFromID(hwndDlg, ID_EXIT); WinSetWindowULong(hButton, QWL_STYLE, WinQueryWindowULong(hButton, QWL_STYLE ) | WS_TABSTOP); ═══ ═══ #define INCL_WIN #include #include #include "hints.h" typedef struct _CHARMSG *PCHARMSG; MRESULT EXPENTRY DlgProc(HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY NumericProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2); VOID Button_Paint(HWND, HPS, USHORT); PFNWP EntryFieldProc; // Public Entry Field procedure /******************************************************************************/ VOID cdecl main() { HAB hab; HMQ hmq; HWND hDlg; hab = WinInitialize(NULL); hmq = WinCreateMsgQueue(hab, 0); WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, DLG_HINTS, NULL); /*--------------------------------------------------------------*/ /* hDlg = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, */ /* DLG_HINTS, NULL); */ /* WinProcessDlg(hDlg); */ /*--------------------------------------------------------------*/ WinDestroyMsgQueue(hmq); WinTerminate(hab); } /******************************************************************************/ MRESULT EXPENTRY DlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2) { static HWND hDlgBoxIcon, hwndEntry, hABar, hMenu; HWND hButton, hEntry, hPwd; static BOOL NewTitle = FALSE; static ULONG MenuHt; ULONG Colour, val, lStyle; SWCNTRL PgmEntry; POINTL Pt; USHORT id; HPS hps; RECTL rc; SHORT X_Left, Y_Bot; LONG ScreenHeight, ScreenWidth; CHAR szPswd[9]; USERBUTTON *ubtn; //============================================================================= switch (msg) { case WM_INITDLG: EntryFieldProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_ENTRY2), NumericProc); WinSendMsg(WinWindowFromID(hwndDlg, ID_PASSWORD), EM_SETTEXTLIMIT, MRFROMSHORT(8), NULL); WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY1), EM_SETREADONLY, (MPARAM)TRUE, NULL); hDlgBoxIcon = WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); WinDefDlgProc(hwndDlg, WM_SETICON, (MPARAM)hDlgBoxIcon, (MPARAM)0); WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, ID_ENTRY2)); hABar = WinLoadMenu(hwndDlg, NULL, ID_MENU); WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM)FID_MENU, (MPARAM)NULL); hMenu = WinLoadMenu(hwndDlg, NULL, ID_MENU2); MenuHt = WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); Colour = CLR_DARKGREEN; WinSetPresParam(WinWindowFromID( hwndDlg, ID_STATUS ), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); Colour = CLR_YELLOW; WinSetPresParam(WinWindowFromID( hwndDlg, ID_STATUS ), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); ScreenWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScreenHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); WinQueryWindowRect(hwndDlg, &rc); /*---------------*/ X_Left = (SHORT)(ScreenWidth - rc.xRight) / 2; /* Centre window */ Y_Bot = (SHORT)(ScreenHeight - rc.yTop) / 2; /*---------------*/ WinSetWindowPos(hwndDlg, HWND_TOP, X_Left, Y_Bot, 0, 0, SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); PgmEntry.hwnd = hwndDlg; PgmEntry.hwndIcon = hDlgBoxIcon; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, "Hints & Tips"); hwndEntry = WinAddSwitchEntry(&PgmEntry); return (MRESULT)TRUE; break; /*-----------------------------------------------------------------------*/ /* case WM_PAINT: */ /* WinDefDlgProc(hwndDlg, msg, mp1, mp2); */ /* hps = WinGetPS(hwndDlg); */ /* WinQueryWindowRect(hwndDlg, &rc); */ /* WinCalcFrameRect(hwndDlg, &rc, TRUE); */ /* rc.yTop = rc.yBottom + WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); */ /* WinDrawText(hps, -1, "Status = OK", &rc, CLR_YELLOW, CLR_DARKGREEN, */ /* DT_CENTER | DT_VCENTER | DT_ERASERECT); */ /* WinReleasePS(hps); */ /* break; */ /*-----------------------------------------------------------------------*/ case WM_BUTTON2DOWN: Pt.x = MOUSEMSG(&msg)->x; Pt.y = MOUSEMSG(&msg)->y + MenuHt; WinPostMsg(hMenu, MM_STARTMENUMODE, MPFROM2SHORT(TRUE, TRUE), NULL); WinSetWindowPos(hMenu, HWND_TOP, (USHORT)Pt.x, (USHORT)Pt.y, 0, 0, SWP_MOVE | SWP_SHOW); break; case WM_NEXTMENU: return (MRESULT)NULL; case WM_ADJUSTWINDOWPOS: if (((PSWP)mp1)->fs & SWP_MINIMIZE) { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), FALSE); WinShowWindow(WinWindowFromID(hwndDlg, ID_STATUS), FALSE); WinDestroyWindow(hABar); } else if (((PSWP)mp1)->fs & SWP_RESTORE) { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), TRUE); WinShowWindow(WinWindowFromID(hwndDlg, ID_STATUS), TRUE); hABar = WinLoadMenu(hwndDlg, NULL, ID_MENU); WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM)FID_MENU, (MPARAM)NULL); } return WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; case WM_CONTROL: switch(HIUSHORT(mp1)) { case BN_PAINT: switch(LOUSHORT(mp1)) /* Which Button? */ { case ID_USERBUTTON: ubtn = (USERBUTTON *)mp2; Button_Paint(ubtn->hwnd, ubtn->hps, ubtn->fsState); return (MRESULT)TRUE; default: break; } } break; case WM_COMMAND: switch(SHORT1FROMMP(mp1)) { case ID_TEST1: DosBeep(500, 100); return FALSE; case ID_TEST2: DosBeep(1000, 100); return FALSE; case ID_TEST3: DosBeep(1500, 100); return FALSE; case ID_ITEM1: DosBeep(500, 100); return FALSE; case ID_ITEM2: DosBeep(1000, 100); return FALSE; case ID_ITEM3: DosBeep(1500, 100); return FALSE; case ID_ITEM4: DosBeep(2000, 100); return FALSE; case ID_ITEM5: DosBeep(2500, 100); return FALSE; case ID_USERBUTTON: DosBeep(1000, 100); DosBeep(500, 100); return FALSE; case ID_OK: WinSetWindowText(WinWindowFromID(hwndDlg, ID_LBREAK), "Line 1\012Line 2\012Line 3"); if (NewTitle) NewTitle = FALSE; else NewTitle = TRUE; if (NewTitle) { WinSetWindowText(hwndDlg, "Sample Dialog Box with New Title"); /*--------------------------------------------------------*/ /* WinSetDlgItemText(hwndDlg, FID_TITLEBAR, "New Title"); */ /*--------------------------------------------------------*/ WinSetWindowText(WinWindowFromID(hwndDlg, ID_EXIT), "Quit"); WinSetWindowText(WinWindowFromID(hwndDlg, ID_STATUS), "New Status"); hButton = WinWindowFromID(hwndDlg, ID_EXIT); WinSetWindowULong(hButton, QWL_STYLE, WinQueryWindowULong(hButton, QWL_STYLE ) & ~WS_TABSTOP); } else { WinSetWindowText(hwndDlg, "Sample Dialog Box"); WinSetWindowText(WinWindowFromID(hwndDlg, ID_EXIT), "Exit"); WinSetWindowText(WinWindowFromID(hwndDlg, ID_STATUS), "Old Status"); hButton = WinWindowFromID(hwndDlg, ID_EXIT); WinSetWindowULong(hButton, QWL_STYLE, WinQueryWindowULong(hButton, QWL_STYLE ) | WS_TABSTOP); } hEntry = WinWindowFromID(hwndDlg, ID_ENTRY2); WinSetWindowULong(hEntry, QWL_STYLE, WinQueryWindowULong(hEntry, QWL_STYLE ) | ES_CENTER); id = WinQueryWindowUShort(WinWindowFromID(hwndDlg, ID_ENTRY1), QWS_ID); WinSetDlgItemShort(hwndDlg, ID_ENTRY1, id, FALSE); id = WinQueryWindowUShort(WinWindowFromID(hwndDlg, ID_ENTRY2), QWS_ID); WinSetDlgItemShort(hwndDlg, ID_ENTRY2, id, FALSE); WinQueryWindowText(WinWindowFromID(hwndDlg, ID_PASSWORD), sizeof(szPswd), szPswd); WinQueryDlgItemText(hwndDlg, ID_PASSWORD, sizeof(szPswd), szPswd); WinQueryDlgItemShort(hwndDlg, ID_ENTRY1, &id, FALSE); // Unsigned WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwndDlg, ID_ENTRY2)); /*------------------------------------------------*/ /* Position cursor between 1st and 2nd characters */ /*------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(1, 1), 0L); /*------------------------------------------------*/ /* Position cursor between 1st and 2nd characters */ /* and mark 2nd and 3rd */ /*------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(1, 3), 0L); /*---------------------------------------------------------*/ /* Position cursor at start of field and mark entire field */ /*---------------------------------------------------------*/ WinSendMsg(WinWindowFromID(hwndDlg, ID_ENTRY2), EM_SETSEL, MPFROM2SHORT(0, 5), 0L); lStyle = WinQueryWindowULong(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE); if (lStyle & BS_DEFAULT) // Default { DosBeep(100, 200); /*------------------------------------------------------------*/ /* WinSendMsg(WinWindowFromID(hwndDlg, ID_OK), BM_SETDEFAULT, */ /* (MPARAM)FALSE, NULL); */ /*------------------------------------------------------------*/ /*--------------------------------------------------------------*/ /* WinSendMsg(WinWindowFromID(hwndDlg, ID_EXIT), BM_SETDEFAULT, */ /* (MPARAM)TRUE, NULL); */ /*--------------------------------------------------------------*/ WinSetWindowBits(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE, 0L, BS_DEFAULT); WinInvalidateRect(WinWindowFromID(hwndDlg, ID_OK), NULL, FALSE); } else // Not default { DosBeep(1000, 200); /*-----------------------------------------------------------*/ /*WinSendMsg(WinWindowFromID(hwndDlg, ID_OK), BM_SETDEFAULT, */ /* (MPARAM)TRUE, NULL); */ /*-----------------------------------------------------------*/ WinSetWindowBits(WinWindowFromID(hwndDlg, ID_OK), QWL_STYLE, BS_DEFAULT, BS_DEFAULT); WinInvalidateRect(WinWindowFromID(hwndDlg, ID_OK), NULL, FALSE); } return FALSE; case ID_EXIT: WinDestroyPointer(hDlgBoxIcon); WinRemoveSwitchEntry(hwndEntry); WinPostMsg(hwndDlg, WM_QUIT, 0L, 0L); break; default: return FALSE; } WinDismissDlg(hwndDlg, TRUE); /* Removes the dialog box */ break; default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2); } return FALSE; } MRESULT EXPENTRY NumericProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 ) { PCHARMSG p; if (msg == WM_CHAR) // If this is a char msg { p = CHARMSG(&msg); // Address char structure if ((p->fs & (KC_KEYUP|KC_CHAR)) == KC_CHAR) // ONLY key down transitions */ { if ((p->chr < 0x30 || p->chr > 0x39) && // Not numeric (p->chr != 8) && // Not backspace (p->chr != 9) && // Not tab (p->chr != 0x2D) && // Not - (p->chr != 13)) // Not enter { WinAlarm(HWND_DESKTOP, WA_WARNING); return (MRESULT)TRUE; } } } /* Call public entry field procedure */ return ((*EntryFieldProc)(hwnd, msg, mp1, mp2)); } VOID Button_Paint(HWND hwnd, HPS hps, USHORT Status) { RECTL DestPt; HBITMAP hbm; /*------------------------------------------------------------------------*/ /* hbm = WinGetSysBitmap(HWND_DESKTOP, SBMP_DRIVE); */ /* WinQueryWindowRect(hwnd, &DestPt); */ /* WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&DestPt, CLR_YELLOW, CLR_BLACK, */ /* (Status ? DBM_INVERT : DBM_NORMAL) | DBM_STRETCH); */ /*------------------------------------------------------------------------*/ hbm = GpiLoadBitmap(hps, NULL, ID_LOCK, 0L, 0L); WinQueryWindowRect(hwnd, &DestPt); WinDrawBitmap(hps, hbm, NULL, (PPOINTL)&DestPt, 0L, 0L, (Status ? DBM_INVERT : DBM_NORMAL) | DBM_STRETCH); } ═══ ═══ #define ID_LOCK 279 #define ID_USERBUTTON 278 #define ID_PASSWORD 277 #define ID_LBREAK 276 #define ID_DLGICON 275 #define ID_STATUS 274 #define ID_OPTIONS2 273 #define ID_ITEM5 272 #define ID_ITEM4 271 #define ID_ITEM3 270 #define ID_ITEM2 269 #define ID_ITEM1 268 #define ID_MENU2 267 #define ID_TEST3 266 #define ID_TEST2 265 #define ID_TEST1 264 #define ID_OPTIONS 263 #define ID_MENU 262 #define ID_ENTRY2 261 #define ID_ENTRY1 260 #define ID_ICON 259 #define ID_EXIT 258 #define ID_OK 257 #define DLG_HINTS 256 ═══ ═══ hints + /A:16 /CO hints.exe hints.map /NOD llibce.lib+ os2.lib hints.def ═══ ═══ NAME Hints WINDOWAPI DESCRIPTION 'Test program for OS/2 Hints and Tips' STUB 'OS2STUB.EXE' DATA MULTIPLE HEAPSIZE 8192 STACKSIZE 8192 PROTMODE ═══ ═══ #include #include "hints.h" ICON ID_ICON hints.ico ICON ID_DLGICON hints.ico BITMAP ID_LOCK lock.bmp MENU ID_MENU PRELOAD BEGIN SUBMENU "~Options", ID_OPTIONS BEGIN MENUITEM "Test ~1", ID_TEST1 MENUITEM "Test ~2", ID_TEST2 MENUITEM "Test ~3", ID_TEST3 END END MENU ID_MENU2 PRELOAD BEGIN SUBMENU "", ID_OPTIONS2 BEGIN MENUITEM "Menu Item ~1", ID_ITEM1 MENUITEM "Menu Item ~2", ID_ITEM2 MENUITEM "Menu Item ~3", ID_ITEM3 MENUITEM SEPARATOR MENUITEM "Menu Item ~4", ID_ITEM4 MENUITEM "Menu Item ~5", ID_ITEM5 END END rcinclude hints.dlg ═══ ═══ DLGINCLUDE 1 "HINTS.H" DLGTEMPLATE DLG_HINTS LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "Sample Dialog Box", DLG_HINTS, 105, 56, 195, 101, FS_NOBYTEALIGN | FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_SYSMENU | FCF_TITLEBAR | FCF_MINBUTTON BEGIN CONTROL "", ID_ENTRY1, 67, 72, 36, 8, WC_ENTRYFIELD, ES_LEFT | ES_MARGIN | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_ENTRY2, 67, 57, 36, 8, WC_ENTRYFIELD, ES_LEFT | ES_MARGIN | WS_TABSTOP | WS_VISIBLE CTLDATA 8, 5, 0, 0 CONTROL "", ID_PASSWORD, 77, 37, 45, 8, WC_ENTRYFIELD, ES_LEFT | ES_MARGIN | ES_UNREADABLE | WS_TABSTOP | WS_VISIBLE CONTROL "OK", ID_OK, 5, 15, 29, 13, WC_BUTTON, BS_PUSHBUTTON | BS_DEFAULT | WS_TABSTOP | WS_VISIBLE CONTROL "Exit", ID_EXIT, 45, 15, 29, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_USERBUTTON, 150, 12, 32, 25, WC_BUTTON, BS_USERBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Entry Field 1", 100, 5, 70, 55, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE CONTROL "Entry Field 2", 101, 5, 55, 55, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE CONTROL "This is a status line", ID_STATUS, 0, 0, 195, 8, WC_STATIC, SS_TEXT | DT_CENTER | DT_TOP | WS_GROUP | WS_VISIBLE CONTROL ID_DLGICON, ID_DLGICON, 5, 35, 20, 16, WC_STATIC, SS_ICON | WS_GROUP | WS_VISIBLE CONTROL "Line one\012Line two\012Line three", ID_LBREAK, 115, 53, 70, 28, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | DT_WORDBREAK | WS_GROUP | WS_VISIBLE CONTROL "Password", 102, 30, 35, 44, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_GROUP | WS_VISIBLE END END ═══ ═══ hints.exe: hints.obj \ hints.def hints.res link @hints.l rc hints.res hints.obj: hints.c hints.h cl /c /Alfu /W2 /Gs /Gc /Zi /Od hints.c hints.res: hints.h hints.rc hints.dlg hints.ico rc -r hints.rc ═══ ═══ #define INCL_WIN #include #include #include "hints.h" MRESULT EXPENTRY DlgProc(HWND, USHORT, MPARAM, MPARAM); /******************************************************************************/ VOID cdecl main() { HAB hab; HMQ hmq; HWND hDlg; hab = WinInitialize(NULL); hmq = WinCreateMsgQueue(hab, 0); WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, DLG_HINTS, NULL); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /******************************************************************************/ MRESULT EXPENTRY DlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2) { static HWND hDlgBoxIcon, hwndEntry; SWCNTRL PgmEntry; RECTL rc; SHORT X_Left, Y_Bot; LONG ScreenHeight, ScreenWidth; CHAR font[25]; SEL Selector; PBYTE Buffer; IPT ipt; HFILE hFile; USHORT Action, BytesRead; ULONG Colour; static SHORT Idx = 0; static PSZ Columns[] = { "001 002 003 004 005 006", "010 011 012 013 014 015", "101 102 103 104 105 106"}; static PSZ FontTable[] = { "8.Courier", "10.Courier", "12.Courier", "8.Helv", "10.Helv", "12.Helv", "14.Helv", "18.Helv", "24.Helv", "10.System Monospaced", "12.System Monospaced", "12.System Proportional", "8.Tms Rmn", "10.Tms Rmn", "12.Tms Rmn", "14.Tms Rmn", "18.Tms Rmn", "24.Tms Rmn"}; //============================================================================= switch (msg) { case WM_INITDLG: hDlgBoxIcon = WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); WinDefDlgProc(hwndDlg, WM_SETICON, (MPARAM)hDlgBoxIcon, (MPARAM)0); ScreenWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScreenHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); WinQueryWindowRect(hwndDlg, &rc); /*---------------*/ X_Left = (SHORT)(ScreenWidth - rc.xRight) / 2; /* Centre window */ Y_Bot = (SHORT)(ScreenHeight - rc.yTop) / 2; /*---------------*/ WinSetWindowPos(hwndDlg, HWND_TOP, X_Left, Y_Bot, 0, 0, SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); PgmEntry.hwnd = hwndDlg; PgmEntry.hwndIcon = hDlgBoxIcon; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, "Hints & Tips"); hwndEntry = WinAddSwitchEntry(&PgmEntry); WinSendDlgItemMsg(hwndDlg, ID_RADIO3, BM_SETCHECK, MPFROM2SHORT(TRUE, 0), NULL); strcpy(font, "12.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetDlgItemText(hwndDlg, ID_ENTRY1, "12.Courier"); WinSetDlgItemText(hwndDlg, ID_MULTILINE, "12.Courier"); for (Idx = 0; Idx < 3; Idx++) { WinSendMsg(WinWindowFromID(hwndDlg, ID_LISTBOX), LM_INSERTITEM, MRFROMSHORT(LIT_END), MRFROMP(Columns[Idx])); } for (Idx = 0; Idx < 18; Idx++) { WinSendMsg(WinWindowFromID(hwndDlg, ID_LISTBOX), LM_INSERTITEM, MRFROMSHORT(LIT_END), MRFROMP(FontTable[Idx])); } Idx = 0; return (MRESULT)TRUE; break; case WM_ADJUSTWINDOWPOS: if (((PSWP)mp1)->fs & SWP_MINIMIZE) { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), FALSE); } else if (((PSWP)mp1)->fs & SWP_RESTORE) { WinShowWindow(WinWindowFromID(hwndDlg, ID_OK), TRUE); } return WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; case WM_CONTROL: switch( SHORT1FROMMP( mp1 ) ) { case ID_RADIO1: switch( SHORT2FROMMP( mp1 ) ) { case BN_CLICKED: strcpy(font, "8.Courier"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, "8.Courier"); WinSetDlgItemText(hwndDlg, ID_MULTILINE, "8.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); Colour = CLR_RED; WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); Colour = CLR_YELLOW; WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); break; default: break; } break; case ID_RADIO2: switch( SHORT2FROMMP( mp1 ) ) { case BN_CLICKED: strcpy(font, "10.Courier"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, "10.Courier"); WinSetDlgItemText(hwndDlg, ID_MULTILINE, "10.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); break; default: break; } break; case ID_RADIO3: switch( SHORT2FROMMP( mp1 ) ) { case BN_CLICKED: strcpy(font, "12.Courier"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, "12.Courier"); WinSetDlgItemText(hwndDlg, ID_MULTILINE, "12.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); break; default: break; } break; case ID_RADIO4: switch( SHORT2FROMMP( mp1 ) ) { case BN_CLICKED: strcpy(font, "8.Helv"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, "8.Helv"); WinSetDlgItemText(hwndDlg, ID_MULTILINE, "8.Helv"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); break; default: break; } break; } case WM_COMMAND: switch(SHORT1FROMMP(mp1)) { case ID_OK: DosAllocSeg(0, &Selector, SEG_GETTABLE); // Allocate 64K segment Buffer = MAKEP(Selector, 0); // Get pointer to segment DosOpen("C:\\CONFIG.SYS", &hFile, &Action, (ULONG)NULL, (USHORT)NULL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_SEQUENTIAL | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, (ULONG)NULL); DosRead(hFile, Buffer, 65535L, &BytesRead); DosClose(hFile); WinSendMsg(WinWindowFromID(hwndDlg, ID_MULTILINE), MLM_SETIMPORTEXPORT, (MPARAM)Buffer, MPFROMLONG(65535L)); ipt = -1; WinSendMsg(WinWindowFromID(hwndDlg, ID_MULTILINE), MLM_IMPORT, (MPARAM)&ipt, MPFROMLONG((LONG)BytesRead)); DosFreeSeg(Selector); return FALSE; case ID_CLEAR: /*-----------------------------------------------*/ /* WinSetDlgItemText(hwndDlg, ID_MULTILINE, ""); */ /*-----------------------------------------------*/ WinSetWindowText(WinWindowFromID(hwndDlg, ID_MULTILINE), ""); return FALSE; case ID_FONT: strcpy(font, FontTable[Idx]); WinSetPresParam(WinWindowFromID(hwndDlg, ID_LISTBOX), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetPresParam(WinWindowFromID(hwndDlg, ID_MULTILINE), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); WinSetWindowText(WinWindowFromID(hwndDlg, ID_ENTRY1), ""); WinSetWindowText(WinWindowFromID(hwndDlg, ID_ENTRY1), FontTable[Idx++]); if (Idx == 18) Idx = 0; return FALSE; case ID_EXIT: WinDestroyPointer(hDlgBoxIcon); WinRemoveSwitchEntry(hwndEntry); WinPostMsg(hwndDlg, WM_QUIT, 0L, 0L); break; default: return FALSE; } WinDismissDlg(hwndDlg, TRUE); /* Removes the dialog box */ break; default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2); } return FALSE; } ═══ ═══ #define DLG_HINTS 256 #define ID_OK 257 #define ID_EXIT 258 #define ID_ICON 259 #define ID_MULTILINE 260 #define ID_RADIO1 261 #define ID_RADIO2 262 #define ID_RADIO3 263 #define ID_ENTRY1 264 #define ID_RADIO4 265 #define ID_CLEAR 266 #define ID_FONT 267 #define ID_LISTBOX 268 ═══ ═══ #define INCL_WINSYS #include #include "hints.h" ICON ID_ICON hints.ico rcinclude hints.dlg ═══ ═══ DLGINCLUDE 1 "HINTS.H" DLGTEMPLATE DLG_HINTS LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "Sample Dialog Box", DLG_HINTS, 68, 30, 276, 159, FS_NOBYTEALIGN | FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_SYSMENU | FCF_TITLEBAR | FCF_MINBUTTON BEGIN CONTROL "Group 1", 100, 8, 76, 84, 77, WC_STATIC, SS_GROUPBOX | WS_GROUP | WS_VISIBLE CONTROL "8.Courier", ID_RADIO1, 16, 128, 65, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "10.Courier", ID_RADIO2, 16, 113, 65, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "12.Courier", ID_RADIO3, 16, 98, 65, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "8.Helv", ID_RADIO4, 16, 83, 65, 10, WC_BUTTON, BS_AUTORADIOBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_ENTRY1, 105, 119, 158, 28, WC_ENTRYFIELD, ES_CENTER | ES_MARGIN | WS_GROUP | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_LISTBOX, 103, 80, 162, 32, WC_LISTBOX, LS_NOADJUSTPOS | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_MULTILINE, 8, 20, 259, 54, WC_MLE, MLS_BORDER | MLS_HSCROLL | MLS_VSCROLL | WS_TABSTOP | WS_VISIBLE CONTROL "Read File", ID_OK, 6, 5, 70, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Clear MLE", ID_CLEAR, 85, 5, 70, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE PRESPARAMS PP_BACKGROUNDCOLORINDEX, CLR_RED PRESPARAMS PP_FOREGROUNDCOLORINDEX, CLR_YELLOW PRESPARAMS PP_FONTNAMESIZE, "10.Courier" CONTROL "Change Font", ID_FONT, 167, 5, 62, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Exit", ID_EXIT, 240, 5, 29, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE END END ═══ ═══ #define INCL_WIN #define INCL_GPILCIDS #define INCL_GPIPRIMITIVES #define INCL_DOS #include #include #include "hints.h" MRESULT EXPENTRY DlgProc(HWND, USHORT, MPARAM, MPARAM); /******************************************************************************/ VOID cdecl main() { HAB hab; HMQ hmq; HWND hDlg; hab = WinInitialize(NULL); hmq = WinCreateMsgQueue(hab, 0); WinDlgBox(HWND_DESKTOP, HWND_DESKTOP, DlgProc, NULL, DLG_HINTS, NULL); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /******************************************************************************/ MRESULT EXPENTRY DlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2) { static HWND hwndEntry; HWND hwndItem; SWCNTRL PgmEntry; RECTL rc; SHORT X_Left, Y_Bot, Midx; static SHORT Idx, Oidx; LONG ScreenHeight, ScreenWidth; CHAR font[15]; ULONG Colour; SEL sel; typedef struct _DBDATA { USHORT Key; CHAR Capital[20]; } DBDATA, FAR *PDBDATA; PDBDATA pDB_Data; static PSZ szCountry[] = {"Austria", "Belgium", "Canada", "Denmark", "Egypt", "Finland", "Greece", "Hungary", "India", "Japan", "Kenya", "Libya", "Morocco", "Nigeria", "Oman", "Peru", "Qatar", "Romania", "Spain", "Turkey", "Uruguay", "Venezuela", "Wales", "Xanxere", "Yemen", "Zambia"}; static PSZ szCapital[] = {"Vienna", "Brussels", "Ottawa", "Copenhagen", "Cairo", "Helsinki", "Athens", "Budapest", "Delhi", "Tokyo", "Nairobi", "Tripoli", "Rabat", "Lagos", "Muscat", "Lima", "Doha", "Bucharest", "Madrid", "Ankara", "Montevideo", "Caracas", "Cardiff", "None", "Sana", "Lusaka"}; CHAR szCtry[10], szCap[12], szListBuff[50]; CHAR *Country, *Capital; ULONG KeyValue; POWNERITEM pOwner; SHORT cxText, cyText; HPS hps; FONTMETRICS fm; POINTL points[TXTBOX_COUNT], pt; //============================================================================= switch (msg) { case WM_INITDLG: WinEnableWindow(WinWindowFromID(hwndDlg, ID_PROCMULT), FALSE); strcpy(font, "18.Helv"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); Colour = CLR_RED; WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY3), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); Colour = CLR_YELLOW; WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY1), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); WinSetPresParam(WinWindowFromID(hwndDlg, ID_ENTRY3), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); ScreenWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScreenHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); WinQueryWindowRect(hwndDlg, &rc); /*---------------*/ X_Left = (SHORT)(ScreenWidth - rc.xRight) / 2; /* Centre window */ Y_Bot = (SHORT)(ScreenHeight - rc.yTop) / 2; /*---------------*/ WinSetWindowPos(hwndDlg, HWND_TOP, X_Left, Y_Bot, 0, 0, SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); PgmEntry.hwnd = hwndDlg; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, "Hints & Tips"); hwndEntry = WinAddSwitchEntry(&PgmEntry); for (Idx = 0; Idx < 26; Idx++) { /*--------------------------------------------------------------*/ /* If all we want to do is store the key value... */ /* */ /* WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_INSERTITEM, */ /* MPFROMSHORT(LIT_END), */ /* MPFROMP(szCountry[Idx])); */ /* KeyValue = Idx + 1; */ /* WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SETITEMHANDLE, */ /* (MPARAM)Idx, (MPARAM)KeyValue); */ /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ /* Otherwise we need to save a pointer to our structure... */ /* */ /*--------------------------------------------------------------*/ WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szCountry[Idx])); DosAllocSeg(22, &sel, 0); pDB_Data = MAKEP(sel, 0); pDB_Data->Key = Idx + 1; strcpy(pDB_Data->Capital, szCapital[Idx]); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SETITEMHANDLE, (MPARAM)Idx, MPFROMP(pDB_Data)); WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szCountry[Idx])); strcpy(szListBuff, szCountry[Idx]); strcat(szListBuff, "\t"); strcat(szListBuff, szCapital[Idx]); WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_INSERTITEM, MPFROMSHORT(LIT_END), MPFROMP(szListBuff)); } WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SELECTITEM, MPFROMSHORT(0), (MPARAM)TRUE); break; case WM_MEASUREITEM: hps = WinGetPS(WinWindowFromID(hwndDlg, ID_OLISTBOX)); WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Idx, sizeof(szListBuff)), MPFROMP(szListBuff)); GpiQueryFontMetrics(hps, (LONG)sizeof(FONTMETRICS), &fm); cyText = (SHORT)fm.lMaxBaselineExt; GpiQueryTextBox(hps, (LONG)strlen(szListBuff), szListBuff, TXTBOX_COUNT, points); /*-------------------------------------------------*/ /* May need to add on a bit to cxText to ensure */ /* the entire item can be read when fully scrolled */ /*-------------------------------------------------*/ cxText = (USHORT)points[TXTBOX_TOPRIGHT].x + 20; WinReleasePS(hps); return MRFROM2SHORT(cyText, cxText); case WM_DRAWITEM: pOwner = (POWNERITEM)mp2; rc.xRight = pOwner->rclItem.xRight/3*2; rc.xLeft = pOwner->rclItem.xLeft; rc.yTop = pOwner->rclItem.yTop; rc.yBottom = pOwner->rclItem.yBottom; GpiSetBackMix(pOwner->hps, BM_OVERPAINT); if ((!pOwner->fsState) || // Unselected (pOwner->idItem == 5)) // Don't allow Finland { GpiSetBackColor(pOwner->hps, CLR_DARKGREEN); GpiSetColor(pOwner->hps, CLR_YELLOW); } else // Selected { GpiSetBackColor(pOwner->hps, CLR_YELLOW); GpiSetColor(pOwner->hps, CLR_DARKGREEN); } WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(pOwner->idItem, sizeof(szListBuff)), MPFROMP(szListBuff)); Country = strtok(szListBuff, "\t"); Capital = strtok(NULL, "\t"); WinDrawText(pOwner->hps, strlen(Country), Country, &rc, 0L, 0L, DT_LEFT | DT_TEXTATTRS | DT_ERASERECT); /*-----------------------------------*/ /* Draw next item in right rectangle */ /* allowing for horiz scrolling */ /*-----------------------------------*/ if (pOwner->rclItem.xLeft != 1) // i.e. we have been scrolled rc.xLeft = rc.xRight + pOwner->rclItem.xLeft - 1; else rc.xLeft = rc.xRight; rc.xRight = pOwner->rclItem.xRight; WinDrawText(pOwner->hps, strlen(Capital), Capital, &rc, 0L, 0L, DT_LEFT | DT_TEXTATTRS | DT_ERASERECT); pOwner->fsStateOld = pOwner->fsState = 0; // Don't let PM hilite return (MRESULT)TRUE; // Don't let PM draw case WM_CONTROL: switch(SHORT1FROMMP(mp1)) { case ID_SLISTBOX: switch(SHORT2FROMMP(mp1)) { case LN_SELECT: Idx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYSELECTION, 0L, 0L); if (Idx != LIT_NONE) { WinEnableWindow(WinWindowFromID(hwndDlg, ID_DELETE), TRUE); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Idx, sizeof(szCtry)), MPFROMP(szCtry)); WinSetDlgItemText(hwndDlg, ID_ENTRY3, szCtry); /*-----------------------------------------------------------------*/ /* Retrieve the key value... */ /* */ /* KeyValue = (ULONG)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, */ /* LM_QUERYITEMHANDLE, */ /* MPFROMSHORT(Idx), NULL); */ /* WinSetDlgItemShort(hwndDlg, ID_ENTRY2, (SHORT)KeyValue, FALSE); */ /*-----------------------------------------------------------------*/ /*-------------------------------------------------------------*/ /* Or, retrieve all data associated with the listbox item... */ /* */ /*-------------------------------------------------------------*/ pDB_Data = (PDBDATA)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMHANDLE, MPFROMSHORT(Idx), NULL); WinSetDlgItemText(hwndDlg, ID_ENTRY1, pDB_Data->Capital); WinSetDlgItemShort(hwndDlg, ID_ENTRY2, (SHORT)pDB_Data->Key, FALSE); } break; default: break; } break; case ID_MLISTBOX: switch(SHORT2FROMMP(mp1)) { case LN_SELECT: WinEnableWindow(WinWindowFromID(hwndDlg, ID_PROCMULT), TRUE); break; default: break; } break; case ID_OLISTBOX: switch(SHORT2FROMMP(mp1)) { case LN_SELECT: Oidx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYSELECTION, 0L, 0L); if (Oidx == 5) // Don't allow Finland { DosBeep(1000, 100); break; } WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Oidx, sizeof(szListBuff)), MPFROMP(szListBuff)); Country = strtok(szListBuff, "\t"); Capital = strtok(NULL, "\t"); WinSetDlgItemText(hwndDlg, ID_ENTRY1, Capital); WinSetDlgItemText(hwndDlg, ID_ENTRY2, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY3, Country); break; default: break; } break; } case WM_COMMAND: switch(SHORT1FROMMP(mp1)) { case ID_DESELECT: WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SELECTITEM, MPFROMSHORT(Idx), (MPARAM)FALSE); WinSendDlgItemMsg(hwndDlg, ID_OLISTBOX, LM_SELECTITEM, MPFROMSHORT(Oidx), (MPARAM)FALSE); WinEnableWindow(WinWindowFromID(hwndDlg, ID_DELETE), FALSE); WinSetDlgItemText(hwndDlg, ID_ENTRY1, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY2, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY3, ""); return FALSE; case ID_DELETE: pDB_Data = (PDBDATA)WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_QUERYITEMHANDLE, MPFROMSHORT(Idx), NULL); DosFreeSeg(SELECTOROF(pDB_Data)); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_DELETEITEM, MPFROMSHORT(Idx), NULL); WinSetDlgItemText(hwndDlg, ID_ENTRY1, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY2, ""); WinSetDlgItemText(hwndDlg, ID_ENTRY3, ""); WinSendDlgItemMsg(hwndDlg, ID_SLISTBOX, LM_SELECTITEM, MPFROMSHORT(0), (MPARAM)TRUE); return FALSE; case ID_PROCMULT: WinSendMsg(hwndDlg, WM_COMMAND, MPFROMSHORT(ID_DESELECT), 0L); Midx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_QUERYSELECTION, (MPARAM)LIT_FIRST, 0L); while(Midx != LIT_NONE) { WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_QUERYITEMTEXT, MPFROM2SHORT(Midx, sizeof(szCtry)), MPFROMP(szCtry)); WinSetDlgItemText(hwndDlg, ID_ENTRY3, szCtry); WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_SELECTITEM, MPFROMSHORT(Midx), (MPARAM)FALSE); /*------------------------------*/ DosSleep(1000L); /* DON'T DO THIS IN PM PROGRAMS */ /* AFFECTS PERFORMANCE SEVERELY */ /*------------------------------*/ Midx = (SHORT)WinSendDlgItemMsg(hwndDlg, ID_MLISTBOX, LM_QUERYSELECTION, (MPARAM)Midx, 0L); } WinSetDlgItemText(hwndDlg, ID_ENTRY3, "Done"); DosBeep(500, 200); WinEnableWindow(WinWindowFromID(hwndDlg, ID_PROCMULT), FALSE); return FALSE; case ID_EXIT: WinRemoveSwitchEntry(hwndEntry); WinPostMsg(hwndDlg, WM_QUIT, 0L, 0L); break; default: return FALSE; } WinDismissDlg(hwndDlg, TRUE); /* Removes the dialog box */ break; default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2); } return FALSE; } ═══ ═══ #define ID_PROCMULT 266 #define ID_ENTRY3 265 #define ID_ENTRY2 264 #define ID_DELETE 263 #define ID_ENTRY1 262 #define ID_OLISTBOX 261 #define ID_MLISTBOX 260 #define ID_SLISTBOX 259 #define ID_EXIT 258 #define ID_DESELECT 257 #define DLG_HINTS 256 ═══ ═══ #include #include "hints.h" rcinclude hints.dlg ═══ ═══ DLGINCLUDE 1 "HINTS.H" DLGTEMPLATE DLG_HINTS LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "Listbox Sample", DLG_HINTS, 30, 24, 317, 172, FS_NOBYTEALIGN | FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_SYSMENU | FCF_TITLEBAR BEGIN CONTROL "~Single Selection", 101, 8, 155, 80, 8, WC_STATIC, SS_TEXT | DT_CENTER | DT_TOP | DT_MNEMONIC | WS_GROUP | WS_VISIBLE CONTROL "", ID_SLISTBOX, 8, 71, 80, 80, WC_LISTBOX, WS_TABSTOP | WS_VISIBLE CONTROL "~Multiple Selection", 102, 115, 155, 80, 8, WC_STATIC, SS_TEXT | DT_CENTER | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "", ID_MLISTBOX, 115, 71, 80, 80, WC_LISTBOX, LS_MULTIPLESEL | WS_TABSTOP | WS_VISIBLE CONTROL "~Ownerdraw", 103, 216, 155, 91, 8, WC_STATIC, SS_TEXT | DT_CENTER | DT_TOP | DT_MNEMONIC | WS_VISIBLE CONTROL "", ID_OLISTBOX, 216, 71, 91, 83, WC_LISTBOX, LS_OWNERDRAW | LS_HORZSCROLL | WS_TABSTOP | WS_VISIBLE CONTROL "Deselect", ID_DESELECT, 5, 5, 49, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Delete", ID_DELETE, 65, 5, 40, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Process MultSel", ID_PROCMULT, 115, 5, 79, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "Exit", ID_EXIT, 205, 5, 40, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_ENTRY1, 77, 25, 100, 16, WC_ENTRYFIELD, ES_CENTER | ES_AUTOSCROLL | ES_MARGIN | ES_READONLY | WS_GROUP | WS_VISIBLE CONTROL "Capital City", 104, 9, 28, 54, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_VISIBLE CONTROL "Key", 105, 200, 28, 21, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_VISIBLE CONTROL "", ID_ENTRY2, 232, 30, 39, 8, WC_ENTRYFIELD, ES_CENTER | ES_MARGIN | ES_READONLY | WS_VISIBLE CONTROL "Country", 106, 9, 50, 48, 8, WC_STATIC, SS_TEXT | DT_LEFT | DT_TOP | WS_VISIBLE CONTROL "", ID_ENTRY3, 77, 51, 100, 8, WC_ENTRYFIELD, ES_CENTER | ES_MARGIN | ES_READONLY | WS_VISIBLE END END ═══ ═══ VOID AddMenuItem(HWND hwnd) { HWND hSysMenu, hSysSubMenu; MENUITEM SysMenu; SHORT I, idSysMenu; static MENUITEM Item[2] = {MIT_END, MIS_SEPARATOR, 0, 0, NULL, NULL, MIT_END, MIS_TEXT, 0, ID_ABOUT, NULL, NULL}; static CHAR *Text[2] = {NULL, "~About..."}; hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE), FID_SYSMENU); idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION, NULL, NULL)); WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE), MPFROMP(&SysMenu)); hSysSubMenu = SysMenu.hwndSubMenu; for (I = 0; I < 2; I++) WinSendMsg(hSysSubMenu, MM_INSERTITEM, MPFROMP(Item+I), MPFROMP(Text[I])); } ═══ ═══ case WM_INITMENU: switch (SHORT1FROMMP(mp1)) { case IDM_TWO: /*---------------------------*/ /* Toggle menu item 1 on/off */ /*---------------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); hMenu = WinWindowFromID(hFrame, FID_MENU); WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(MI_ITEM1, TRUE), MPFROM2SHORT(MIA_CHECKED, fbChecked ? MIA_CHECKED : 0)); break; } break; case WM_COMMAND: switch (SHORT1FROMMP(mp1)) { case MI_ITEM1: fbChecked = (fbChecked ? FALSE : TRUE); break; ; ; ; } break; ═══ ═══ /*-------------------------------------------*/ /* Delete 'Size' and 'Move' from system menu */ /*-------------------------------------------*/ hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU); WinSendMsg(hwndSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_SIZE, TRUE), MPFROMSHORT(NULL)); WinSendMsg(hwndSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_MOVE, TRUE), MPFROMSHORT(NULL)); ═══ ═══ /*------------------------*/ /* Disable all menu items */ /*------------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hFrame, FID_MENU), FALSE); /*-----------------------*/ /* Enable all menu items */ /*-----------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hFrame, FID_MENU), TRUE); ═══ ═══ /*-------------------------------------*/ /* To disable CLOSE in the system menu */ /*-------------------------------------*/ hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU); WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)); /*--------------------*/ /* To enable it again */ /*--------------------*/ WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROM2SHORT(MIA_DISABLED, 0)); ═══ ═══ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinDestroyWindow(WinWindowFromID(hFrame, FID_MENU)); WinLoadMenu(hFrame, NULL, ID_MENU2); WinSendMsg(hFrame, WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)NULL); ═══ ═══ case ID_ABOUT: WinMessageBox(HWND_DESKTOP, hwnd, "Version 1\n24 April 1991\nWritten by Bryan Goodyer", "PM Hints and Tips", 0, MB_INFORMATION | MB_OK | MB_MOVEABLE ); break; ═══ ═══ case WM_BUTTON2DOWN: Pt.x = MOUSEMSG(&msg)->x; Pt.y = MOUSEMSG(&msg)->y + MenuHt; WinPostMsg(hMenu, MM_STARTMENUMODE, MPFROM2SHORT(TRUE, TRUE), NULL); WinSetWindowPos(hMenu, HWND_TOP, (USHORT)Pt.x, (USHORT)Pt.y, 0, 0, SWP_MOVE | SWP_SHOW); break; case WM_NEXTMENU: return (MRESULT)NULL; ═══ ═══ BEGIN MENUITEM "Menu Item ~1", MI_ITEM1, MIS_TEXT MENUITEM "Menu Item ~2", MI_ITEM2, MIS_TEXT, MIA_NODISMISS END ═══ ═══ static HWND hABar; case WM_INITDLG: ; ; hABar = WinLoadMenu(hwndDlg, NULL, ID_MENU); WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM)FID_MENU, (MPARAM)NULL); MenuHt = WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); hMenu = WinLoadMenu(hwndDlg, NULL, ID_MENU2); ; ; break ═══ ═══ static HWND hMenu; static ULONG MenuHt; POINTL Pt; case WM_CREATE: hMenu = WinLoadMenu(hwnd, NULL, ID_MENU2); MenuHt = WinQuerySysValue(HWND_DESKTOP, SV_CYMENU); break; case WM_BUTTON2DOWN: Pt.x = MOUSEMSG(&msg)->x; Pt.y = MOUSEMSG(&msg)->y + MenuHt; WinPostMsg(hMenu, MM_STARTMENUMODE, MPFROM2SHORT(TRUE, TRUE), NULL); WinSetWindowPos(hMenu, HWND_TOP, (SHORT)Pt.x, (SHORT)Pt.y, 0, 0, SWP_MOVE | SWP_SHOW); break; ═══ ═══ MENU ID_MENU2 PRELOAD BEGIN SUBMENU "", ID_OPTIONS2 BEGIN MENUITEM "Menu Item ~1", ID_ITEM1 MENUITEM "Menu Item ~2", ID_ITEM2 MENUITEM "Menu Item ~3", ID_ITEM3 MENUITEM SEPARATOR MENUITEM "Menu Item ~4", ID_ITEM4 MENUITEM "Menu Item ~5", ID_ITEM5 END END ═══ ═══ VOID DelClose(HWND hwnd) { HWND hSysMenu, hSysSubMenu; MENUITEM SysMenu; SHORT idItem, idSep, idSysMenu; hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE), FID_SYSMENU); idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION, NULL, NULL)); WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE), MPFROMP(&SysMenu)); hSysSubMenu = SysMenu.hwndSubMenu; idItem = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMPOSITIONFROMID, MPFROM2SHORT(SC_CLOSE, FALSE), NULL)); if (idItem != MIT_ERROR) { idSep = idItem + 1; // Get separator ID idSep = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(idSep), NULL)); WinSendMsg(hSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROMSHORT(NULL)); WinSendMsg(hSysSubMenu, MM_DELETEITEM, MPFROM2SHORT(idSep, FALSE), NULL); } } ═══ ═══ case WM_ADJUSTWINDOWPOS: if (((PSWP)mp1)->fs & SWP_MINIMIZE) { WinDestroyWindow(hABar); } else if (((PSWP)mp1)->fs & SWP_RESTORE) { ; ; hABar = WinLoadMenu(hwndDlg, NULL, ID_MENU); WinSendMsg(hwndDlg, WM_UPDATEFRAME, (MPARAM)FID_MENU, (MPARAM)NULL); ; ; } return WinDefDlgProc(hwndDlg, msg, mp1, mp2); break; ═══ ═══ case WM_BUTTON1DOWN: /*-----------------------*/ /* Force menu to dismiss */ /*-----------------------*/ hMenu = WinWindowFromID(hFrame, FID_MENU); WinPostMsg(hMenu, MM_STARTMENUMODE, MPFROM2SHORT(FALSE, TRUE), (MPARAM)NULL); WinPostMsg(hMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), (MPARAM)NULL); ; ; ; break; ═══ ═══ MENU ID_MAINWND PRELOAD BEGIN SUBMENU "E~xit", IDM_ONE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END MENU ID_MENU2 BEGIN SUBMENU "~Option 1", IDM_TWO BEGIN MENUITEM "Menu Item ~1", MI_ITEM1, MIS_TEXT MENUITEM "Menu Item ~2", MI_ITEM2, MIS_TEXT END SUBMENU "E~xit", IDM_THREE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END ═══ ═══ #define INCL_WIN #include #include #include #include "hints.h" MRESULT EXPENTRY MainWndProc (HWND, USHORT, MPARAM, MPARAM); VOID APIENTRY WinSetTitle (PSZ); BOOL APIENTRY WinNoShutdown(USHORT, BOOL); VOID AddMenuItem (HWND); VOID DelClose (HWND); /****************************************************************************/ VOID cdecl main (void) { HAB hab; HMQ hmq; HWND hwndFrame, hwndEntry, hwndClient, hwndSysMenu; QMSG qmsg; ULONG flFrameFlags; CHAR Title[80]; SWCNTRL PgmEntry; SHORT X_Left, Y_Bot, Height, Width; LONG ScrHeight, ScrWidth; /****************************************************************************/ hab = WinInitialize(0); hmq = WinCreateMsgQueue(hab, 0); WinRegisterClass(hab, "Hints", MainWndProc, CS_SIZEREDRAW, 0); WinLoadString( hab, NULL, ID_TITLE, sizeof(Title), Title ); flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_ACCELTABLE | FCF_ICON | FCF_NOBYTEALIGN; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flFrameFlags, "Hints", (PSZ)Title, 0L, NULL, ID_MAINWND, &hwndClient); WinCreateWindow(hwndClient, WC_BUTTON, "Switch Menus", WS_VISIBLE, 10, 10, 120, 30, hwndClient, HWND_TOP, ID_SWITCH, 0, 0); ScrWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScrHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); Width = 400; Height = 300; X_Left = ((SHORT)ScrWidth - Width) / 2; Y_Bot = ((SHORT)ScrHeight - Height) / 2; /*-----------------------------------------------------------------------*/ /* Startup in background */ /* */ /* WinSetWindowPos(hwndFrame, HWND_BOTTOM, X_Left, Y_Bot, Width, Height, */ /* SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ZORDER); */ /*-----------------------------------------------------------------------*/ /*-----------------------*/ /* Startup in foreground */ /*-----------------------*/ WinSetWindowPos(hwndFrame, NULL, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); /*------------------*/ /* Add to task list */ /*------------------*/ PgmEntry.hwnd = hwndFrame; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, Title); hwndEntry = WinAddSwitchEntry(&PgmEntry); /*---------------------------------*/ /* Disable 'End Task' in task list */ /*---------------------------------*/ WinNoShutdown(0, TRUE); /*--------------------------------*/ /* Disable 'Close' in system menu */ /*--------------------------------*/ hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU); WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)); /*---------------------------------------*/ /* Disable 'Switch to...' in system menu */ /*---------------------------------------*/ WinSendMsg(hwndSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_TASKMANAGER, TRUE), MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)); /*-------------------------------------------*/ /* Delete 'Size' and 'Move' from system menu */ /*-------------------------------------------*/ WinSendMsg(hwndSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_SIZE, TRUE), MPFROMSHORT(NULL)); WinSendMsg(hwndSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_MOVE, TRUE), MPFROMSHORT(NULL)); while (TRUE) { while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); /*---------------------------------*/ /* Don't allow exit from task list */ /*---------------------------------*/ if (qmsg.mp1 == NULL) break; else { DosBeep(100, 200); WinCancelShutdown(hmq, FALSE); } } /*------------------------------------*/ /* Remove from task list and clean up */ /*------------------------------------*/ WinRemoveSwitchEntry(WinQuerySwitchHandle(hwndFrame, 0)); WinDestroyWindow(hwndFrame); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /****************************************************************************/ MRESULT EXPENTRY MainWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { SWCNTRL PgmEntry; HWND hFrame, hMenu, hSwL, hSysMenu; static BOOL fbSwitched = FALSE, fbChecked = FALSE; switch (msg) { case WM_CREATE: /*----------------------------*/ /* Add 'About' to system menu */ /*----------------------------*/ AddMenuItem(hwnd); /*------------------------*/ /* Disable all menu items */ /*------------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hFrame, FID_MENU), FALSE); /*---------------------------------------------*/ /* Make system modal */ /* */ /* WinSetSysModalWindow(HWND_DESKTOP, hFrame); */ /*---------------------------------------------*/ break; case WM_INITMENU: switch (SHORT1FROMMP(mp1)) { case IDM_TWO: /*---------------------------*/ /* Toggle menu item 1 on/off */ /*---------------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); hMenu = WinWindowFromID(hFrame, FID_MENU); WinSendMsg(hMenu, MM_SETITEMATTR, MPFROM2SHORT(MI_ITEM1, TRUE), MPFROM2SHORT(MIA_CHECKED, fbChecked ? MIA_CHECKED : 0)); break; } break; case WM_BUTTON1DOWN: /*--------------------------------*/ /* Enable 'End Task' in task list */ /*--------------------------------*/ WinNoShutdown(0, FALSE); /*-------------------------------*/ /* Enable 'Close' in system menu */ /*-------------------------------*/ hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE), FID_SYSMENU); WinSendMsg(hSysMenu, MM_SETITEMATTR, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROM2SHORT(MIA_DISABLED, 0)); /*-----------------------*/ /* Enable all menu items */ /*-----------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hFrame, FID_MENU), TRUE); /*-----------------------*/ /* Force menu to dismiss */ /*-----------------------*/ hMenu = WinWindowFromID(hFrame, FID_MENU); WinPostMsg(hMenu, MM_STARTMENUMODE, MPFROM2SHORT(FALSE, TRUE), (MPARAM)NULL); WinPostMsg(hMenu, MM_ENDMENUMODE, MPFROMSHORT(TRUE), (MPARAM)NULL); /*------------------------*/ /* Change task list entry */ /*------------------------*/ PgmEntry.hwnd = WinQueryWindow(hwnd, QW_PARENT, FALSE); PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, "Tips and Hints"); WinChangeSwitchEntry(WinQuerySwitchHandle(PgmEntry.hwnd, 0), &PgmEntry); /*-----------------------*/ /* Query task list entry */ /*-----------------------*/ hSwL = WinQuerySwitchHandle(WinQueryWindow(hwnd, QW_PARENT, FALSE), 0); WinQuerySwitchEntry(hSwL, &PgmEntry); /*-------------------------------------------*/ /* Remove system modality */ /* */ /* WinSetSysModalWindow(HWND_DESKTOP, NULL); */ /*-------------------------------------------*/ break; case WM_BUTTON2DOWN: /*----------------------------------*/ /* Delete 'Close' and its Separator */ /*----------------------------------*/ DelClose(hwnd); break; case WM_COMMAND: switch (SHORT1FROMMP(mp1)) { case ID_SWITCH: /*--------------*/ /* Switch menus */ /*--------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); if (!fbSwitched) { WinDestroyWindow(WinWindowFromID(hFrame, FID_MENU)); WinLoadMenu(hFrame, NULL, ID_MENU2); WinSendMsg(hFrame, WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)NULL); fbSwitched = TRUE; } else { WinDestroyWindow(WinWindowFromID(hFrame, FID_MENU)); WinLoadMenu(hFrame, NULL, ID_MAINWND); WinSendMsg(hFrame, WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)NULL); fbSwitched = FALSE; } break; case ID_ABOUT: /*-------------------*/ /* Display About box */ /*-------------------*/ WinMessageBox(HWND_DESKTOP, hwnd, "Version 1\n24 April 1991\nWritten by Bryan Goodyer", "PM Hints and Tips", 0, MB_INFORMATION | MB_OK | MB_MOVEABLE ); break; case MI_ITEM1: fbChecked = (fbChecked ? FALSE : TRUE); break; case MI_EXIT: WinPostMsg(hwnd, WM_QUIT, 0L, 0L); break; default: break; } break; case WM_ERASEBACKGROUND: return (MRESULT)TRUE; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } VOID AddMenuItem(HWND hwnd) { HWND hSysMenu, hSysSubMenu; MENUITEM SysMenu; SHORT I, idSysMenu; static MENUITEM Item[2] = {MIT_END, MIS_SEPARATOR, 0, 0, NULL, NULL, MIT_END, MIS_TEXT, 0, ID_ABOUT, NULL, NULL}; static CHAR *Text[2] = {NULL, "~About..."}; hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE), FID_SYSMENU); idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION, NULL, NULL)); WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE), MPFROMP(&SysMenu)); hSysSubMenu = SysMenu.hwndSubMenu; for (I = 0; I < 2; I++) WinSendMsg(hSysSubMenu, MM_INSERTITEM, MPFROMP(Item+I), MPFROMP(Text[I])); } VOID DelClose(HWND hwnd) { HWND hSysMenu, hSysSubMenu; MENUITEM SysMenu; SHORT idItem, idSep, idSysMenu; hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE), FID_SYSMENU); idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION, NULL, NULL)); WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE), MPFROMP(&SysMenu)); hSysSubMenu = SysMenu.hwndSubMenu; idItem = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMPOSITIONFROMID, MPFROM2SHORT(SC_CLOSE, FALSE), NULL)); if (idItem != MIT_ERROR) { idSep = idItem + 1; // Get separator ID idSep = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(idSep), NULL)); WinSendMsg(hSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_CLOSE, TRUE), MPFROMSHORT(NULL)); WinSendMsg(hSysSubMenu, MM_DELETEITEM, MPFROM2SHORT(idSep, FALSE), NULL); } } ═══ ═══ #define ID_MAINWND 200 #define ID_TITLE 201 #define ID_ABOUT 202 #define MI_EXIT 203 #define MI_RESUME 204 #define ID_MENU2 205 #define MI_ITEM1 206 #define MI_ITEM2 207 #define ID_SWITCH 208 #define IDM_ONE 209 #define IDM_TWO 210 #define IDM_THREE 211 ═══ ═══ #include #include "hints.h" STRINGTABLE PRELOAD BEGIN ID_TITLE, "PM Hints and Tips" END ICON ID_MAINWND hints.ico ACCELTABLE ID_MAINWND BEGIN VK_F3, MI_EXIT, VIRTUALKEY END MENU ID_MAINWND PRELOAD BEGIN SUBMENU "E~xit", IDM_ONE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END MENU ID_MENU2 BEGIN SUBMENU "~Option 1", IDM_TWO BEGIN MENUITEM "Menu Item ~1", MI_ITEM1, MIS_TEXT MENUITEM "Menu Item ~2", MI_ITEM2, MIS_TEXT, MIA_NODISMISS END SUBMENU "E~xit", IDM_THREE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END ═══ ═══ hints.exe: hints.obj \ hints.def hints.res link @hints.l rc hints.res hints.obj: hints.c hints.h cl /c /Alfu /W2 /Gs /Gc /Zi /Od hints.c hints.res: hints.h hints.rc hints.ico rc -r hints.rc ═══ ═══ HPOINTER hptr; case WM_CONTROLPOINTER: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return(hptr); case WM_MOUSEMOVE: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return (MPARAM)TRUE; ═══ ═══ WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); ═══ ═══ POINTL ptl; WinMapWindowPoints(HWND_DESKTOP, hwnd, &ptl, 1); ═══ ═══ POINTL ptl; WinQueryPointerPos(HWND_DESKTOP, &ptl); ═══ ═══ /*------------------------*/ /* In your main procedure */ /*------------------------*/ MRESULT EXPENTRY EntryProc(HWND, USHORT, MPARAM, MPARAM); PFNWP EntryFieldProc; // Public Entry Field procedure /*------------------------------*/ /* In your dialog box procedure */ /*------------------------------*/ case WM_INITDLG: EntryFieldProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_ENTRY), EntryProc); ; ; ; break; /*--------------------*/ /* Subclass procedure */ /*--------------------*/ MRESULT EXPENTRY EntryProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; switch (msg) { case WM_MOUSEMOVE: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return (MPARAM)TRUE; } // Call public entry field procedure return ((*EntryFieldProc)(hwnd, msg, mp1, mp2)); } ═══ ═══ /*------------------------*/ /* In your main procedure */ /*------------------------*/ MRESULT EXPENTRY ListProc(HWND, USHORT, MPARAM, MPARAM); PFNWP ListboxProc; // Public Listbox procedure /*------------------------------*/ /* In your dialog box procedure */ /*------------------------------*/ case WM_INITDLG: ListboxProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_LISTBOX), ListProc); ; ; ; break; /*--------------------*/ /* Subclass procedure */ /*--------------------*/ MRESULT EXPENTRY ListProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; switch (msg) { case WM_CONTROLPOINTER: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return(hptr); } // Call public listbox procedure return ((*ListboxProc)(hwnd, msg, mp1, mp2)); } ═══ ═══ #define INCL_WIN #include #include #include #include "hints.h" MRESULT EXPENTRY MainWndProc (HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY TestDlgProc (HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY EntryProc (HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY ListProc (HWND, USHORT, MPARAM, MPARAM); PFNWP EntryFieldProc; // Public Entry Field procedure PFNWP ListboxProc; // Public Listbox procedure BOOL fbBusy = TRUE; /****************************************************************************/ VOID cdecl main (void) { HAB hab; HMQ hmq; HWND hwndFrame, hwndEntry, hwndClient, hstatic; QMSG qmsg; ULONG flFrameFlags; CHAR Title[80]; SWCNTRL PgmEntry; SHORT X_Left, Y_Bot, Height, Width; LONG ScrHeight, ScrWidth; /****************************************************************************/ hab = WinInitialize(0); hmq = WinCreateMsgQueue(hab, 0); WinRegisterClass(hab, "Hints", MainWndProc, CS_SIZEREDRAW, 0); WinLoadString( hab, NULL, ID_TITLE, sizeof(Title), Title ); flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_ACCELTABLE | FCF_ICON | FCF_NOBYTEALIGN; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flFrameFlags, "Hints", (PSZ)Title, 0L, NULL, ID_MAINWND, &hwndClient); WinCreateWindow(hwndClient, WC_BUTTON, "Test DLG", WS_VISIBLE, 10, 10, 150, 30, hwndClient, HWND_TOP, ID_DLG, 0, 0); WinCreateWindow(hwndClient, WC_BUTTON, "Remove Hourglass", WS_VISIBLE, 175, 10, 200, 30, hwndClient, HWND_TOP, ID_REMOVE, 0, 0); WinCreateWindow(hwndClient, WC_STATIC, "", WS_VISIBLE | SS_TEXT, 10, 125, 400, 30, hwndClient, HWND_TOP, ID_PTRTEXT1, 0, 0); WinCreateWindow(hwndClient, WC_STATIC, "", WS_VISIBLE | SS_TEXT, 10, 75, 400, 30, hwndClient, HWND_TOP, ID_PTRTEXT2, 0, 0); ScrWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScrHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); Width = 450; Height = 300; X_Left = ((SHORT)ScrWidth - Width) / 2; Y_Bot = ((SHORT)ScrHeight - Height) / 2; /*-----------------------*/ /* Startup in foreground */ /*-----------------------*/ WinSetWindowPos(hwndFrame, NULL, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); /*------------------*/ /* Add to task list */ /*------------------*/ PgmEntry.hwnd = hwndFrame; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, Title); hwndEntry = WinAddSwitchEntry(&PgmEntry); while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); /*------------------------------------*/ /* Remove from task list and clean up */ /*------------------------------------*/ WinRemoveSwitchEntry(WinQuerySwitchHandle(hwndFrame, 0)); WinDestroyWindow(hwndFrame); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /****************************************************************************/ MRESULT EXPENTRY MainWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; POINTL ptl; CHAR szText[100], szCoord[10]; switch (msg) { case WM_PAINT: WinQueryPointerPos(HWND_DESKTOP, &ptl); strcpy(szText, "(Screen Coords) Mouse X = "); ltoa(ptl.x, szCoord, 10); strcat(szText, szCoord); strcat(szText, " Mouse Y = "); ltoa(ptl.y, szCoord, 10); strcat(szText, szCoord); WinSetWindowText(WinWindowFromID(hwnd, ID_PTRTEXT1), szText); WinMapWindowPoints(HWND_DESKTOP, hwnd, &ptl, 1); strcpy(szText, "(Window Coords) Mouse X = "); ltoa(ptl.x, szCoord, 10); strcat(szText, szCoord); strcat(szText, " Mouse Y = "); ltoa(ptl.y, szCoord, 10); strcat(szText, szCoord); WinSetWindowText(WinWindowFromID(hwnd, ID_PTRTEXT2), szText); break; case WM_CONTROLPOINTER: if (!fbBusy) break; /*-----------------------------------------------------*/ /* Load icon */ /* hptr = WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); */ /*-----------------------------------------------------*/ /*-----------------------------*/ /* Change pointer to hourglass */ /*-----------------------------*/ hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return(hptr); case WM_BUTTON2DOWN: WinSetCapture(HWND_DESKTOP, hwnd); break; case WM_BUTTON2UP: WinSetCapture(HWND_DESKTOP, NULL); break; case WM_MOUSEMOVE: WinInvalidateRect(hwnd, NULL, FALSE); if (!fbBusy) break; /*-----------------------------------------------------*/ /* Load icon */ /* hptr = WinLoadPointer(HWND_DESKTOP, NULL, ID_ICON); */ /*-----------------------------------------------------*/ /*-----------------------------*/ /* Change pointer to hourglass */ /*-----------------------------*/ hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return (MPARAM)TRUE; case WM_COMMAND: switch (SHORT1FROMMP(mp1)) { case ID_DLG: WinDlgBox(HWND_DESKTOP, hwnd, TestDlgProc, NULL, DLG_HINTS, NULL ); break; case ID_REMOVE: fbBusy = FALSE; WinEnableWindow(WinWindowFromID(hwnd, ID_REMOVE), FALSE); break; case MI_EXIT: WinPostMsg(hwnd, WM_QUIT, 0L, 0L); break; default: break; } break; case WM_ERASEBACKGROUND: return (MRESULT)TRUE; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } MRESULT EXPENTRY TestDlgProc(HWND hwndDlg, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; switch (msg) { case WM_INITDLG: if (!fbBusy) break; EntryFieldProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_ENTRY), EntryProc); ListboxProc = WinSubclassWindow(WinWindowFromID(hwndDlg, ID_LISTBOX), ListProc); WinEnableWindow(WinWindowFromID(hwndDlg, ID_ENTRY), FALSE); break; case WM_CONTROLPOINTER: if (!fbBusy) return (WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE)); hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return(hptr); case WM_COMMAND: switch(SHORT1FROMMP(mp1)) { case ID_OK: WinDismissDlg(hwndDlg, TRUE); break; default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2); } WinDismissDlg(hwndDlg, TRUE); break; default: return WinDefDlgProc(hwndDlg, msg, mp1, mp2); } return FALSE; } MRESULT EXPENTRY EntryProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; switch (msg) { case WM_MOUSEMOVE: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return (MPARAM)TRUE; } // Call public entry field procedure return ((*EntryFieldProc)(hwnd, msg, mp1, mp2)); } MRESULT EXPENTRY ListProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { HPOINTER hptr; switch (msg) { case WM_CONTROLPOINTER: hptr = WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE); WinSetPointer(HWND_DESKTOP, hptr); return(hptr); } // Call public listbox procedure return ((*ListboxProc)(hwnd, msg, mp1, mp2)); } ═══ ═══ #define ID_PTRTEXT2 262 #define ID_PTRTEXT1 261 #define ID_REMOVE 260 #define ID_DLG 259 #define ID_LISTBOX 258 #define ID_OK 257 #define DLG_HINTS 256 #define ID_ICON 206 #define ID_ENTRY 205 #define MI_RESUME 204 #define MI_EXIT 203 #define IDM_ONE 202 #define ID_TITLE 201 #define ID_MAINWND 200 ═══ ═══ #include #include "hints.h" STRINGTABLE PRELOAD BEGIN ID_TITLE, "PM Hints and Tips" END ICON ID_MAINWND hints.ico ICON ID_ICON wait.ico ACCELTABLE ID_MAINWND BEGIN VK_F3, MI_EXIT, VIRTUALKEY END MENU ID_MAINWND PRELOAD BEGIN SUBMENU "E~xit", IDM_ONE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END rcinclude hints.dlg ═══ ═══ DLGINCLUDE 1 "HINTS.H" DLGTEMPLATE DLG_HINTS LOADONCALL MOVEABLE DISCARDABLE BEGIN DIALOG "Test Dialog Box", DLG_HINTS, 22, 20, 114, 101, FS_NOBYTEALIGN | FS_DLGBORDER | WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_TITLEBAR BEGIN CONTROL "OK", ID_OK, 5, 5, 29, 13, WC_BUTTON, BS_PUSHBUTTON | BS_DEFAULT | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_ENTRY, 7, 84, 100, 8, WC_ENTRYFIELD, ES_LEFT | ES_MARGIN | WS_TABSTOP | WS_VISIBLE CONTROL "", ID_LISTBOX, 5, 21, 104, 56, WC_LISTBOX, WS_TABSTOP | WS_VISIBLE END END ═══ ═══ hints.exe: hints.obj \ hints.def hints.res link @hints.l rc hints.res hints.obj: hints.c hints.h cl /c /Alfu /W2 /Gs /Gc /Zi /Od hints.c hints.res: hints.h hints.rc hints.ico hints.dlg wait.ico rc -r hints.rc ═══ ═══ ULONG Colour; Colour = CLR_RED; WinSetPresParam(WinWindowFromID(hwndDlg, ID_CLEAR), PP_BACKGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); Colour = CLR_YELLOW; WinSetPresParam(WinWindowFromID(hwndDlg, ID_CLEAR), PP_FOREGROUNDCOLORINDEX, (ULONG)sizeof(Colour), &Colour); ═══ ═══ CONTROL "Clear MLE", ID_CLEAR, 85, 5, 70, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE PRESPARAMS PP_BACKGROUNDCOLORINDEX, CLR_RED PRESPARAMS PP_FOREGROUNDCOLORINDEX, CLR_YELLOW ═══ ═══ CHAR font[11]; /*------------------------------------------------*/ /* Length parameter must include NULL terminator, */ /* so use SIZEOF and not STRLEN */ /*------------------------------------------------*/ strcpy(font, "10.Courier"); WinSetPresParam(WinWindowFromID(hwndDlg, ID_CLEAR), PP_FONTNAMESIZE, (ULONG)sizeof(font), font); ═══ ═══ CONTROL "Clear MLE", ID_CLEAR, 85, 5, 70, 13, WC_BUTTON, BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE PRESPARAMS PP_FONTNAMESIZE, "10.Courier" ═══ ═══ static HWND hwndEntry; SWCNTRL PgmEntry; PgmEntry.hwnd = hwndFrame; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, Title); hwndEntry = WinAddSwitchEntry(&PgmEntry); while(WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); WinRemoveSwitchEntry(hwndEntry); ═══ ═══ SWCNTRL PgmEntry; case WM_xxx: ; ; PgmEntry.hwnd = WinQueryWindow(hwnd, QW_PARENT, FALSE); PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, "Tips and Hints"); WinChangeSwitchEntry(WinQuerySwitchHandle(PgmEntry.hwnd, 0), &PgmEntry); break; ═══ ═══ VOID APIENTRY WinSetTitle(PSZ); case WM_xxx: ; ; WinSetTitle("Tips and Hints"); break; ═══ ═══ while (TRUE) { while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); if (qmsg.mp1 == NULL) break; else WinCancelShutdown(hmq, FALSE); } ═══ ═══ BOOL APIENTRY WinNoShutdown(USHORT sessionid, BOOL fNoShutdown); WinNoShutdown(0, TRUE); // To disable WinNoShutdown(0, FALSE); // To enable ═══ ═══ hSwL = WinQuerySwitchHandle(hwndFrame, 0); ═══ ═══ hSwL = WinQuerySwitchHandle(WinQueryWindow(hwnd, QW_PARENT, FALSE), 0); WinQuerySwitchEntry(hSwL, &PgmEntry); ═══ ═══ #define INCL_WIN #include #include #include #include "hints.h" MRESULT EXPENTRY MainWndProc (HWND, USHORT, MPARAM, MPARAM); /****************************************************************************/ VOID cdecl main (void) { HAB hab; HMQ hmq; HWND hwndFrame, hwndClient; QMSG qmsg; ULONG flFrameFlags; CHAR Title[80]; SWCNTRL PgmEntry; SHORT X_Left, Y_Bot, Height, Width; LONG ScrHeight, ScrWidth; /****************************************************************************/ hab = WinInitialize(0); hmq = WinCreateMsgQueue(hab, 0); WinRegisterClass(hab, "Hints", MainWndProc, CS_SIZEREDRAW, 0); WinLoadString( hab, NULL, ID_TITLE, sizeof(Title), Title ); flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_ACCELTABLE | FCF_ICON; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flFrameFlags, "Hints", (PSZ)Title, 0L, NULL, ID_MAINWND, &hwndClient); ScrWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScrHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); Width = 400; Height = 300; X_Left = ((SHORT)ScrWidth - Width) / 2; Y_Bot = ((SHORT)ScrHeight - Height) / 2; /*-----------------------*/ /* Startup in foreground */ /*-----------------------*/ WinSetWindowPos(hwndFrame, NULL, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); /*------------------*/ /* Add to task list */ /*------------------*/ PgmEntry.hwnd = hwndFrame; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, Title); WinAddSwitchEntry(&PgmEntry); while (WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); /*------------------------------------*/ /* Remove from task list and clean up */ /*------------------------------------*/ WinRemoveSwitchEntry(WinQuerySwitchHandle(hwndFrame, 0)); WinDestroyWindow(hwndFrame); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /****************************************************************************/ MRESULT EXPENTRY MainWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { switch (msg) { case WM_COMMAND: switch (SHORT1FROMMP(mp1)) { case MI_EXIT: WinPostMsg(hwnd, WM_QUIT, 0L, 0L); break; default: break; } break; case WM_ERASEBACKGROUND: return (MRESULT)TRUE; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } ═══ ═══ #define ID_MAINWND 200 #define ID_TITLE 201 #define IDM_ONE 202 #define MI_EXIT 203 #define MI_RESUME 204 ═══ ═══ #include #include "hints.h" STRINGTABLE PRELOAD BEGIN ID_TITLE, "PM Hints and Tips" END ICON ID_MAINWND hints.ico ACCELTABLE ID_MAINWND BEGIN VK_F3, MI_EXIT, VIRTUALKEY END MENU ID_MAINWND PRELOAD BEGIN SUBMENU "E~xit", IDM_ONE BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END ═══ ═══ hints.exe: hints.obj \ hints.def hints.res link @hints.l rc hints.res hints.obj: hints.c hints.h cl /c /Alfu /W2 /Gs /Gc /Zi /Od hints.c hints.res: hints.h hints.rc hints.ico rc -r hints.rc ═══ ═══ SHORT X_Left, Y_Bot, Height, Width; LONG ScrHeight, ScrWidth; ScrWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScrHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); /*-----------------------------------------------*/ Width = 400; /* Or set as a percentage of screen size */ Height = 300; /* eg. Width = ScrWidth/2; Height = ScrHeight/2; */ /*-----------------------------------------------*/ X_Left = ((SHORT)ScrWidth - Width) / 2; Y_Bot = ((SHORT)ScrHeight - Height) / 2; WinSetWindowPos(hwndFrame, HWND_TOP, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowText(hwndFrame, "Hints - Size and Position Fixed"); ═══ ═══ FCF_STANDARD includes the following flags - o FCF_TITLEBAR o FCF_SYSMENU o FCF_MINMAX o FCF_SIZEBORDER o FCF_TASKLIST o FCF_MENU o FCF_ACCELTABLE o FCF_SHELLPOSITION o FCF_ICON If you required all these flags except FCF_ACCELTABLE then you could set up your own identifier as follows - #define FCF_NOACCEL FCF_STANDARD & ~FCF_ACCELTABLE ═══ ═══ WinMapWindowPoints(hwnd, WinQueryWindow(hwnd, QW_PARENT, FALSE), (PPOINTL)&WinRect, 2); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowPos(hwndFrame, NULL, 0, 0, 0, 0, SWP_MINIMIZE); ═══ ═══ case WM_MINMAXFRAME: if (((PSWP)mp1)->fs & SWP_MINIMIZE) { /*-----------------------*/ /* About to be minimized */ /*-----------------------*/ } else if (((PSWP)mp1)->fs & SWP_MAXIMIZE) { /*-----------------------*/ /* About to be maximized */ /*-----------------------*/ } else if (((PSWP)mp1)->fs & SWP_RESTORE) { /*----------------------*/ /* About to be restored */ /*----------------------*/ } break; ═══ ═══ WinEnableWindow (WinWindowFromID (hwndFrame, FID_MINMAX), FALSE); ═══ ═══ flCFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_NOBYTEALIGN | FCF_SIZEBORDER | FCF_MINMAX; hwndChildFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flCFrameFlags, "Hints2", (PSZ)CTitle, 0L, NULL, 0, &hwndChild); WinSetOwner(hwndChildFrame, hwndFrame); WinSetWindowPos(hwndChildFrame, HWND_TOP, 350, 100, 200, 200, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); ═══ ═══ RECTL rc; HPS hps; HWND hwndActiveWin; PID pid; TID tid; CHAR szText[20], szPid[6]; case WM_PAINT: hwndActiveWin = WinQueryActiveWindow(HWND_DESKTOP, FALSE); WinQueryWindowProcess(hwndActiveWin, &pid, &tid); strcpy(szText, "Process ID = "); strcat(szText, itoa(pid, szPid, 10)); WinQueryWindowRect(hwnd, &rc); hps = WinBeginPaint(hwnd, NULL, &rc); WinDrawText (hps, strlen(szText), szText, &rc, SYSCLR_WINDOWTEXT, SYSCLR_WINDOW, DT_LEFT | DT_ERASERECT); WinEndPaint(hps); break; case WM_TIMER: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER); WinInvalidateRect(hwnd, NULL, TRUE); /* Cause PID to be displayed */ break; ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hwndFrame, FID_TITLEBAR), FALSE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinEnableWindow(WinWindowFromID(hwndFrame, FID_TITLEBAR), TRUE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowULong(hwndFrame, QWL_STYLE, (WinQueryWindowULong(hwndFrame, QWL_STYLE) & ~FS_SIZEBORDER | FS_DLGBORDER)); WinInvalidateRect(hwndFrame, NULL, TRUE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowULong(hwndFrame, QWL_STYLE, (WinQueryWindowULong(hwndFrame, QWL_STYLE) & ~FS_DLGBORDER | FS_SIZEBORDER)); WinInvalidateRect(hwndFrame, NULL, TRUE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowBits(hwndFrame, QWL_STYLE, (~FS_SIZEBORDER | FS_DLGBORDER), ( FS_SIZEBORDER | FS_DLGBORDER)); WinInvalidateRect(hwndFrame, NULL, TRUE); ═══ ═══ hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowBits(hwndFrame, QWL_STYLE, (FS_SIZEBORDER | ~FS_DLGBORDER), (FS_SIZEBORDER | FS_DLGBORDER)); WinInvalidateRect(hwndFrame, NULL, TRUE); ═══ ═══ WinQueryWindowRect(hwnd, (PRECTL)&WinRect); ═══ ═══ case WM_MINMAXFRAME: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowUShort(hwndFrame, QWS_XRESTORE, 100); WinSetWindowUShort(hwndFrame, QWS_YRESTORE, 100); WinSetWindowUShort(hwndFrame, QWS_CXRESTORE, 200); WinSetWindowUShort(hwndFrame, QWS_CYRESTORE, 200); break; ═══ ═══ ACCELTABLE ID_MAINWND BEGIN VK_F3, MI_EXIT, VIRTUALKEY END ICON ID_MAINWND hints.ico MENU ID_MAINWND PRELOAD BEGIN . . . END ═══ ═══ case WM_SAVEAPPLICATION: WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT, FALSE), &swp); PrfWriteProfileData(HINI_USERPROFILE, "Hints", "Size", &swp, (ULONG)sizeof(swp)); return NULL; ═══ ═══ /*--------------------------------------------------------------*/ /* This should probably go just after your WinCreate... call */ /*--------------------------------------------------------------*/ ULONG DataLength; DataLength = sizeof(swp); if (!PrfQueryProfileData(HINI_USERPROFILE, "Hints", "Size", &swp, &DataLength)) { swp.x = 100; /*-----------------------------------*/ swp.y = 100; /* Profile not found so use defaults */ swp.cx = 200; /*-----------------------------------*/ swp.cy = 200; } WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); ═══ ═══ SHORT X_Left, Y_Bot, Height, Width; X_Left = 100; Y_Bot = 100; Width = 400; Height = 300; WinSetWindowPos(hwndFrame, HWND_TOP, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); ═══ ═══ WinSetWindowPos(hwndFrame, HWND_BOTTOM, X_Left, Y_Bot, Width, Height, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ZORDER); ═══ ═══ swp.x = 100; /*----------------------------*/ swp.y = 100; /* Set restored size/position */ swp.cx = 200; /*----------------------------*/ swp.cy = 200; WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE | SWP_MINIMIZE); ═══ ═══ swp.x = 100; /*----------------------------*/ swp.y = 100; /* Set restored size/position */ swp.cx = 200; /*----------------------------*/ swp.cy = 200; WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE | SWP_MAXIMIZE); ═══ ═══ /*-------------------------------------------------------------*/ /* Declare your subclassed window procedure and pointer to the */ /* default frame window procedure */ /*-------------------------------------------------------------*/ MRESULT EXPENTRY SubFrameProc(HWND, USHORT, MPARAM, MPARAM); PFNWP OldFrameProc; /*-------------------------------------------------------------*/ /* Immediately after creating your main window store the */ /* address of the default frame window procedure */ /*-------------------------------------------------------------*/ OldFrameProc = WinSubclassWindow(hwndFrame, (PFNWP)SubFrameProc); /*-------------------------------------------------------------*/ /* The following example procedure allows your window to be */ /* reduced in size to 25x25 pels. */ /*-------------------------------------------------------------*/ MRESULT EXPENTRY SubFrameProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { PTRACKINFO ptrack; switch(msg) { case WM_QUERYTRACKINFO: /*----------------------------------------------------------*/ /* Invoke the default frame window procedure first in order */ /* to update the tracking rectangle to the new position. */ /*----------------------------------------------------------*/ OldFrameProc(hwnd, msg, mp1, mp2); ptrack = (PTRACKINFO)mp2; ptrack->ptlMinTrackSize.x = 25; ptrack->ptlMinTrackSize.y = 25; return((MRESULT)TRUE); break; default: return(OldFrameProc(hwnd, msg, mp1, mp2)); break; } return((MRESULT)NULL); } ═══ ═══ ScrWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); ScrHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, (SHORT)ScrWidth, (SHORT)ScrHeight, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); ═══ ═══ /*----------------------------------*/ /* To start a 500 millisecond timer */ /*----------------------------------*/ WinStartTimer(hab, hwndClient, TimerID, 500); ═══ ═══ WinStopTimer(hab, hwndClient, TimerID); ═══ ═══ case WM_TIMER: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER); break; ═══ ═══ case WM_CREATE: ; ; /*-------------------*/ /* Make system modal */ /*-------------------*/ hFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetSysModalWindow(HWND_DESKTOP, hFrame); break; case WM_xxx: /*------------------------*/ /* Remove system modality */ /*------------------------*/ WinSetSysModalWindow(HWND_DESKTOP, NULL); break; ═══ ═══ #define INCL_WIN #include #include #include #include "hints.h" PFNWP OldFrameProc; MRESULT EXPENTRY MainWndProc (HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY ChildWndProc (HWND, USHORT, MPARAM, MPARAM); MRESULT EXPENTRY NewFrame (HWND, USHORT, MPARAM, MPARAM); /****************************************************************************/ VOID cdecl main (void) { HAB hab; HMQ hmq; static HWND hwndEntry, hwndClient, hwndChild, hwndFrame, hwndChildFrame; QMSG qmsg; ULONG flFrameFlags, flCFrameFlags, DataLength; CHAR Title[80], CTitle[80]; SWCNTRL PgmEntry; SWP swp; /****************************************************************************/ hab = WinInitialize(0); hmq = WinCreateMsgQueue(hab, 0); WinRegisterClass(hab, "Hints", MainWndProc, CS_SIZEREDRAW, 0); WinRegisterClass(hab, "Hints2", ChildWndProc, CS_SIZEREDRAW, 0); WinLoadString( hab, NULL, ID_TITLE, sizeof(Title), Title ); WinLoadString( hab, NULL, ID_CTITLE, sizeof(CTitle), CTitle ); flCFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_NOBYTEALIGN | FCF_SIZEBORDER | FCF_MINMAX; flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MENU | FCF_SIZEBORDER | FCF_MINMAX | FCF_ACCELTABLE | FCF_NOBYTEALIGN; hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flFrameFlags, "Hints", (PSZ)Title, 0L, NULL, ID_MAINWND, &hwndClient); OldFrameProc = WinSubclassWindow(hwndFrame, (PFNWP)NewFrame); DataLength = sizeof(swp); if (!PrfQueryProfileData(HINI_USERPROFILE, "Hints", "Size", &swp, &DataLength)) { swp.x = 100; swp.y = 100; swp.cx = 200; swp.cy = 200; /*-------------------------------------------------------------*/ /* For full screen - */ /* */ /* swp.cx = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN); */ /* swp.cy = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN); */ /*-------------------------------------------------------------*/ } WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); hwndChildFrame = WinCreateStdWindow(HWND_DESKTOP, 0L, &flCFrameFlags, "Hints2", (PSZ)CTitle, 0L, NULL, 0, &hwndChild); WinSetOwner(hwndChildFrame, hwndFrame); WinSetWindowPos(hwndChildFrame, HWND_TOP, 350, 100, 200, 200, SWP_SIZE | SWP_MOVE | SWP_SHOW | SWP_ACTIVATE); PgmEntry.hwnd = hwndFrame; PgmEntry.hwndIcon = NULL; PgmEntry.hprog = NULL; PgmEntry.idProcess = NULL; PgmEntry.idSession = NULL; PgmEntry.uchVisibility = SWL_VISIBLE; PgmEntry.fbJump = SWL_JUMPABLE; strcpy(PgmEntry.szSwtitle, Title); hwndEntry = WinAddSwitchEntry(&PgmEntry); WinStartTimer( hab, hwndClient, 1, 500 ); WinSendMsg(hwndFrame, WM_SETICON, WinQuerySysPointer(HWND_DESKTOP, SPTR_APPICON, FALSE), NULL); WinSendMsg(hwndChildFrame, WM_SETICON, WinQuerySysPointer(HWND_DESKTOP, SPTR_APPICON, FALSE), NULL); while(WinGetMsg(hab, &qmsg, NULL, 0, 0)) WinDispatchMsg(hab, &qmsg); WinStopTimer( hab, hwndClient, 1); WinDestroyWindow(hwndFrame); WinRemoveSwitchEntry(hwndEntry); WinDestroyMsgQueue(hmq); WinTerminate(hab); } /****************************************************************************/ MRESULT EXPENTRY MainWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { RECTL rc; SWP swp; HPS hps; HWND hwndActiveWin, hwndFrame; PID pid; TID tid; CHAR szText[20], szPid[6]; switch (msg) { case WM_PAINT: hwndActiveWin = WinQueryActiveWindow(HWND_DESKTOP, FALSE); WinQueryWindowProcess(hwndActiveWin, &pid, &tid); strcpy(szText, "Process ID = "); strcat(szText, itoa(pid, szPid, 10)); WinQueryWindowRect(hwnd, &rc); /*------------------------------------------------------------------*/ /* WinMapWindowPoints(hwnd, WinQueryWindow(hwnd, QW_PARENT, FALSE), */ /* (PPOINTL)&rc, 2); */ /*------------------------------------------------------------------*/ hps = WinBeginPaint(hwnd, NULL, &rc); WinDrawText (hps, strlen(szText), szText, &rc, SYSCLR_WINDOWTEXT, SYSCLR_WINDOW, DT_LEFT | DT_ERASERECT); WinEndPaint(hps); break; case WM_TIMER: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER); WinInvalidateRect(hwnd, NULL, TRUE); /* Cause PID to be displayed */ break; case WM_BUTTON1DOWN: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowText(hwndFrame, "Hints - Size and Position Fixed"); WinEnableWindow (WinWindowFromID (hwndFrame, FID_TITLEBAR), FALSE); WinEnableWindow (WinWindowFromID (hwndFrame, FID_MINMAX), FALSE); WinSetWindowBits(hwndFrame, QWL_STYLE, (~FS_SIZEBORDER | FS_DLGBORDER), ( FS_SIZEBORDER | FS_DLGBORDER)); /*-----------------------------------------------------------------*/ /* WinSetWindowULong(hwndFrame, QWL_STYLE, */ /* (WinQueryWindowULong(hwndFrame, QWL_STYLE) & */ /* ~FS_SIZEBORDER | FS_DLGBORDER)); */ /*-----------------------------------------------------------------*/ WinInvalidateRect(hwndFrame, NULL, TRUE); break; case WM_BUTTON2DOWN: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowText(hwndFrame, "Hints"); WinEnableWindow (WinWindowFromID (hwndFrame, FID_TITLEBAR), TRUE); WinEnableWindow (WinWindowFromID (hwndFrame, FID_MINMAX), TRUE); WinSetWindowBits(hwndFrame, QWL_STYLE, (FS_SIZEBORDER | ~FS_DLGBORDER), (FS_SIZEBORDER | FS_DLGBORDER)); /*-----------------------------------------------------------------*/ /* WinSetWindowULong(hwndFrame, QWL_STYLE, */ /* (WinQueryWindowULong(hwndFrame, QWL_STYLE) & */ /* ~FS_DLGBORDER | FS_SIZEBORDER)); */ /*-----------------------------------------------------------------*/ WinInvalidateRect(hwndFrame, NULL, TRUE); break; case WM_MINMAXFRAME: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); if (((PSWP)mp1)->fs & SWP_MINIMIZE) { DosBeep(100, 100); } else if (((PSWP)mp1)->fs & SWP_MAXIMIZE) { DosBeep(1000, 100); } else if (((PSWP)mp1)->fs & SWP_RESTORE) { DosBeep(500, 100); } WinSetWindowUShort(hwndFrame, QWS_XRESTORE, 100); WinSetWindowUShort(hwndFrame, QWS_YRESTORE, 100); WinSetWindowUShort(hwndFrame, QWS_CXRESTORE, 200); WinSetWindowUShort(hwndFrame, QWS_CYRESTORE, 200); break; case WM_SAVEAPPLICATION: WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT, FALSE), &swp); PrfWriteProfileData(HINI_USERPROFILE, "Hints", "Size", &swp, (ULONG)sizeof(swp)); return NULL; case WM_COMMAND: switch (SHORT1FROMMP(mp1)) { case MI_MIN: hwndFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinSetWindowPos(hwndFrame, NULL, 0, 0, 0, 0, SWP_MINIMIZE); break; case MI_EXIT: WinPostMsg(hwnd, WM_QUIT, 0L, 0L); break; } case WM_ERASEBACKGROUND: return (MRESULT)TRUE; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } /****************************************************************************/ MRESULT EXPENTRY NewFrame(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { PTRACKINFO ptrack; switch(msg) { case WM_QUERYTRACKINFO: /*----------------------------------------------------------*/ /* Invoke the default frame window procedure first in order */ /* to update the tracking rectangle to the new position. */ /*----------------------------------------------------------*/ OldFrameProc(hwnd, msg, mp1, mp2); ptrack = (PTRACKINFO)mp2; ptrack->ptlMinTrackSize.x = 25; ptrack->ptlMinTrackSize.y = 25; return((MRESULT)TRUE); break; default: return(OldFrameProc(hwnd, msg, mp1, mp2)); break; } return((MRESULT)NULL); } /****************************************************************************/ MRESULT EXPENTRY ChildWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2) { RECTL rc; HPS hps; CHAR szText[22]; HWND hwndChildFrame; switch(msg) { case WM_PAINT: strcpy(szText, "I am a child of Hints"); WinQueryWindowRect(hwnd, &rc); hps = WinBeginPaint(hwnd, NULL, &rc); WinDrawText (hps, strlen(szText), szText, &rc, SYSCLR_WINDOWTEXT, SYSCLR_WINDOW, DT_LEFT | DT_ERASERECT); WinEndPaint(hps); break; case WM_ERASEBACKGROUND: return (MRESULT)TRUE; case WM_CLOSE: hwndChildFrame = WinQueryWindow(hwnd, QW_PARENT, FALSE); WinDestroyWindow(hwndChildFrame); break; } return WinDefWindowProc(hwnd, msg, mp1, mp2); } ═══ ═══ #define ID_MAINWND 200 #define ID_CHILDWND 201 #define ID_TITLE 202 #define ID_CTITLE 203 #define MI_EXIT 100 #define MI_RESUME 101 #define MI_MIN 102 ═══ ═══ hints + /A:16 /CO hints.exe hints.map /NOD llibce.lib+ os2.lib hints.def ═══ ═══ NAME Hints WINDOWAPI DESCRIPTION 'Test program for OS/2 Hints and Tips' STUB 'OS2STUB.EXE' DATA MULTIPLE HEAPSIZE 8192 STACKSIZE 8192 PROTMODE ═══ ═══ #include #include "hints.h" STRINGTABLE PRELOAD BEGIN ID_TITLE, "Hints" ID_CTITLE, "Child Window of Hints" END ACCELTABLE ID_MAINWND BEGIN VK_F3, MI_EXIT, VIRTUALKEY END MENU ID_MAINWND PRELOAD BEGIN MENUITEM "~Minimize", MI_MIN, MIS_TEXT SUBMENU "E~xit", 1 BEGIN MENUITEM "~Exit Program\tF3", MI_EXIT, MIS_TEXT MENUITEM "~Resume Program", MI_RESUME, MIS_TEXT END END ═══ ═══ hints.exe: hints.obj \ hints.def hints.res link @hints.l rc hints.res hints.obj: hints.c hints.h cl /c /Alfu /W2 /Gs /Gc /Zi /Od hints.c hints.res: hints.h hints.rc rc -r hints.rc