windows-nt/Source/XPSP1/NT/shell/osshell/control/midi
..
cparrow.c
cparrow.h
extern.h
hack.h
key.c
lengths.c
makefile
map.c
mapcopy.c
midi.c
midi.def
midi.h
midi.ico
midi.rc
midi.rcv
midimap.c
midimap.cfg
midimap.h
patch.c
preclude.h
propbox.c
readme.1st
readme.txt
setup.c
sources

MIDI Mapper Control Panel Applet        Mike McQueen (t-mikemc) 1-Oct-90
--------------------------------
                                        Hastily updated by LaurieGr

This document describes how the MIDI Mapper applet was put together, in
order to hopefully make it easier for someone other than myself to find
and fix any bugs or change some features.

Currently the source for this applet is divided into seven modules,
four header files and a resource script file.


Descrption of MIDI Mapper applet:
================================

Modules
-------
        
LIBINIT.ASM
        Contains the LibEntry function.  This piece of code sends shivers
        up my spine every time I look at it.  Someone (other than ToddLa)
        really ought to make a nice clean standard DLL entry point asm
        module.  Doesn't apply to NT.

MIDI.C
        Contains the LibMain and WEP functions for windows.

        Contains the CPlApplet export function for multimedia control panel.
        This is the entry point that the controlpanel calls.
        Start debugging here!

        Contains the 'MIDI Mapper' dialog box function.  Among other things,
        this dialog box has three combo boxes into which the available setups,
        patchmaps and keymaps are respectively enumerated.  When someone
        deletes a map, it's not actually deleted from the file, but rather
        its entry is simply removed from the combo box.  If the guy then
        clicks on the 'OK' button, interpreted as 'OK, go ahead and actually
        delete the maps', I compare the available maps to the maps left
        in the combo boxes, and delete any discrepancies.  This is done in
        the EnumFunc function described below.

        This module also contains several functions that are used by one or
        more of the map editing modules.  I probably should have thrown
        together a 'MISC.C' module and tossed all these functions in there,
        but in any case all these functions are at the bottom of the file.
        The WriteBoxRect and SizeBox functions were only used in the version
        of the applet that allowed sizing of map-editing boxes.  If sizing
        is never ever going to be used, these can be removed.

        **EnumFunc**

        This lovely little treat of a function is the callback for the
        mapEnumerate function from midimap.c in the MMSYSTEM DLL.  it is used
        by calls to mapEnumerate from 3 different modules, MIDI.C, SETUP.C
        and PATCH.C.
        mapEnumerate is called to enumerate Setups, Maps, Patches or ports
        which don't have an awful lot in common.  It's also called from
        all over the place.  The price for having only one copy of the 16
        statements that actually do the enumeration is that all the different
        callback functions are forced into the same straightjacket of
        parameters.  On 16 bit it inevitably had a handle packed into half
        a DWORD.  The callback which is executed once for each element now
        has three parameters to cater for all cases (with a little casting)
        and some subset of these are actually used in each case.

        The SETUP.C and PATCH.C modules simply call it to enumerate the
        available patchmaps and keymaps into their combo boxes, respectively.

        In MIDI.C, the HIWORD of the dwUser parameter is either set to
        MMENUM_DELETE, MMENUM_BASIC or  MMENUM_INTOCOMBO.

        If it is set to MMENUM_INTOCOMBO, it indicates that this enumeration
        is taking place into the combo box of the MIDI Mapper dialog box.
        When this happens, a handle is allocated for the length of the
        description string, and this handle is set to be the new combo box
        entry's ITEMDATA.  This is how I update the description when the user
        changes the current selection in the combo box in the main dialog.

        If it is set to MMENUM_DELETE, it indicates that a check is being done
        to see if any entrys in the combo box differ from the available maps
        being enumerated.  In this case, if a map name is sent to EnumFunc
        from mapEnumerate, and it does not exist in the combo box, it will be
        deleted right then and there with a call to mapDelete (another
        midimap.c function).
        
SETUP.C
PATCH.C
KEY.C
        These modules are pretty similar in content, so I am going to try to
        describe them all in one plop.  A lot of the functions from these
        three modules have the same name, but are prefixed with 'Setup',
        'Patch' or 'Key' depending on which module they are in. I'm going to
        use 'xxx' to mean any or all of those three prefixes.

        The 'xxxBox' functions are the three dialog box functions for the
        three map-editing dialog boxes.

        The 'xxxPaint' functions are the only places where anything is ever
        drawn on the screen.  These functions are essentially the BeginPaint
        EndPaint blocks for each map editor.

        In the setup editor, I do a funny little trick to allow tabbing onto
        three-state buttons, and it would probably be a good idea to explain
        it.  Every time SetupSetFocus is called, I remove the WS_TABSTOP style
        attribute from the 3-state button on the last edit line, and add it
        to the 3-state button on the new edit line.  I also change the text to
        "&A" which allows the ALT-A accelerator to work.

        Global variables which pertain to all three of these modules are
        described under the 'extern.h' header file.
        
