home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-28 | 39.5 KB | 1,026 lines |
- Path: sparky!uunet!ukma!cs.widener.edu!dsinc!pitt.edu!infidel
- From: tomh@wes.on.ca (Tom Haapanen)
- Newsgroups: comp.os.ms-windows.announce
- Subject: Windows Programmer FAQ: ASCII format, 02/04
- Message-ID: <1993Jan28.030802.117.comp.os.ms-windows.FAQ-prg.2@pitt.edu>
- Date: 27 Jan 93 16:59:07 GMT
- Sender: infidel+@pitt.edu
- Followup-To: comp.os.ms-windows.misc
- Organization: Waterloo Engineering Software
- Lines: 1013
- Approved: infidel+@pitt.edu
-
- The following is part 02 of 04 of the ASCII text version of the
- Microsoft Windows Programmer FAQ. While some of you may find this the best
- format, the more popular format is the WinHelp file. These are posted
- simultaneously with the ASCII version to comp.binaries.ms-windows.
-
- You can obtain a copy of the WinHelp version as "faqprg01.zip" by ftp
- from sonygate.sony.com [192.63.138.2], in /pub/comp.binaries.ms-windows.
- It will also be placed on ftp.cica.indiana.edu once disk space permits.
-
-
-
- BEGIN--------------cut here--------cut here------------cut here----------
- from the system menu, if there is one.
-
- Also, you can alternately disable resizing by creating the windows with
- ~WS_THICKFRAME, and disabling the Size... item on the system menu.
-
- ...........................................................................
-
- 5.1.10. Getting the handle of the active window
- ------------------------------------------------
- To get the active window's handle, just call
- hActiveWindow = GetFocus();
-
- ...........................................................................
-
- 5.1.11. Keeeping a window on top
- ---------------------------------
- To keep a window on top of all other windows without requiring it to be the
- active window (akin to the behaviour exhibited by the Windows 3.1 clock),
- you can make the following function call:
- SetWindowPos(hWnd, (HWND)-1, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- Note that it is not considered polite behavior by an application to always
- keep its window topmost, unless you at least give the user the option of
- disabling this "feature".
-
- ...........................................................................
-
- 5.1.12. Limiting window size
- -----------------------------
- To limit window size, you'll need to process the WM_GETMINMAXINFO message,
- and fill in the structure describing the minimum and maximum window sizes.
-
- ...........................................................................
-
- 5.1.13. Right-justifying menu items
- ------------------------------------
- To right-justify an entire menu item or just a part of it, place a \a in
- the string just before the right-justified part.
-
- Incidentally, the Windows 3.0 CUA guidelines no longer call for right-
- justifying the Help menu on the menu bar.
-
- ...........................................................................
-
- 5.1.14. Right-justifying menu items at runtime
- -----------------------------------------------
- It's undocumented, but what you need is a 0x08 in the menu string. The
- easiest way to do this is to place a \b in the string before the right-
- justified part (either the text of the accelerator key).
-
- Incidentally, the Windows 3.0 CUA guidelines no longer call for right
- justifying the Help menu on the menu bar.
-
- ...........................................................................
-
- 5.1.15. Trapping mouse clicks on desktop
- -----------------------------------------
- To trap mouseclicks on the desktop, you will need to subclass the desktop
- window. The following code fragment illustrates the technique (sample code
- courtesy of Blake Coverett, blakeco@microsoft.com ):
-
- To subclass the desktop:
- hWndDesktop=GetDesktopWindow();
- hSaveTask=GetCurrentTask();
- lpfnDesktop=(FARPROC)GetWindowLong(hWndDesktop, GWL_WNDPROC);
- lpfnSubClassProc=MakeProcInstance((FARPROC)WndProc, hInst);
- SetWindowLong(hWndDesktop, GWL_WNDPROC,
- (LPARAM)(LONG)lpfnSubClassProc);
-
- and then to undo it when ready to unload:
- SetWindowLong(hWnd,GWL_WNDPROC, (LPARAM)(LONG)lpfnDesktop);
- PostAppMessage(hSaveTask,WM_QUIT,0,0);
-
- ...........................................................................
-
- 5.1.16. Using status bars with MDI
- -----------------------------------
- Add the following code fragments to the indicated places in the WinProc()
- of an application, or the FrameWinProc() of a MDI application.
-
- case WM_CREATE:
- hWndClient = CreateWindow( "MDIClient",...,
- WS_CHILD|WS_VISIBLE|WS_CLIBSIBLINGS|
- WS_HSCROLL|WS_VSCROLL,... );
- hWndStatus = CreateWindow( "Static",...,
- WS_CHILD|WS_VISIBLE|SS_LEFT|SS_NOPREFIX,... );
- ...
- case WM_SIZE:
- GetClientRect( hWnd,&rect );
- // Calculate DIVIDING_LINE such that.
- // rect.top < DIVIDING_LINE < rect.bottom
- // One choice:
- // DIVIDING_LINE = rect.bottom - GetSystemMetrics(SM_CYMENU);
- MoveWindow( hWndClient,rect.left,rect.top,
- rect.right,DIVIDING_LINE,TRUE );
- MoveWindow( hWndStatus,rect.left,DIVIDING_LINE,
- rect.right,rect.bottom,TRUE );
- break; // Do *not* pass to DefFrameProc() of MDI app!!!
- ...
- // To change the status text:
- SendMessage( hWndStatus,WM_SETTEXT,0,(LONG)(LPSTR)szStatusText );
-
- Notes:
- * For non-MDI applications, all references to hWndClient above will simply
- be removed.
- * Menu selection can be tracked by setting the status text at a response to
- the WM_MENUSELECT message.
- * To draw a line between status bar and the rest of the client area, the
- DIVIDING_LINE should be adjusted in either MoveWindow() call to leave a
- gap between, which is called InvalidateRect() for, and actually being
- painted in response to the WM_PAINT.
- * The parent window should have WS_CLIPCHILDREN style bit set.
-
- ---------------------------------------------------------------------------
-
- 5.2. Dialogs
- =============
-
- ...........................................................................
-
- 5.2.1. A dialog as an MDI child window [Borland OWL]
- -----------------------------------------------------
- If you want to use a dialog as an MDI child window, you can use the
- following code as the basis of your own implementation. Thanks to Martin
- Calsyn (martin@iastate.edu) for the sample code.
-
- What follows are three files:
- TMDIDLOG.H The interface for modeless MDI-child dialogs.
- TMDIDLOG.CPP The implementation of same
- EXAMPLE.CPP An (partial) example of using the TMDIDLOG
- classes.
-
- You need to sub-class TMDIDialogWindow in order to give your MDI child a
- unique icon, etc (not shown in the example) and to implement the
- CreateChildDialog abstract method. And, of course, you need to sub-class
- TMDIDialog in order to establish a transfer structure, interface objects
- and all the things you usually do with sub-classes of TDialog.
-
- The classes included below work by presenting the dialog as a child of a
- TBWindow which is itself a child of the MDI. These classes are based on
- tips and suggestions offered by the Borland advisor line.
-
- Martin claims that the transfer of this technique to MS MFC is trivial.
-
- ---------------------------- TMDIDLOG.H -------------------------
-
- #ifndef __tmdidlog_h__
- #define __tmdidlog_h__
-
- #include <owl.h>
- #include <bwindow.h>
-
- _CLASSDEF(TMDIDialog)
- _CLASSDEF(TMDIDialogWindow)
-
- class TMDIDialog : public TDialog
- {
- public:
- TMDIDialog(PTWindowsObject AParent,LPSTR AName,PTModule AModule=NULL) :
- TDialog(AParent, AName, AModule) {};
- TMDIDialog(PTWindowsObject AParent,int ResourceId,PTModule
- AModule=NULL):
- TDialog( AParent, ResourceId, AModule ) {};
- virtual void WMSetFocus( RTMessage Msg ) = [WM_FIRST + WM_SETFOCUS];
- virtual void CloseWindow( int ret );
- virtual void CloseWindow();
- virtual void Cancel( RTMessage msg ) = [ID_FIRST + IDCANCEL];
-
- friend class TMDIDialogWindow;
-
- protected:
- TMDIDialogWindow *mdiw;
- };
-
- class TMDIDialogWindow : public TBWindow
- {
- public:
- TMDIDialogWindow(PTWindowsObject aParent,LPSTR aName,
- PTModule aModule = NULL);
- virtual void WMMDIActivate( RTMessage Msg ) = [WM_FIRST +
- WM_MDIACTIVATE];
- virtual void WMSetFocus( RTMessage Msg ) = [WM_FIRST + WM_SETFOCUS];
- virtual void WMSize( RTMessage Msg ) = [WM_FIRST + WM_SIZE];
- virtual void SetupWindow();
- virtual LPSTR GetClassName() { return "_TMDIDialogWindow"; };
- virtual void GetWindowClass( WNDCLASS& aWndClass );
- virtual void WMGetMinMaxInfo( RTMessage msg ) = [WM_FIRST +
- WM_GETMINMAXINFO];
- virtual TMDIDialog *CreateChildDialog() = 0;
-
- private:
- PTMDIDialog dlog;
- };
-
- #endif
-
- ------------------------- TMDIDLOG.CPP --------------------------
-
- #include "tmdidlog.h"
-
- TMDIDialogWindow::TMDIDialogWindow(PTWindowsObject aParent,
- LPSTR aName,
- PTModule aModule) :
- TBWindow(aParent,aName,aModule)
- {
- dlog = NULL;
- GetApplication()->SetKBHandler( this );
- SetFlags( WB_KBHANDLER, FALSE );
- }
-
- void TMDIDialogWindow::WMMDIActivate( RTMessage Msg )
- {
- TWindow::WMMDIActivate( Msg );
-
- if ( Msg.WParam == TRUE ) {
- GetApplication()->SetKBHandler(this);
- if (dlog!=NULL)
- SetFocus(((PTDialog)dlog)->HWindow );
- }
- }
-
- void TMDIDialogWindow::GetWindowClass( WNDCLASS& aWndClass )
- {
- TWindow::GetWindowClass(aWndClass);
- }
-
- void TMDIDialogWindow::WMSetFocus(RTMessage Msg)
- {
- PostMessage(HWindow, WM_MDIACTIVATE, TRUE, 0L );
- DefWndProc(Msg);
- }
-
- void TMDIDialogWindow::SetupWindow()
- {
- TWindow::SetupWindow();
-
- dlog = CreateChildDialog();
- if (dlog) {
- dlog->mdiw = this;
- RECT r;
- GetApplication()->MakeWindow(dlog);
- SetFocus(dlog->HWindow);
- GetWindowRect(HWindow,&r);
- Attr.X = r.left;
- Attr.Y = r.top;
- GetWindowRect(dlog->HWindow,&r);
- AdjustWindowRect(&r,WS_CAPTION|WS_BORDER,0);
- Attr.W = r.right - r.left;
- Attr.H = r.bottom - r.top;
- MoveWindow(HWindow,Attr.X, Attr.Y, Attr.W, Attr.H, 1);
- }
- }
-
- void TMDIDialogWindow::WMGetMinMaxInfo( RTMessage msg )
- {
- if (dlog) {
- MINMAXINFO *lpmmi = (MINMAXINFO *)msg.LParam;
- RECT r;
- POINT pt1,pt2;
- GetWindowRect(HWindow,&r);
- pt1.x = r.left;
- pt1.y = r.top;
- GetWindowRect(dlog->HWindow,&r);
- AdjustWindowRect(&r,WS_CAPTION|WS_BORDER,0);
- pt2.x = r.right - r.left;
- pt2.y = r.bottom - r.top;
- lpmmi->ptMaxSize = pt2;
- lpmmi->ptMaxPosition = pt1;
- lpmmi->ptMinTrackSize = pt2;
- lpmmi->ptMaxTrackSize = pt2;
- }
- }
-
- void TMDIDialogWindow::WMSize( RTMessage Msg )
- {
- RECT r;
- TWindow::WMSize( Msg );
- if (!IsIconic(HWindow)) {
- GetWindowRect(dlog->HWindow,&r);
- AdjustWindowRect(&r,WS_CAPTION|WS_BORDER,0);
- Attr.W = r.right - r.left;
- Attr.H = r.bottom - r.top;
- MoveWindow(HWindow, Attr.X, Attr.Y, Attr.W, Attr.H, 1);
- }
- }
-
- //
- // TMDIDialog methods...
- //
-
- void TMDIDialog::WMSetFocus( RTMessage Msg )
- {
- GetApplication()->SetKBHandler( this );
- DefWndProc( Msg );
- }
-
- void TMDIDialog::CloseWindow(int ret)
- {
- TDialog::CloseWindow(ret);
- mdiw->CloseWindow();
- }
-
- void TMDIDialog::CloseWindow()
- {
- TDialog::CloseWindow();
- mdiw->CloseWindow();
- }
-
- void TMDIDialog::Cancel(RTMessage msg)
- {
- CloseWindow(IDCANCEL);
- }
-
- -------------------------- EXAMPLE.CPP --------------------------
-
- //
- // #include owl, tmdidlog.h and others as needed
- //
-
- //
- // ChildDialog is a dialog box defined in the RC file under
- // the name 'MY_DLOG'. The definition of MY_DLOG is pretty plain
- // except that it should have the following attributes:
- // STYLE WS_CHILD | WS_VISIBLE
- // and optionally CLASS "BORDLG"
- // That is, it should have no caption, sys menu, or border of any
- // type. It should also have an origin of 0,0 otherwise it will
- // be offset within the MDI child window.
- //
- // An instance of ClientDialog can be created as a modeless MDI
- // client by doing : `new ChildDialogWindow(this, "Title", NULL)'
- // from your MDI frame object or other appropriate place.
- //
-
- class ChildDialog : public TMDIDialog
- {
- public:
- ChildDialog(PTWindowsObject aParent,
- LPSTR aName, PTModule aModule = NULL);
-
- };
-
- ChildDialogWindow::ChildDialogWindow(PTWindowsObject aParent,LPSTR aName,
- PTModule aModule)
- : TMDIDialogWindow(aParent,aName,aModule)
- {
- obj_id = object_id;
- }
-
- TMDIDialog* ChildDialogWindow::CreateChildDialog()
- {
- return (TMDIDialog*)new ChildDialog(this,(LPSTR)"MY_DLOG",NULL);
- }
-
- ChildDialog::ChildDialog(PTWindowsObject aParent,
- LPSTR aName, PTModule aModule)
- : TMDIDialog(aParent,aName,aModule)
- {
- // The usual stuff: Initialize the transfer structure, create
- // interface objects, etc.
-
- }
-
-
- ...........................................................................
-
- 5.2.2. Adding controls to a non-dialog window
- ----------------------------------------------
- You can do this by simply calling CreateWindow() with one of the predefined
- child window control class names (see the control class definition table in
- the SDK reference manual).
-
- ...........................................................................
-
- 5.2.3. Doing a timeout in a dialog
- -----------------------------------
- Start a timer in your WM_INITDIALOG processing. If your dialog box receives
- the WM_TIMER message, kill the timer and post yourself a WM_COMMAND messgae
- with wParam == IDOK. If the user presses any button, restart the timer.
-
- ...........................................................................
-
- 5.2.4. Minimize button on modal dialog moves when clicked
- ----------------------------------------------------------
- It's a bug in Windows 3.1. To duplicate this, create a modal dialog with
- the styles CAPTION, MODAL FRAME, MINIMIZE-BOX, activate the dialog, press
- the Minimize button -- and watch it move to the top right corner, on top of
- the modal frame!
-
- The workaround: don't use a Minimize box on a modal dialog.
-
- ...........................................................................
-
- 5.2.5. Modifying common dialogs
- --------------------------------
- If you want to modify a common dialog, do not delete controls from the
- templates, as the common dialog procedures expect these controls to exist.
- Instead, make them invisible or move them outside the boundaries of the
- dialog gox to prevent the user from seeing or accessing them.
-
- ...........................................................................
-
- 5.2.6. Null dialog handles from Borland custom dialogs
- -------------------------------------------------------
- If you keep getting null dialog handles with Borland C++ unless I have
- Turbo C++ running, your dialog is probably of the BorDlg class, which
- requires code in BWCC.DLL. However, you have probably not done anything to
- force BWCC.DLL to be loaded with your application, so the dialog manager
- cannot find the necessary routines to draw the dialog. The easiest way to
- force BWCC.DLL to be loaded is to call BWCCGetVersion() at the very
- beginning of your application, and to link in BWCC.LIB.
-
- Alternatly, you can do a
- WinExec("loadbwcc.exe");
- when you start up your application, as long as loadbwcc.exe is available.
-
- ...........................................................................
-
- 5.2.7. Preventing switching away from a modal dialog
- -----------------------------------------------------
- The design of the Windows API means that if there are two dialogs active
- simultaneously, the user can switch between the two, even one of them is
- modal. To prevent this, you should use EnableWindow() to explicitly diable
- any modeless dialogs when your modal dialog starts up.
-
- ...........................................................................
-
- 5.2.8. Using a dialog as your main window
- ------------------------------------------
- First, you have to create a dialog box first. Include a class name(you
- name
- it). Then, in your WinMain function, register a class using that class
- name
- and add the constant DLGWINDOWEXTRA to the window extra byte component.
- This
- constant is defined in Windows.h. Then, use CreateDialog() to display the
- dialog, make sure the last 2 parameters are set to NULL. In your WndProc
- function, instead of calling DefWindowProc, call DefDlgProc. Then, you are
- basically all set. Make sure in your dialog definition you create your
- dialog
- box initially visible. For further information, see your docs.
-
-
- ...........................................................................
-
- 5.2.9. Using Borland custom dialogs with other compilers
- ---------------------------------------------------------
- You can't integrate bwcc.dll with the Dialog Editor but you can manually
- modify the dialog file and use appropriate BWCC control classes and styles.
-
- Include bwcc.h in your header file and then add bwcc.lib to your link
- options (before libw.lib). Also make sure bwcc.dll can be found in either
- the Windows directory or the current directory when the app starts or in
- the path.
-
- Examples (thanks to Sam Espartero, sqe@hpcc01.corp.hp.com):
-
- Link Options:
- /align:16 /NOD PLAYCD USERCODE MCICDA SUPERCLS,PLAYCD.EXE,,
- LIBW MLIBCEW bwcc mmsystem, PLAYCD.DEF
-
- Dialog File:
-
- ABOUT DIALOG 4, 5, 199, 137
- STYLE WS_POPUPWINDOW | DS_MODALFRAME | WS_VISIBLE |
- WS_CLIPSIBLINGS | WS_DLGFRAME
- CAPTION "Sample BWCC Dialog"
- CLASS "BorDlg"
- BEGIN
- CONTROL "", 100, "Static", SS_ICON | WS_CHILD | WS_VISIBLE,
- 5, 16, 16, 16
- CONTROL "", -1, "BorShade", WS_CHILD | WS_BORDER,
- 33,6,161,126
- ...
-
- CONTROL "", IDOK, "BorBtn", BS_DEFPUSHBUTTON | WS_TABSTOP |
- WS_CHILD, 154, 9, 32, 20
- END
-
- Message box:
-
- #ifdef BWCC
- BWCCMessageBox(GetActiveWindow(), "Unknown MCI Error!",
- "MCI Error", MB_OK | MB_ICONHAND);
- #else
- MessageBox(GetActiveWindow(), "Unknown MCI Error!",
- "MCI Error", MB_OK | MB_ICONHAND);
- #endif
-
- ---------------------------------------------------------------------------
-
- 5.3. Controls
- ==============
-
- ...........................................................................
-
- 5.3.1. Allowing ENTER in a multiline edit control
- --------------------------------------------------
- To allow the use of the Enter key, there is no need to subclass the edit
- control. An easier way in Windows 3.1 and later (which also works better!)
- is to specify ES_WANTRETURN as part of the style for the edit control (see
- the Windows 3.1 SDK documentation for details).
-
- ...........................................................................
-
- 5.3.2. Aligning multi-column listboxes
- ---------------------------------------
- In the resource file make sure the list box has the LBS_USETABSTOPS style.
- When you add the items to the listbox, separate the fields with tabs. You
- can either use the default tab stops, or set your own by sending the
- LBS_SETTABSTOPS message to the listbox. For more information, see the SDK
- Reference, volumes 1 and 2.
-
- It is also possible to use a fixed font, but the tabstop solution usually
- ends up looking much better.
-
- ...........................................................................
-
- 5.3.3. Changing button colors
- ------------------------------
- In Windows 3.0, the button face is defined by two colors. The grey (white
- with EGA) face and a dark grey (grey if ega) shadow. The colors also
- change when the button goes from a normal to pushed in state. The
- WM_CTLCOLOR message only allows you to change one color at a time so to
- which of the button face colors should this apply? (Windows 2.x button
- faces had only one color so it made sense.)
-
- Maybe something tricky could have been done by using the background color
- for the shadow and foreground color for the face and perhaps doing
- something strange to get the text color in another way... And how do you
- return 2 brushes (you now need a foreground and a background brush)? Or
- maybe even better, make colors a property of the window and some windows
- could have multiple color properties...
-
- Anyway, Windows doesn't look at the WM_CTLCOLOR message for buttons and
- thus doesn't allow you to change the button colors. Try it with a listbox
- instead... The only way to change button colors is to specify
- ButtonColor=, ButtonShadow= and ButtonText= in the [Colors] section of your
- win.ini file.
-
- In Windows 3.1, the button text, shadow and face colors can also be defined
- using the Control Panel.
-
- ...........................................................................
-
- 5.3.4. Creating controls at runtime in Visual Basic
- ----------------------------------------------------
- To create controls dynamically, you need to create a control array at
- design time. You can then extend it at runtime, and specify new properties
- for the new controls you have created.
-
- ...........................................................................
-
- 5.3.5. Combo boxes with tab stops
- ----------------------------------
- Windows does not support combo boxes with tab stops. If you need such
- items, you have three choices:
- * Use an owner-draw combo box. This will allow you to draw the items at
- the precise locations you need. Text-only owner-draw controls are not
- difficult to implement.
- * Use GetTextExtent() to determine the length of each part, padding with
- blanks until it approximately lines up. Fairly easy, but not fast and
- not precise.
- * Change the font of the control to either Courier or the fixed System
- font. While this is simple to do, your combo box font will not be
- consistent with the rest of your dialog box controls.
-
- ...........................................................................
-
- 5.3.6. Custom button bitmaps in Borland dialogs
- ------------------------------------------------
- To create owner-drawn buttons for new additional buttons beyond those
- supplied in bwcc.dll, you first need to create the button bitmaps. Create
- them 63 pixels wide by 39 deep, and number them "logically".
-
- The bitmap numbers are related to the resource id of the button that you
- want to use them. Use the following numbers:
- button id + 1000 Unpressed bitmap
- button id + 3000 Pressed bitmap
- button id + 2000 Unpressed bitmap, EGA
- button id + 4000 Pressed bitmap, EGA
- If you use these bitmap ids, bwcc.dll will use the bitmaps on the buttons
- automatically.
-
- ...........................................................................
-
- 5.3.7. Drawing on a dialog background
- --------------------------------------
- To draw on a dialog background, you can either subclass the dialog, or,
- more simply, respond to the WM_PAINT message in your dialog procedure,
- calling ValidateRect() after you have redrawn the background.
-
- ...........................................................................
-
- 5.3.8. Hiding dialog controls
- ------------------------------
- EnableWindow(GetDlgItem(hDlg, IDD_CONTROLTOHIDE), FALSE);
- ShowWindow(GetDlgItem(hDlg, IDD_CONTROLTOHIDE), SW_HIDE);
- UpdateWindow(GetDlgItem(hDlg, IDD_CONTROLTOHIDE));
-
- ...........................................................................
-
- 5.3.9. Listboxes with large amounts of data
- --------------------------------------------
- A standard listbox is limited to 32K of data. If you need a listbox with a
- larger number of items, you can use one of the following options:
- * Use an owner-draw listbox with LBS_HASSTRINGS. This will allow 4096
- items.
- * Use an owner-draw listbox LBS_OWNERDRAWFIXED but without
- LBS_HASSTRINGS. This is somewhat more work, but will allow 8192
- items.
- Some third-party libraries also implement listbox classes which can handle
- huge amounts of data.
- Finally, Microsoft has a virtual listbox implementation available by ftp at
- ftp.uu.net, in the directory /vendor/microsoft/developer-network.
-
- ...........................................................................
-
- 5.3.10. Subclassing standard controls
- --------------------------------------
- You can subclass standard controls by having your own window procedure
- handle the messages for the windows you create (using SetWindowLong()).
- The only caveat here is for useability: make sure that your subclassed
- controls don't behave in an unexpected manner.
-
- What is definitely a bad idea is modify the class procedure of a standard
- control (using SetClassLong()) and changing the window procedure for all
- such windows, as this will affect all edit controls in all applications
- currently running in the Windows session.
-
- ...........................................................................
-
- 5.3.11. Using a window as a modal dialog
- -----------------------------------------
- To use a window as a modal dialog, you will need to implement your own
- message loop for that window, complete with PeekMessage(),
- TranslateMessage() and DispatchMessage() calls. This will allow you to
- accept events only for the current window, discarding all other events.
-
- ---------------------------------------------------------------------------
-
- 5.4. Memory
- ============
-
- ...........................................................................
-
- 5.4.1. Using new() in C++
- --------------------------
- In Borland C++ 2.0, and in 3.x's medium model, new() ends up calling
- LocalAlloc(), allocating memory from your near 64K segment. In BCC 3.x's
- large and compact models (and in Microsoft C/C++ 7.0), however, it will
- make one GlobalAlloc() and do subsegment allocations to allow you access to
- the full memory without making excessive demands on the system limit of
- 4096 (8192 in 386 enhanced mode) global memory handles.
-
- ...........................................................................
-
- 5.4.2. Global memory owned by DLL
- ----------------------------------
- If you use GlobalAlloc in a DLL, the application that called the DLL will
- own the object. There is a way around this, though: allocate the memory
- using the GMEM_DDESHARE flag; this will make the allocating code segment
- (rather than the current task) own the memory.
-
- ...........................................................................
-
- 5.4.3. Determining size of physical memory
- -------------------------------------------
- You need to make a DPMI call to obtain that piece of information. DPMI
- call 0500h with ES:DI pointing to a 30h byte buffer returns the "Free
- Memory Information":
-
- Offset Description
- 00h Largest available free block in bytes
- 04h Maximum unlocked page allocation
- 08h Maximum locked page allocation
- 0Ch Linear address space size in pages
- 10h Total number of unlocked pages
- 14h Number of free pages
- 18h Total number of physical pages
- 1Ch Free linear address space in pages
- 20h Size of paging file/partition in pages
- 24h-2Fh Reserved
-
- The size of one page in bytes can be determined by function 0604h, which
- returns the page size in bytes in BX:CX. To call a DPMI function, invoke
- the interrupt 31h. Carry bit will be clear if call was successful.
-
- The complete DPMI 0.9 specification is available free from Intel Literature
- JP26, Santa Clara. It's also available on ftp.cica.indiana.edu.
-
-
- ---------------------------------------------------------------------------
-
- 5.5. GDI
- =========
-
- ...........................................................................
-
- 5.5.1. Animation
- -----------------
- If you want to do good-quality animation under Windows 3.1 without
- requiring that each user have a 486/50 with an accelerated video card, you
- should consider using a differential animation technique. There is a good
- example available on ftp.uunet.uu.net (and also on CompuServe) under
- /vendor/microsoft/multimedia/sample called rleapp, which uses this
- technique. Another sample program in the same directory, transblt,
- demonstrates a technique for doing fast BitBlits.
-
- Both techniques are also documented in the technotes in /vendor/microsoft/
- multimedia/technote.
-
- ...........................................................................
-
- 5.5.2. Background color
- ------------------------
- If you insist on a white background, use
- WinClass.hbrBackground = GetStockObject(GCW_WHITEBRUSH);
- for your window background. If it doesn't matter to you, however, you
- should use the Control Panel-defined window background color instead:
- WinClass.hbrBackground = CreateSolidBrush(COLOR_WINDOW + 1);
-
-
- ...........................................................................
-
- 5.5.3. Changing palette entries in 16-color mode
- -------------------------------------------------
- If you are using a standard driver, you will need to bypass Windows to do
- it (if you happen to have a 16-color driver which support palettes, you can
- use standard Windows palette management functions).
-
- Microsoft will tell you to buy the DDK, but there is another way. Now, the
- Windows system palette maps onto the VGA 16-color palette as follows:
-
- VGAPAL SYSPAL VGAPAL SYSPAL
- 00 00 08 07
- 01 01 09 13
- 02 02 10 14
- 03 03 11 15
- 04 04 12 16
- 05 05 13 17
- 06 06 14 18
- 07 12 15 19
-
- So you can define some macros to take care of the mapping:
-
- #define syspal(n) (n<7 ? n : (n>8 ? n+4 : (n=7 ? 12 : 7)))
- #define vgapal(n) (n<7 ? n : (n>12 ? n-4 : (n=7 ? 8 : 7)))
-
- When you get a WM_SETFOCUS event, save the current state of the hardware
- colormap and installs the one you want. When you get a WM_KILLFOCUS event,
- restore the original palette. Don't use the palette registers directly,
- though, just modify the color registersthat they point to. (For details on
- redefining a VGA palette, see a book such as A Programmer's Guide to PC and
- PS/2 Video Systems by Richard Wilton.)
-
- ...........................................................................
-
- 5.5.4. DIB bitmaps
- -------------------
- Microsoft has higher-level DIB library and DLL available for downloading
- from CompuServe. Unfortunately, it is not currently available by ftp.
-
- ...........................................................................
-
- 5.5.5. Speeding up WM_PAINT redraws
- ------------------------------------
- To speed up your WM_PAINT processing, you may want to use a technique
- similar to the following one, as presented by John Grant
- (jagrant@emr1.emr.ca):
-
- There are two reasons for redrawing your window:
- * because Windows tells you to do it
- * because something application specific requires it
-
- You shouldn't have to redraw everything from scratch every time you get a
- WM_PAINT message - just save it as a bitmap and repaint from the bitmap.
- However, there are cases when the bitmap becomes invalid and you have to re-
- paint the hard way.
-
- In the main window WndProc, I respond to Windows messages as follows (note
- there may be other code too, I just put in the stuff relevant to the
- redraw):
-
- case WM_CREATE: KillBitmap();
- break;
- case WM_SIZE: KillBitmap();
- break;
- case WM_PAINT: DrawMyPicture(hwnd);
- break;
- case WM_DESTROY: KillBitmap();
- PostQuitMessage(0);
- break;
-
- Notice that you should not do KillBitmap() when I handle WM_PAINT. If, in
- response to an application-specific condition, you want to force a redraw,
- do the following:
-
- KillBitmap();
- InvalidateRect(hwnd,NULL,TRUE); // generates WM_PAINT
-
- Now, for an application specific sample code fragment:
-
- // global variable
- static HBITMAP hbitmap_main = NULL;
-
- void DrawMyPicture(HWND hwnd)
- {
- PAINTSTRUCT ps;
- HDC hdc;
-
- hdc = BeginPaint(hwnd, &ps);
- if (hbitmap_main == NULL){
- DrawMyPictureTheHardWay(hwnd, hdc);
- hbitmap_main = SaveClientAreaAsBitmap(hwnd);
- } else {
- DrawBitMap(hdc, hwnd, 0, 0, hbitmap_main);
- }
- EndPaint(hwnd,&ps);
- }
-
- void KillBitmap(void)
- {
- if (hbitmap_main != NULL){
- DeleteObject(hbitmap_main);
- hbitmap_main = NULL;
- }
- }
-
- Don't use PAINTSTRUCT.rcPaint which describes the area that Windows says
- needs repainting; just BitBlt the whole thing and Windows will clip it.
- No, it's not overkill - it's fast!
-
- Finally, two routines that you can put in your library for use with all
- your apps.
-
-
- /*-----------------------------------------------------------------*
- | save entire client area of window into a bitmap |
- *-----------------------------------------------------------------*/
-
- HBITMAP SaveClientAreaAsBitmap(HWND hwnd)
- {
- RECT rect;
- HDC hdc,hmemdc;
- HBITMAP hbitmap,old_hbitmap;
-
- hbitmap=NULL;
- hmemdc=NULL;
- hdc=NULL;
-
- //get source device context for the client area
- hdc=GetDC(hwnd);
- if(hdc==NULL) goto done;
-
- //get destination memory hdc compatible with client area
- hmemdc=CreateCompatibleDC(hdc);
- if(hmemdc==NULL) goto done;
-
- //create compatible bitmap for client area
- GetClientRect(hwnd,&rect); //.top & .left are both 0
- hbitmap=CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
- if(hbitmap==NULL) goto done;
-
- //select client area bitmap into device context so we can write on it
- old_hbitmap=SelectObject(hmemdc,hbitmap);
-
- //and copy it to the new hmemdc
- BitBlt( hmemdc,0,0, //destination (x,y)
- rect.right,rect.bottom, //width, height
- hdc,0,0, //source (x,y)
- SRCCOPY);
-
- //all done
- SelectObject(hmemdc,old_hbitmap);
-
- done: if(hdc !=NULL) ReleaseDC(hwnd,hdc);
- if(hmemdc!=NULL) DeleteDC(hmemdc);
-
- return(hbitmap);
- }
-
-
- /*----------------------------------------------------------------*
- | Draw a bitmap into the current device context. |
- | This is essentially the same as Petzold's code. |
- *----------------------------------------------------------------*/
- void DrawBitMap(HDC hdc,int xleft,int ytop,HBITMAP hbitmap)
- {
- RECT rect;
- HDC hmemdc;
- BITMAP bm;
- POINT point;
- HBITMAP old_hbitmap;
-
- hmemdc=NULL;
- old_hbitmap=NULL;
-
- //create memory device context & select bitmap
- hmemdc=CreateCompatibleDC(hdc);
- if(hmemdc==NULL) goto done;
- old_hbitmap=SelectObject(hmemdc,hbitmap);
-
- SetMapMode(hmemdc,GetMapMode(hdc)); //same as for hdc
-
- //get bitmap dimensions & convert to logical
- GetObject(hbitmap,sizeof(bm),&bm);
- point.x=bm.bmWidth;
- point.y=bm.bmHeight;
- DPtoLP(hdc,&point,1);
-
- BitBlt(hdc,xleft,ytop, //destination
- point.x,point.y, //width, height
- hmemdc,0,0, //source
- SRCCOPY);
-
- done: if(old_hbitmap!=NULL) SelectObject(hmemdc,old_hbitmap);
- if(hmemdc!=NULL) DeleteDC(hmemdc);
- return;
- }
-
-
- ...........................................................................
-
- 5.5.6. Using CMY colors instead of RGB
- ---------------------------------------
- To use CMY colors with the Windows GDI instead of RGB, you can define the
- following macro to supplement the standard RGB one:
- #define CMY(c, m, y) RGB(255 - c, 255 - m, 255 - y)
-
- ...........................................................................
-
- 5.5.7. Using only solid colors
- -------------------------------
- If you want to use only solid colors (that is, get the nearest solid color
- to the one you specified), use the GetNearestColor() function call to map
- an RGB value to a solid cor available in the current color palette. Also,
- if you are using a palette, you can call the PALETTERGB(r,g,b) macro
- instead of the usual RGB(r,g,b) to map to the nearest color in the palette.
-
- ---------------------------------------------------------------------------
-
- 5.6. Text and fonts
- ====================
-
- ...........................................................................
-
- 5.6.1. Creating new fonts
- --------------------------
- To create new TrueType fonts, you will need a commercial package such as
- Fontographer or FontMonger. While FontMonger is a more limited tool, it is
- quite inexpensive and often sufficient for smaller projects. Fontographer
- is a semi-professional tool with a higher price tag. Neither tool allows
- you to construct your own hints for small point sizes.
-
- ...........................................................................
-
- 5.6.2. Rotating fonts
- ----------------------
- First, you cannot rotate screen fonts. Effectively this means that you can
- only rotate TrueType and Type 1 (ATM) fonts. To do the rotation, you will
- have to create a new logical font with the correct escapement value.
- Select the font into the display context, do your displaying, select the
- original font back in, and delete the font object.
-
- Note that Type 1 fonts, which are considered device fonts, use a reversed
- direction for the rotation from TrueType fonts; you'll have to check the
- font type before doing the rotation, or otherwise you will have some fonts
- angled up and others down.
-
- ...........................................................................
-
- 5.6.3. TrueType width calculation
- ----------------------------------
- The most accurate widths for TrueType fonts can be obtained using the
- following method (courtesy of Glenn Adams (glenn@wheat-chex.ai.mit.edu)):
- 1. Using EnumFonts() (or EnumFontFamilies()), obtain lpntm->ntmSizeEM.
- This value "specifies the size of the em square for the font, in the
- units for which the font was designed (notional units)." Most fonts
- will have the value of 2048.
- 2. Create a font using the above size as the lfHeight. This will create a
- font with metrics that coincide with the coordinate space used in the
- font's design, i.e., no scaling will occur in the logical coordinate
- space.
- 3. Use GetCharABCWidths() to get the ABC width structures for all the
- font's glyphs. You can now compute the widths quite accurately, along
- with overhang and overhang. Keep in mind that the horizontal escapement
- (i.e., the distance current point is advanced after rendering a glyph)
- is equal to A + B + C of the returned widths. If A is negative, the
- glyph extends outside the EM square to the left; if C is negative, then
- the glyph extends outside the EM square to the right.
- One last point: the above widths will not take into account grid fitting,
- which will occur in actual display. But, if you set the mapping mode to
- MM_ISOTROPIC and use a logical coordinate space which coresponds to the
- font design size, you can do all your layout computations using design
- sizes without regard to final viewport mapping.
-
- ---------------------------------------------------------------------------
-
- 5.7. Miscellaneous
- END--cut here--cut here
-