home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 6.ddi / DOC.ZIP / WIN31.DOC < prev    next >
Encoding:
Text File  |  1992-06-10  |  90.2 KB  |  2,549 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. CONTENTS
  7. ___________________________________________________________________________
  8.  
  9.  
  10.  
  11.  
  12.  
  13. Changes to windows.h from 3.0 to           Message cracker examples  . . 26
  14. 3.1  . . . . . . . . . . . . . . . 1       Message handler function
  15. Catching coding errors at                  signatures  . . . . . . . . . 28
  16. compile-time: STRICT . . . . . . . 1       Improving reusability:
  17.   Why STRICT?  . . . . . . . . . . 2       Template_DefProc  . . . . . . 28
  18.   Compiling 3.0 applications . . . 3       Private and registered window
  19.   New typedefs, constants, and             messages  . . . . . . . . . . 29
  20.   helper macros  . . . . . . . . . 4       Message crackers and window
  21.     COMSTAT structure change . . . 5       instance data . . . . . . . . 30
  22.   Making your code STRICT                  Message crackers and dialog
  23.   compliant  . . . . . . . . . . . 6       procedures  . . . . . . . . . 33
  24.   STRICT conversion hints  . . .  10       Message crackers and window
  25.   Common compiler warnings and             subclassing . . . . . . . . . 34
  26.   errors . . . . . . . . . . . .  11       Dialog procedures: A better
  27. Macro APIs and message crackers . 14       way . . . . . . . . . . . . . 36
  28.   Macro APIs . . . . . . . . . .  15         Executing default dialog
  29.       3.1-only macro APIs  . . .  18         procedure functionality . . 37
  30.   Control message APIs . . . . .  18         Returning message results from
  31.     Control API Examples . . . .  18         dialog procedures . . . . . 37
  32.   Message cracker macros . . . .  22         How it works  . . . . . . . 37
  33.     Using message crackers and               A simplified example using
  34.     forwarders . . . . . . . . .  23         predefined macro APIs . . . 39
  35.     Saving time and improving              Converting existing code to use
  36.     readability with HANDLE_MSG . 24       message crackers  . . . . . . 41
  37.     How message crackers work  .  25
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.                                      i
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64. TABLES
  65. ___________________________________________________________________________
  66.  
  67.  
  68.  
  69.  
  70.  
  71. 1: New handle types  . . . . . . . 5
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.                                     ii
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122. ===========================================================================
  123. Changes to windows.h from 3.0 to 3.1
  124. ===========================================================================
  125.  
  126.                     The windows.h header file included with Borland C++ 3.1
  127.                     contains various features that make application
  128.                     development faster and easier by helping you find
  129.                     problems as you compile your code. These improvements
  130.                     include:
  131.  
  132.                     o STRICT option provides stricter type checking,
  133.                       helping you find type mismatch errors quickly.
  134.  
  135.                     o windows.h has been completely reorganized so that
  136.                       related functions, types, structures, and constants
  137.                       are grouped together.
  138.  
  139.                     o New UINT type used for 32-bit Windows upward
  140.                       compatibility
  141.  
  142.                     o New unique typedefs for all handle types, such as
  143.                       HINSTANCE and HMODULE.
  144.  
  145.                     o Various constants and typedefs missing in the 3.0
  146.                       windows.h have been added.
  147.  
  148.                     o Windows 3.0 compatibility: windows.h can be used to
  149.                       compile applications that run under Windows 3.0.
  150.  
  151.                     o Proper use of "const" for API pointer parameters and
  152.                       structure fields where pointer is read-only.
  153.  
  154.                     If you have ObjectWindows, also see OWL31.DOC in your
  155.                     OWL\DOC directory for details about how these changes
  156.                     affect ObjectWindows and your ObjectWindows
  157.                     applications.
  158.  
  159.  
  160.  
  161. ===========================================================================
  162. Catching coding errors at compile-time: STRICT
  163. ===========================================================================
  164.  
  165.                     The new windows.h supports an option called STRICT that
  166.                     enables the strictest possible compiler error checking.
  167.                     Strict compile-time checking helps you find programming
  168.                     errors when you compile your application, rather than
  169.                     at runtime.
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.                     The idea is that you define STRICT before including
  177.                     windows.h, which causes the various types and function
  178.                     prototypes in windows.h to be declared in a way that
  179.                     enforces very strict type checking. For example,
  180.                     without STRICT, it is possible to pass an HWND to a
  181.                     function that requires an HDC without any kind of
  182.                     compiler warning: with STRICT defined, this results in
  183.                     a compiler error.
  184.  
  185.                     Specific features provided by the STRICT option
  186.                     include:
  187.  
  188.                     o Strict handle type checking (you can't pass an HWND
  189.                       where an HDC is declared).
  190.  
  191.                     o Correct and more consistent declaration of certain
  192.                       parameter and return value types (for example,
  193.                       GlobalLock returns void FAR* instead of LPSTR).
  194.  
  195.                     o Fully prototyped typedefs for all callback function
  196.                       types (for example, dialog procedures, hook
  197.                       procedures, and window procedures)
  198.  
  199.                     o Windows 3.0 backward compatible: STRICT can be used
  200.                       with the 3.1 windows.h for creating applications that
  201.                       will run under Windows 3.0.
  202.  
  203.                     o The COMM DCB and COMSTAT structures are now declared
  204.                       in an ANSI compatible way.
  205.  
  206.  
  207.        Why STRICT?  =======================================================
  208.  
  209.                     The best way to think of STRICT is as a way for you to
  210.                     get the most out of the error checking capabilities
  211.                     built into Borland C++. STRICT is of great benefit
  212.                     especially with code under development, because it
  213.                     helps you catch bugs right away when you compile your
  214.                     code, rather than having to track it down at runtime
  215.                     with a debugger. By catching certain kinds of bugs
  216.                     right away, it's less likely that you'll ship your
  217.                     applications with bugs that weren't encountered in
  218.                     testing.
  219.  
  220.                     STRICT also makes it easier to migrate your code to the
  221.                     32-bit Windows platform later, because it will help you
  222.                     locate and deal with type incompatibilities that will
  223.                     arise when migrating to 32 bits.
  224.  
  225.  
  226.  
  227.                                    - 2 -
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.                     It's not very difficult to convert your application to
  235.                     use STRICT, and it can be done in stages if needed.
  236.  
  237.                     In order to take advantage of the STRICT option, you
  238.                     will probably have to make some simple changes to your
  239.                     source code (described in detail later).
  240.  
  241.                     We think you'll find that STRICT makes modifying,
  242.                     maintaining, and even reading your code much easier,
  243.                     and well worth the effort to convert your application.
  244.  
  245.  
  246.      Compiling 3.0  =======================================================
  247.       applications
  248.                     Unless you define STRICT, your 3.0 applications will
  249.                     compile with windows.h without serious modifications.
  250.                     The type declarations for many of the Windows APIs and
  251.                     callback functions have changed; those changes are
  252.                     backward compatible for C code, but not for C++ code.
  253.                     If you use C++, you'll notice compile- and link-time
  254.                     errors in many Windows API functions because of changes
  255.                     to types like WORD to UINT. See the following sections
  256.                     for more information.
  257.  
  258.                     All of the features of Borland C++ 3.1 can be used to
  259.                     develop applications that will run under Windows 3.0.
  260.                     There are two things you must do:
  261.  
  262.                     1. Define WINVER to 0x0300 before including windows.h
  263.  
  264.                        This ensures that only 3.0 compatible functions,
  265.                        structures, and definitions are available for use.
  266.                        You can do this in your makefile with
  267.                        -DWINVER=0x0300 in the compiler command line, in the
  268.                        IDE in the Options|Compiler|Code Generation|Defines
  269.                        input box, or in your code by adding "#define WINVER
  270.                        0x0300" before you include windows.h.
  271.  
  272.                     2. Use the -30 parameter to BRC or RC.
  273.  
  274.                        This marks your executable as a 3.0 application, so
  275.                        that Windows 3.0 won't prevent it from running with
  276.                        a "This application requires a later version of
  277.                        Windows" message. You will typically run RC twice in
  278.                        your makefile: Once to produce the .res file (with
  279.                        the -r switch), and a second time to combine your
  280.                        linked .exe and .res files into the final
  281.                        application. The -30 parameter must be used with the
  282.  
  283.  
  284.  
  285.                                    - 3 -
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.                        second invocation of RC. See Chapter 4 in the
  293.                        Borland C++ User's Guide for instructions on how to
  294.                        add the -30 parameter to your IDE projects.
  295.  
  296.  
  297.      New typedefs,  =======================================================
  298.     constants, and
  299.      helper macros  The following typedefs and constants have been added to
  300.                     windows.h. All are 3.0 compatible:
  301.  
  302.             WINAPI  Used in place of FAR PASCAL in API declarations. If you
  303.                     are writing a DLL with exported API entry points, you
  304.                     can use this for your own APIs.
  305.  
  306.           CALLBACK  Used in place of FAR PASCAL in application callback
  307.                     routines such as window procedures and dialog
  308.                     procedures
  309.  
  310.             LPCSTR  Same as LPSTR, except used for read-only string
  311.                     pointers. Typedefed as const char FAR*.
  312.  
  313.               UINT  Portable unsigned integer type whose size is determined
  314.                     by host environment (16 bits for Win 3.1). Synonym for
  315.                     "unsigned int". Used in place of WORD except in the
  316.                     rare cases where a 16-bit unsigned quantity is desired
  317.                     even on 32-bit platforms.
  318.  
  319.            LRESULT  Type used for declaration of all 32-bit polymorphic
  320.                     return values.
  321.  
  322.             LPARAM  Type used for declaration of all 32-bit polymorphic
  323.                     parameters.
  324.  
  325.             WPARAM  Type used for declaration of all 16-bit polymorphic
  326.                     parameters.
  327.  
  328.    MAKELPARAM(low,  Macro used for combining two 16-bit quantities into an
  329.              high)  LPARAM.
  330.  
  331.   MAKELRESULT(low,  Macro used for combining two 16-bit quantities into an
  332.              high)  LRESULT.
  333.  
  334.   MAKELP(sel, off)  Macro used for combining a selector and an offset into
  335.                     a FAR VOID* pointer.
  336.  
  337.     SELECTOROF(lp)  Macro used to extract the selector part of a far ptr.
  338.                     Returns a UINT.
  339.  
  340.  
  341.  
  342.  
  343.                                    - 4 -
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.       OFFSETOF(lp)  Macro used to extract the offset part of a far ptr.
  351.                     Returns a UINT.
  352.  
  353.  FIELDOFFSET(type,  Macro used for calculating the offset of a field in a
  354.             field)  data structure. The type parameter is the type of
  355.                     structure, and field is the name of the field whose
  356.                     offset is desired.
  357.  
  358.  
  359.                     -------------------------------------------------------
  360. New handle types      Typedef           Meaning
  361.                     -------------------------------------------------------
  362.  
  363.                       HINSTANCE         Instance handle type
  364.                       HMODULE           Module handle type
  365.                       HLOCAL            Local handle type
  366.                       HGLOBAL           Global handle type
  367.                       HTASK             Task handle type
  368.                       HFILE             File handle type
  369.                       HRSRC             Resource handle type
  370.                       HGDIOBJ           Generic GDI object handle type
  371.                                         (except HMETAFILE)
  372.                       HMETAFILE         Metafile handle type
  373.                       HDWP              DeferWindowPos handle
  374.                       HACCEL            Accelerator table handle
  375.           3.1 only    HDRVR             Driver handle
  376.  
  377.                     -------------------------------------------------------
  378.  
  379.  
  380. ------------------  The 3.0 declaration of the COMSTAT structure was not
  381.  COMSTAT structure  ANSI compatible: ANSI does not allow the use of
  382.             change  BYTE-sized bitfield declarations. To allow windows.h to
  383. ------------------  be used with full ANSI compliance, the COMSTAT
  384.                     structure has changed. The 7 bit fields below are now
  385.                     accessed as byte flags of the single status field:
  386.  
  387.  
  388.                     -------------------------------------------------------
  389.                       Old field name    Bit of status field
  390.                     -------------------------------------------------------
  391.  
  392.                       fCtsHold          CSTF_CTSHOLD
  393.                       fDsrHold          CSTF_DSRHOLD
  394.                       fRlsdHold         CSTF_RLSDHOLD
  395.                       fXoffHold         CSTF_XOFFHOLD
  396.                       fXoffSent         CSTF_XOFFSENT
  397.  
  398.  
  399.  
  400.  
  401.                                    - 5 -
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.                       fEof              CSTF_EOF
  409.                       fTxim             CSTF_TXIM
  410.  
  411.                     -------------------------------------------------------
  412.  
  413.                     No change is required if you are compiling with WINVER
  414.                     set to 0x0300 and are not using STRICT.
  415.  
  416.                     If you have code that accesses any of these fields,
  417.                     here's how you have to change your code:
  418.  
  419. Old code                      New code
  420. ---------------------------------------------------------------------------
  421.  
  422. if (comstat.fEof || ...)      if ((comstat.status & CSTF_EOF) || ...)
  423. comstat.fCtsHold = TRUE;      comstat.status |= CSTF_CTSHOLD;
  424. comstat.fTxim = FALSE;        comstat.status ~= CSTF_TXIM;
  425.  
  426.                     Be careful to properly parenthesize "&" expressions.
  427.                     See windows.h for more details.
  428.  
  429.  
  430.   Making your code  =======================================================
  431.   STRICT compliant
  432.                     Using STRICT with your existing Windows application
  433.                     code is not very difficult. Here's what you need to do:
  434.  
  435.                     o Decide what you want be STRICT compliant.
  436.  
  437.                       The first step is to decide what you want to be
  438.                       STRICT compliant.
  439.  
  440.                       STRICT is most valuable with newly developed code or
  441.                       code that you're maintaining or changing regularly.
  442.                       If you have a lot of stable code that has already
  443.                       been written and tested, and is not changed or
  444.                       maintained very often, you may decide that it's not
  445.                       worth the trouble to convert to STRICT.
  446.  
  447.                       If you are writing a C++ application, you don't have
  448.                       the option of applying STRICT to only some of your
  449.                       source files. Because of the way C++ "type safe
  450.                       linking" works, you may get linking errors if you mix
  451.                       and match STRICT and non-STRICT source files in your
  452.                       application.
  453.  
  454.                     o Enable strict compiler error checking
  455.  
  456.  
  457.  
  458.  
  459.                                    - 6 -
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.                       First, turn on all Borland C++'s warning and error
  467.                       messages. In the IDEs, you can use Options|Compiler|
  468.                       Messages|Display|All; for the command-line compiler,
  469.                       use the -w switch. Do this without turning on STRICT
  470.                       for now.
  471.  
  472.                       In you're writing applications in C, you might want
  473.                       to compile them as C++ to take advantage of C++'s
  474.                       stricter type checking and type-safe linking. You can
  475.                       do this by renaming .C files to .CPP or by using the
  476.                       IDEs' Options|Compiler|C++ Options|C++ Always option
  477.                       or the command-line compiler's -p switch.
  478.  
  479.                     o Change your code to use new STRICT types
  480.  
  481.                       First you need to go through your own source and
  482.                       header files and change type declarations to use the
  483.                       new types defined in windows.h. Below are the common
  484.                       types that should be changed:
  485.  
  486.  
  487.                       -----------------------------------------------------
  488.                         Old type          New type(s)
  489.                       -----------------------------------------------------
  490.  
  491.                         HANDLE            HINSTANCE, HMODULE, HGLOBAL,
  492.                                           HLOCAL, etc. as appropriate
  493.  
  494.                         WORD              UINT (EXCEPT where you really
  495.                                           want a 16-bit value even on a
  496.                                           32-bit platform) or WPARAM
  497.  
  498.                         LONG              LPARAM or LRESULT as appropriate
  499.  
  500.                         FARPROC           WNDPROC, DLGPROC, HOOKPROC, etc.
  501.                                           as appropriate (MakeProcInstance
  502.                                           and FreeProcInstance calls
  503.                                           require casting)
  504.  
  505.                       -----------------------------------------------------
  506.  
  507.                       See "Strict Conversion Notes" below for particular
  508.                       things to watch out for when changing your code.
  509.  
  510.                       The UINT type is important for 32-bit Windows
  511.                       migration. On 16-bit windows, WORD and UINT are
  512.                       identical: 16 bit unsigned quantities. On a 32-bit
  513.                       platform, a UINT will be 32 bits and WORD is 16 bits.
  514.  
  515.  
  516.  
  517.                                    - 7 -
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.                       This allows much more efficient code to be generated
  525.                       on the 32-bit platform where UINTs are used. You
  526.                       should use WORD in your code ONLY in those places
  527.                       where you want a 16 bit value, even on a 32-bit
  528.                       platform.
  529.  
  530.                       Because C++ mangles function names, any callback
  531.    C++ users note!    function whose arguments have changed between Windows
  532.                       3.0 and 3.1 (from WORD to UINT, for example) will
  533.                       generate link-time errors. You must either change the
  534.                       argument types or replace the 3.1 version of
  535.                       windows.h with the 3.0 version (in win30.h). It's
  536.                       highly recommended that you change the parameter
  537.                       types.
  538.  
  539.                       You may also want to use CALLBACK instead of FAR
  540.                       PASCAL in the declaration of your various callback
  541.                       functions, though this isn't necessary.
  542.  
  543.                       You may be able to save yourself some work by not
  544.                       converting the body of your window and dialog
  545.                       procedures to use WPARAM, LPARAM, and LRESULT right
  546.                       away, since those types are compatible with WORD and
  547.                       LONG, even in STRICT.
  548.  
  549.                     o Make sure your functions are declared before use
  550.  
  551.                       To compile as C++ or with all warnings enabled, all
  552.                       of your application functions must be properly
  553.                       declared before they are used. It's best to have all
  554.                       your declarations in an include file, rather than
  555.                       declaring them in your source files as needed: it's
  556.                       much easier to maintain your code this way should you
  557.                       need to change any of the declarations in the future.
  558.                       Chances are you will need to be making changes to the
  559.                       function declarations as you change over to the new
  560.                       STRICT data types.
  561.  
  562.                       While it's not strictly necessary to do so, it's a
  563.                       good idea to provide function parameter names in your
  564.                       function prototypes. This makes header files much
  565.                       easier to read, and provides a degree of
  566.                       self-documentation.
  567.  
  568.                     o Recompile without STRICT and fix resulting warnings
  569.  
  570.                       Without defining STRICT anywhere, recompile your
  571.                       application and fix any warnings that result. You can
  572.  
  573.  
  574.  
  575.                                    - 8 -
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.                       use the Borland C++ IDE's Search|Next Error (Alt+F7)
  583.                       command to speed up those fixes.
  584.  
  585.                       Some common compiler warnings--and how you should
  586.                       deal with them--are described later in this section.
  587.                       Use the rules found there to make the appropriate
  588.                       changes to your source.
  589.  
  590.                     o Run the app to make sure all is well.
  591.  
  592.                       After you've gotten your application to compile
  593.                       cleanly as C++ or with all warnings enabled, it's a
  594.                       good idea to run your app and put it through it's
  595.                       paces to make sure all is well.
  596.  
  597.                     o Define STRICT
  598.  
  599.                       After you've made a first pass and gotten things to
  600.                       compile cleanly without STRICT, it's time to turn it
  601.                       on and make the next round of changes.
  602.  
  603.                       If you've decided that you want to make your entire
  604.                       app STRICT, then the best and easiest thing to do is
  605.                       define STRICT in your makefile, by passing the
  606.                       -DSTRICT flag to the compiler or to use the Options|
  607.                       Compiler|Code Generation|Defines input box. If you
  608.                       want to do it on a per-source file basis, then simply
  609.                       define STRICT in the source file before you include
  610.                       windows.h.
  611.  
  612.                     o Recompile and clean up resulting errors
  613.  
  614.                       Once you've made the changes to your window and
  615.                       dialog procedures as outlined above, you're ready to
  616.                       recompile everything.
  617.  
  618.                       After turning on STRICT you'll probably get new
  619.                       errors and warnings that you'll need to go through
  620.                       and clean up.
  621.  
  622.                       You might also get link-time errors because of
  623.    C++ users note!    mismatched function parameter types. Check your
  624.                       function prototypes and definititions carefully.
  625.  
  626.                       The list of warnings and errors below will explain
  627.                       how to deal with most of the problems that arise.
  628.  
  629.  
  630.  
  631.  
  632.  
  633.                                    - 9 -
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  STRICT conversion  =======================================================
  641.              hints
  642.                     1. Always declare function pointers with the proper
  643.                        function type, rather than FARPROC. You'll need to
  644.                        cast function pointers to and from the proper
  645.                        function type when using MakeProcInstance,
  646.                        FreeProcInstance, and other functions that take or
  647.                        return a FARPROC:
  648.  
  649.                         BOOL CALLBACK DlgProc(HWND hwnd, UINT msg,
  650.                                               WPARAM wParam,
  651.                                               LPARAM lParam);
  652.                         DLGPROC lpfnDlg;
  653.  
  654.                         lpfnDlg=(DLGPROC)MakeProcInstance(DlgProc, hinst);
  655.                         ...
  656.                         FreeProcInstance((FARPROC)lpfnDlg);
  657.  
  658.                     2. Take special care with HMODULEs and HINSTANCEs. For
  659.                        the most part, the Kernel module management
  660.                        functions use HINSTANCEs, but there are a few APIs
  661.                        that return or accept only HMODULEs.
  662.  
  663.        WinMain and  3. If you've copied any API function declarations from
  664.    LibMain are two     windows.h, they may have changed, and your local
  665.   common examples.     declaration may be out of date. Remove your local
  666.                        declaration.
  667.  
  668.                     4. Properly cast the results of LocalLock and
  669.                        GlobalLock to the proper kind of data pointer.
  670.                        Parameters to these and other memory management
  671.                        functions should be cast to LHANDLE or GHANDLE, as
  672.                        appropriate.
  673.  
  674.                     5. Properly cast the result of GetWindowWord and
  675.                        GetWindowLong and the parameters to SetWindowWord
  676.                        and SetWindowLong.
  677.  
  678.                     6. When casting SendMessage, DefWindowProc, and
  679.                        SendDlgItemMsg or any other function that returns an
  680.                        LRESULT or LONG to a handle of some kind, you must
  681.                        first cast the result to a UINT:
  682.  
  683.                         HBRUSH hbr;
  684.  
  685.                         hbr = (HBRUSH)(UINT)SendMessage(hwnd, WM_CTLCOLOR,
  686.  
  687.  
  688.  
  689.  
  690.  
  691.                                   - 10 -
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.                                                         ..., ...);
  699.  
  700.                     7. The CreateWindow and CreateWindowEx hmenu parameter
  701.                        is sometimes used to pass an integer control ID. In
  702.                        this case you must cast this to an HMENU:
  703.  
  704.                         HWND hwnd;
  705.                         int id;
  706.  
  707.                         hwnd = CreateWindow("Button", "Ok", BS_PUSHBUTTON,
  708.                                             x, y, cx, cy, hwndParent,
  709.                                             (HMENU)id, //Cast required here
  710.                                             hinst, NULL);
  711.  
  712.                     8. Polymorphic data types (WPARAM, LPARAM, LRESULT,
  713.                        void FAR *) should be assigned to variables of a
  714.                        known type as soon as possible. You should avoid
  715.                        using them in your own code when the type of the
  716.                        value is known. This will minimize the number of
  717.                        potentially unsafe and non-32-bit-portable casting
  718.                        you will have to do in your code. The macro APIs and
  719.                        message cracker mechanisms provided in windowsx.h
  720.                        will take care of almost all packing and unpacking
  721.                        of these data types, in a 32-bit portable way.
  722.  
  723.                     9. Become familiar with the common compiler warnings
  724.                        and errors that you're likely to encounter as you
  725.                        convert to STRICT.
  726.  
  727.  
  728.    Common compiler  =======================================================
  729.       warnings and
  730.             errors  Here are some common compiler warnings and errors you
  731.                     might get when trying to make your application compile
  732.                     cleanly as C++ or with all messages enabled, with or
  733.                     without STRICT.
  734.  
  735.                     These are also the kinds of warnings and errors you'll
  736.                     receive as you maintain STRICT source code.
  737.  
  738. Warning: Function should return a vlue
  739.                     This warning means that a function declared to return a
  740.                     value does not return a value. In older, non-ANSI C
  741.                     code, it was common to declare functions that did not
  742.                     return a value with no return type:
  743.  
  744.                      foo(i)
  745.                      int i;
  746.  
  747.  
  748.  
  749.                                   - 11 -
  750.  
  751.  
  752.  
  753.  
  754.  
  755.  
  756.                      {
  757.                        ...
  758.                      }
  759.  
  760.                     Functions declared in this manner are treated by the
  761.                     compiler as being declared to return an "int". If the
  762.                     function does not return anything, it should be
  763.                     declared "void":
  764.  
  765.                      void foo(int i)
  766.                      {
  767.                        ...
  768.                      }
  769.  
  770.  
  771. Warning: Call to function <function> with no prototype
  772.                     This means that a function was used before it was fully
  773.                     prototyped, or declared. It can also arise when a
  774.                     function that takes no arguments is not prototyped with
  775.                     void:
  776.  
  777.                      void bar(); /* Should be: bar(void) */
  778.  
  779.                      main()
  780.                      {
  781.                        bar();
  782.                      }
  783.  
  784. Error: Lvalue required
  785. Error: Type mismatch in parameter
  786.                     These errors indicate that you are trying to assign or
  787.                     pass a non-pointer type when a pointer type is
  788.                     required. With STRICT defined, all handle types as well
  789.                     as LRESULT, WPARAM, and LPARAM are internally declared
  790.                     as pointer types, so trying to pass an int, WORD, or
  791.                     LONG as a handle will result in these errors.
  792.  
  793.                     These errors should be fixed by properly declaring the
  794.                     non-pointer values you're assigning or passing. In the
  795.                     case of special constants  such as (HWND)1 to indicate
  796.                     "insert at bottom" to the window positioning
  797.                     functions, you should use the new macro such as
  798.                     HWND_BOTTOM.
  799.  
  800.                     Only in rare cases should you suppress a type mismatch
  801.                     error with a cast: This can often generate incorrect
  802.                     code.
  803.  
  804.  
  805.  
  806.  
  807.                                   - 12 -
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814. Error: Type mismatch in parameter <parameter>
  815. foo.c(335) : warning C4049: 'argument' : indirection to different types
  816.                     These warnings indicate that you are passing or
  817.                     assigning a pointer of the wrong type. This is the
  818.                     warning you get if you pass the wrong type of handle to
  819.                     a function. This is because under STRICT all handle
  820.                     types are defined as pointers to unique structures.
  821.  
  822.                     To suppress these warnings, fix the type mismatch error
  823.                     in your code. Once again, it's dangerous to suppress
  824.                     these warnings with a cast, since there may be an
  825.                     underlying type error in your app.
  826.  
  827. Error: Type mismatch in redeclaration of <parameter>
  828.                     This error will result if you have inconsistent
  829.                     declarations of a variable, parameter, or function in
  830.                     your source code.
  831.  
  832. Warning: Conversion may lose significant digits
  833.                     This warning results when a value is converted by the
  834.                     compiler, such as from LONG to int. You're being warned
  835.                     because you may lose information from this cast.
  836.  
  837.                     If you're sure there are no information-loss problems,
  838.                     you can suppress this warning with the appropriate
  839.                     explicit cast to the smaller type.
  840.  
  841. Warning: Non-portable pointer conversion
  842.                     This error results when you cast a near pointer or a
  843.                     handle to a 32-bit value such as LRESULT, LPARAM, LONG
  844.                     or DWORD. This warning almost always represents a bug,
  845.                     because the hi-order 16 bits of the value will contain
  846.                     a non-zero value. The compiler first converts the
  847.                     16-bit near pointer to a 32-bit far pointer by placing
  848.                     the current data segment value in the high 16 bits,
  849.                     then converts this far pointer to the 32-bit value.
  850.  
  851.                     To avoid this warning and ensure that a 0 is placed in
  852.                     the hi 16 bits, you must first cast the handle to a
  853.                     UINT:
  854.  
  855.                      HWND hwnd;
  856.                      LRESULT result = (LRESULT)(UINT)hwnd;
  857.  
  858.                     In cases where you DO want the 32-bit value to contain
  859.                     a far pointer, you can avoid the warning with an
  860.                     explicit cast to a far pointer:
  861.  
  862.  
  863.  
  864.  
  865.                                   - 13 -
  866.  
  867.  
  868.  
  869.  
  870.  
  871.  
  872.                      char near* pch;
  873.                      LPARAM lParam = (LPARAM)(LPSTR)pch;
  874.  
  875. Error: Size of the type is unknown or zero
  876.                     This error results from trying to change the value of a
  877.                     void pointer with + or +=. These typically result from
  878.                     the fact that certain Windows functions that return
  879.                     pointers to arbitrary types (such as GlobalLock and
  880.                     LocalLock) are defined to return void FAR* rather than
  881.                     LPSTR.
  882.  
  883.                     To solve these problems, you should assign the void*
  884.                     value to a properly- declared variable (with the
  885.                     appropriate cast):
  886.  
  887.                      BYTE FAR* lpb = (BYTE FAR*)GlobalLock(h);
  888.  
  889.                      lpb += sizeof(DWORD);
  890.  
  891.  
  892. Error: Not an allowed type
  893.                     This error typically results from trying to dereference
  894.                     a void pointer. This usually results from directly
  895.                     using the return value of GlobalLock or LocalLock as a
  896.                     pointer. To solve this problem, assign the return value
  897.                     to a variable of the appropriate type (with the
  898.                     appropriate cast) before using the pointer:
  899.  
  900.                      BYTE FAR* lpb = (BYTE FAR*)GlobalLock(h);
  901.  
  902.                      *lpb = 0;
  903.  
  904. Warning: Parameter <parameter> is never used
  905.                     This message can result in callback functions when your
  906.                     code does not use certain parameters. You can either
  907.                     turn off this warning, or use the argsused pragma to
  908.                     suppress it.
  909.  
  910.  
  911.  
  912. ===========================================================================
  913. Macro APIs and message crackers
  914. ===========================================================================
  915.  
  916.                     The macro APIs, message crackers and control APIs are
  917.                     defined in  the file windowsx.h.  The new handle types,
  918.                     structures, and  helper macros as well as the STRICT
  919.                     option are a part of the standard windows.h.
  920.  
  921.  
  922.  
  923.                                   - 14 -
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.         Macro APIs  =======================================================
  931.  
  932.                     windowsx.h contains a number of new APIs implemented as
  933.                     macros that call other APIs.  Generally they make your
  934.                     code both easier to read and write, and they can save
  935.                     you lots of typing.  These macros are all portable to
  936.                     32-bit Windows.
  937.  
  938.  
  939. void FAR* WINAPI GlobalAllocPtr(WORD flags, DWORD cb)
  940.                     Same as GlobalAlloc, except that it returns a far
  941.                     pointer directly.
  942.  
  943. void FAR* WINAPI GlobalReAllocPtr(void FAR* lp, DWORD cbNew, WORD flags)
  944.                     Same as GlobalReAlloc, except that it takes and returns
  945.                     a far pointer.
  946.  
  947. BOOL WINAPI GlobalFreePtr(void FAR* lp)
  948.                     Same as GlobalFree, except used with far pointer
  949.                     alloced (or realloced) with functions above.
  950.  
  951. BOOL WINAPI GlobalLockPtr(void FAR* lp)
  952.                     Same as GlobalLock, except used with far pointer.
  953.  
  954. BOOL WINAPI GlobalUnlockPtr(void FAR* lp)
  955.                     Same as GlobalUnlock, except used with far pointer.
  956.  
  957. HMODULE WINAPI GetInstanceModule(HINSTANCE hInstance);
  958.                     Maps an instance handle to a module handle.
  959.  
  960. void    WINAPI UnlockResource(HGLOBAL hResource);
  961.                     Unlocks a global resource handle locked with
  962.                     LockResource.
  963.  
  964. BOOL    WINAPI DeletePen(HPEN hpen)
  965.                     Deletes a pen (with proper typecasting)
  966.  
  967. HPEN    WINAPI GetStockPen(int i);
  968.                     Returns one of the stock pens indicated by i (properly
  969.                     cast to HPEN).
  970.  
  971. HPEN    WINAPI SelectPen(HDC hdc, HPEN hpenSelect)
  972.                     Selects a pen and returns previously selected pen (with
  973.                     proper type casting).
  974.  
  975. BOOL    WINAPI DeleteBrush(HBRUSH hbr)
  976.  
  977.  
  978.  
  979.  
  980.  
  981.                                   - 15 -
  982.  
  983.  
  984.  
  985.  
  986.  
  987.  
  988.                     Deletes a brush (with proper typecasting)
  989.  
  990. HBRUSH  WINAPI GetStockBrush(int i);
  991.                     Returns one of the stock brushes indicated by i
  992.                     (properly cast to HBRUSH).
  993.  
  994. HBRUSH  WINAPI SelectBrush(HDC hdc, HBRUSH hbrSelect)
  995.                     Selects a brush and returns previously selected brush
  996.                     (with proper type casting).
  997.  
  998. BOOL    WINAPI DeleteFont(HFONT hfont)
  999.                     Deletes a font (with proper typecasting)
  1000.  
  1001. HFONT   WINAPI GetStockFont(int i);
  1002.                     Returns one of the stock fonts indicated by i (properly
  1003.                     cast to HFONT)
  1004.  
  1005. HFONT   WINAPI SelectFont(HDC hdc, HFONT hfontSelect)
  1006.                     Selects a font and returns previously selected font
  1007.                     (with proper type casting).
  1008.  
  1009. BOOL    WINAPI DeleteBitmap(HBITMAP hbm)
  1010.                     Deletes a bitmap (with proper typecasting)
  1011.  
  1012. HBITMAP WINAPI SelectBitmap(HDC hdc, HBITMAP hbmSelect)
  1013.                     Selects a bitmap and returns previously selected bitmap
  1014.                     (with proper type casting)
  1015.  
  1016. BOOL    WINAPI DeleteRgn(HRGN hrgn)
  1017.                     Deletes a region (with proper typecasting)
  1018.  
  1019. int     WINAPI CopyRgn(HRGN hrgnDst, HRGN hrgnSrc);
  1020.                     Copies hrgnSrc to hrgnDst.
  1021.  
  1022. int     WINAPI IntersectRgn(HRGN hrgnResult, HRGN hrgnA, HRGN hrgnB);
  1023.                     Intersects hrgnA with hrgnB, setting hrgnResult to the
  1024.                     result.
  1025.  
  1026. int     WINAPI SubtractRgn(HRGN hrgnResult, HRGN hrgnA, HRGN hrgnB);
  1027.                     Subtracts hrgnB from hrgnA, setting hrgnResult to the
  1028.                     result.
  1029.  
  1030. int     WINAPI UnionRgn(HRGN hrgnResult, HRGN hrgnA, HRGN hrgnB);
  1031.                     Computes the union of hrgnA and hrgnB, setting
  1032.                     hrgnResult to the result.
  1033.  
  1034. int     WINAPI XorRgn(HRGN hrgnResult, HRGN hrgnA, HRGN hrgnB);
  1035.  
  1036.  
  1037.  
  1038.  
  1039.                                   - 16 -
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.                     XORs hrgnA with hrgnB, setting hrgnResult to the
  1047.                     result.
  1048.  
  1049. void    WINAPI InsetRect(RECT FAR* lprc, int dx, int dy)
  1050.                     Insets the edges of a rectangle by dx and dy.
  1051.  
  1052. HINSTANCE WINAPI GetWindowInstance(HWND hwnd)
  1053.                     Returns the instance handle associated with a window.
  1054.  
  1055. DWORD   WINAPI GetWindowStyle(HWND hwnd)
  1056.                     Returns the window style of a window.
  1057.  
  1058. DWORD   WINAPI GetWindowExStyle(HWND hwnd)
  1059.                     Returns the extended window style of a window
  1060.  
  1061. int     WINAPI GetWindowID(HWND hwnd)
  1062.                     Returns the window ID of a window.
  1063.  
  1064. void    WINAPI SetWindowRedraw(HWND hwnd, BOOL fRedraw)
  1065.                     Disables or enables drawing in a window, without hiding
  1066.                     the window.
  1067.  
  1068. WNDPROC WINAPI SubclassWindow(HWND hwnd, WNDPROC lpfnWndProc)
  1069.                     Subclasses a window by storing a new window procedure
  1070.                     address.  Returns previous window procedure address.
  1071.  
  1072. BOOL    WINAPI IsMinimized(HWND hwnd)
  1073.                     Returns TRUE if hwnd is minimized
  1074.  
  1075. BOOL    WINAPI IsMaximized(HWND hwnd)
  1076.                     Returns TRUE if hwnd is maximized
  1077.  
  1078. BOOL    WINAPI IsRestored(HWND hwnd)
  1079.                     Returns TRUE if hwnd is restored.
  1080.  
  1081. BOOL    WINAPI IsLButtonDown(void)
  1082.                     Returns TRUE if the left mouse button is down.
  1083.  
  1084. BOOL    WINAPI IsRButtonDown(void)
  1085.                     Returns TRUE if the right mouse button is down.
  1086.  
  1087. BOOL    WINAPI IsMButtonDown(void)
  1088.                     Returns TRUE if the middle mouse button is down.
  1089.  
  1090.  
  1091.  
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097.                                   - 17 -
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104.                     3.1-only macro APIs
  1105.                     =======================================================
  1106.  
  1107. void    WINAPI MapWindowPoints(HWND hwndFrom, HWND hwndTo, POINT FAR* lppt,
  1108. WORD cpt);
  1109.                     Maps cpt points at *lppt from the coordinate system of
  1110.                     hwndFrom to that of hwndTo.
  1111.  
  1112. void    WINAPI MapWindowRect(HWND hwndFrom, HWND hwndTo, RECT FAR* lprc)
  1113.                     Maps a rectangle from the coordinate system of hwndFrom
  1114.                     to that of hwndTo.
  1115.  
  1116.  
  1117.    Control message  =======================================================
  1118.               APIs
  1119.                     New APIs have been added for use in dealing with the
  1120.                     various controls. These APIs are implemented as macros
  1121.                     that call SendMessage, and they take care of packing
  1122.                     the various parameters into wParam and lParam and
  1123.                     casting the return value as needed.
  1124.  
  1125.                     These macros are fully portable to 32-bit Windows: The
  1126.                     32-bit versions will transparently take into account
  1127.                     any differences in parameter packing on the 32-bit
  1128.                     platform.
  1129.  
  1130.                     These macros make your source code smaller and more
  1131.                     readable.  They're especially valuable with STRICT in
  1132.                     order to prevent type errors and incorrect message
  1133.                     parameter passing.
  1134.  
  1135.                     There is a 1-to-1 correspondence between a control API
  1136.                     and a window message or window manager API.  In the
  1137.                     interests of brevity, the control APIs are simply
  1138.                     listed below: For more information, you can check out
  1139.                     the macro definitions in windowsx.h and the
  1140.                     documentation for the corresponding window message.
  1141.  
  1142.                     Some of the new control APIs are usable with Windows
  1143.                     3.1 only, and are not available if you #define WINVER
  1144.                     0x0300.
  1145.  
  1146.  
  1147. ------------------  Here is an example showing how these new APIs are used.
  1148.        Control API  First, here is some code that uses old-style
  1149.           Examples  SendMessage calls to print all the lines in an edit
  1150. ------------------  control:
  1151.  
  1152.  
  1153.  
  1154.  
  1155.                                   - 18 -
  1156.  
  1157.  
  1158.  
  1159.  
  1160.  
  1161.  
  1162. void PrintLines(HWND hwndEdit)
  1163. {
  1164.   int line;
  1165.   int lineLast = (int)SendMessage(hwndEdit, EM_GETLINECOUNT,
  1166.                                     0, 0L);
  1167.   for (line = 0; line < lineLast; line++)
  1168.   {
  1169.     int cch;
  1170.     char ach[80];
  1171.  
  1172.     *((LPINT)ach) = sizeof(ach);
  1173.     cch = (int)SendMessage(hwndEdit, EM_GETLINE,
  1174.                            line, (LONG)(LPSTR)ach);
  1175.     printf(ach);
  1176.     // ... or whatever ...
  1177.   }
  1178. }
  1179.  
  1180.                     Using control APIs, this code would be simplified as
  1181.                     follows:
  1182.  
  1183. void PrintLines(HWND hwndEdit)
  1184. {
  1185.   int line;
  1186.   int lineLast = Edit_GetLineCount(hwndEdit);
  1187.  
  1188.   for (line = 0; line < lineLast; line++)
  1189.   {
  1190.     int cch;
  1191.     char ach[80];
  1192.  
  1193.     cch = Edit_GetLine(hwndEdit, line, ach, sizeof(ach));
  1194.  
  1195.     printf(ach);
  1196.     // ... or whatever ...
  1197.   }
  1198. }
  1199.  
  1200.                     The new style code is much easier to read (and write),
  1201.                     doesn't generate compiler warnings, and doesn't have
  1202.                     any non-portable casts.
  1203.  
  1204.                     Here is a complete list of the control APIs.  See
  1205.                     windowsx.h for more info.
  1206.  
  1207.                         Static_Enable(hwnd, fEnable)
  1208.                         Static_GetText(hwnd, lpch, cchMax)
  1209.                         Static_GetTextLength(hwnd)
  1210.  
  1211.  
  1212.  
  1213.                                   - 19 -
  1214.  
  1215.  
  1216.  
  1217.  
  1218.  
  1219.  
  1220.                         Static_SetText(hwnd, lpsz)
  1221.                         Static_SetIcon(hwnd, hIcon)
  1222.                         Static_GetIcon(hwnd, hIcon)
  1223.  
  1224.                         Button_Enable(hwnd, fEnable)
  1225.                         Button_GetText(hwnd, lpch, cchMa
  1226.                         Button_GetTextLength(hwnd)
  1227.                         Button_SetText(hwnd, lpsz)
  1228.                         Button_GetCheck(hwnd)
  1229.                         Button_SetCheck(hwnd, check)
  1230.                         Button_GetState(hwnd)
  1231.                         Button_SetState(hwnd, state)
  1232.                         Button_SetStyle(hwnd, style, fRedraw)
  1233.  
  1234.                         Edit_Enable(hwnd, fEnable)
  1235.                         Edit_GetText(hwnd, lpch, cchMax)
  1236.                         Edit_GetTextLength(hwnd)
  1237.                         Edit_SetText(hwnd, lpsz)
  1238.                         Edit_LimitText(hwnd, cchMax)
  1239.                         Edit_GetLineCount(hwnd)
  1240.                         Edit_GetLine(hwnd, line, lpch, cchMax)
  1241.                         Edit_GetRect(hwnd, lprc)
  1242.                         Edit_SetRect(hwnd, lprc)
  1243.                         Edit_SetRectNoPaint(hwnd, lprc)
  1244.                         Edit_GetSel(hwnd)
  1245.                         Edit_SetSel(hwnd, ichStart, ichEnd)
  1246.                         Edit_ReplaceSel(hwnd, lpszReplace)
  1247.                         Edit_GetModify(hwnd)
  1248.                         Edit_SetModify(hwnd, fModified)
  1249.                         Edit_LineFromChar(hwnd, ich)
  1250.                         Edit_LineIndex(hwnd, line)
  1251.                         Edit_LineLength(hwnd, line)
  1252.                         Edit_Scroll(hwnd, dv, dh)
  1253.                         Edit_CanUndo(hwnd)
  1254.                         Edit_Undo(hwnd)
  1255.                         Edit_EmptyUndoBuffer(hwnd)
  1256.                         Edit_SetPasswordChar(hwnd, ch)
  1257.                         Edit_SetTabStops(hwnd, cTabs, lpTabs)
  1258.                         Edit_SetWordBreak(hwnd, lpfnWordBreak)
  1259.                         Edit_FmtLines(hwnd, fAddEOL)
  1260.                         Edit_GetHandle(hwnd)
  1261.                         Edit_SetHandle(hwnd, h)
  1262.                         Edit_GetFirstVisible(hwnd)
  1263.  
  1264.                         ScrollBar_Enable(hwnd, flags)
  1265.                         ScrollBar_Show(hwnd, fShow)
  1266.                         ScrollBar_SetPos(hwnd, pos, fRedraw)
  1267.                         ScrollBar_GetPos(hwnd)
  1268.  
  1269.  
  1270.  
  1271.                                   - 20 -
  1272.  
  1273.  
  1274.  
  1275.  
  1276.  
  1277.  
  1278.                         ScrollBar_SetRange(hwnd, posMin, posMax, fRedraw)
  1279.                         ScrollBar_GetRange(hwnd, lpposMin, lpposMax)
  1280.  
  1281.                         ListBox_Enable(hwnd, fEnable)
  1282.                         ListBox_GetCount(hwnd)
  1283.                         ListBox_ResetContent(hwnd)
  1284.                         ListBox_AddString(hwnd, lpsz)
  1285.                         ListBox_InsertString(hwnd, lpsz, index)
  1286.                         ListBox_AddItemData(hwnd, data)
  1287.                         ListBox_InsertItemData(hwnd, lpsz, index)
  1288.                         ListBox_DeleteString(hwnd, index)
  1289.                         ListBox_GetTextLen(hwnd, index)
  1290.                         ListBox_GetText(hwnd, index, lpszBuffer)
  1291.                         ListBox_GetItemData(hwnd, index)
  1292.                         ListBox_SetItemData(hwnd, index, data)
  1293.                         ListBox_FindString(hwnd, indexStart, lpszFind)
  1294.                         ListBox_FindItemData(hwnd, indexStart, data)
  1295.                         ListBox_SetSel(hwnd, fSelect, index)
  1296.                         ListBox_SelItemRange(hwnd, fSelect, first, last)
  1297.                         ListBox_GetCurSel(hwnd)
  1298.                         ListBox_SetCurSel(hwnd, index)
  1299.                         ListBox_SelectString(hwnd, indexStart, lpszFind)
  1300.                         ListBox_SelectItemData(hwnd, indexStart, data)
  1301.                         ListBox_GetSel(hwnd, index)
  1302.                         ListBox_GetSelCount(hwnd)
  1303.                         ListBox_GetTopIndex(hwnd)
  1304.                         ListBox_GetSelItems(hwnd, cItems, lpIndices)
  1305.                         ListBox_SetTopIndex(hwnd, indexTop)
  1306.                         ListBox_SetColumnWidth(hwnd, cxColumn)
  1307.                         ListBox_GetHorizontalExtent(hwnd)
  1308.                         ListBox_SetHorizontalExtent(hwnd, cxExtent)
  1309.                         ListBox_SetTabStops(hwnd, cTabs, lpTabs)
  1310.                         ListBox_GetItemRect(hwnd, index, lprc)
  1311.                         ListBox_SetCaretIndex(hwnd, index)
  1312.                         ListBox_GetCaretIndex(hwnd)
  1313.                         ListBox_SetAnchorIndex(hwnd, index)
  1314.                         ListBox_GetAnchorIndex(hwnd)
  1315.                         ListBox_Dir(hwnd, attrs, lpszFileSpec)
  1316.                         ListBox_AddFile(hwnd, lpszFilename)
  1317.  
  1318.           3.1 only      ListBox_SetItemHeight(hwnd, index, cy)
  1319.           3.1 only      ListBox_GetItemHeight(hwnd, index)
  1320.  
  1321.                         ComboBox_Enable(hwnd, fEnable)
  1322.                         ComboBox_GetText(hwnd, lpch, cchMax)
  1323.                         ComboBox_GetTextLength(hwnd)
  1324.                         ComboBox_SetText(hwnd, lpsz)
  1325.                         ComboBox_LimitText(hwnd, cchLimit)
  1326.  
  1327.  
  1328.  
  1329.                                   - 21 -
  1330.  
  1331.  
  1332.  
  1333.  
  1334.  
  1335.  
  1336.                         ComboBox_GetEditSel(hwnd)
  1337.                         ComboBox_SetEditSel(hwnd, ichStart, ichEnd)
  1338.                         ComboBox_GetCount(hwnd)
  1339.                         ComboBox_ResetContent(hwnd)
  1340.                         ComboBox_AddString(hwnd, lpsz)
  1341.                         ComboBox_InsertString(hwnd, index, lpsz)
  1342.                         ComboBox_AddItemData(hwnd, data)
  1343.                         ComboBox_InsertItemData(hwnd, index, data)
  1344.                         ComboBox_DeleteString(hwnd, index)
  1345.                         ComboBox_GetLBTextLen(hwnd, index)
  1346.                         ComboBox_GetLBText(hwnd, index, lpszBuffer)
  1347.                         ComboBox_GetItemData(hwnd, index)
  1348.                         ComboBox_SetItemData(hwnd, index, data)
  1349.                         ComboBox_FindString(hwnd, indexStart, lpszFind)
  1350.                         ComboBox_FindItemData(hwnd, indexStart, data)
  1351.                         ComboBox_GetCurSel(hwnd)
  1352.                         ComboBox_SetCurSel(hwnd, index)
  1353.                         ComboBox_SelectString(hwnd, indexStart, lpszSelect)
  1354.                         ComboBox_SelectItemData(hwnd, indexStart, data)
  1355.                         ComboBox_Dir(hwnd, attrs, lpszFileSpec)
  1356.                         ComboBox_ShowDropdown(hwnd, fShow)
  1357.  
  1358.           3.1 only      ComboBox_GetDroppedState(hwnd)
  1359.           3.1 only      ComboBox_GetDroppedControlRect(hwnd, lprc)
  1360.           3.1 only      ComboBox_GetItemHeight(hwnd)
  1361.           3.1 only      ComboBox_SetItemHeight(hwnd, cyItem)
  1362.           3.1 only      ComboBox_GetExtendedUI(hwnd)
  1363.           3.1 only      ComboBox_SetExtendedUI(hwnd, flags)
  1364.  
  1365.  
  1366.    Message cracker  =======================================================
  1367.             macros
  1368.                     The message cracker macros provide a convenient,
  1369.                     portable, and type-safe mechanism for dealing with
  1370.                     window messages, their parameters, and their return
  1371.                     values.
  1372.  
  1373.                     The basic idea is that instead of having to pick apart
  1374.                     message parameters with casts and HIWORD/LOWORD and
  1375.                     such, you simply declare and implement a function that
  1376.                     has the properly typed parameters and return value.
  1377.                     The message crackers efficiently pick apart the message
  1378.                     parameters, call your function, and return the
  1379.                     appropriate value from the window message.
  1380.  
  1381.                     Message forwarder macros allow you to forward a message
  1382.                     via DefWindowProc, SendMessage, or CallWindowProc. The
  1383.                     macros do the work of packing explicitly typed
  1384.  
  1385.  
  1386.  
  1387.                                   - 22 -
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393.  
  1394.                     arguments into wParam and lParam and calling the
  1395.                     appropriate function.
  1396.  
  1397.                     With these macros, you don't have to worry about what
  1398.                     parameters go where and what kind of casting you need
  1399.                     to do.  They are also portable to 32-bit Windows (where
  1400.                     some of the message parameters have changed).
  1401.  
  1402.  
  1403. ------------------  For each window message, there are two macros: A
  1404.      Using message  cracker and a forwarder. To see how these macros work,
  1405.       crackers and  let's use the WM_CREATE message as an example. Here is
  1406.         forwarders  a code fragment showing how a window procedure could
  1407. ------------------  use message crackers to handle the WM_CREATE message.
  1408.                     For now, our WM_CREATE message processing will simply
  1409.                     call DefWindowProc.
  1410.  
  1411.                     NOTE: The following examples use STRICT-style
  1412.                     declarations, but you can use message crackers without
  1413.                     STRICT.
  1414.  
  1415. // Message handler function prototype (declared in a .h file)
  1416.  
  1417. BOOL MyCls_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct);
  1418.  
  1419. // Window procedure for class "MyCls" (defined in a .c file)
  1420.  
  1421. LRESULT _export CALLBACK MyCls_WndProc(HWND hwnd, UINT msg,
  1422.                                        WPARAM wParam,
  1423.                                        LPARAM lParam)
  1424. {
  1425.   switch (msg)
  1426.   {
  1427.     case WM_CREATE:
  1428.       return HANDLE_WM_CREATE(hwnd, wParam, lParam,
  1429.                               MyCls_OnCreate);
  1430.     default:
  1431.       return DefWindowProc(hwnd, msg, wParam, lParam);
  1432.   }
  1433. }
  1434.  
  1435. // WM_CREATE message handler function.
  1436. // For now, just calls DefWindowProc.
  1437.  
  1438. BOOL MyCls_OnCreate(HWND hwnd,
  1439.                     CREATESTRUCT FAR* lpCreateStruct)
  1440. {
  1441.   return FORWARD_WM_CREATE(hwnd, lpCreateStruct, DefWindowProc);
  1442.  
  1443.  
  1444.  
  1445.                                   - 23 -
  1446.  
  1447.  
  1448.  
  1449.  
  1450.  
  1451.  
  1452. }
  1453.  
  1454.                     Some important points:
  1455.  
  1456.                     o You must declare and implement a function to handle
  1457.                       the message, which must have a particular "signature"
  1458.                       (the order and type of the parameters, and the type
  1459.                       of the return value, if any).
  1460.  
  1461.                     o You pass this message handler function as the last
  1462.                       parameter to the HANDLE_WM_XXX function. This
  1463.                       function must be declared and fully prototyped before
  1464.                       being used with a message cracker.
  1465.  
  1466.                     o You must always return the value returned by the
  1467.                       HANDLE_WM_XXX function, even if the message handler
  1468.                       function is declared void.
  1469.  
  1470.                     o The FORWARD_WM_XXX function always has the same
  1471.                       signature (parameters and return type) as its
  1472.                       corresponding message handler function, with the
  1473.                       addition of the last parameter, which is the API or
  1474.                       function to be used to forward the message.
  1475.  
  1476.                     o You don't need to use message crackers to handle all
  1477.                       your messages. Old-style message handling code can be
  1478.                       mixed with message crackers in the same window
  1479.                       procedure.
  1480.  
  1481.                     o By convention, message handler functions are named
  1482.                       "Class_OnXXX", where Class is the window class name
  1483.                       and XXX is the name of the corresponding message,
  1484.                       minus the "WM_" and using mixed case instead of all
  1485.                       caps. This is just a convention: you can use any name
  1486.                       you like for the function (although you can't alter
  1487.                       its signature).
  1488.  
  1489.  
  1490. ------------------  The HANDLE_MSG macro can be used to reduce the amount
  1491.    Saving time and  of "noise" in your window procedures and save yourself
  1492.          improving  some typing.  The HANDLE_MSG macro replaces the "case
  1493.   readability with  WM_XXX:", the HANDLE_WM_XXX call, and the return.  So,
  1494.         HANDLE_MSG  instead of
  1495. ------------------
  1496.  
  1497. case WM_CREATE:
  1498.   return HANDLE_WM_CREATE(hwnd, wParam, lParam, MyCls_OnCreate);
  1499.  
  1500.  
  1501.  
  1502.  
  1503.                                   - 24 -
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.                     you can just type:
  1511.  
  1512. HANDLE_MSG(hwnd, WM_CREATE, MyCls_OnCreate);
  1513.  
  1514.                     HANDLE_MSG is optional.  Some people prefer to "spell
  1515.                     out" the goings-on in their window procedures, and
  1516.                     others prefer the convenience and brevity of the
  1517.                     HANDLE_MSG form.
  1518.  
  1519.                     HANDLE_MSG requires that you name your window procedure
  1520.                     message parameters wParam and lParam. The examples in
  1521.                     this document use HANDLE_MSG.
  1522.  
  1523.  
  1524. ------------------  To see how message crackers work, we'll take a look at
  1525.        How message  the definition of the message cracker macros as found
  1526.      crackers work  in windowsx.h (these definitions are somewhat
  1527. ------------------  simplified for the sake of clarity):
  1528.  
  1529. // BOOL Cls_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct)
  1530.  
  1531. #define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
  1532. ((fn)(hwnd, (CREATESTRUCT FAR*)lParam) ? 0L : (LRESULT)-1L)
  1533.  
  1534. #define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \
  1535. (BOOL)(DWORD)(fn)(hwnd, WM_CREATE, 0, (LPARAM)lpCreateStruct)
  1536.  
  1537.                     The comment shows the signature of the message handler
  1538.                     function that you must declare and implement.
  1539.  
  1540.                     Essentially all these macros do is convert the wParam
  1541.                     and lParam message parameters to and from specific,
  1542.                     explicitly typed parameters and invoke a function.
  1543.  
  1544.                     The HANDLE_WM_CREATE macro calls the handler function
  1545.                     with the appropriate parameters, obtained by casting
  1546.                     wParam and lParam appropriately.  The return value of
  1547.                     the handler value is mapped to the proper LRESULT
  1548.                     return value, in this case 0L or -1L.  If the handler
  1549.                     function returns no value, then 0L is returned.
  1550.  
  1551.                     The FORWARD_WM_CREATE macro calls the supplied message
  1552.                     function (which must have the same signature as
  1553.                     DefWindowProc) with the proper hwnd, wParam, and lParam
  1554.                     parameters calculated from the parameters supplied to
  1555.                     the macro.
  1556.  
  1557.                     The HANDLE_MSG macro is quite simple too:
  1558.  
  1559.  
  1560.  
  1561.                                   - 25 -
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568. #define HANDLE_MSG(hwnd, message, fn)    \
  1569. case message: return HANDLE_##message(fn, hwnd, wParam, lParam)
  1570.  
  1571.                     It simply does the "case" for you, and returns the
  1572.                     result of the proper HANDLE_WM_XXX function.  The
  1573.                     message parameter names wParam and lParam are
  1574.                     hard-wired into this macro.
  1575.  
  1576.  
  1577. ------------------  Here is a more detailed example of a window procedure
  1578.    Message cracker  for the "Template" class that uses message crackers and
  1579.           examples  message forwarders:
  1580. ------------------
  1581. // Excerpt from header file for class Template
  1582.  
  1583. // Window procedure prototype
  1584.  
  1585. LRESULT _export CALLBACK Template_WndProc(HWND hwnd, WORD msg,
  1586.                                           WPARAM wParam,
  1587.                                           LPARAM lParam)
  1588.  
  1589. // Default message handler
  1590.  
  1591. #define Template_DefProc    DefWindowProc
  1592.  
  1593. // Template class message handler functions,
  1594. // declared in a header file:
  1595.  
  1596. void Template_OnMouseMove(HWND hwnd, int x,
  1597.                           int y, UINT keyFlags);
  1598. void Template_OnLButtonDown(HWND hwnd, BOOL fDoubleClick,
  1599.                             int x, int y, UINT keyFlags);
  1600. void Template_OnLButtonUp(HWND hwnd, int x,
  1601.                           int y, UINT keyFlags);
  1602. HBRUSH Template_OnCtlColor(HWND hwnd, HDC hdc,
  1603.                            HWND hwndChild, int type);
  1604.  
  1605.  
  1606. // Exerpt from c source file for class Template
  1607.  
  1608. // Template window procedure implementation.
  1609.  
  1610. LRESULT _export CALLBACK Template_WndProc(HWND hwnd, WORD msg,
  1611.                                           WPARAM wParam,
  1612.                                           LPARAM lParam)
  1613. {
  1614.   switch (msg)
  1615.   {
  1616.  
  1617.  
  1618.  
  1619.                                   - 26 -
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.     HANDLE_MSG(hwnd, WM_MOUSEMOVE, Template_OnMouseMove);
  1627.     HANDLE_MSG(hwnd, WM_LBUTTONDOWN, Template_OnLButtonDown);
  1628.     HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK, Template_OnLButtonDown);
  1629.     HANDLE_MSG(hwnd, WM_LBUTTONUP, Template_OnLButtonUp);
  1630.     default:
  1631.       return Template_DefProc(hwnd, msg, wParam, lParam);
  1632.   }
  1633. }
  1634.  
  1635. // Message handler function implementations:
  1636.  
  1637. void Template_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  1638. {
  1639. ...
  1640. }
  1641.  
  1642. void Template_OnLButtonDown(HWND hwnd, BOOL fDoubleClick,
  1643.                             int x, int y, UINT keyFlags)
  1644. {
  1645. ...
  1646. }
  1647.  
  1648. void Template_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  1649. {
  1650. ...
  1651. }
  1652.  
  1653. HBRUSH Template_OnCtlColor(HWND hwnd, HDC hdc,
  1654.                            HWND hwndChild, int type)
  1655. {
  1656.   switch (type)
  1657.   {
  1658.     case CTLCOLOR_BTN:
  1659.       // Pass the WM_CTLCOLOR message on to the parent,
  1660.       // and use the edit control colors.
  1661.       return FORWARD_WM_CTLCOLOR(GetParent(hwnd), hdc, hwndChild,
  1662.                                  CTLCOLOR_EDIT, SendMessage);
  1663.       break;
  1664.  
  1665.     default:
  1666.       // Perform default processing of the message.
  1667.       return FORWARD_WM_CTLCOLOR(hwnd, hdc, hwndChild,
  1668.                                  type, Template_DefProc);
  1669.   }
  1670. }
  1671.  
  1672.  
  1673.  
  1674.  
  1675.  
  1676.  
  1677.                                   - 27 -
  1678.  
  1679.  
  1680.  
  1681.  
  1682.  
  1683.  
  1684. ------------------  For the most part, the OnXXX message handler function
  1685.    Message handler  parameters have the same name and type as those shown
  1686.           function  in the documentation of the corresponding window
  1687.         signatures  message. To find out exactly what those messages are,
  1688. ------------------  look at the commented function prototype in windowsx.h
  1689.                     before the message cracker for the message you're
  1690.                     interested in.
  1691.  
  1692.                     There are a few cases where the OnXXX functions work a
  1693.                     bit differently than the corresponding window message:
  1694.  
  1695.                     o OnCreate (and OnNCCreate) must return TRUE if all is
  1696.                       well, or the window will not be created and
  1697.                       CreateWindow will return NULL.
  1698.  
  1699.                     o The signatures for OnKey and On?ButtonDown functions
  1700.                       are a little different from their corresponding
  1701.                       messages.  OnKey handles both key up and key down
  1702.                       messages with the fDown parameter. The On?ButtonDown
  1703.                       functions handle double click messages too, with the
  1704.                       fDoubleClick parameter (though you must be sure to
  1705.                       register your window class with CS_DBLCLKS if you
  1706.                       want to handle double clicks).
  1707.  
  1708.                     o The OnChar function is not passed the virtual key or
  1709.                       key flags information, as this information is not
  1710.                       usable in a WM_CHAR handling. This is because
  1711.                       different virtual keys can generate the same WM_CHAR
  1712.                       messages, and certain key macro processors will
  1713.                       generate WM_CHAR messages with no virtual key or
  1714.                       flags.
  1715.  
  1716.  
  1717. ------------------  For every window class, there is a function that must
  1718.          Improving  be called to perform the default processing for that
  1719.       reusability:  window.  Normally, this call is DefWindowProc, but if
  1720.   Template_DefProc  you're subclassing a window, it's CallWindowProc, or if
  1721. ------------------  you're implementing an MDI child window, it's
  1722.                     DefMDIChildProc, etc.
  1723.  
  1724.                     A very common programming mistake is to copy code from
  1725.                     another window procedure without making the appropriate
  1726.                     change to the default message handler function. This
  1727.                     can lead to subtle, hard to track down bugs.
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.                                   - 28 -
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.  
  1742.                     This is the purpose of the Template_DefProc macro
  1743.                     defined and used in the example above.  Every class
  1744.                     should have an appropriate XXX_DefProc macro (or
  1745.                     function) defined which will perform default message
  1746.                     processing.
  1747.  
  1748.                     In the example above, the default message handler is
  1749.                     DefWindowProc, so Template_DefProc is defined as
  1750.                     follows:
  1751.  
  1752.                      #define Template_DefProc   DefWindowProc.
  1753.  
  1754.                     For an MDI child window, it might be:
  1755.  
  1756.                      #define MdiWnd_DefProc     DefMDIChildProc
  1757.  
  1758.                     The advantage of this scheme is that to steal code from
  1759.                     another window procedure, you need only change the
  1760.                     class name prefix, and the proper default handling will
  1761.                     be taken care of automatically.
  1762.  
  1763.  
  1764. ------------------  Message crackers and forwarders work well with new
  1765.        Private and  window messages that you define.  You must write a
  1766.  registered window  message cracker and forwarder macro for the new message
  1767.           messages  -- the easiest way to do this is to copy and modify
  1768. ------------------  existing macros from windowsx.h.
  1769.  
  1770.                     If your new message value is a constant (e.g.,
  1771.                     WM_USER+100), then you can use HANDLE_MSG to handle the
  1772.                     message in your window procedure.  However, if your new
  1773.                     message is registered with RegisterWindowMessage,
  1774.                     HANDLE_MSG can't be used, because variables cannot be
  1775.                     used as switch statement case values: only constants
  1776.                     can.  In this case, you can handle it as follows:
  1777.  
  1778. // In Template class initialization code:
  1779.  
  1780. UINT WM_NEWMESSAGE = 0;
  1781.  
  1782. WM_NEWMESSAGE = RegisterWindowMessage("WM_NEWMESSAGE");
  1783.  
  1784.     ...
  1785.  
  1786. // In Template_WndProc: window procedure:
  1787.  
  1788. LRESULT _export CALLBACK Template_WndProc(HWND hwnd, WORD msg,
  1789.                                           WPARAM wParam,
  1790.  
  1791.  
  1792.  
  1793.                                   - 29 -
  1794.  
  1795.  
  1796.  
  1797.  
  1798.  
  1799.  
  1800.                                           LPARAM lParam)
  1801. {
  1802.   if (msg == WM_NEWMESSAGE)
  1803.     HANDLE_WM_NEWMESSAGE(hwnd, wParam, lParam,
  1804.                          Template_OnNewMessage);
  1805.  
  1806.   switch (msg)
  1807.   {
  1808.     HANDLE_MSG(hwnd, WM_MOUSEMOVE, Template_OnMouseMove);
  1809.     ...
  1810.   }
  1811. }
  1812.  
  1813.  
  1814. ------------------  It's very common for a window to have some additional
  1815.   Message crackers  "instance data" associated with it that is kept in a
  1816.         and window  separate data structure allocated by the application.
  1817.      instance data  This separate data structure is associated with its
  1818. ------------------  corresponding window by storing a pointer to the
  1819.                     structure in a  specially-named window property or in a
  1820.                     window word (allocated by setting  the cbWndExtra field
  1821.                     of the WNDCLASS structure when the class is
  1822.                     registered).
  1823.  
  1824.                     The message crackers fully support this style of
  1825.                     programming by allowing you to pass a pointer to the
  1826.                     instance data as the first parameter to the message
  1827.                     handlers instead of a window handle.  The following
  1828.                     example should make this clear:
  1829.  
  1830.  
  1831. // Window instance data structure.
  1832. // Must include window handle field.
  1833.  
  1834. typedef struct _FOO
  1835. {
  1836.     HWND hwnd;
  1837.     int otherStuff;
  1838. } FOO;
  1839.  
  1840. // "Foo" window class was registered with
  1841. // cbWndExtra = sizeof(FOO*), so we can use
  1842. // a window word to store back pointer.
  1843. // Window properties can also be used.
  1844.  
  1845. // These macros get and set the hwnd -> FOO* backpointer.
  1846. // Use GetWindowWord or GetWindowLong as appropriate based
  1847. // on the default size of data pointers.
  1848.  
  1849.  
  1850.  
  1851.                                   - 30 -
  1852.  
  1853.  
  1854.  
  1855.  
  1856.  
  1857.  
  1858. #if (defined(__SMALL__) | defined(__MEDIUM__))
  1859. #define Foo_GetPtr(hwnd) \
  1860.         (FOO*)GetWindowWord((hwnd), 0)
  1861. #define Foo_SetPtr(hwnd, pfoo) \
  1862.         (FOO*)SetWindowWord((hwnd), 0, (WORD)(pfoo))
  1863. #else
  1864. #define Foo_GetPtr(hwnd) \
  1865.         (FOO*)GetWindowLong((hwnd), 0)
  1866. #define Foo_SetPtr(hwnd, pfoo) \
  1867.         (FOO*)SetWindowLong((hwnd), 0, (LONG)(pfoo))
  1868. #endif
  1869.  
  1870. // Default message handler
  1871.  
  1872. #define Foo_DefProc DefWindowProc
  1873.  
  1874. // Message handler functions, declared with a FOO* as their
  1875. // first argument, rather than an HWND.  Other than that,
  1876. // their signature is identical to that shown in windowsx.h.
  1877.  
  1878. BOOL Foo_OnCreate(FOO* pfoo, CREATESTRUCT FAR* lpcs);
  1879. void Foo_OnPaint(FOO* pfoo);
  1880.  
  1881. // Code to register the Foo window class:
  1882.  
  1883. BOOL Foo_Init(HINSTANCE hinst)
  1884. {
  1885.     WNDCLASS cls;
  1886.  
  1887.     cls.hCursor         = ...;
  1888.     cls.hIcon           = ...;
  1889.     cls.lpszMenuName    = ...;
  1890.     cls.hInstance       = hinst;
  1891.     cls.lpszClassName   = "Foo";
  1892.     cls.hbrBackground   = ...;
  1893.     cls.lpfnWndProc     = Foo_WndProc;
  1894.     cls.style           = CS_DBLCLKS;
  1895.     cls.cbWndExtra      = sizeof(FOO*);  // room for instance
  1896.                                          // data ptr
  1897.     cls.cbClsExtra      = 0;
  1898.  
  1899.     return RegisterClass(&cls);
  1900. }
  1901.  
  1902. // The window procedure for class "Foo".  This demonstrates how
  1903. // instance data is attached to a window and passed to the
  1904. // message handler functions.  It's fully STRICT enabled,
  1905. // and Win 3.0 compatible.
  1906.  
  1907.  
  1908.  
  1909.                                   - 31 -
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.  
  1916. LRESULT CALLBACK _export Foo_WndProc(HWND hwnd, UINT msg,
  1917.                                      WPARAM wParam,
  1918.                                      LPARAM lParam)
  1919. {
  1920.   FOO* pfoo = Foo_GetPtr(hwnd);
  1921.  
  1922.   if (pfoo == NULL)
  1923.   {
  1924.     // If we're creating the window, then try to allocate it.
  1925.  
  1926.     if (msg == WM_NCCREATE)
  1927.     {
  1928.       // Create the instance data structure, set up the hwnd
  1929.       // backpointer field, and associate it with the window.
  1930.  
  1931.       pfoo = (FOO*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1932.                               sizeof(FOO));
  1933.  
  1934.       // If an error occured, return 0L to fail the CreateWindow
  1935.       // call. This will cause CreateWindow to return NULL.
  1936.  
  1937.       if (pfoo == NULL)
  1938.         return 0L;
  1939.  
  1940.       pfoo->hwnd = hwnd;
  1941.       Foo_SetPtr(hwnd, pfoo);
  1942.  
  1943.       // NOTE: the rest of the FOO structure should be
  1944.       // initialized inside of Template_OnCreate
  1945.       // (or Template_OnNCCreate).
  1946.       // Further creation data may be accessed through the
  1947.       // CREATESTRUCT FAR* parameter.
  1948.     }
  1949.     else
  1950.     {
  1951.       // It turns out WM_NCCREATE is NOT necessarily the first
  1952.       // message recieved by a top-level window
  1953.       // (WM_GETMINMAXINFO is).
  1954.       // Pass messages that precede WM_NCCREATE on through to
  1955.       // Foo_DefProc
  1956.  
  1957.       return Foo_DefProc(hwnd, msg, wParam, lParam);
  1958.     }
  1959.   }
  1960.  
  1961.   if (msg == WM_NCDESTROY)
  1962.   {
  1963.     // The window is being destroyed: free up the FOO structure.
  1964.  
  1965.  
  1966.  
  1967.                                   - 32 -
  1968.  
  1969.  
  1970.  
  1971.  
  1972.  
  1973.  
  1974.     // NOTE: If you want to handle WM_NCDESTROY with a message
  1975.     // cracker (NOT RECOMMENDED), you can uncomment the lines
  1976.     // below.
  1977.  
  1978.     // LRESULT result = HANDLE_MSG(hwnd, WM_NCDESTROY,
  1979.                                    Client_OnNCDestroy);
  1980.  
  1981.     // Deallocation of any fields of the FOO structure should
  1982.     // be done inside the OnNCDestroy function.
  1983.  
  1984.     LocalFree((HLOCAL)pfoo);
  1985.  
  1986.     pfoo = NULL;
  1987.     Foo_SetPtr(hwnd, NULL);
  1988.  
  1989.     //return result;
  1990.   }
  1991.  
  1992.   switch (msg)
  1993.   {
  1994.     HANDLE_MSG(pfoo, WM_CREATE, Foo_OnCreate);
  1995.     HANDLE_MSG(pfoo, WM_PAINT, Foo_OnPaint);
  1996.     ...
  1997.  
  1998.     default:
  1999.       return Foo_DefProc(hwnd, msg, wParam, lParam);
  2000.   }
  2001. }
  2002.  
  2003.  
  2004. ------------------  Dialog procedures are different from window procedures
  2005.   Message crackers  in that they return a BOOL indicating whether the
  2006.         and dialog  message was processed rather than an LRESULT. For this
  2007.         procedures  reason, you can't use HANDLE_MSG: You must invoke the
  2008. ------------------  message cracker macro explicitly.
  2009.  
  2010.                     Here's an example that shows how you'd use message
  2011.                     crackers in a dialog procedure:
  2012.  
  2013.                      BOOL MyDlg_OnInitDialog(HWND hwndDlg, HWND hwndFocus,
  2014.                                              LPARAM lParam);
  2015.                      void MyDlg_OnCommand(HWND hwnd, int id, HWND hwndCtl,
  2016.                                           UINT codeNotify);
  2017.  
  2018.                      BOOL _export CALLBACK MyDlg_DlgProc(HWND hwndDlg, UINT
  2019.                      msg,
  2020.                                                          WPARAM wParam,
  2021.                      LPARAM lParam)
  2022.  
  2023.  
  2024.  
  2025.                                   - 33 -
  2026.  
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.                      {
  2033.                        switch (msg)
  2034.                        {
  2035.                          // Since HANDLE_WM_INITDIALOG returns an LRESULT,
  2036.                          // we must cast it to a BOOL before returning.
  2037.  
  2038.                          case WM_INITDIALOG:
  2039.                            return (BOOL)HANDLE_WM_INITDIALOG(hwndDlg,
  2040.                      wParam, lParam,
  2041.                                                              MyDlg_OnInitDialog);
  2042.  
  2043.                          case WM_COMMAND:
  2044.                            HANDLE_WM_COMMAND(hwndDlg, wParam, lParam,
  2045.                                              MyDlg_OnCommand);
  2046.                            return TRUE;
  2047.                            break;
  2048.  
  2049.                          default:
  2050.                            return FALSE;
  2051.                        }
  2052.                      }
  2053.  
  2054.                     If you'd like to process messages that return values
  2055.                     such as WM_ERASEBKGND in your dialog procedure, or
  2056.                     would like to make it easier to share code between your
  2057.                     window procedures and your dialog procedures, you may
  2058.                     want to make use of the techniques shown later in
  2059.                     "Dialog Procedures: A Better Way."
  2060.  
  2061.  
  2062. ------------------  Message crackers can also be used to simplify window
  2063.   Message crackers  subclassing code. With message crackers, unprocessed
  2064.         and window  messages must be forwarded using the appropriate
  2065.        subclassing  FORWARD_WM_* macro.  When you are subclassing a window,
  2066. ------------------  the proper way to forward unprocessed messages is by
  2067.                     calling CallWindowProc, passing it the previous window
  2068.                     procedure address, along with the four standard window
  2069.                     message parameters.
  2070.  
  2071.                     The FORWARD_WM_* macros can't be used directly with
  2072.                     CallWindowProc, because they can only invoke functions
  2073.                     having the standard window procedure signature:
  2074.                     CallWindowProc has an extra WNDPROC parameter.
  2075.  
  2076.                     This problem is handled easily by simply declaring
  2077.                     XXX_DefProc as a function instead of a macro.  Your
  2078.                     function must call CallWindowProc instead of calling
  2079.                     DefWindowProc:
  2080.  
  2081.  
  2082.  
  2083.                                   - 34 -
  2084.  
  2085.  
  2086.  
  2087.  
  2088.  
  2089.  
  2090.                     Here's an example showing how this works:
  2091.  
  2092. // Global variable that holds the previous window
  2093. // procedure address of the subclassed window:
  2094.  
  2095. WNDPROC Foo_lpfnwpDefProc = NULL;
  2096.  
  2097. // Code fragment to subclass a window
  2098. // and store previous wndproc value:
  2099.  
  2100. void SubclassFoo(HWND hwndFoo)
  2101. {
  2102.   // Global application instance handle:
  2103.   extern HINSTANCE g_hinstFoo;
  2104.   ...
  2105.  
  2106.   // SubclassWindow is a macro API that calls SetWindowLong
  2107.   // as appropriate to change the window procedure of hwndFoo.
  2108.  
  2109.   Foo_lpfnwpDefProc = SubclassWindow(hwndFoo,
  2110.                       (WNDPROC)MakeProcInstance
  2111.                       ((FARPROC)Foo_WndProc, g_hinstFoo));
  2112.   ...
  2113. }
  2114.  
  2115. // Default message handler function
  2116.  
  2117. // This function invokes the superclasses' window procedure.
  2118. // It must be declared with the same signature as any window
  2119. // procedure, so it can be used with the FORWARD_WM_* macros.
  2120.  
  2121. LRESULT Foo_DefProc(HWND hwnd, UINT msg,
  2122.                     WPARAM wParam, LPARAM lParam)
  2123. {
  2124.   return CallWindowProc(Foo_lpfnwpDefProc,
  2125.                         hwnd, msg, wParam, lParam);
  2126. }
  2127.  
  2128. // Foo window procedure.  Everything here is the same as in the
  2129. // normal non-subclassed case: the differences are encapsulated // in
  2130. Foo_DefProc.
  2131.  
  2132. LRESULT CALLBACK Foo_WndProc(HWND hwnd, UINT msg,
  2133.                              WPARAM wParam, LPARAM lParam)
  2134. {
  2135.   switch (msg)
  2136.   {
  2137.     HANDLE_MSG(hwnd, WM_CHAR, Foo_OnChar);
  2138.  
  2139.  
  2140.  
  2141.                                   - 35 -
  2142.  
  2143.  
  2144.  
  2145.  
  2146.  
  2147.  
  2148.     ...
  2149.     default:
  2150.       // Be sure to call Foo_DefProc, NOT DefWindowProc!
  2151.  
  2152.       return Foo_DefProc(hwnd, msg, wParam, lParam);
  2153.   }
  2154. }
  2155.  
  2156. // Message handlers
  2157.  
  2158. void Foo_OnChar(HWND hwnd, UINT ch, int cRepeat)
  2159. {
  2160.   if (ch == ... || whatever)
  2161.   {
  2162.     // handle it here
  2163.   }
  2164.   else
  2165.   {
  2166.     // Forward the message on to Foo_DefProc
  2167.     FORWARD_WM_CHAR(hwnd, ch, cRepeat, Foo_DefProc);
  2168.   }
  2169. }
  2170.  
  2171.  
  2172. ------------------  There are two longstanding sources of confusion and
  2173. Dialog procedures:  bugs in Windows dialog procedures: 1. There is no way
  2174.       A better way  to return a value from a message handled by a dialog
  2175. ------------------  procedure, and 2. it's not possible to execute the
  2176.                     default dialog behavior for a message before executing
  2177.                     your own code in your dialog procedure.
  2178.  
  2179.                     Here is a simple solution to both of these problems
  2180.                     that is compatible with both Windows 3.0 and 3.1.  It
  2181.                     unifies the way window procedures and dialog procedures
  2182.                     are coded, and it works very nicely with message
  2183.                     crackers.
  2184.  
  2185.               Note  These techniques, like message crackers, are completely
  2186.                     optional.  You can use these techniques with or without
  2187.                     message crackers.
  2188.  
  2189.                     You can code a dialog procedure just as if it were a
  2190.                     window procedure: you have the same freedom to return
  2191.                     values and execute the default dialog processing
  2192.                     messages as you do with window procedures.  It's also
  2193.                     easier to copy or share code between dialog and window
  2194.                     procedures.
  2195.  
  2196.  
  2197.  
  2198.  
  2199.                                   - 36 -
  2200.  
  2201.  
  2202.  
  2203.  
  2204.  
  2205.  
  2206.                     Executing default dialog procedure functionality
  2207.                     =======================================================
  2208.  
  2209.                     Although Windows provides the DefDlgProc API, it can't
  2210.                     be used as is for our purposes because its
  2211.                     implementation calls the dialog procedure again.  If we
  2212.                     called it from our dialog procedure, the dialog
  2213.                     procedure would be called again, recursively, until we
  2214.                     run out of stack space and crash.  To prevent this
  2215.                     infinite recursion, we need only detect that we're
  2216.                     being called recursively and return FALSE, which will
  2217.                     cause the default processing to be performed.
  2218.  
  2219.  
  2220.                     Returning message results from dialog procedures
  2221.                     =======================================================
  2222.  
  2223.                     Windows 3.0 and 3.1 both support a general mechanism
  2224.                     for returning values from messages handled in dialog
  2225.                     procedures.  Essentially, you store the return value
  2226.                     with SetWindowLong, which will get returned from the
  2227.                     message when your dialog procedure returns TRUE.
  2228.  
  2229.                     There are some special cases you have to worry about:
  2230.                     in some cases, the return value must be returned in
  2231.                     place of the BOOL return value.
  2232.  
  2233.  
  2234.                     How it works
  2235.                     =======================================================
  2236.  
  2237.                     Here is some code that shows how all this comes
  2238.                     together:
  2239.  
  2240. // function prototypes in header file..
  2241.  
  2242. BOOL CALLBACK _export MyDlg_OldProc(HWND hwndDlg, UINT msg,
  2243.                                     WPARAM wParam,
  2244.                                     LPARAM lParam);
  2245.  
  2246. LRESULT MyDlg_DlgProc(HWND hwndDlg, UINT msg,
  2247.                       WPARAM wParam, LPARAM lParam);
  2248.  
  2249.  
  2250. // implementation in .c file..
  2251.  
  2252. // static (or global) variable for preventing infinite recursion
  2253.  
  2254.  
  2255.  
  2256.  
  2257.                                   - 37 -
  2258.  
  2259.  
  2260.  
  2261.  
  2262.  
  2263.  
  2264. static BOOL fMyDlgRecurse = FALSE;
  2265.  
  2266. BOOL CALLBACK _export MyDlg_OldProc(HWND hwndDlg, UINT msg,
  2267.                                     WPARAM wParam,
  2268.                                     LPARAM lParam);
  2269. {
  2270.   LRESULT result;
  2271.  
  2272.   // Check for possible recursion.  If so, just return FALSE
  2273.   // after clearing the recursion flag, to ensure that the
  2274.   // default processing is executed.
  2275.  
  2276.   if (fMyDlgRecurse)
  2277.   {
  2278.     fMyDlgRecurse = FALSE;
  2279.     return FALSE;
  2280.   }
  2281.  
  2282.   result = MyDlg_DlgProc(hwndDlg, msg, wParam, lParam);
  2283.  
  2284.   // Here if we handled the message, and want to return result.
  2285.  
  2286.   switch (msg)
  2287.   {
  2288.     // The following messages are special-cased by the dialog
  2289.     // manager, and assumed to be returned as a BOOL from the
  2290.     // dialog procedure:
  2291.  
  2292.     case WM_INITDIALOG:
  2293.     case WM_CTLCOLOR:
  2294.     case WM_COMPAREITEM:
  2295.     case WM_VKEYTOITEM:
  2296.     case WM_CHARTOITEM:
  2297.     case WM_QUERYDRAGICON:
  2298.       return (BOOL)LOWORD(result);
  2299.  
  2300.     default:
  2301.       // All other messages use the DWL_MSGRESULT window words:
  2302.       SetWindowLong(hwndDlg, DWL_MSGRESULT, (LPARAM)result);
  2303.       return TRUE;
  2304.   }
  2305. }
  2306.  
  2307. LRESULT MyDlg_DlgProc(HWND hwndDlg, UINT msg,
  2308.                       WPARAM wParam, LPARAM lParam);
  2309. {
  2310.   switch (msg)
  2311.   {
  2312.  
  2313.  
  2314.  
  2315.                                   - 38 -
  2316.  
  2317.  
  2318.  
  2319.  
  2320.  
  2321.  
  2322.     HANDLE_MSG(hwndDlg, WM_INITDIALOG, MyDlg_OnInitDialog);
  2323.     HANDLE_MSG(hwndDlg, WM_COMMAND, MyDlg_OnCommand);
  2324.  
  2325.     default:
  2326.       // Call DefDlgProc to invoke default dialog processing
  2327.       // for messages we don't handle ourself.  Set recursion
  2328.       // flag before we go, so MyDlg_OldDlgProc knows to
  2329.       // return FALSE.
  2330.  
  2331.       fMyDlgRecurse = TRUE;
  2332.       return DefDlgProc(hwndDlg, msg, wParam, lParam);
  2333.   }
  2334. }
  2335.  
  2336.                     You must declare a static (or global) BOOL variable
  2337.                     that is initialized to FALSE.  It's safe to use the
  2338.                     same global variable for all your dialogs, even if one
  2339.                     dialog procedure brings up another dialog box.
  2340.  
  2341.                     What's important is that the same boolean variable be
  2342.                     used in the "OldDlgProc" and before the call to
  2343.                     DefDlgProx: a local BOOL variable must NOT be used, or
  2344.                     infinite recursion will result.
  2345.  
  2346.  
  2347.                     A simplified example using predefined macro APIs
  2348.                     =======================================================
  2349.  
  2350.                     Three macro APIs are defined in windowsx.h that
  2351.                     drastically simplify the code shown above.  They are
  2352.                     SetDlgMsgResult, DefDlgProcEx, and
  2353.                     CheckDefDlgRecursion.
  2354.  
  2355.                     Here's the same dialog code, this time using these
  2356.                     macro APIs:
  2357.  
  2358. // prototypes..
  2359.  
  2360. BOOL CALLBACK _export MyDlg_OldProc(HWND hwndDlg, UINT msg,
  2361.                                     WPARAM wParam,
  2362.                                     LPARAM lParam);
  2363.  
  2364. LRESULT MyDlg_DlgProc(HWND hwndDlg, UINT msg,
  2365.                       WPARAM wParam, LPARAM lParam);
  2366.  
  2367.  
  2368. // implementation..
  2369.  
  2370.  
  2371.  
  2372.  
  2373.                                   - 39 -
  2374.  
  2375.  
  2376.  
  2377.  
  2378.  
  2379.  
  2380. static BOOL fDefDlgEx = FALSE;
  2381.  
  2382. BOOL CALLBACK _export MyDlg_OldProc(HWND hwndDlg, UINT msg,
  2383.                                     WPARAM wParam,
  2384.                                     LPARAM lParam);
  2385. {
  2386.   CheckDefDlgRecursion(&fDefDlgEx);
  2387.   return SetDlgMsgResult(hwndDlg, msg,
  2388.          MyDlg_DlgProc(hwndDlg, msg, wParam, lParam));
  2389. }
  2390.  
  2391. LRESULT MyDlg_DefProc(HWND hwndDlg, UINT msg,
  2392.                       WPARAM wParam, LPARAM lParam);
  2393. {
  2394.   return DefDlgProcEx(hwnd, msg, wParam, lParam, &fDefDlgEx);
  2395. }
  2396.  
  2397. LRESULT MyDlg_DlgProc(HWND hwndDlg, UINT msg,
  2398.                       WPARAM wParam, LPARAM lParam);
  2399. {
  2400.   switch (msg)
  2401.   {
  2402.     HANDLE_MSG(hwndDlg, WM_INITDIALOG, MyDlg_OnInitDialog);
  2403.     HANDLE_MSG(hwndDlg, WM_COMMAND, MyDlg_OnCommand);
  2404.  
  2405.     default:
  2406.       return MyDlg_DefProc(hwnd, msg, wParam, lParam);
  2407.   }
  2408. }
  2409.  
  2410.                     As mentioned earlier, it's safe to use the same boolean
  2411.                     fDefDlgEx variable for all your dialog procedures, or
  2412.                     you can define one for each of your dialogs. What's
  2413.                     important is that the same boolean variable be used for
  2414.                     the CheckDefDlgRecursion call AND the DefDlgProcEx call
  2415.                     in a given dialog procedure: a local BOOL variable must
  2416.                     NOT be used, or infinite recursion will result.
  2417.  
  2418.                     You can also use the same _DefProc function declaration
  2419.                     for all of your dialog procedures that use the same
  2420.                     fDefDlgEx variable: for example, you could implement
  2421.                     the following function:
  2422.  
  2423.  
  2424. LRESULT CommonDlg_DefProc(HWND hwndDlg, UINT msg,
  2425.                           WPARAM wParam, LPARAM lParam)
  2426. {
  2427.   return DefDlgProcEx(hwnd, msg, wParam, lParam, &fDefDlgEx);
  2428.  
  2429.  
  2430.  
  2431.                                   - 40 -
  2432.  
  2433.  
  2434.  
  2435.  
  2436.  
  2437.  
  2438. }
  2439.  
  2440.                     then, for each dialog class, #define something like:
  2441.  
  2442.                      #define MyDlg_DefProc  CommonDlg_DefProc
  2443.  
  2444.  
  2445. ------------------  Converting existing code over to use message crackers
  2446.         Converting  is not particularly difficult.  Here are some
  2447.   existing code to  suggestions that should help:
  2448.        use message
  2449.           crackers  o Have a look at the sample app MAKEAPP for some more
  2450. ------------------    detailed examples of the use of message crackers and
  2451.                       message forwarders.
  2452.  
  2453.                     o It's a good idea (though not necessary) to first
  2454.                       convert your code to use STRICT.  With STRICT
  2455.                       enabled, the compiler can help you find parameter
  2456.                       type mismatch and other errors much easier.
  2457.  
  2458.                     o It's best to declare all your message handler
  2459.                       functions in an include file, rather than declaring
  2460.                       them directly in the .c file that uses them.  You
  2461.                       don't have to use the ClassName_OnXXX naming
  2462.                       convention for your function, but we've found that
  2463.                       it's quite a helpful way to organize the code for a
  2464.                       window class.
  2465.  
  2466.                     o When declaring or implementing a message forwarder
  2467.                       function, just use your editor to search for and copy
  2468.                       the message handler function prototype comment from
  2469.                       windowsx.h and paste it into your source code. This
  2470.                       way you don't have to type it from scratch.
  2471.  
  2472.                     o Use the FORWARD_WM_* macros to send or forward
  2473.                       non-control messages to other windows by passing
  2474.                       SendMessage as the first parameter.
  2475.  
  2476.                     o If you have defined your own private window messages,
  2477.                       you should define a message cracker and forwarder for
  2478.                       each.  This is pretty simple to do: Just copy an
  2479.                       existing cracker and forwarder from windowsx.h and
  2480.                       edit it. Be sure to fully parenthesize your use of
  2481.                       macro parameters, and be careful with the casts you
  2482.                       use.
  2483.  
  2484.                     Converting existing window and dialog procedures to
  2485.                     message crackers can be a fair amount of work,
  2486.  
  2487.  
  2488.  
  2489.                                   - 41 -
  2490.  
  2491.  
  2492.  
  2493.  
  2494.  
  2495.  
  2496.                     especially if the window and dialog procedures are
  2497.                     large.  You can mix and match old-style message
  2498.                     handlers with message crackers, so you may want to use
  2499.                     message crackers for new message handlers, or for
  2500.                     existing code you plan on modifying extensively.
  2501.  
  2502.                     Converting dialog procedures over to the new-style
  2503.                     LRESULT-returning dialog procedures is also something
  2504.                     that isn't required for all your dialog procedures.
  2505.                     You can convert those that you plan to modify, or that
  2506.                     contain code that you may want to reuse in other dialog
  2507.                     procedures.
  2508.  
  2509.  
  2510.  
  2511.  
  2512.  
  2513.  
  2514.  
  2515.  
  2516.  
  2517.  
  2518.  
  2519.  
  2520.  
  2521.  
  2522.  
  2523.  
  2524.  
  2525.  
  2526.  
  2527.  
  2528.  
  2529.  
  2530.  
  2531.  
  2532.  
  2533.  
  2534.  
  2535.  
  2536.  
  2537.  
  2538.  
  2539.  
  2540.  
  2541.  
  2542.  
  2543.  
  2544.  
  2545.  
  2546.  
  2547.                                   - 42 -
  2548.  
  2549.