PROPBOX.C
        Contains only a dialog box function for getting properties for a new
        map of any type.  If the 'fSaveAs' variable is set, it will
        automagically check for duplicate names.  Unfortunately, I don't have
        any way of doing a 'save as...' in the current version.  If you think
        of a way, you could just call this dialog box with the fSaveAs
        variable set.

CPARROW.C
        Contains a routine for registering a window class for a control panel
        arrow control, as well as the window function for that class.  There
        is a arrow in WINCOM, and there is another arrow in SCRNSVR (that's
        where I stole this code from).  I think my version works/looks better
        than both of the others.  I also think it still needs to be worked
        on.  I think that if and when this ever gets done, it should go in
        WINCOM and then the static link modules could go away.

Headers
-------

MIDI.H
        Contains all sorts of definitions, and I've tried to document them
        as best as possible.
        
PRECLUDE.H
        Contains 'preclude' definitions for windows.h and mmsystem.h, to
        make compiling a little faster.

CPARROW.H
        Contains the prototypes for the arrow class (un)registering functions.

EXTERN.H
        Contains external variable definitions, with limited comments.  I'll
        comment them again right here:

extern HWND     hWnd                    // 'Current' window handle
                hEdit,                  // Edit control handle
                hArrow;                 // Arrow control handle
extern RECT     rcBox;                  // Clipping/scroll rectangle
extern int      rgxPos [8],             // horizontal line positions
                yBox,                   // rows of data y extent
                xClient,                // Window client area x pixels
                yClient,                // Window client area y pixels
                iCurPos,                // Current position on screen
                iVertPos,               // Current vertical scroll position
                iVertMax,               // Maximum veritcal scroll position
                nLines,                 // Number of lines of data
                yChar,                  // Height of character in font
                xChar,                  // Width of average character in font
                iMap;                   // Flag for GetMBData
extern char     szCurrent [],           // Name of current map
                szCurDesc [],           // Description of current map
                szMidiCtl [],           // "MIDI Control Panel"
                szNone [];              // Static text string '[ None ]'
extern BOOL     fModified,              // Has map been modified?
                fNew,                   // Is this a new map?
                fSaveAs,                // Is propbox being used for Save As?
                fHidden;                // Is the active edit line hidden?

Resource script
---------------
        midi.rc


Problems with MIDI Mapper applet:
================================

Currently, the maximum number of any type of map (setup,patchmap,keymap) is
limited to 100.  This is a deficiency in midimap routines which are part of
mmsystem.  If someone calls the mapWrite function with the flag set to the
type of a map of which there are 100, the write will fail.  The only way to
currently get around this problem is deleting maps.

In the process of changing the current selection of either the "Keymap Name"
combobox in the Patchmap editor, or the "Patchmap Name" combobox in the Setup
editor, memory is potentially being reallocated without fail checks, which
means it should be possible to run out of memory in a bad way if the current
selection of these comboboxes is changed a lot.

For the patchmap editor, all keymaps are the
same size.  I should never have to reallocate the whole setup just so it turns
out to be the exact same size!  Anyway, the problem arises when you have a
patchmap with some keymaps.  Someone derefernces a keymap from a specific
patch number in the patchmap editor (that is, selects the [none] entry for
that particular patch).  This in turns causes the keymap offset of that
patchmap to be set to zero.  If the person proceeds to re-reference that
patchmap back to the same keymap, or any other keymap, the entire setup will
be reallocated, to the same size.  Although this will call will probably never
fail, it is unnecessary.

A flag lying around in the patchmap structure which indicates that the memory
for a keymap has been allocated make this very useful.  Perhaps it would be a
good idea to define a range of flags in the dwFlags structure entry of the
MIDIKEYMAP/MIDIPATCHMAP/MIDIMAP data structures which are for internal use
only, some reserved bits.

The formula for the size of the new setup is <old setupsize> + <new patchsize>,
which does not take into account subtracting <old patchsize>.  The reason for
this is that the patchmap may be referenced by other channels in the setup.
You cannot free the memory of the patchmap just because one channel doesn't
reference it anymore.  The thing is, it would be really easy to check and see
if anyother channel references it.  There are two APIs called:

mapPatchMapInSetup and..
mapKeyMapInPatchMap

which are exported from mmsystem.  These routines should be used by the

SetupComboMsg

function, under the CBN_SELCHANGE message.  It is here that the existence
of any given patchmap name in the current setup can be determined by calls
to the former API.  It is not necessary to reallocate an entire setup if
one channel in that setup suddenly references a patchmap that is already
referenced in that setup.  All that should happen is the new channel's
patchmap offset value should be set to that of the existing channel.  In a
similar instance, if a patchmap is dereferenced by a channel of a setup, and
it is determined that no other channels of that setup use that patchmap, the
size of that patchmap may be subtracted from the setup reallocation size.