This is the Windows/DOS Developer's Journal SDK Annotation File, a
growing collection of useful annotations for the standard online Windows
API help file, win31wh.hlp, which is included with every Windows C++
compiler.  You can either cut and paste these annotations into your own
SDK help file (use ALT-E-A to create a help topic annotation), or you
can copy the accompanying .ann file to your main Windows directory. 
Unfortunately, WinHelp does not support any automated way of merging
annotation files, so you either have to add our annotations by hand, or
clobber your own annotations (if any) by copying in our .ann file.

For some reason, Microsoft shipped a changed (but not much improved)
version of the standard API help file with Visual C++ v1.5. The .ann
file has been revised to be compatible with that help file as well
as the standard one. If you have problems, send me (Ron Burk) mail
at 70302,2566, or 70302.2566@compuserve.com.


If you have a useful annotation you would like to submit to our
collection, send it to:

  CompuServe: 70302,2566  (Internet: 70302.2566@compuserve.com)

If we use your submission, we will send you a free Windows/DOS
Developer's Journal T-shirt, emblazoned on the back with an original
drawing by Kansas artist T. Watson Bogaard!


        Windows/DOS Developer's Journal

           Advanced  Serious  Technical

Windows/DOS Developer's Journal is the monthly publication for advanced
Windows programmers.  We cover a variety of topics such as VxDs,
undocumented functions, Windows NT, MFC, WinHelp programming, graphics,
communications, and so on -- usually in the form of reusable code that
you can use immediately.  In addition, each month contains regular
features like these:

    * SDK Annotations
         (they appear in the magazine before they appear in this file)
    * Windows Q&A
         (Paul Bonneau tackles the toughest Windows programming questions)
    * Bug++ of the Month
         (nasty bugs in the popular Windows C++ compilers)
    * Tech Tips
         (reader-submitted tips and techniques)
    * Books in Brief
         (a quick look at recently published books)
    * Shareware Spotlight
         (a look at shareware programming tools)
    * Practical C++
         (using C++ in real-life projects)

and more.  W/DDJ costs $34.99/year in the US, $45/year Canada/Mexico, or
$64/year elsewhere.  For more information, or to subscribe, contact R&D
Publications at (913) 841-1631; fax (913) 841-2624; email
wdsub@rdpub.com. 


     
  
------------------------------------------------------------

W/DDJ SDK Annotation #1
TOPIC: Dialog Boxes

If a listbox is the first control in a dialog's tab order
and the dialog box was not created with the WS_VISIBLE
style, the listbox does not correctly draw itself with the
focus. 

Reference: p35, March 1993 Windows/DOS Developer's Journal.

------------------------------------------------------------

W/DDJ SDK Annotation #2
TOPIC: Property Lists

The oft-quoted maxim that using window properties is slower
than using class or window extra bytes (via
GetWindowWord()/SetWindowWord()) is totally false if you use
a global atom rather than a string to name the property. 
Properties were about 20% slower than window words under
Windows 3.0, but under Windows 3.1 GetProp() is about 300%
faster than GetWindowWord(). 

Reference: p 49, March 1993 Windows/DOS Developer's Journal.

------------------------------------------------------------

W/DDJ SDK Annotation #3
TOPIC: WM_MOUSEMOVE (2.x)

The documentation incorrectly states that the x and y
arguments are in screen coordinates.  They are in client
coordinates. 


------------------------------------------------------------

W/DDJ SDK Annotation #4 (revised)
TOPIC: SetWindowsHookEx (3.1)

SetWindowsHookEx() has a bug: using it to install a
task-specific hook can cause various failures.  The
workaround is to pass it a module handle rather than an
instance handle.  You can obtain a module handle from
GetModuleHandle().  If you only have the current instance
handle and not the name of the module, use the following
undocumented hack under Windows 3.1:

GetModuleHandle(MAKELP(0,hInstance));

If you #include <windowsx.h>, you can instead use the macro
GetInstanceModule(hInstance).  Under Windows NT, just pass a NULL to
obtain the handle of the current process.  Note that the MSDN News
article on this subject has the arguments to MAKELP() backwards. 


Reference: MSDN News #1, 1993
Revised by: Tom Nolan

------------------------------------------------------------

W/DDJ SDK Annotation #5
TOPIC: CS_BYTEALIGNWINDOW 0x2000

The documentation makes it sound like this style bit is the
one you want for efficient bitblts.  In fact, most of your
bitblts will be to the client area of the window, not the
non-client area, so CS_BYTEALIGNCLIENT is the style bit you
should set if you are concerned about bitblt operation
efficiency.  Unaligned windows are slower at VGA resolution,
but typically not an issue with higher resolution
adapters (such as 256-color SVGA). 

Reference: p65, December 1993 Windows/DOS Developer's Journal.


------------------------------------------------------------

W/DDJ SDK Annotation #6
TOPIC: CODE Module Definition Statement

The documentation for the FIXED attribute is incorrect.  Under Windows
3.1, if you mark code or data segments in your .exe FIXED, the loader
ignores that attribute -- the segments will be moveable.  If you mark
code or data segments in your .dll FIXED, however, the loader will make
them fixed and will page lock them as well.  Due to the implementation
of GlobalPageLock(), that can result in your segments using up precious
DOS memory, eventually preventing Windows from spawning new applications
(since each new application needs at least 512 bytes of DOS memory for a
task database entry).  The October 1994 Windows/DOS Developer's Journal
provides code to allocate fixed memory without using up precious
conventional memory. 


------------------------------------------------------------

W/DDJ SDK Annotation #7
TOPIC: WS_EX_TRANSPARENT 0x00000020L

Note that this bit does not really create transparent
windows.  If you create a window with this style, it is true
that the windows below it will show through as its
background.  However, if you then move your new window, it
will have the same background as it did in its original
position -- blotting out whatever it is covering in its new
position. 

------------------------------------------------------------

W/DDJ SDK Annotation #8
TOPIC: WM_NCHITTEST (2.x)

You can process this message to allow the user to drag a
window that does not have a title bar.  When you receive a
WM_NCHITTEST message and the mouse is in your client area
(or whatever conditions you want to start the drag), just
return HTCAPTION rather than passing the message on to
DefWindowProc(). 

Reference: p 37, March 1993 Windows/DOS Developer's Journal.


------------------------------------------------------------

W/DDJ SDK Annotation #9
TOPIC: WM_TIMER (2.x)

Although it sounds odd, you can use a WM_TIMER message as a
way to kill another application, if you can obtain the
handle of the main of the application you want to kill. 
Create a timer callback function that does nothing but pass
its first argument (window handle) to DestroyWindow().  Then
use PostMessage() to post (to the other app's main window) a
WM_TIMER message that points to your callback function. 
Your timer callback will get executed in the context of the
target application. 

Reference: p 64, September 1992 Windows/DOS Developer's Journal.



------------------------------------------------------------

W/DDJ SDK Annotation #10
TOPIC: MemoryWrite (3.1)

MemoryWrite() has a bug in it: it trashes the high 16 bits
of the EDI register (the 32-bit version of the DI register). 
The workaround is to save the register before calling
MemoryWrite() and restore it afterward. 

Reference: p. 71, April 1994 Windows/DOS Developer's Journal



------------------------------------------------------------

W/DDJ SDK Annotation #11
TOPIC: EscapeCommFunction (2.x)

The documentation omits one potential value for the
nFunction parameter, although it is defined in windows.h. 
The name is GETBASEIRQ and it returns the base address of
the COM port in the lower word and the IRQ setting in the
high word.  If the high word is -1 the port doesn't exist;
if it is 0, the comm driver does not support this escape
(which is the case, for example with some kinds of enhanced
serial boards). 

Submitted by: Thomas Zeisluft

------------------------------------------------------------

W/DDJ SDK Annotation #12
TOPIC: MessageBox (2.x)

Do not call MessageBox() from within the LibMain() of an
implicitly-linked DLL.  It will fail because the application
will not yet have a message queue at that point, and
MessageBox() (or anything else) cannot create its window
when the message queue does not yet exist.  Once the
application executes its internal startup code and calls
InitApp(), then it has a message queue and can safely call
functions that create windows. 

------------------------------------------------------------

W/DDJ SDK Annotation #13
TOPIC: LB_ADDSTRING (2.x)

If you are changing the contents of a listbox (for example,
by adding or deleting multiple strings), you may want to
minimize screen redrawing and maximize speed by disabling
window redrawing during your operation.  Follow these steps:

1) Send a WM_REDRAW with wParam equal to FALSE to the listbox.
2) Perform your adds or deletes.
3) Send a WM_REDRAW with wParam equal to TRUE to the listbox.
4) Use InvalidateRect() to force the listbox to redraw itself.



------------------------------------------------------------

W/DDJ SDK Annotation #14
TOPIC: RegisterWindowMessage (2.x)

Do you really need to register a private window message?
Probably not, if all you need is an intra-app message number
that does not conflict with any Windows message numbers. 
Microsoft has revised its statement about what message
numbers are available for your private use.  Microsoft now
guarantees that you can use message numbers 0x8000 through
0xBFFF and they will not conflict with any system messages. 
They also claim the next SDK (Chicago?) will define WM_APP
equal to 0x8000 in windows.h. 

Reference: Microsoft Knowledge Base article Q86835



------------------------------------------------------------

W/DDJ SDK Annotation #15
TOPIC: WM_CHAR (2.x)

The documentation incorrectly claims that wParam is the
virtual key code.  In fact, it is the ASCII value of the key
pressed.  For example, pressing the '$' (ASCII 0x5B) key
produces a wParam equal to 0x5B -- if you interpreted that
as a virtual key code, you would incorrectly believe that
the user had pressed VK_HOME!

Submitted by: Brent Rector

------------------------------------------------------------

W/DDJ SDK Annotation #16
TOPIC: WinHelp (3.0)

The documentation says that the return value is nonzero if WinHelp() is
successful.  In fact, WinHelp() only returns failure for systemic
problems, like being unable to allocate global memory, or being unable
to spawn winhelp.exe.  If WinHelp() successfully passes your request to
winhelp.exe, it returns success, period.  So, for example, if the named
help file is invalid, or you try to jump to a help topic that does not
exist, or any number of other logical errors, WinHelp() still returns
success. 

------------------------------------------------------------

W/DDJ SDK Annotation #17
TOPIC: WM_ENTERIDLE (2.x)

The documentation says that this messsage gets sent to your
application's "main window".  In fact, a dialog sends the WM_ENTERIDLE
message to its own parent window, which may or may not happen to be your
application's main window. 


------------------------------------------------------------

W/DDJ SDK Annotation #18
TOPIC: OPENFILENAME (3.1)

The documentation does not completely describe the behavior when
selecting multiple files.  To allow the user to select multiple files,
you turn on the flag OFN_ALLOWMULTISELECT.  If you do that and call
OpenFile(), and if the user then selects multiple files, then OpenFile()
will copy (into lpstrFile) the path, followed by a space, followed by
space-separated filenames.  For example, if the user selected files
"fred.1" and "fred.2" from directory "c:\test", lpstrFile would then
point to the following string:

    "c:\test fred.1 fred.2"

However, the documentation does not point out that if the user selects
only one file, then the path is not kept separate from the filename. 
Using the previous example, if the user selected only file "fred.1",
then lpstrFile would point to this:

    "c:\test\fred.1"

Submitted by Julian Templeman



------------------------------------------------------------

W/DDJ SDK Annotation #19
TOPIC: CreateRoundRectRgn (3.0)

This function has a bug.  It will produce a GP fault if the region
rectangle is empty (either nLeftRect equals nRightRect, or nBottomRect
equals nTopRect).  About the only workaround is to create a wrapper
function that first checks whether the rectangle is empty. 

Reference: p67, June 1994 Windows/DOS Developer's Journal
Submitted by Chris Mason



------------------------------------------------------------

W/DDJ SDK Annotation #20
TOPIC: EnableMenuItem (2.x)

When you are making changes to a window menu, the menu bar is not
immediately updated.  To force those changes (such as enabling/disabling
menu items) to be visible right away, make sure you call DrawMenuBar(). 

------------------------------------------------------------

W/DDJ SDK Annotation #21
TOPIC: DrawText (2.x)

DrawText() has an off-by-one error that can result in a GP fault.  The
bug is evoked when you use pass an explicit string length instead of
NULL-terminating the text string.  The bug is not evoked if you use the
DT_NOPREFIX flag, or if you NULL-terminate the text string (the easiest
workaround). 

Reference: p53, August 1994 Windows/DOS Developer's Journal

------------------------------------------------------------

W/DDJ SDK Annotation #22
TOPIC: WM_MEASUREITEM (3.0)

Windows supports owner-draw menus, but only popup owner-draw menus work
correctly.  If you try to create an owner-draw menubar for a window,
Windows will not send you the WM_MEASUREITEM message as it should. 

Reference: Microsoft Knowledge Base article Q69969

------------------------------------------------------------

W/DDJ SDK Annotation #23
TOPIC: WINDOWPOS (3.1)

The documentation says that y is "the position of the right edge of the
window".  It is, of course, the position of the top edge of the window. 


------------------------------------------------------------

W/DDJ SDK Annotation #24
TOPIC: Shell Dynamic-Data Exchange Interface Overview (3.1)

The documentation says you can use DDE to get a list of Program Manager
groups by "issuing a request for the Group item." In fact, that is not
the correct item name -- you must use 'Groups', not 'Group'. 



------------------------------------------------------------

W/DDJ SDK Annotation #25
TOPIC: TrackPopupMenu (3.0)

The documentation incorrectly states that you can pass the
TPM_RIGHTBUTTON flag if you want the menu to respond to the right
(secondary) mouse button instead of the left (primary) mouse button.  In
fact, passing TPM_RIGHTBUTTON causes the menu to respond to the right
mouse button as well as the left.  There is apparently no combination of
bits that cause the menu to respond only to the right mouse button. 


