/*
 * Message spying routines
 *
 * Copyright 1994, Bob Amstadt
 *           1995, Alex Korobka
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "windef.h"
#include "wingdi.h"
#include "winreg.h"
#include "wine/winuser16.h"
#include "wine/winbase16.h"
#include "wine/unicode.h"
#include "win.h"
#include "wine/debug.h"
#include "spy.h"
#include "commctrl.h"

WINE_DEFAULT_DEBUG_CHANNEL(message);

#define SPY_MAX_MSGNUM   WM_USER
#define SPY_INDENT_UNIT  4  /* 4 spaces */

#define DEBUG_SPY 0

static const char * const MessageTypeNames[SPY_MAX_MSGNUM + 1] =
{
    "WM_NULL",			/* 0x00 */
    "WM_CREATE",
    "WM_DESTROY",
    "WM_MOVE",
    "wm_sizewait",
    "WM_SIZE",
    "WM_ACTIVATE",
    "WM_SETFOCUS",
    "WM_KILLFOCUS",
    "WM_SETVISIBLE",
    "WM_ENABLE",
    "WM_SETREDRAW",
    "WM_SETTEXT",
    "WM_GETTEXT",
    "WM_GETTEXTLENGTH",
    "WM_PAINT",
    "WM_CLOSE",			/* 0x10 */
    "WM_QUERYENDSESSION",
    "WM_QUIT",
    "WM_QUERYOPEN",
    "WM_ERASEBKGND",
    "WM_SYSCOLORCHANGE",
    "WM_ENDSESSION",
    "wm_systemerror",
    "WM_SHOWWINDOW",
    "WM_CTLCOLOR",
    "WM_WININICHANGE",
    "WM_DEVMODECHANGE",
    "WM_ACTIVATEAPP",
    "WM_FONTCHANGE",
    "WM_TIMECHANGE",
    "WM_CANCELMODE",
    "WM_SETCURSOR",		/* 0x20 */
    "WM_MOUSEACTIVATE",
    "WM_CHILDACTIVATE",
    "WM_QUEUESYNC",
    "WM_GETMINMAXINFO",
    "wm_unused3",
    "wm_painticon",
    "WM_ICONERASEBKGND",
    "WM_NEXTDLGCTL",
    "wm_alttabactive",
    "WM_SPOOLERSTATUS",
    "WM_DRAWITEM",
    "WM_MEASUREITEM",
    "WM_DELETEITEM",
    "WM_VKEYTOITEM",
    "WM_CHARTOITEM",
    "WM_SETFONT",		/* 0x30 */
    "WM_GETFONT",
    "WM_SETHOTKEY",
    "WM_GETHOTKEY",
    "wm_filesyschange",
    "wm_isactiveicon",
    "wm_queryparkicon",
    "WM_QUERYDRAGICON",
    "wm_querysavestate",
    "WM_COMPAREITEM",
    "wm_testing",
    NULL,
    "wm_otherwindowcreated",
    "wm_otherwindowdestroyed",
    "wm_activateshellwindow",
    NULL,

    NULL, 		        /* 0x40 */
    "wm_compacting", NULL, NULL,
    "WM_COMMNOTIFY", NULL,
    "WM_WINDOWPOSCHANGING",	/* 0x0046 */
    "WM_WINDOWPOSCHANGED",	/* 0x0047 */
    "WM_POWER", NULL,
    "WM_COPYDATA",
    "WM_CANCELJOURNAL", NULL, NULL,
    "WM_NOTIFY", NULL,

    /* 0x0050 */
    "WM_INPUTLANGCHANGEREQUEST",
    "WM_INPUTLANGCHANGE",
    "WM_TCARD",
    "WM_HELP",
    "WM_USERCHANGED",
    "WM_NOTIFYFORMAT", NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0060 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0070 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL,
    "WM_CONTEXTMENU",
    "WM_STYLECHANGING",
    "WM_STYLECHANGED",
    "WM_DISPLAYCHANGE",
    "WM_GETICON",

    "WM_SETICON",		/* 0x0080 */
    "WM_NCCREATE",		/* 0x0081 */
    "WM_NCDESTROY",		/* 0x0082 */
    "WM_NCCALCSIZE",		/* 0x0083 */
    "WM_NCHITTEST",        	/* 0x0084 */
    "WM_NCPAINT",          	/* 0x0085 */
    "WM_NCACTIVATE",       	/* 0x0086 */
    "WM_GETDLGCODE",		/* 0x0087 */
    "WM_SYNCPAINT",
    "WM_SYNCTASK", NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0090 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x00A0 */
    "WM_NCMOUSEMOVE",		/* 0x00A0 */
    "WM_NCLBUTTONDOWN",		/* 0x00A1 */
    "WM_NCLBUTTONUP",		/* 0x00A2 */
    "WM_NCLBUTTONDBLCLK",	/* 0x00A3 */
    "WM_NCRBUTTONDOWN",		/* 0x00A4 */
    "WM_NCRBUTTONUP",		/* 0x00A5 */
    "WM_NCRBUTTONDBLCLK",	/* 0x00A6 */
    "WM_NCMBUTTONDOWN",		/* 0x00A7 */
    "WM_NCMBUTTONUP",		/* 0x00A8 */
    "WM_NCMBUTTONDBLCLK",	/* 0x00A9 */
    NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x00B0 - Win32 Edit controls */
    "EM_GETSEL",                /* 0x00b0 */
    "EM_SETSEL",                /* 0x00b1 */
    "EM_GETRECT",               /* 0x00b2 */
    "EM_SETRECT",               /* 0x00b3 */
    "EM_SETRECTNP",             /* 0x00b4 */
    "EM_SCROLL",                /* 0x00b5 */
    "EM_LINESCROLL",            /* 0x00b6 */
    "EM_SCROLLCARET",           /* 0x00b7 */
    "EM_GETMODIFY",             /* 0x00b8 */
    "EM_SETMODIFY",             /* 0x00b9 */
    "EM_GETLINECOUNT",          /* 0x00ba */
    "EM_LINEINDEX",             /* 0x00bb */
    "EM_SETHANDLE",             /* 0x00bc */
    "EM_GETHANDLE",             /* 0x00bd */
    "EM_GETTHUMB",              /* 0x00be */
    NULL,                       /* 0x00bf */

    NULL,                       /* 0x00c0 */
    "EM_LINELENGTH",            /* 0x00c1 */
    "EM_REPLACESEL",            /* 0x00c2 */
    NULL,                       /* 0x00c3 */
    "EM_GETLINE",               /* 0x00c4 */
    "EM_LIMITTEXT",             /* 0x00c5 */
    "EM_CANUNDO",               /* 0x00c6 */
    "EM_UNDO",                  /* 0x00c7 */
    "EM_FMTLINES",              /* 0x00c8 */
    "EM_LINEFROMCHAR",          /* 0x00c9 */
    NULL,                       /* 0x00ca */
    "EM_SETTABSTOPS",           /* 0x00cb */
    "EM_SETPASSWORDCHAR",       /* 0x00cc */
    "EM_EMPTYUNDOBUFFER",       /* 0x00cd */
    "EM_GETFIRSTVISIBLELINE",   /* 0x00ce */
    "EM_SETREADONLY",           /* 0x00cf */

    "EM_SETWORDBREAKPROC",      /* 0x00d0 */
    "EM_GETWORDBREAKPROC",      /* 0x00d1 */
    "EM_GETPASSWORDCHAR",       /* 0x00d2 */
    "EM_SETMARGINS",            /* 0x00d3 */
    "EM_GETMARGINS",            /* 0x00d4 */
    "EM_GETLIMITTEXT",          /* 0x00d5 */
    "EM_POSFROMCHAR",           /* 0x00d6 */
    "EM_CHARFROMPOS",           /* 0x00d7 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x00E0 - Win32 Scrollbars */
    "SBM_SETPOS",               /* 0x00e0 */
    "SBM_GETPOS",               /* 0x00e1 */
    "SBM_SETRANGE",             /* 0x00e2 */
    "SBM_GETRANGE",             /* 0x00e3 */
    "SBM_ENABLE_ARROWS",        /* 0x00e4 */
    NULL,
    "SBM_SETRANGEREDRAW",       /* 0x00e6 */
    NULL, NULL,
    "SBM_SETSCROLLINFO",        /* 0x00e9 */
    "SBM_GETSCROLLINFO",        /* 0x00ea */
    NULL, NULL, NULL, NULL, NULL,

    /* 0x00F0 - Win32 Buttons */
    "BM_GETCHECK",              /* 0x00f0 */
    "BM_SETCHECK",              /* 0x00f1 */
    "BM_GETSTATE",              /* 0x00f2 */
    "BM_SETSTATE",              /* 0x00f3 */
    "BM_SETSTYLE",              /* 0x00f4 */
    "BM_CLICK",                 /* 0x00f5 */
    "BM_GETIMAGE",              /* 0x00f6 */
    "BM_SETIMAGE",              /* 0x00f7 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_KEYDOWN",		/* 0x0100 */
    "WM_KEYUP",			/* 0x0101 */
    "WM_CHAR",			/* 0x0102 */
    "WM_DEADCHAR",		/* 0x0103 */
    "WM_SYSKEYDOWN",		/* 0x0104 */
    "WM_SYSKEYUP",		/* 0x0105 */
    "WM_SYSCHAR",		/* 0x0106 */
    "WM_SYSDEADCHAR",		/* 0x0107 */
    "WM_KEYLAST",		/* 0x0108 */
    NULL,
    "WM_CONVERTREQUEST",
    "WM_CONVERTRESULT",
    "WM_INTERIM",
    "WM_IME_STARTCOMPOSITION",	/* 0x010d */
    "WM_IME_ENDCOMPOSITION",	/* 0x010e */
    "WM_IME_COMPOSITION",	/* 0x010f */

    "WM_INITDIALOG",		/* 0x0110 */
    "WM_COMMAND",		/* 0x0111 */
    "WM_SYSCOMMAND",       	/* 0x0112 */
    "WM_TIMER",			/* 0x0113 */
    "WM_HSCROLL",		/* 0x0114 */
    "WM_VSCROLL",		/* 0x0115 */
    "WM_INITMENU",              /* 0x0116 */
    "WM_INITMENUPOPUP",         /* 0x0117 */
    "WM_SYSTIMER",		/* 0x0118 */
    NULL, NULL, NULL, NULL, NULL, NULL,
    "WM_MENUSELECT",            /* 0x011f */

    "WM_MENUCHAR",              /* 0x0120 */
    "WM_ENTERIDLE",             /* 0x0121 */

    "WM_MENURBUTTONUP",         /* 0x0122 */
    "WM_MENUDRAG",              /* 0x0123 */
    "WM_MENUGETOBJECT",         /* 0x0124 */
    "WM_UNINITMENUPOPUP",       /* 0x0125 */
    "WM_MENUCOMMAND",           /* 0x0126 */
    "WM_CHANGEUISTATE",         /* 0x0127 */
    "WM_UPDATEUISTATE",         /* 0x0128 */
    "WM_QUERYUISTATE",          /* 0x0129 */

    NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0130 */
    NULL,
    "WM_LBTRACKPOINT",          /* 0x0131 */
    "WM_CTLCOLORMSGBOX",        /* 0x0132 */
    "WM_CTLCOLOREDIT",          /* 0x0133 */
    "WM_CTLCOLORLISTBOX",       /* 0x0134 */
    "WM_CTLCOLORBTN",           /* 0x0135 */
    "WM_CTLCOLORDLG",           /* 0x0136 */
    "WM_CTLCOLORSCROLLBAR",     /* 0x0137 */
    "WM_CTLCOLORSTATIC",        /* 0x0138 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0140 - Win32 Comboboxes */
    "CB_GETEDITSEL",            /* 0x0140 */
    "CB_LIMITTEXT",             /* 0x0141 */
    "CB_SETEDITSEL",            /* 0x0142 */
    "CB_ADDSTRING",             /* 0x0143 */
    "CB_DELETESTRING",          /* 0x0144 */
    "CB_DIR",                   /* 0x0145 */
    "CB_GETCOUNT",              /* 0x0146 */
    "CB_GETCURSEL",             /* 0x0147 */
    "CB_GETLBTEXT",             /* 0x0148 */
    "CB_GETLBTEXTLEN",          /* 0x0149 */
    "CB_INSERTSTRING",          /* 0x014a */
    "CB_RESETCONTENT",          /* 0x014b */
    "CB_FINDSTRING",            /* 0x014c */
    "CB_SELECTSTRING",          /* 0x014d */
    "CB_SETCURSEL",             /* 0x014e */
    "CB_SHOWDROPDOWN",          /* 0x014f */

    "CB_GETITEMDATA",           /* 0x0150 */
    "CB_SETITEMDATA",           /* 0x0151 */
    "CB_GETDROPPEDCONTROLRECT", /* 0x0152 */
    "CB_SETITEMHEIGHT",         /* 0x0153 */
    "CB_GETITEMHEIGHT",         /* 0x0154 */
    "CB_SETEXTENDEDUI",         /* 0x0155 */
    "CB_GETEXTENDEDUI",         /* 0x0156 */
    "CB_GETDROPPEDSTATE",       /* 0x0157 */
    "CB_FINDSTRINGEXACT",       /* 0x0158 */
    "CB_SETLOCALE",             /* 0x0159 */
    "CB_GETLOCALE",             /* 0x015a */
    "CB_GETTOPINDEX",           /* 0x015b */
    "CB_SETTOPINDEX",           /* 0x015c */
    "CB_GETHORIZONTALEXTENT",   /* 0x015d */
    "CB_SETHORIZONTALEXTENT",   /* 0x015e */
    "CB_GETDROPPEDWIDTH",       /* 0x015f */

    "CB_SETDROPPEDWIDTH",       /* 0x0160 */
    "CB_INITSTORAGE",           /* 0x0161 */
    NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0170 - Win32 Static controls */
    "STM_SETICON",              /* 0x0170 */
    "STM_GETICON",              /* 0x0171 */
    "STM_SETIMAGE",             /* 0x0172 */
    "STM_GETIMAGE",             /* 0x0173 */
    NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0180 - Win32 Listboxes */
    "LB_ADDSTRING",             /* 0x0180 */
    "LB_INSERTSTRING",          /* 0x0181 */
    "LB_DELETESTRING",          /* 0x0182 */
    "LB_SELITEMRANGEEX",        /* 0x0183 */
    "LB_RESETCONTENT",          /* 0x0184 */
    "LB_SETSEL",                /* 0x0185 */
    "LB_SETCURSEL",             /* 0x0186 */
    "LB_GETSEL",                /* 0x0187 */
    "LB_GETCURSEL",             /* 0x0188 */
    "LB_GETTEXT",               /* 0x0189 */
    "LB_GETTEXTLEN",            /* 0x018a */
    "LB_GETCOUNT",              /* 0x018b */
    "LB_SELECTSTRING",          /* 0x018c */
    "LB_DIR",                   /* 0x018d */
    "LB_GETTOPINDEX",           /* 0x018e */
    "LB_FINDSTRING",            /* 0x018f */

    "LB_GETSELCOUNT",           /* 0x0190 */
    "LB_GETSELITEMS",           /* 0x0191 */
    "LB_SETTABSTOPS",           /* 0x0192 */
    "LB_GETHORIZONTALEXTENT",   /* 0x0193 */
    "LB_SETHORIZONTALEXTENT",   /* 0x0194 */
    "LB_SETCOLUMNWIDTH",        /* 0x0195 */
    "LB_ADDFILE",               /* 0x0196 */
    "LB_SETTOPINDEX",           /* 0x0197 */
    "LB_GETITEMRECT",           /* 0x0198 */
    "LB_GETITEMDATA",           /* 0x0199 */
    "LB_SETITEMDATA",           /* 0x019a */
    "LB_SELITEMRANGE",          /* 0x019b */
    "LB_SETANCHORINDEX",        /* 0x019c */
    "LB_GETANCHORINDEX",        /* 0x019d */
    "LB_SETCARETINDEX",         /* 0x019e */
    "LB_GETCARETINDEX",         /* 0x019f */

    "LB_SETITEMHEIGHT",         /* 0x01a0 */
    "LB_GETITEMHEIGHT",         /* 0x01a1 */
    "LB_FINDSTRINGEXACT",       /* 0x01a2 */
    "LB_CARETON",               /* 0x01a3 */
    "LB_CARETOFF",              /* 0x01a4 */
    "LB_SETLOCALE",             /* 0x01a5 */
    "LB_GETLOCALE",             /* 0x01a6 */
    "LB_SETCOUNT",              /* 0x01a7 */
    "LB_INITSTORAGE",           /* 0x01a8 */
    "LB_ITEMFROMPOINT",         /* 0x01a9 */
    NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x01B0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x01C0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x01D0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x01E0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x01F0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_MOUSEMOVE",		/* 0x0200 */
    "WM_LBUTTONDOWN",		/* 0x0201 */
    "WM_LBUTTONUP",		/* 0x0202 */
    "WM_LBUTTONDBLCLK",		/* 0x0203 */
    "WM_RBUTTONDOWN",		/* 0x0204 */
    "WM_RBUTTONUP",		/* 0x0205 */
    "WM_RBUTTONDBLCLK",		/* 0x0206 */
    "WM_MBUTTONDOWN",		/* 0x0207 */
    "WM_MBUTTONUP",		/* 0x0208 */
    "WM_MBUTTONDBLCLK",		/* 0x0209 */
    "WM_MOUSEWHEEL",            /* 0x020A */
    NULL, NULL, NULL, NULL, NULL,

    "WM_PARENTNOTIFY",		/* 0x0210 */
    "WM_ENTERMENULOOP",         /* 0x0211 */
    "WM_EXITMENULOOP",          /* 0x0212 */
    "WM_NEXTMENU", 		/* 0x0213 */
    "WM_SIZING",
    "WM_CAPTURECHANGED",
    "WM_MOVING", NULL,
    "WM_POWERBROADCAST",
    "WM_DEVICECHANGE", NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_MDICREATE",             /* 0x0220 */
    "WM_MDIDESTROY",            /* 0x0221 */
    "WM_MDIACTIVATE",           /* 0x0222 */
    "WM_MDIRESTORE",            /* 0x0223 */
    "WM_MDINEXT",               /* 0x0224 */
    "WM_MDIMAXIMIZE",           /* 0x0225 */
    "WM_MDITILE",               /* 0x0226 */
    "WM_MDICASCADE",            /* 0x0227 */
    "WM_MDIICONARRANGE",        /* 0x0228 */
    "WM_MDIGETACTIVE",          /* 0x0229 */

    "WM_DROPOBJECT",
    "WM_QUERYDROPOBJECT",
    "WM_BEGINDRAG",
    "WM_DRAGLOOP",
    "WM_DRAGSELECT",
    "WM_DRAGMOVE",

    /* 0x0230*/
    "WM_MDISETMENU",            /* 0x0230 */
    "WM_ENTERSIZEMOVE",		/* 0x0231 */
    "WM_EXITSIZEMOVE",		/* 0x0232 */
    "WM_DROPFILES", 		/* 0x0233 */
    "WM_MDIREFRESHMENU", NULL, NULL, NULL,
    /* 0x0238*/
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0240 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0250 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0260 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0280 */
    NULL, "WM_IME_SETCONTEXT", "WM_IME_NOTIFY", "WM_IME_CONTROL", "WM_IME_COMPOSITIONFULL", "WM_IME_SELECT", "WM_IME_CHAR", NULL,
    "WM_IME_REQUEST", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    "WM_IME_KEYDOWN", "WM_IME_KEYUP", NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x02a0 */
    NULL, "WM_MOUSEHOVER", NULL, "WM_MOUSELEAVE", NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x02c0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_CUT", 			/* 0x0300 */
    "WM_COPY",
    "WM_PASTE",
    "WM_CLEAR",
    "WM_UNDO",
    "WM_RENDERFORMAT",
    "WM_RENDERALLFORMATS",
    "WM_DESTROYCLIPBOARD",
    "WM_DRAWCLIPBOARD",
    "WM_PAINTCLIPBOARD",
    "WM_VSCROLLCLIPBOARD",
    "WM_SIZECLIPBOARD",
    "WM_ASKCBFORMATNAME",
    "WM_CHANGECBCHAIN",
    "WM_HSCROLLCLIPBOARD",
    "WM_QUERYNEWPALETTE",	/* 0x030f*/

    "WM_PALETTEISCHANGING",
    "WM_PALETTECHANGED",
    "WM_HOTKEY", 		/* 0x0312 */
	  NULL, NULL, NULL, NULL,
    "WM_PRINT",
    "WM_PRINTCLIENT",
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x0340 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_QUERYAFXWNDPROC",   /*  0x0360 */
    "WM_SIZEPARENT",        /*  0x0361 */
    "WM_SETMESSAGESTRING",  /*  0x0362 */
    "WM_IDLEUPDATECMDUI",   /*  0x0363 */
    "WM_INITIALUPDATE",     /*  0x0364 */
    "WM_COMMANDHELP",       /*  0x0365 */
    "WM_HELPHITTEST",       /*  0x0366 */
    "WM_EXITHELPMODE",      /*  0x0367 */
    "WM_RECALCPARENT",      /*  0x0368 */
    "WM_SIZECHILD",         /*  0x0369 */
    "WM_KICKIDLE",          /*  0x036A */
    "WM_QUERYCENTERWND",    /*  0x036B */
    "WM_DISABLEMODAL",      /*  0x036C */
    "WM_FLOATSTATUS",       /*  0x036D */
    "WM_ACTIVATETOPLEVEL",  /*  0x036E */
    "WM_QUERY3DCONTROLS",   /*  0x036F */
    NULL,NULL,NULL,
    "WM_SOCKET_NOTIFY",     /*  0x0373 */
    "WM_SOCKET_DEAD",       /*  0x0374 */
    "WM_POPMESSAGESTRING",  /*  0x0375 */
    "WM_OCC_LOADFROMSTREAM",     /* 0x0376 */
    "WM_OCC_LOADFROMSTORAGE",    /* 0x0377 */
    "WM_OCC_INITNEW",            /* 0x0378 */
    "WM_QUEUE_SENTINEL",         /* 0x0379 */
    "WM_OCC_LOADFROMSTREAM_EX",  /* 0x037A */
    "WM_OCC_LOADFROMSTORAGE_EX", /* 0x037B */

    NULL,NULL,NULL,NULL,

    "WM_PENWINFIRST",           /* 0x0380 */
    "WM_RCRESULT",              /* 0x0381 */
    "WM_HOOKRCRESULT",          /* 0x0382 */
    "WM_GLOBALRCCHANGE",        /* 0x0383 */
    "WM_SKB",                   /* 0x0384 */
    "WM_HEDITCTL",              /* 0x0385 */
    NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    "WM_PENWINLAST",            /* 0x038F */

    "WM_COALESCE_FIRST",        /* 0x0390 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    "WM_COALESCE_LAST",         /* 0x039F */

    /* 0x03a0 */
    "MM_JOY1MOVE",
    "MM_JOY2MOVE",
    "MM_JOY1ZMOVE",
    "MM_JOY2ZMOVE",
                            NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x03b0 */
    NULL, NULL, NULL, NULL, NULL,
    "MM_JOY1BUTTONDOWN",
    "MM_JOY2BUTTONDOWN",
    "MM_JOY1BUTTONUP",
    "MM_JOY2BUTTONUP",
    "MM_MCINOTIFY",
                NULL,
    "MM_WOM_OPEN",
    "MM_WOM_CLOSE",
    "MM_WOM_DONE",
    "MM_WIM_OPEN",
    "MM_WIM_CLOSE",

    /* 0x03c0 */
    "MM_WIM_DATA",
    "MM_MIM_OPEN",
    "MM_MIM_CLOSE",
    "MM_MIM_DATA",
    "MM_MIM_LONGDATA",
    "MM_MIM_ERROR",
    "MM_MIM_LONGERROR",
    "MM_MOM_OPEN",
    "MM_MOM_CLOSE",
    "MM_MOM_DONE",
                NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    /* 0x03e0 */
    "WM_DDE_INITIATE",  /* 0x3E0 */
    "WM_DDE_TERMINATE",	/* 0x3E1 */
    "WM_DDE_ADVISE",	/* 0x3E2 */
    "WM_DDE_UNADVISE",	/* 0x3E3 */
    "WM_DDE_ACK",	/* 0x3E4 */
    "WM_DDE_DATA",	/* 0x3E5 */
    "WM_DDE_REQUEST",	/* 0x3E6 */
    "WM_DDE_POKE",	/* 0x3E7 */
    "WM_DDE_EXECUTE",	/* 0x3E8 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,


    /* 0x03f0 */
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

    "WM_USER"                   /* 0x0400 */
};


#define SPY_MAX_LVMMSGNUM   140
static const char * const LVMMessageTypeNames[SPY_MAX_LVMMSGNUM + 1] =
{
    "LVM_GETBKCOLOR",		/* 1000 */
    "LVM_SETBKCOLOR",
    "LVM_GETIMAGELIST",
    "LVM_SETIMAGELIST",
    "LVM_GETITEMCOUNT",
    "LVM_GETITEMA",
    "LVM_SETITEMA",
    "LVM_INSERTITEMA",
    "LVM_DELETEITEM",
    "LVM_DELETEALLITEMS",
    "LVM_GETCALLBACKMASK",
    "LVM_SETCALLBACKMASK",
    "LVM_GETNEXTITEM",
    "LVM_FINDITEMA",
    "LVM_GETITEMRECT",
    "LVM_SETITEMPOSITION",
    "LVM_GETITEMPOSITION",
    "LVM_GETSTRINGWIDTHA",
    "LVM_HITTEST",
    "LVM_ENSUREVISIBLE",
    "LVM_SCROLL",
    "LVM_REDRAWITEMS",
    "LVM_ARRANGE",
    "LVM_EDITLABELA",
    "LVM_GETEDITCONTROL",
    "LVM_GETCOLUMNA",
    "LVM_SETCOLUMNA",
    "LVM_INSERTCOLUMNA",
    "LVM_DELETECOLUMN",
    "LVM_GETCOLUMNWIDTH",
    "LVM_SETCOLUMNWIDTH",
    "LVM_GETHEADER",
    NULL,
    "LVM_CREATEDRAGIMAGE",
    "LVM_GETVIEWRECT",
    "LVM_GETTEXTCOLOR",
    "LVM_SETTEXTCOLOR",
    "LVM_GETTEXTBKCOLOR",
    "LVM_SETTEXTBKCOLOR",
    "LVM_GETTOPINDEX",
    "LVM_GETCOUNTPERPAGE",
    "LVM_GETORIGIN",
    "LVM_UPDATE",
    "LVM_SETITEMSTATE",
    "LVM_GETITEMSTATE",
    "LVM_GETITEMTEXTA",
    "LVM_SETITEMTEXTA",
    "LVM_SETITEMCOUNT",
    "LVM_SORTITEMS",
    "LVM_SETITEMPOSITION32",
    "LVM_GETSELECTEDCOUNT",
    "LVM_GETITEMSPACING",
    "LVM_GETISEARCHSTRINGA",
    "LVM_SETICONSPACING",
    "LVM_SETEXTENDEDLISTVIEWSTYLE",
    "LVM_GETEXTENDEDLISTVIEWSTYLE",
    "LVM_GETSUBITEMRECT",
    "LVM_SUBITEMHITTEST",
    "LVM_SETCOLUMNORDERARRAY",
    "LVM_GETCOLUMNORDERARRAY",
    "LVM_SETHOTITEM",
    "LVM_GETHOTITEM",
    "LVM_SETHOTCURSOR",
    "LVM_GETHOTCURSOR",
    "LVM_APPROXIMATEVIEWRECT",
    "LVM_SETWORKAREAS",
    "LVM_GETSELECTIONMARK",
    "LVM_SETSELECTIONMARK",
    "LVM_SETBKIMAGEA",
    "LVM_GETBKIMAGEA",
    "LVM_GETWORKAREAS",
    "LVM_SETHOVERTIME",
    "LVM_GETHOVERTIME",
    "LVM_GETNUMBEROFWORKAREAS",
    "LVM_SETTOOLTIPS",
    "LVM_GETITEMW",
    "LVM_SETITEMW",
    "LVM_INSERTITEMW",
    "LVM_GETTOOLTIPS",
    NULL,
    NULL,
    NULL,
    NULL,
    "LVM_FINDITEMW",
    NULL,
    NULL,
    NULL,
    "LVM_GETSTRINGWIDTHW",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "LVM_GETCOLUMNW",
    "LVM_SETCOLUMNW",
    "LVM_INSERTCOLUMNW",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "LVM_GETITEMTEXTW",
    "LVM_SETITEMTEXTW",
    "LVM_GETISEARCHSTRINGW",
    "LVM_EDITLABELW",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "LVM_SETBKIMAGEW",
    "LVM_GETBKIMAGEW"	/* 0x108B */
};


#define SPY_MAX_TVMSGNUM   65
static const char * const TVMessageTypeNames[SPY_MAX_TVMSGNUM + 1] =
{
    "TVM_INSERTITEMA",		/* 1100 */
    "TVM_DELETEITEM",
    "TVM_EXPAND",
    NULL,
    "TVM_GETITEMRECT",
    "TVM_GETCOUNT",
    "TVM_GETINDENT",
    "TVM_SETINDENT",
    "TVM_GETIMAGELIST",
    "TVM_SETIMAGELIST",
    "TVM_GETNEXTITEM",
    "TVM_SELECTITEM",
    "TVM_GETITEMA",
    "TVM_SETITEMA",
    "TVM_EDITLABELA",
    "TVM_GETEDITCONTROL",
    "TVM_GETVISIBLECOUNT",
    "TVM_HITTEST",
    "TVM_CREATEDRAGIMAGE",
    "TVM_SORTCHILDREN",
    "TVM_ENSUREVISIBLE",
    "TVM_SORTCHILDRENCB",
    "TVM_ENDEDITLABELNOW",
    "TVM_GETISEARCHSTRINGA",
    "TVM_SETTOOLTIPS",
    "TVM_GETTOOLTIPS",
    "TVM_SETINSERTMARK",
    "TVM_SETITEMHEIGHT",
    "TVM_GETITEMHEIGHT",
    "TVM_SETBKCOLOR",
    "TVM_SETTEXTCOLOR",
    "TVM_GETBKCOLOR",
    "TVM_GETTEXTCOLOR",
    "TVM_SETSCROLLTIME",
    "TVM_GETSCROLLTIME",
    "TVM_UNKNOWN35",
    "TVM_UNKNOWN36",
    "TVM_SETINSERTMARKCOLOR",
    "TVM_GETINSERTMARKCOLOR",
    "TVM_GETITEMSTATE",
    "TVM_SETLINECOLOR",
    "TVM_GETLINECOLOR",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "TVM_INSERTITEMW",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "TVM_GETITEMW",
    "TVM_SETITEMW",
    "TVM_GETISEARCHSTRINGW",
    "TVM_EDITLABELW"
};


#define SPY_MAX_HDMMSGNUM   19
static const char * const HDMMessageTypeNames[SPY_MAX_HDMMSGNUM + 1] =
{
    "HDM_GETITEMCOUNT",		/* 1200 */
    "HDM_INSERTITEMA",
    "HDM_DELETEITEM",
    "HDM_GETITEMA",
    "HDM_SETITEMA",
    "HDM_LAYOUT",
    "HDM_HITTEST",
    "HDM_GETITEMRECT",
    "HDM_SETIMAGELIST",
    "HDM_GETIMAGELIST",
    "HDM_INSERTITEMW",
    "HDM_GETITEMW",
    "HDM_SETITEMW",
    NULL,
    NULL,
    "HDM_ORDERTOINDEX",
    "HDM_CREATEDRAGIMAGE",
    "GETORDERARRAYINDEX",
    "SETORDERARRAYINDEX",
    "SETHOTDIVIDER"
};


#define SPY_MAX_TCMMSGNUM   62
static const char * const TCMMessageTypeNames[SPY_MAX_TCMMSGNUM + 1] =
{
    NULL,		/* 1300 */
    NULL,
    "TCM_SETIMAGELIST",
    "TCM_GETIMAGELIST",
    "TCM_GETITEMCOUNT",
    "TCM_GETITEMA",
    "TCM_SETITEMA",
    "TCM_INSERTITEMA",
    "TCM_DELETEITEM",
    "TCM_DELETEALLITEMS",
    "TCM_GETITEMRECT",
    "TCM_GETCURSEL",
    "TCM_SETCURSEL",
    "TCM_HITTEST",
    "TCM_SETITEMEXTRA",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "TCM_ADJUSTRECT",
    "TCM_SETITEMSIZE",
    "TCM_REMOVEIMAGE",
    "TCM_SETPADDING",
    "TCM_GETROWCOUNT",
    "TCM_GETTOOLTIPS",
    "TCM_SETTOOLTIPS",
    "TCM_GETCURFOCUS",
    "TCM_SETCURFOCUS",
    "TCM_SETMINTABWIDTH",
    "TCM_DESELECTALL",
    "TCM_HIGHLIGHTITEM",
    "TCM_SETEXTENDEDSTYLE",
    "TCM_GETEXTENDEDSTYLE",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    "TCM_GETITEMW",
    "TCM_SETITEMW",
    "TCM_INSERTITEMW"
};

#define SPY_MAX_PGMMSGNUM   13
static const char * const PGMMessageTypeNames[SPY_MAX_PGMMSGNUM + 1] =
{
    NULL,		/* 1400 */
    "PGM_SETCHILD",
    "PGM_RECALCSIZE",
    "PGM_FORWARDMOUSE",
    "PGM_SETBKCOLOR",
    "PGM_GETBKCOLOR",
    "PGM_SETBORDER",
    "PGM_GETBORDER",
    "PGM_SETPOS",
    "PGM_GETPOS",
    "PGM_SETBUTTONSIZE",
    "PGM_GETBUTTONSIZE",
    "PGM_GETBUTTONSTATE",
    "PGM_GETDROPTARGET"
};


#define SPY_MAX_CCMMSGNUM   9
static const char * const CCMMessageTypeNames[SPY_MAX_CCMMSGNUM + 1] =
{
    NULL,		/* 0x2000 */
    "CCM_SETBKCOLOR",
    "CCM_SETCOLORSCHEME",
    "CCM_GETCOLORSCHEME",
    "CCM_GETDROPTARGET",
    "CCM_SETUNICODEFORMAT",
    "CCM_GETUNICODEFORMAT",
    "CCM_SETVERSION",
    "CCM_GETVERSION",
    "CCM_SETNOTIFYWINDOW"
};

#define SPY_MAX_WINEMSGNUM   6
static const char * const WINEMessageTypeNames[SPY_MAX_WINEMSGNUM + 1] =
{
    "WM_WINE_DESTROYWINDOW",
    "WM_WINE_SETWINDOWPOS",
    "WM_WINE_SHOWWINDOW",
    "WM_WINE_SETPARENT",
    "WM_WINE_SETWINDOWLONG",
    "WM_WINE_ENABLEWINDOW"
};

/* Virtual key names */
#define SPY_MAX_VKKEYSNUM 255
static const char * const VK_KeyNames[SPY_MAX_VKKEYSNUM + 1] =
{
    NULL,		/* 0x00 */
    "VK_LBUTTON",	/* 0x01 */
    "VK_RBUTTON",	/* 0x02 */
    "VK_CANCEL",	/* 0x03 */
    "VK_MBUTTON",	/* 0x04 */
    NULL,		/* 0x05 */
    NULL,		/* 0x06 */
    NULL,		/* 0x07 */
    "VK_BACK",		/* 0x08 */
    "VK_TAB",		/* 0x09 */
    NULL,		/* 0x0A */
    NULL,		/* 0x0B */
    "VK_CLEAR",		/* 0x0C */
    "VK_RETURN",	/* 0x0D */
    NULL,		/* 0x0E */
    NULL,		/* 0x0F */
    "VK_SHIFT",		/* 0x10 */
    "VK_CONTROL",	/* 0x11 */
    "VK_MENU",		/* 0x12 */
    "VK_PAUSE",		/* 0x13 */
    "VK_CAPITAL",	/* 0x14 */
    NULL,		/* 0x15 */
    NULL,		/* 0x16 */
    NULL,		/* 0x17 */
    NULL,		/* 0x18 */
    NULL,		/* 0x19 */
    NULL,		/* 0x1A */
    "VK_ESCAPE",	/* 0x1B */
    NULL,		/* 0x1C */
    NULL,		/* 0x1D */
    NULL,		/* 0x1E */
    NULL,		/* 0x1F */
    "VK_SPACE",		/* 0x20 */
    "VK_PRIOR",		/* 0x21 */
    "VK_NEXT",		/* 0x22 */
    "VK_END",		/* 0x23 */
    "VK_HOME",		/* 0x24 */
    "VK_LEFT",		/* 0x25 */
    "VK_UP",		/* 0x26 */
    "VK_RIGHT",		/* 0x27 */
    "VK_DOWN",		/* 0x28 */
    "VK_SELECT",	/* 0x29 */
    "VK_PRINT",		/* 0x2A */
    "VK_EXECUTE",	/* 0x2B */
    "VK_SNAPSHOT",	/* 0x2C */
    "VK_INSERT",	/* 0x2D */
    "VK_DELETE",	/* 0x2E */
    "VK_HELP",		/* 0x2F */
    "VK_0",		/* 0x30 */
    "VK_1",		/* 0x31 */
    "VK_2",		/* 0x32 */
    "VK_3",		/* 0x33 */
    "VK_4",		/* 0x34 */
    "VK_5",		/* 0x35 */
    "VK_6",		/* 0x36 */
    "VK_7",		/* 0x37 */
    "VK_8",		/* 0x38 */
    "VK_9",		/* 0x39 */
    NULL,		/* 0x3A */
    NULL,		/* 0x3B */
    NULL,		/* 0x3C */
    NULL,		/* 0x3D */
    NULL,		/* 0x3E */
    NULL,		/* 0x3F */
    NULL,		/* 0x40 */
    "VK_A",		/* 0x41 */
    "VK_B",		/* 0x42 */
    "VK_C",		/* 0x43 */
    "VK_D",		/* 0x44 */
    "VK_E",		/* 0x45 */
    "VK_F",		/* 0x46 */
    "VK_G",		/* 0x47 */
    "VK_H",		/* 0x48 */
    "VK_I",		/* 0x49 */
    "VK_J",		/* 0x4A */
    "VK_K",		/* 0x4B */
    "VK_L",		/* 0x4C */
    "VK_M",		/* 0x4D */
    "VK_N",		/* 0x4E */
    "VK_O",		/* 0x4F */
    "VK_P",		/* 0x50 */
    "VK_Q",		/* 0x51 */
    "VK_R",		/* 0x52 */
    "VK_S",		/* 0x53 */
    "VK_T",		/* 0x54 */
    "VK_U",		/* 0x55 */
    "VK_V",		/* 0x56 */
    "VK_W",		/* 0x57 */
    "VK_X",		/* 0x58 */
    "VK_Y",		/* 0x59 */
    "VK_Z",		/* 0x5A */
    "VK_LWIN",		/* 0x5B */
    "VK_RWIN",		/* 0x5C */
    "VK_APPS",		/* 0x5D */
    NULL,		/* 0x5E */
    NULL,		/* 0x5F */
    "VK_NUMPAD0",	/* 0x60 */
    "VK_NUMPAD1",	/* 0x61 */
    "VK_NUMPAD2",	/* 0x62 */
    "VK_NUMPAD3",	/* 0x63 */
    "VK_NUMPAD4",	/* 0x64 */
    "VK_NUMPAD5",	/* 0x65 */
    "VK_NUMPAD6",	/* 0x66 */
    "VK_NUMPAD7",	/* 0x67 */
    "VK_NUMPAD8",	/* 0x68 */
    "VK_NUMPAD9",	/* 0x69 */
    "VK_MULTIPLY",	/* 0x6A */
    "VK_ADD",		/* 0x6B */
    "VK_SEPARATOR",	/* 0x6C */
    "VK_SUBTRACT",	/* 0x6D */
    "VK_DECIMAL",	/* 0x6E */
    "VK_DIVIDE",	/* 0x6F */
    "VK_F1",		/* 0x70 */
    "VK_F2",		/* 0x71 */
    "VK_F3",		/* 0x72 */
    "VK_F4",		/* 0x73 */
    "VK_F5",		/* 0x74 */
    "VK_F6",		/* 0x75 */
    "VK_F7",		/* 0x76 */
    "VK_F8",		/* 0x77 */
    "VK_F9",		/* 0x78 */
    "VK_F10",		/* 0x79 */
    "VK_F11",		/* 0x7A */
    "VK_F12",		/* 0x7B */
    "VK_F13",		/* 0x7C */
    "VK_F14",		/* 0x7D */
    "VK_F15",		/* 0x7E */
    "VK_F16",		/* 0x7F */
    "VK_F17",		/* 0x80 */
    "VK_F18",		/* 0x81 */
    "VK_F19",		/* 0x82 */
    "VK_F20",		/* 0x83 */
    "VK_F21",		/* 0x84 */
    "VK_F22",		/* 0x85 */
    "VK_F23",		/* 0x86 */
    "VK_F24",		/* 0x87 */
    NULL,		/* 0x88 */
    NULL,		/* 0x89 */
    NULL,		/* 0x8A */
    NULL,		/* 0x8B */
    NULL,		/* 0x8C */
    NULL,		/* 0x8D */
    NULL,		/* 0x8E */
    NULL,		/* 0x8F */
    "VK_NUMLOCK",	/* 0x90 */
    "VK_SCROLL",	/* 0x91 */
    NULL,		/* 0x92 */
    NULL,		/* 0x93 */
    NULL,		/* 0x94 */
    NULL,		/* 0x95 */
    NULL,		/* 0x96 */
    NULL,		/* 0x97 */
    NULL,		/* 0x98 */
    NULL,		/* 0x99 */
    NULL,		/* 0x9A */
    NULL,		/* 0x9B */
    NULL,		/* 0x9C */
    NULL,		/* 0x9D */
    NULL,		/* 0x9E */
    NULL,		/* 0x9F */
    "VK_LSHIFT",	/* 0xA0 */
    "VK_RSHIFT",	/* 0xA1 */
    "VK_LCONTROL",	/* 0xA2 */
    "VK_RCONTROL",	/* 0xA3 */
    "VK_LMENU",		/* 0xA4 */
    "VK_RMENU",		/* 0xA5 */
    NULL,		/* 0xA6 */
    NULL,		/* 0xA7 */
    NULL,		/* 0xA8 */
    NULL,		/* 0xA9 */
    NULL,		/* 0xAA */
    NULL,		/* 0xAB */
    NULL,		/* 0xAC */
    NULL,		/* 0xAD */
    NULL,		/* 0xAE */
    NULL,		/* 0xAF */
    NULL,		/* 0xB0 */
    NULL,		/* 0xB1 */
    NULL,		/* 0xB2 */
    NULL,		/* 0xB3 */
    NULL,		/* 0xB4 */
    NULL,		/* 0xB5 */
    NULL,		/* 0xB6 */
    NULL,		/* 0xB7 */
    NULL,		/* 0xB8 */
    NULL,		/* 0xB9 */
    "VK_OEM_1",		/* 0xBA */
    "VK_OEM_PLUS",	/* 0xBB */
    "VK_OEM_COMMA",	/* 0xBC */
    "VK_OEM_MINUS",	/* 0xBD */
    "VK_OEM_PERIOD",	/* 0xBE */
    "VK_OEM_2",		/* 0xBF */
    "VK_OEM_3",		/* 0xC0 */
    NULL,		/* 0xC1 */
    NULL,		/* 0xC2 */
    NULL,		/* 0xC3 */
    NULL,		/* 0xC4 */
    NULL,		/* 0xC5 */
    NULL,		/* 0xC6 */
    NULL,		/* 0xC7 */
    NULL,		/* 0xC8 */
    NULL,		/* 0xC9 */
    NULL,		/* 0xCA */
    NULL,		/* 0xCB */
    NULL,		/* 0xCC */
    NULL,		/* 0xCD */
    NULL,		/* 0xCE */
    NULL,		/* 0xCF */
    NULL,		/* 0xD0 */
    NULL,		/* 0xD1 */
    NULL,		/* 0xD2 */
    NULL,		/* 0xD3 */
    NULL,		/* 0xD4 */
    NULL,		/* 0xD5 */
    NULL,		/* 0xD6 */
    NULL,		/* 0xD7 */
    NULL,		/* 0xD8 */
    NULL,		/* 0xD9 */
    NULL,		/* 0xDA */
    "VK_OEM_4",		/* 0xDB */
    "VK_OEM_5",		/* 0xDC */
    "VK_OEM_6",		/* 0xDD */
    "VK_OEM_7",		/* 0xDE */
    "VK_OEM_8",		/* 0xDF */
    NULL,		/* 0xE0 */
    "VK_OEM_AX",	/* 0xE1 */
    "VK_OEM_102",	/* 0xE2 */
    "VK_ICO_HELP",	/* 0xE3 */
    "VK_ICO_00",	/* 0xE4 */
    "VK_PROCESSKEY",	/* 0xE5 */
    NULL,		/* 0xE6 */
    NULL,		/* 0xE7 */
    NULL,		/* 0xE8 */
    NULL,		/* 0xE9 */
    NULL,		/* 0xEA */
    NULL,		/* 0xEB */
    NULL,		/* 0xEC */
    NULL,		/* 0xED */
    NULL,		/* 0xEE */
    NULL,		/* 0xEF */
    NULL,		/* 0xF0 */
    NULL,		/* 0xF1 */
    NULL,		/* 0xF2 */
    NULL,		/* 0xF3 */
    NULL,		/* 0xF4 */
    NULL,		/* 0xF5 */
    "VK_ATTN",		/* 0xF6 */
    "VK_CRSEL",		/* 0xF7 */
    "VK_EXSEL",		/* 0xF8 */
    "VK_EREOF",		/* 0xF9 */
    "VK_PLAY",		/* 0xFA */
    "VK_ZOOM",		/* 0xFB */
    "VK_NONAME",	/* 0xFC */
    "VK_PA1",		/* 0xFD */
    "VK_OEM_CLEAR",	/* 0xFE */
    NULL		/* 0xFF */
};


/************************************************************************/


/* WM_USER+n message values for "common controls" */

typedef struct
{
    const char *name;      /* name of control message           */
    UINT        value;     /* message number (0x0401-0x0fff     */
    UINT        len;       /* length of space at lParam to dump */
} USER_MSG;


typedef struct
{
const WCHAR      *classname;  /* class name to match                  */
const USER_MSG   *classmsg;   /* pointer to first USER_MSG for class  */
      USER_MSG   *lastmsg;    /* pointer to last USER_MSG for class   */
} CONTROL_CLASS;

#define USM(a,b) { #a ,a,b}
#define SZOF(a)  sizeof(a)

/* To dump memory at the lParam for any of these messages,  */
/* replace the "0" with a "SZOF(structure)", or with a      */
/* number. (First method prefered.)                         */

static const USER_MSG rebar_array[] = {
          USM(RB_INSERTBANDA,          0),
          USM(RB_DELETEBAND,           0),
          USM(RB_GETBARINFO,           0),
          USM(RB_SETBARINFO,           0),
          USM(RB_GETBANDINFO,          0),
          USM(RB_SETBANDINFOA,         0),
          USM(RB_SETPARENT,            0),
          USM(RB_HITTEST,              0),
          USM(RB_GETRECT,              0),
          USM(RB_INSERTBANDW,          0),
          USM(RB_SETBANDINFOW,         0),
          USM(RB_GETBANDCOUNT,         0),
          USM(RB_GETROWCOUNT,          0),
          USM(RB_GETROWHEIGHT,         0),
          USM(RB_IDTOINDEX,            0),
          USM(RB_GETTOOLTIPS,          0),
          USM(RB_SETTOOLTIPS,          0),
          USM(RB_SETBKCOLOR,           0),
          USM(RB_GETBKCOLOR,           0),
          USM(RB_SETTEXTCOLOR,         0),
          USM(RB_GETTEXTCOLOR,         0),
          USM(RB_SIZETORECT,           0),
          USM(RB_BEGINDRAG,            0),
          USM(RB_ENDDRAG,              0),
          USM(RB_DRAGMOVE,             0),
          USM(RB_GETBARHEIGHT,         0),
          USM(RB_GETBANDINFOW,         0),
          USM(RB_GETBANDINFOA,         0),
          USM(RB_MINIMIZEBAND,         0),
          USM(RB_MAXIMIZEBAND,         0),
          USM(RB_GETBANDBORDERS,       0),
          USM(RB_SHOWBAND,             0),
          USM(RB_SETPALETTE,           0),
          USM(RB_GETPALETTE,           0),
          USM(RB_MOVEBAND,             0),
          {0,0,0} };

static const USER_MSG toolbar_array[] = {
          USM(TB_ENABLEBUTTON          ,0),
          USM(TB_CHECKBUTTON           ,0),
          USM(TB_PRESSBUTTON           ,0),
          USM(TB_HIDEBUTTON            ,0),
          USM(TB_INDETERMINATE         ,0),
          USM(TB_MARKBUTTON	       ,0),
          USM(TB_ISBUTTONENABLED       ,0),
          USM(TB_ISBUTTONCHECKED       ,0),
          USM(TB_ISBUTTONPRESSED       ,0),
          USM(TB_ISBUTTONHIDDEN        ,0),
          USM(TB_ISBUTTONINDETERMINATE ,0),
          USM(TB_ISBUTTONHIGHLIGHTED   ,0),
          USM(TB_SETSTATE              ,0),
          USM(TB_GETSTATE              ,0),
          USM(TB_ADDBITMAP             ,0),
          USM(TB_ADDBUTTONSA           ,0),
          USM(TB_INSERTBUTTONA         ,0),
          USM(TB_DELETEBUTTON          ,0),
          USM(TB_GETBUTTON             ,0),
          USM(TB_BUTTONCOUNT           ,0),
          USM(TB_COMMANDTOINDEX        ,0),
          USM(TB_SAVERESTOREA          ,0),
          USM(TB_CUSTOMIZE             ,0),
          USM(TB_ADDSTRINGA            ,0),
          USM(TB_GETITEMRECT           ,0),
          USM(TB_BUTTONSTRUCTSIZE      ,0),
          USM(TB_SETBUTTONSIZE         ,0),
          USM(TB_SETBITMAPSIZE         ,0),
          USM(TB_AUTOSIZE              ,0),
          USM(TB_GETTOOLTIPS           ,0),
          USM(TB_SETTOOLTIPS           ,0),
          USM(TB_SETPARENT             ,0),
          USM(TB_SETROWS               ,0),
          USM(TB_GETROWS               ,0),
          USM(TB_GETBITMAPFLAGS        ,0),
          USM(TB_SETCMDID              ,0),
          USM(TB_CHANGEBITMAP          ,0),
          USM(TB_GETBITMAP             ,0),
          USM(TB_GETBUTTONTEXTA        ,0),
          USM(TB_REPLACEBITMAP         ,0),
          USM(TB_SETINDENT             ,0),
          USM(TB_SETIMAGELIST          ,0),
          USM(TB_GETIMAGELIST          ,0),
          USM(TB_LOADIMAGES            ,0),
          USM(TB_GETRECT               ,0),
          USM(TB_SETHOTIMAGELIST       ,0),
          USM(TB_GETHOTIMAGELIST       ,0),
          USM(TB_SETDISABLEDIMAGELIST  ,0),
          USM(TB_GETDISABLEDIMAGELIST  ,0),
          USM(TB_SETSTYLE              ,0),
          USM(TB_GETSTYLE              ,0),
          USM(TB_GETBUTTONSIZE         ,0),
          USM(TB_SETBUTTONWIDTH        ,0),
          USM(TB_SETMAXTEXTROWS        ,0),
          USM(TB_GETTEXTROWS           ,0),
          USM(TB_GETOBJECT             ,0),
          USM(TB_GETBUTTONINFOW        ,0),
          USM(TB_SETBUTTONINFOW        ,0),
          USM(TB_GETBUTTONINFOA        ,0),
          USM(TB_SETBUTTONINFOA        ,0),
          USM(TB_INSERTBUTTONW         ,0),
          USM(TB_ADDBUTTONSW           ,0),
          USM(TB_HITTEST               ,0),
          USM(TB_SETDRAWTEXTFLAGS      ,0),
          USM(TB_GETHOTITEM            ,0),
          USM(TB_SETHOTITEM            ,0),
          USM(TB_SETANCHORHIGHLIGHT    ,0),
          USM(TB_GETANCHORHIGHLIGHT    ,0),
          USM(TB_GETBUTTONTEXTW        ,0),
          USM(TB_SAVERESTOREW          ,0),
          USM(TB_ADDSTRINGW            ,0),
          USM(TB_MAPACCELERATORA       ,0),
          USM(TB_GETINSERTMARK         ,0),
          USM(TB_SETINSERTMARK         ,0),
          USM(TB_INSERTMARKHITTEST     ,0),
          USM(TB_MOVEBUTTON            ,0),
          USM(TB_GETMAXSIZE            ,0),
          USM(TB_SETEXTENDEDSTYLE      ,0),
          USM(TB_GETEXTENDEDSTYLE      ,0),
          USM(TB_GETPADDING            ,0),
          USM(TB_SETPADDING            ,0),
          USM(TB_SETINSERTMARKCOLOR    ,0),
          USM(TB_GETINSERTMARKCOLOR    ,0),
          USM(TB_MAPACCELERATORW       ,0),
          USM(TB_GETSTRINGW            ,0),
          USM(TB_GETSTRINGA            ,0),
          USM(TB_UNKWN45D              ,8),
          USM(TB_UNKWN45E              ,0),
          USM(TB_UNKWN460              ,0),
          USM(TB_UNKWN463              ,8),
          USM(TB_UNKWN464              ,0),
          {0,0,0} };

static const USER_MSG tooltips_array[] = {
          USM(TTM_ACTIVATE             ,0),
          USM(TTM_SETDELAYTIME         ,0),
          USM(TTM_ADDTOOLA             ,0),
          USM(TTM_DELTOOLA             ,0),
          USM(TTM_NEWTOOLRECTA         ,0),
          USM(TTM_RELAYEVENT           ,0),
          USM(TTM_GETTOOLINFOA         ,0),
          USM(TTM_HITTESTA             ,0),
          USM(TTM_GETTEXTA             ,0),
          USM(TTM_UPDATETIPTEXTA       ,0),
          USM(TTM_GETTOOLCOUNT         ,0),
          USM(TTM_ENUMTOOLSA           ,0),
          USM(TTM_GETCURRENTTOOLA      ,0),
          USM(TTM_WINDOWFROMPOINT      ,0),
          USM(TTM_TRACKACTIVATE        ,0),
          USM(TTM_TRACKPOSITION        ,0),
          USM(TTM_SETTIPBKCOLOR        ,0),
          USM(TTM_SETTIPTEXTCOLOR      ,0),
          USM(TTM_GETDELAYTIME         ,0),
          USM(TTM_GETTIPBKCOLOR        ,0),
          USM(TTM_GETTIPTEXTCOLOR      ,0),
          USM(TTM_SETMAXTIPWIDTH       ,0),
          USM(TTM_GETMAXTIPWIDTH       ,0),
          USM(TTM_SETMARGIN            ,0),
          USM(TTM_GETMARGIN            ,0),
          USM(TTM_POP                  ,0),
          USM(TTM_UPDATE               ,0),
	  USM(TTM_GETBUBBLESIZE        ,0),
          USM(TTM_ADDTOOLW             ,0),
          USM(TTM_DELTOOLW             ,0),
          USM(TTM_NEWTOOLRECTW         ,0),
          USM(TTM_GETTOOLINFOW         ,0),
          USM(TTM_SETTOOLINFOW         ,0),
          USM(TTM_HITTESTW             ,0),
          USM(TTM_GETTEXTW             ,0),
          USM(TTM_UPDATETIPTEXTW       ,0),
          USM(TTM_ENUMTOOLSW           ,0),
          USM(TTM_GETCURRENTTOOLW      ,0),
          {0,0,0} };

static const USER_MSG comboex_array[] = {
          USM(CBEM_INSERTITEMA        ,0),
          USM(CBEM_SETIMAGELIST       ,0),
          USM(CBEM_GETIMAGELIST       ,0),
          USM(CBEM_GETITEMA           ,0),
          USM(CBEM_SETITEMA           ,0),
          USM(CBEM_GETCOMBOCONTROL    ,0),
          USM(CBEM_GETEDITCONTROL     ,0),
          USM(CBEM_SETEXSTYLE         ,0),
          USM(CBEM_GETEXTENDEDSTYLE   ,0),
          USM(CBEM_HASEDITCHANGED     ,0),
          USM(CBEM_INSERTITEMW        ,0),
          USM(CBEM_SETITEMW           ,0),
          USM(CBEM_GETITEMW           ,0),
          USM(CBEM_SETEXTENDEDSTYLE   ,0),
          {0,0,0} };

static const USER_MSG propsht_array[] = {
          USM(PSM_SETCURSEL           ,0),
          USM(PSM_REMOVEPAGE          ,0),
          USM(PSM_ADDPAGE             ,0),
          USM(PSM_CHANGED             ,0),
          USM(PSM_RESTARTWINDOWS      ,0),
          USM(PSM_REBOOTSYSTEM        ,0),
          USM(PSM_CANCELTOCLOSE       ,0),
          USM(PSM_QUERYSIBLINGS       ,0),
          USM(PSM_UNCHANGED           ,0),
          USM(PSM_APPLY               ,0),
          USM(PSM_SETTITLEA           ,0),
          USM(PSM_SETWIZBUTTONS       ,0),
          USM(PSM_PRESSBUTTON         ,0),
          USM(PSM_SETCURSELID         ,0),
          USM(PSM_SETFINISHTEXTA      ,0),
          USM(PSM_GETTABCONTROL       ,0),
          USM(PSM_ISDIALOGMESSAGE     ,0),
          USM(PSM_GETCURRENTPAGEHWND  ,0),
          USM(PSM_SETTITLEW           ,0),
          USM(PSM_SETFINISHTEXTW      ,0),
          {0,0,0} };
const WCHAR PropSheetInfoStr[] =
    {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };

static const USER_MSG updown_array[] = {
          USM(UDM_SETRANGE            ,0),
          USM(UDM_GETRANGE            ,0),
          USM(UDM_SETPOS              ,0),
          USM(UDM_GETPOS              ,0),
          USM(UDM_SETBUDDY            ,0),
          USM(UDM_GETBUDDY            ,0),
          USM(UDM_SETACCEL            ,0),
          USM(UDM_GETACCEL            ,0),
          USM(UDM_SETBASE             ,0),
          USM(UDM_GETBASE             ,0),
          USM(UDM_SETRANGE32          ,0),
          USM(UDM_GETRANGE32          ,0),
          USM(UDM_SETPOS32            ,0),
          USM(UDM_GETPOS32            ,0),
          {0,0,0} };

#undef SZOF
#undef USM

static CONTROL_CLASS  cc_array[] = {
    {WC_COMBOBOXEXW,    comboex_array,  0},
    {WC_PROPSHEETW,     propsht_array,  0},
    {REBARCLASSNAMEW,   rebar_array,    0},
    {TOOLBARCLASSNAMEW, toolbar_array,  0},
    {TOOLTIPS_CLASSW,   tooltips_array, 0},
    {UPDOWN_CLASSW,     updown_array,   0},
    {0, 0, 0} };


/************************************************************************/


/* WM_NOTIFY function codes display */

typedef struct
{
    const char *name;     /* name of notify message        */
    UINT        value;     /* notify code value             */
    UINT        len;       /* length of extra space to dump */
} SPY_NOTIFY;

#define SPNFY(a,b) { #a ,a,sizeof(b)-sizeof(NMHDR)}

/* Array MUST be in descending order by the 'value' field  */
/* (since value is UNSIGNED, 0xffffffff is largest and     */
/*  0xfffffffe is smaller). A binary search is used to     */
/* locate the correct 'value'.                             */
static const SPY_NOTIFY spnfy_array[] = {
    /*  common        0U       to  0U-99U  */
    SPNFY(NM_OUTOFMEMORY,        NMHDR),
    SPNFY(NM_CLICK,              NMHDR),
    SPNFY(NM_DBLCLK,             NMHDR),
    SPNFY(NM_RETURN,             NMHDR),
    SPNFY(NM_RCLICK,             NMHDR),
    SPNFY(NM_RDBLCLK,            NMHDR),
    SPNFY(NM_SETFOCUS,           NMHDR),
    SPNFY(NM_KILLFOCUS,          NMHDR),
    SPNFY(NM_CUSTOMDRAW,         NMCUSTOMDRAW),
    SPNFY(NM_HOVER,              NMHDR),
    SPNFY(NM_NCHITTEST,          NMMOUSE),
    SPNFY(NM_KEYDOWN,            NMKEY),
    SPNFY(NM_RELEASEDCAPTURE,    NMHDR),
    SPNFY(NM_SETCURSOR,          NMMOUSE),
    SPNFY(NM_CHAR,               NMCHAR),
    SPNFY(NM_TOOLTIPSCREATED,    NMTOOLTIPSCREATED),
    /* Listview       0U-100U  to  0U-199U  */
    SPNFY(LVN_ITEMCHANGING,      NMLISTVIEW),
    SPNFY(LVN_ITEMCHANGED,       NMLISTVIEW),
    SPNFY(LVN_INSERTITEM,        NMLISTVIEW),
    SPNFY(LVN_DELETEITEM,        NMLISTVIEW),
    SPNFY(LVN_DELETEALLITEMS,    NMLISTVIEW),
    SPNFY(LVN_BEGINLABELEDITA,   NMLVDISPINFOA),
    SPNFY(LVN_ENDLABELEDITA,     NMLVDISPINFOA),
    SPNFY(LVN_COLUMNCLICK,       NMLISTVIEW),
    SPNFY(LVN_BEGINDRAG,         NMLISTVIEW),
    SPNFY(LVN_BEGINRDRAG,        NMLISTVIEW),
    SPNFY(LVN_ODCACHEHINT,       NMLVCACHEHINT),
    SPNFY(LVN_ITEMACTIVATE,      NMITEMACTIVATE),
    SPNFY(LVN_ODSTATECHANGED,    NMLVODSTATECHANGE),
    SPNFY(LVN_HOTTRACK,          NMLISTVIEW),
    SPNFY(LVN_GETDISPINFOA,      NMLVDISPINFOA),
    SPNFY(LVN_SETDISPINFOA,      NMLVDISPINFOA),
    SPNFY(LVN_ODFINDITEMA,       NMLVFINDITEMA),
    SPNFY(LVN_KEYDOWN,           NMLVKEYDOWN),
    SPNFY(LVN_MARQUEEBEGIN,      NMLISTVIEW),
    SPNFY(LVN_GETINFOTIPA,       NMLVGETINFOTIPA),
    SPNFY(LVN_GETINFOTIPW,       NMLVGETINFOTIPW),
    SPNFY(LVN_BEGINLABELEDITW,   NMLVDISPINFOW),
    SPNFY(LVN_ENDLABELEDITW,     NMLVDISPINFOW),
    SPNFY(LVN_GETDISPINFOW,      NMLVDISPINFOW),
    SPNFY(LVN_SETDISPINFOW,      NMLVDISPINFOW),
    SPNFY(LVN_ODFINDITEMW,       NMLVFINDITEMW),
    /* PropertySheet  0U-200U  to  0U-299U  */
    SPNFY(PSN_SETACTIVE,         PSHNOTIFY),
    SPNFY(PSN_KILLACTIVE,        PSHNOTIFY),
    SPNFY(PSN_APPLY,             PSHNOTIFY),
    SPNFY(PSN_RESET,             PSHNOTIFY),
    SPNFY(PSN_HELP,              PSHNOTIFY),
    SPNFY(PSN_WIZBACK,           PSHNOTIFY),
    SPNFY(PSN_WIZNEXT,           PSHNOTIFY),
    SPNFY(PSN_WIZFINISH,         PSHNOTIFY),
    SPNFY(PSN_QUERYCANCEL,       PSHNOTIFY),
    SPNFY(PSN_GETOBJECT,         NMOBJECTNOTIFY),
    /*    SPNFY(PSN_QUERYINITIALFOCUS, .PSHNOTIFY),         NIY      */
    /*    SPNFY(PSN_TRANSLATEACCELERATOR, .PSHNOTIFY),      NIY      */
    /* Header         0U-300U  to  0U-399U  */
    SPNFY(HDN_ITEMCHANGINGA,     NMHDR),
    SPNFY(HDN_ITEMCHANGEDA,      NMHDR),
    SPNFY(HDN_ITEMCLICKA,        NMHDR),
    SPNFY(HDN_ITEMDBLCLICKA,     NMHDR),
    SPNFY(HDN_DIVIDERDBLCLICKA,  NMHDR),
    SPNFY(HDN_BEGINTRACKA,       NMHDR),
    SPNFY(HDN_ENDTRACKA,         NMHDR),
    SPNFY(HDN_GETDISPINFOA,      NMHDR),
    SPNFY(HDN_BEGINDRAG,         NMHDR),
    SPNFY(HDN_ENDDRAG,           NMHDR),
    SPNFY(HDN_ITEMCHANGINGW,     NMHDR),
    SPNFY(HDN_ITEMCHANGEDW,      NMHDR),
    SPNFY(HDN_ITEMCLICKW,        NMHDR),
    SPNFY(HDN_ITEMDBLCLICKW,     NMHDR),
    SPNFY(HDN_DIVIDERDBLCLICKW,  NMHDR),
    SPNFY(HDN_BEGINTRACKW,       NMHDR),
    SPNFY(HDN_ENDTRACKW,         NMHDR),
    SPNFY(HDN_GETDISPINFOW,      NMHDR),
    /* Treeview       0U-400U  to  0U-499U  */
    SPNFY(TVN_SELCHANGINGA,      NMHDR),
    SPNFY(TVN_SELCHANGEDA,       NMHDR),
    SPNFY(TVN_GETDISPINFOA,      NMHDR),
    SPNFY(TVN_SETDISPINFOA,      NMHDR),
    SPNFY(TVN_ITEMEXPANDINGA,    NMHDR),
    SPNFY(TVN_ITEMEXPANDEDA,     NMHDR),
    SPNFY(TVN_BEGINDRAGA,        NMHDR),
    SPNFY(TVN_BEGINRDRAGA,       NMHDR),
    SPNFY(TVN_DELETEITEMA,       NMHDR),
    SPNFY(TVN_BEGINLABELEDITA,   NMHDR),
    SPNFY(TVN_ENDLABELEDITA,     NMHDR),
    SPNFY(TVN_KEYDOWN,           NMHDR),
    SPNFY(TVN_SELCHANGINGW,      NMHDR),
    SPNFY(TVN_SELCHANGEDW,       NMHDR),
    SPNFY(TVN_GETDISPINFOW,      NMHDR),
    SPNFY(TVN_SETDISPINFOW,      NMHDR),
    SPNFY(TVN_ITEMEXPANDINGW,    NMHDR),
    SPNFY(TVN_ITEMEXPANDEDW,     NMHDR),
    SPNFY(TVN_BEGINDRAGW,        NMHDR),
    SPNFY(TVN_BEGINRDRAGW,       NMHDR),
    SPNFY(TVN_DELETEITEMW,       NMHDR),
    SPNFY(TVN_BEGINLABELEDITW,   NMHDR),
    SPNFY(TVN_ENDLABELEDITW,     NMHDR),
    /* Tooltips       0U-520U  to  0U-549U  */
    SPNFY(TTN_GETDISPINFOA,      NMHDR),
    SPNFY(TTN_SHOW,              NMHDR),
    SPNFY(TTN_POP,               NMHDR),
    SPNFY(TTN_GETDISPINFOW,      NMHDR),
    /* Tab            0U-550U  to  0U-580U  */
    SPNFY(TCN_KEYDOWN,           NMHDR),
    SPNFY(TCN_SELCHANGE,         NMHDR),
    SPNFY(TCN_SELCHANGING,       NMHDR),
    SPNFY(TCN_GETOBJECT,         NMHDR),
    /* Common Dialog  0U-601U  to  0U-699U  */
    /* Toolbar        0U-700U  to  0U-720U  */
    SPNFY(TBN_GETBUTTONINFOA,    NMTOOLBARA),
    SPNFY(TBN_BEGINDRAG,         NMTOOLBARA),
    SPNFY(TBN_ENDDRAG,           NMTOOLBARA),
    SPNFY(TBN_BEGINADJUST,       NMHDR),
    SPNFY(TBN_ENDADJUST,         NMHDR),
    SPNFY(TBN_RESET,             NMHDR),
    SPNFY(TBN_QUERYINSERT,       NMTOOLBARA),
    SPNFY(TBN_QUERYDELETE,       NMTOOLBARA),
    SPNFY(TBN_TOOLBARCHANGE,     NMHDR),
    SPNFY(TBN_CUSTHELP,          NMHDR),
    SPNFY(TBN_DROPDOWN,          NMTOOLBARA),
    SPNFY(TBN_GETOBJECT,         NMOBJECTNOTIFY),
    SPNFY(TBN_HOTITEMCHANGE,     NMTBHOTITEM),
    SPNFY(TBN_DRAGOUT,           NMTOOLBARA),
    SPNFY(TBN_DELETINGBUTTON,    NMTOOLBARA),
    SPNFY(TBN_GETDISPINFOA,      NMTBDISPINFOA),
    SPNFY(TBN_GETDISPINFOW,      NMTBDISPINFOW),
    SPNFY(TBN_GETINFOTIPA,       NMTBGETINFOTIPA),
    SPNFY(TBN_GETINFOTIPW,       NMTBGETINFOTIPW),
    SPNFY(TBN_GETBUTTONINFOW,    NMTOOLBARW),
    /* Up/Down        0U-721U  to  0U-740U  */
    SPNFY(UDN_DELTAPOS,          NMHDR),
    /* Month Calendar 0U-750U  to  0U-759U  */
    /* ******************* WARNING ***************************** */
    /* The following appear backwards but needs to be this way.  */
    /* The reason is that MS (and us) define the MCNs as         */
    /*         MCN_FIRST + n                                     */
    /* instead of the way ALL other notifications are            */
    /*         TBN_FIRST - n                                     */
    /* The only place that this is important is in this list     */
    /*                                                           */
    /* Also since the same error was made with the DTN_ items,   */
    /* they overlay the MCN_ and need to be inserted in the      */
    /* other section of the table so that it is in order for     */
    /* the binary search.                                        */
    /*                                                           */
    /* Thank you MS for your obvious quality control!!           */
    /* ******************* WARNING ***************************** */
    /* Date/Time      0U-760U  to  0U-799U  */
    /* SPNFY(MCN_SELECT,            NMHDR), */
    /* SPNFY(MCN_GETDAYSTATE,       NMHDR), */
    /* SPNFY(MCN_SELCHANGE,         NMHDR), */
    /* ******************* WARNING ***************************** */
    /* The following appear backwards but needs to be this way.  */
    /* The reason is that MS (and us) define the MCNs as         */
    /*         DTN_FIRST + n                                     */
    /* instead of the way ALL other notifications are            */
    /*         TBN_FIRST - n                                     */
    /* The only place that this is important is in this list     */
    /* ******************* WARNING ***************************** */
    SPNFY(DTN_FORMATQUERYW,      NMHDR),
    SPNFY(DTN_FORMATW,           NMHDR),
    SPNFY(DTN_WMKEYDOWNW,        NMHDR),
    SPNFY(DTN_USERSTRINGW,       NMHDR),
    SPNFY(MCN_SELECT,            NMHDR),
    SPNFY(MCN_GETDAYSTATE,       NMHDR),
    SPNFY(MCN_SELCHANGE,         NMHDR),
    SPNFY(DTN_CLOSEUP,           NMHDR),
    SPNFY(DTN_DROPDOWN,          NMHDR),
    SPNFY(DTN_FORMATQUERYA,      NMHDR),
    SPNFY(DTN_FORMATA,           NMHDR),
    SPNFY(DTN_WMKEYDOWNA,        NMHDR),
    SPNFY(DTN_USERSTRINGA,       NMHDR),
    SPNFY(DTN_DATETIMECHANGE,    NMHDR),
    /* ComboBoxEx     0U-800U  to  0U-830U  */
    SPNFY(CBEN_GETDISPINFOA,     NMCOMBOBOXEXA),
    SPNFY(CBEN_INSERTITEM,       NMCOMBOBOXEXA),
    SPNFY(CBEN_DELETEITEM,       NMCOMBOBOXEXA),
    SPNFY(CBEN_BEGINEDIT,        NMHDR),
    SPNFY(CBEN_ENDEDITA,         NMCBEENDEDITA),
    SPNFY(CBEN_ENDEDITW,         NMCBEENDEDITW),
    SPNFY(CBEN_GETDISPINFOW,     NMCOMBOBOXEXW),
    SPNFY(CBEN_DRAGBEGINA,       NMCBEDRAGBEGINA),
    SPNFY(CBEN_DRAGBEGINW,       NMCBEDRAGBEGINW),
    /* Rebar          0U-831U  to  0U-859U  */
    SPNFY(RBN_HEIGHTCHANGE,      NMHDR),
    SPNFY(RBN_GETOBJECT,         NMOBJECTNOTIFY),
    SPNFY(RBN_LAYOUTCHANGED,     NMHDR),
    SPNFY(RBN_AUTOSIZE,          NMRBAUTOSIZE),
    SPNFY(RBN_BEGINDRAG,         NMREBAR),
    SPNFY(RBN_ENDDRAG,           NMREBAR),
    SPNFY(RBN_DELETINGBAND,      NMREBAR),
    SPNFY(RBN_DELETEDBAND,       NMREBAR),
    SPNFY(RBN_CHILDSIZE,         NMREBARCHILDSIZE),
    /* IP Adderss     0U-860U  to  0U-879U  */
    SPNFY(IPN_FIELDCHANGED,      NMHDR),
    /* Status bar     0U-880U  to  0U-899U  */
    SPNFY(SBN_SIMPLEMODECHANGE,  NMHDR),
    /* Pager          0U-900U  to  0U-950U  */
    SPNFY(PGN_SCROLL,            NMPGSCROLL),
    SPNFY(PGN_CALCSIZE,          NMPGCALCSIZE),
    {0,0,0}};
static const SPY_NOTIFY *end_spnfy_array;     /* ptr to last good entry in array */
#undef SPNFY


static BOOL16 SPY_Exclude[SPY_MAX_MSGNUM+1];
static BOOL16 SPY_ExcludeDWP = 0;

#define SPY_EXCLUDE(msg) \
    (SPY_Exclude[(msg) > SPY_MAX_MSGNUM ? SPY_MAX_MSGNUM : (msg)])


typedef struct
{
    UINT       msgnum;           /* message number */
    HWND       msg_hwnd;         /* window handle for message          */
    WPARAM     wParam;           /* message parameter                  */
    LPARAM     lParam;           /* message parameter                  */
    INT        data_len;         /* length of data to dump             */
    char       msg_name[60];     /* message name (see SPY_GetMsgName)  */
    WCHAR      wnd_class[60];    /* window class name (full)           */
    WCHAR      wnd_name[16];     /* window name for message            */
} SPY_INSTANCE;

/* This is defined so that the external entry point can return the addr */
static SPY_INSTANCE ext_sp_e;

static int indent_tls_index;

/***********************************************************************
 *           get_indent_level
 */
inline static int get_indent_level(void)
{
    return (int)TlsGetValue( indent_tls_index );
}


/***********************************************************************
 *           set_indent_level
 */
inline static void set_indent_level( int level )
{
    TlsSetValue( indent_tls_index, (void *)level );
}


/***********************************************************************
 *           SPY_GetMsgInternal
 */
static const char *SPY_GetMsgInternal( UINT msg )
{
    static char msg_buffer[20];

    if (msg <= SPY_MAX_MSGNUM)
    {
        if (!MessageTypeNames[msg]) return "???";
        return MessageTypeNames[msg];
    }

    if (msg >= LVM_FIRST && msg <= LVM_FIRST + SPY_MAX_LVMMSGNUM)
    {
        if (!LVMMessageTypeNames[msg-LVM_FIRST]) return "LVM_?";
        return LVMMessageTypeNames[msg-LVM_FIRST];
    }

    if (msg >= TV_FIRST && msg <= TV_FIRST + SPY_MAX_TVMSGNUM)
    {
        if (!TVMessageTypeNames[msg-TV_FIRST]) return "TV_?";
        return TVMessageTypeNames[msg-TV_FIRST];
    }

    if (msg >= HDM_FIRST && msg <= HDM_FIRST + SPY_MAX_HDMMSGNUM)
    {
        if (!HDMMessageTypeNames[msg-HDM_FIRST]) return "HDM_?";
        return HDMMessageTypeNames[msg-HDM_FIRST];
    }

    if (msg >= TCM_FIRST && msg <= TCM_FIRST + SPY_MAX_TCMMSGNUM)
    {
        if (!TCMMessageTypeNames[msg-TCM_FIRST]) return "TCM_?";
        return TCMMessageTypeNames[msg-TCM_FIRST];
    }

    if (msg >= PGM_FIRST && msg <= PGM_FIRST + SPY_MAX_PGMMSGNUM)
    {
        if (!PGMMessageTypeNames[msg-PGM_FIRST]) return "PGM_?";
        return PGMMessageTypeNames[msg-PGM_FIRST];
    }

    if (msg >= CCM_FIRST && msg <= CCM_FIRST + SPY_MAX_CCMMSGNUM)
    {
        if (!CCMMessageTypeNames[msg-CCM_FIRST]) return "???";
        return CCMMessageTypeNames[msg-CCM_FIRST];
    }

    if (msg >= WM_WINE_DESTROYWINDOW && msg <= WM_WINE_DESTROYWINDOW + SPY_MAX_WINEMSGNUM)
    {
        if (!WINEMessageTypeNames[msg-WM_WINE_DESTROYWINDOW]) return "???";
        return WINEMessageTypeNames[msg-WM_WINE_DESTROYWINDOW];
    }

    sprintf( msg_buffer, "WM_USER+%04x", msg - WM_USER );
    return msg_buffer;
}

/***********************************************************************
 *           SPY_Bsearch_Msg
 */
const USER_MSG *SPY_Bsearch_Msg( const USER_MSG *first, const USER_MSG *last, UINT code)
{
    INT count;
    const USER_MSG *test;

    while (last >= first) {
	count = 1 + last - first;
	if (count < 3) {
#if DEBUG_SPY
	    TRACE("code=%d, f-value=%d, f-name=%s, l-value=%d, l-name=%s, l-len=%d,\n",
	       code, first->value, first->name, last->value, last->name, last->len);
#endif
	    if (first->value == code) return first;
	    if (last->value == code) return last;
	    return NULL;
	}
	count = count / 2;
	test = first + count;
#if DEBUG_SPY
	TRACE("first=%p, last=%p, test=%p, t-value=%d, code=%d, count=%d\n",
	   first, last, test, test->value, code, count);
#endif
	if (test->value == code) return test;
	if (test->value > code)
	    last = test - 1;
	else
	    first = test + 1;
    }
    return NULL;
}

/***********************************************************************
 *           SPY_GetMsgStuff
 *
 *  Get message name and other information for dumping
 */
static void SPY_GetMsgStuff( SPY_INSTANCE *sp_e )
{
    const USER_MSG *p;

    sp_e->msg_name[sizeof(sp_e->msg_name)-1] = 0;
    strncpy (sp_e->msg_name, SPY_GetMsgInternal( sp_e->msgnum ),
	     sizeof(sp_e->msg_name)-1);

    sp_e->data_len = 0;
    if (strncmp(sp_e->msg_name, "WM_USER+", 8) == 0) {
	INT i = 0;

#if DEBUG_SPY
	TRACE("looking class %s\n", sp_e->wnd_class);
#endif

	while (cc_array[i].classname &&
	       strcmpW(cc_array[i].classname, sp_e->wnd_class) !=0) i++;

	if (!cc_array[i].classname) return;
#if DEBUG_SPY
	TRACE("process class %s, first %p, last %p\n",
	      debugstr_w(cc_array[i].classname), cc_array[i].classmsg,
	      cc_array[i].lastmsg);
#endif
	p = SPY_Bsearch_Msg (cc_array[i].classmsg, cc_array[i].lastmsg,
			 sp_e->msgnum);
	if (p) {
	    strncpy (sp_e->msg_name, p->name, sizeof(sp_e->msg_name)-1);
	    sp_e->data_len = p->len;
	}
    }
}

/***********************************************************************
 *           SPY_GetWndName
 *
 *  Sets the value of "wnd_name" and "wnd_class" members of the
 *  instance structure.
 *
 */
void SPY_GetWndName( SPY_INSTANCE *sp_e )
{
    DWORD save_error;
    INT len;

    /* save and restore error code over the next call */
    save_error = GetLastError();
    /* special code to detect a property sheet dialog   */
    if ((GetClassLongW(sp_e->msg_hwnd, GCW_ATOM) == (LONG)WC_DIALOGW) &&
	(GetPropW(sp_e->msg_hwnd, PropSheetInfoStr))) {
	strcpyW(sp_e->wnd_class, WC_PROPSHEETW);
    }
    else {
	GetClassNameW(sp_e->msg_hwnd, sp_e->wnd_class, sizeof(sp_e->wnd_class)/sizeof(WCHAR));
    }
    SetLastError(save_error);

    len = InternalGetWindowText(sp_e->msg_hwnd, sp_e->wnd_name, sizeof(sp_e->wnd_name)/sizeof(WCHAR));
    if(!len) /* get class name */
    {
	LPWSTR dst = sp_e->wnd_name;
	LPWSTR src = sp_e->wnd_class;
	int n = sizeof(sp_e->wnd_name)/sizeof(WCHAR) - 3;
	*dst++ = '{';
	while ((n-- > 0) && *src) *dst++ = *src++;
	*dst++ = '}';
	*dst = 0;
    }
}

/***********************************************************************
 *           SPY_GetMsgName
 *
 *  ****  External function  ****
 *
 *  Get message name
 */
const char *SPY_GetMsgName( UINT msg, HWND hWnd )
{
    ext_sp_e.msgnum = msg;
    ext_sp_e.msg_hwnd   = hWnd;
    ext_sp_e.lParam = 0;
    ext_sp_e.wParam = 0;
    SPY_GetWndName(&ext_sp_e);
    SPY_GetMsgStuff(&ext_sp_e);
    return ext_sp_e.msg_name;
}

/***********************************************************************
 *           SPY_GetVKeyName
 */
const char *SPY_GetVKeyName(WPARAM wParam)
{
    const char *vk_key_name;

    if(wParam <= SPY_MAX_VKKEYSNUM && VK_KeyNames[wParam])
	vk_key_name = VK_KeyNames[wParam];
    else
	vk_key_name = "VK_???";

    return vk_key_name;
}

/***********************************************************************
 *           SPY_Bsearch_Notify
 */
const SPY_NOTIFY *SPY_Bsearch_Notify( const SPY_NOTIFY *first, const SPY_NOTIFY *last, UINT code)
{
    INT count;
    const SPY_NOTIFY *test;

    while (last >= first) {
	count = 1 + last - first;
	if (count < 3) {
#if DEBUG_SPY
	    TRACE("code=%d, f-value=%d, f-name=%s, l-value=%d, l-name=%s, l-len=%d,\n",
	       code, first->value, first->name, last->value, last->name, last->len);
#endif
	    if (first->value == code) return first;
	    if (last->value == code) return last;
	    return NULL;
	}
	count = count / 2;
	test = first + count;
#if DEBUG_SPY
	TRACE("first=%p, last=%p, test=%p, t-value=%d, code=%d, count=%d\n",
	   first, last, test, test->value, code, count);
#endif
	if (test->value == code) return test;
	if (test->value < code)
	    last = test - 1;
	else
	    first = test + 1;
    }
    return NULL;
}

/***********************************************************************
 *           SPY_DumpMem
 */
void SPY_DumpMem (LPSTR header, UINT *q, INT len)
{
    int i;

    for(i=0; i<len-12; i+=16) {
	TRACE("%s [%04x] %08x %08x %08x %08x\n",
	      header, i, *q, *(q+1), *(q+2), *(q+3));
	q += 4;
    }
    switch ((len - i + 3) & (~3)) {
    case 16:
	TRACE("%s [%04x] %08x %08x %08x %08x\n",
	      header, i, *q, *(q+1), *(q+2), *(q+3));
	break;
    case 12:
	TRACE("%s [%04x] %08x %08x %08x\n",
	      header, i, *q, *(q+1), *(q+2));
	break;
    case 8:
	TRACE("%s [%04x] %08x %08x\n",
	      header, i, *q, *(q+1));
	break;
    case 4:
	TRACE("%s [%04x] %08x\n",
	      header, i, *q);
	break;
    default:
	break;
    }
}

/***********************************************************************
 *           SPY_DumpStructure
 */
void SPY_DumpStructure (SPY_INSTANCE *sp_e, BOOL enter)
{
    switch (sp_e->msgnum)
	{
	case LVM_INSERTITEMW:
	case LVM_INSERTITEMA:
	case LVM_SETITEMW:
	case LVM_SETITEMA:
	    if (!enter) break;
	    /* fall through */
	case LVM_GETITEMW:
	case LVM_GETITEMA:
	    {
		LPLVITEMA item = (LPLVITEMA) sp_e->lParam;
		if (item) {
		    SPY_DumpMem ("LVITEM", (UINT*)item, sizeof(LVITEMA));
		}
		break;
	    }
	case TCM_INSERTITEMW:
	case TCM_INSERTITEMA:
	case TCM_SETITEMW:
	case TCM_SETITEMA:
	    if (!enter) break;
	    /* fall through */
	case TCM_GETITEMW:
	case TCM_GETITEMA:
	    {
		TCITEMA *item = (TCITEMA *) sp_e->lParam;
		if (item) {
		    SPY_DumpMem ("TCITEM", (UINT*)item, sizeof(TCITEMA));
		}
		break;
	    }
	case TCM_ADJUSTRECT:
	case LVM_GETITEMRECT:
	case LVM_GETSUBITEMRECT:
	    {
		LPRECT rc = (LPRECT) sp_e->lParam;
		if (rc) {
		    TRACE("lParam rect (%d,%d)-(%d,%d)\n",
			  rc->left, rc->top, rc->right, rc->bottom);
		}
		break;
	    }
	case LVM_SETITEMPOSITION32:
	    if (!enter) break;
	    /* fall through */
	case LVM_GETITEMPOSITION:
	case LVM_GETORIGIN:
	    {
		LPPOINT point = (LPPOINT) sp_e->lParam;
		if (point) {
		    TRACE("lParam point x=%ld, y=%ld\n", point->x, point->y);
		}
		break;
	    }
	case SBM_SETRANGE:
	    if (!enter && (sp_e->msgnum == SBM_SETRANGE)) break;
	    TRACE("min=%d max=%d\n", (INT)sp_e->wParam, (INT)sp_e->lParam);
	    break;
	case SBM_GETRANGE:
	    if ((enter && (sp_e->msgnum == SBM_GETRANGE)) ||
		(!enter && (sp_e->msgnum == SBM_SETRANGE))) break;
	    {
		LPINT ptmin = (LPINT) sp_e->wParam;
		LPINT ptmax = (LPINT) sp_e->lParam;
		if (ptmin && ptmax)
		    TRACE("min=%d max=%d\n", *ptmin, *ptmax);
		else if (ptmin)
		    TRACE("min=%d max=n/a\n", *ptmin);
		else if (ptmax)
		    TRACE("min=n/a max=%d\n", *ptmax);
		break;
	    }
	case WM_DRAWITEM:
	    if (!enter) break;
	    {
		DRAWITEMSTRUCT *lpdis = (DRAWITEMSTRUCT*) sp_e->lParam;
		TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
		      lpdis->CtlType, lpdis->CtlID);
		TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n",
		      lpdis->itemID, lpdis->itemAction, lpdis->itemState);
		TRACE("hWnd=0x%04x hDC=0x%04x (%d,%d)-(%d,%d) itemData=0x%08lx\n",
		      lpdis->hwndItem, lpdis->hDC, lpdis->rcItem.left,
		      lpdis->rcItem.top, lpdis->rcItem.right,
		      lpdis->rcItem.bottom, lpdis->itemData);
	    }
	    break;
	case WM_MEASUREITEM:
	    {
		MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*) sp_e->lParam;
		TRACE("MEASUREITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n",
		      lpmis->CtlType, lpmis->CtlID);
		TRACE("itemID=0x%08x itemWidth=0x%08x itemHeight=0x%08x\n",
		      lpmis->itemID, lpmis->itemWidth, lpmis->itemHeight);
		TRACE("itemData=0x%08lx\n", lpmis->itemData);
	    }
	    break;
	case WM_WINDOWPOSCHANGED:
	    if (!enter) break;
	case WM_WINDOWPOSCHANGING:
	    {
		WINDOWPOS *lpwp = (WINDOWPOS *)sp_e->lParam;
		TRACE("WINDOWPOS hwnd=0x%04x, after=0x%04x, at (%d,%d) w=%d h=%d, flags=0x%08x\n",
		      lpwp->hwnd, lpwp->hwndInsertAfter, lpwp->x, lpwp->y,
		      lpwp->cx, lpwp->cy, lpwp->flags);
	    }
	    break;
	case WM_STYLECHANGED:
	    if (!enter) break;
	case WM_STYLECHANGING:
	    {
		LPSTYLESTRUCT ss = (LPSTYLESTRUCT) sp_e->lParam;
		TRACE("STYLESTRUCT: StyleOld=0x%08lx, StyleNew=0x%08lx\n",
		      ss->styleOld, ss->styleNew);
	    }
	    break;
	case WM_NCCALCSIZE:
	    {
		RECT *rc = (RECT *)sp_e->lParam;
		TRACE("Rect (%d,%d)-(%d,%d)\n",
		      rc->left, rc->top, rc->right, rc->bottom);
	    }
	    break;
	case WM_NOTIFY:
	    /* if (!enter) break; */
	    {
		NMHDR * pnmh = (NMHDR*) sp_e->lParam;
		UINT *q, dumplen;
		const SPY_NOTIFY *p;
		WCHAR from_class[60];
		DWORD save_error;

		p = SPY_Bsearch_Notify (&spnfy_array[0], end_spnfy_array,
					pnmh->code);
		if (p) {
		    TRACE("NMHDR hwndFrom=0x%08x idFrom=0x%08x code=%s<0x%08x>, extra=0x%x\n",
			  pnmh->hwndFrom, pnmh->idFrom, p->name, pnmh->code, p->len);
		    dumplen = p->len;

		    /* for CUSTOMDRAW, dump all the data for TOOLBARs */
		    if (pnmh->code == NM_CUSTOMDRAW) {
			/* save and restore error code over the next call */
			save_error = GetLastError();
			GetClassNameW(pnmh->hwndFrom, from_class,
				      sizeof(from_class)/sizeof(WCHAR));
			SetLastError(save_error);
			if (strcmpW(TOOLBARCLASSNAMEW, from_class) == 0)
			    dumplen = sizeof(NMTBCUSTOMDRAW)-sizeof(NMHDR);
		    }
		    if (dumplen > 0) {
			q = (UINT *)(pnmh + 1);
			SPY_DumpMem ("NM extra", q, (INT)dumplen);
		    }
		}
		else
		    TRACE("NMHDR hwndFrom=0x%08x idFrom=0x%08x code=0x%08x\n",
			  pnmh->hwndFrom, pnmh->idFrom, pnmh->code);
	    }
	default:
	    if (sp_e->data_len > 0)
		SPY_DumpMem ("MSG lParam", (UINT *)sp_e->lParam, sp_e->data_len);
	    break;
	}

}
/***********************************************************************
 *           SPY_EnterMessage
 */
void SPY_EnterMessage( INT iFlag, HWND hWnd, UINT msg,
                       WPARAM wParam, LPARAM lParam )
{
    SPY_INSTANCE sp_e;
    int indent;

    if (!TRACE_ON(message) || SPY_EXCLUDE(msg)) return;

    sp_e.msgnum = msg;
    sp_e.msg_hwnd   = hWnd;
    sp_e.lParam = lParam;
    sp_e.wParam = wParam;
    SPY_GetWndName(&sp_e);
    SPY_GetMsgStuff(&sp_e);
    indent = get_indent_level();

    /* each SPY_SENDMESSAGE must be complemented by call to SPY_ExitMessage */
    switch(iFlag)
    {
    case SPY_DISPATCHMESSAGE16:
        TRACE("%*s(%04x) %-16s message [%04x] %s dispatched  wp=%04x lp=%08lx\n",
              indent, "", HWND_16(hWnd),
              debugstr_w(sp_e.wnd_name), msg, sp_e.msg_name, wParam, lParam);
        break;

    case SPY_DISPATCHMESSAGE:
        TRACE("%*s(%08x) %-16s message [%04x] %s dispatched  wp=%08x lp=%08lx\n",
                        indent, "", hWnd, debugstr_w(sp_e.wnd_name), msg,
                        sp_e.msg_name, wParam, lParam);
        break;

    case SPY_SENDMESSAGE16:
    case SPY_SENDMESSAGE:
        {
            char taskName[30];
            HTASK16 hTask = GetWindowTask16( HWND_16(hWnd) );

            if (hTask == GetCurrentTask()) strcpy( taskName, "self" );
            else if (!hTask) strcpy( taskName, "Wine" );
            else
            {
                sprintf( taskName, "task %04x ???", hTask );
                GetModuleName16( hTask, taskName + 10, sizeof(taskName) - 10 );
            }

            if (iFlag == SPY_SENDMESSAGE16)
                TRACE("%*s(%04x) %-16s message [%04x] %s sent from %s wp=%04x lp=%08lx\n",
                      indent, "", HWND_16(hWnd), debugstr_w(sp_e.wnd_name), msg,
                      sp_e.msg_name, taskName, wParam, lParam );
            else
            {   TRACE("%*s(%08x) %-16s message [%04x] %s sent from %s wp=%08x lp=%08lx\n",
			     indent, "", hWnd, debugstr_w(sp_e.wnd_name), msg,
			     sp_e.msg_name, taskName, wParam, lParam );
		SPY_DumpStructure(&sp_e, TRUE);
	    }
        }
        break;

    case SPY_DEFWNDPROC16:
	if( SPY_ExcludeDWP ) return;
        TRACE("%*s(%04x)  DefWindowProc16: %s [%04x]  wp=%04x lp=%08lx\n",
              indent, "", HWND_16(hWnd), sp_e.msg_name, msg, wParam, lParam );
        break;

    case SPY_DEFWNDPROC:
	if( SPY_ExcludeDWP ) return;
        TRACE("%*s(%08x)  DefWindowProc32: %s [%04x]  wp=%08x lp=%08lx\n",
                        indent, "", hWnd, sp_e.msg_name,
                        msg, wParam, lParam );
        break;
    }
    set_indent_level( indent + SPY_INDENT_UNIT );
}


/***********************************************************************
 *           SPY_ExitMessage
 */
void SPY_ExitMessage( INT iFlag, HWND hWnd, UINT msg, LRESULT lReturn,
                       WPARAM wParam, LPARAM lParam )
{
    SPY_INSTANCE sp_e;
    int indent;

    if (!TRACE_ON(message) || SPY_EXCLUDE(msg) ||
	(SPY_ExcludeDWP && (iFlag == SPY_RESULT_DEFWND16 || iFlag == SPY_RESULT_DEFWND)) )
	return;

    sp_e.msgnum = msg;
    sp_e.msg_hwnd   = hWnd;
    sp_e.lParam = lParam;
    sp_e.wParam = wParam;
    SPY_GetWndName(&sp_e);
    SPY_GetMsgStuff(&sp_e);

    if ((indent = get_indent_level()))
    {
        indent -= SPY_INDENT_UNIT;
        set_indent_level( indent );
    }

    switch(iFlag)
    {
    case SPY_RESULT_DEFWND16:
	TRACE(" %*s(%04x)  DefWindowProc16: %s [%04x] returned %08lx\n",
              indent, "", HWND_16(hWnd), sp_e.msg_name, msg, lReturn );
	break;

    case SPY_RESULT_DEFWND:
	TRACE(" %*s(%08x)  DefWindowProc32: %s [%04x] returned %08lx\n",
			indent, "", hWnd, sp_e.msg_name, msg, lReturn );
	break;

    case SPY_RESULT_OK16:
        TRACE(" %*s(%04x) %-16s message [%04x] %s returned %08lx\n",
              indent, "", HWND_16(hWnd), debugstr_w(sp_e.wnd_name), msg,
              sp_e.msg_name, lReturn );
        break;

    case SPY_RESULT_OK:
        TRACE(" %*s(%08x) %-16s message [%04x] %s returned %08lx\n",
                        indent, "", hWnd, debugstr_w(sp_e.wnd_name), msg,
                        sp_e.msg_name, lReturn );
	SPY_DumpStructure(&sp_e, FALSE);
        break;

    case SPY_RESULT_INVALIDHWND16:
        WARN(" %*s(%04x) %-16s message [%04x] %s HAS INVALID HWND\n",
             indent, "", HWND_16(hWnd), debugstr_w(sp_e.wnd_name), msg, sp_e.msg_name );
        break;

    case SPY_RESULT_INVALIDHWND:
        WARN(" %*s(%08x) %-16s message [%04x] %s HAS INVALID HWND\n",
                        indent, "", hWnd, debugstr_w(sp_e.wnd_name), msg,
                        sp_e.msg_name );
        break;
   }
}


/***********************************************************************
 *           SPY_Init
 */
int SPY_Init(void)
{
    int i, j;
    char buffer[1024];
    const SPY_NOTIFY *p;
    const USER_MSG *q;
    HKEY hkey;

    if (!TRACE_ON(message)) return TRUE;

    indent_tls_index = TlsAlloc();
    if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Debug", &hkey))
    {
        DWORD type, count = sizeof(buffer);

        buffer[0] = 0;
        if (!RegQueryValueExA(hkey, "SpyInclude", 0, &type, buffer, &count) &&
            strcmp( buffer, "INCLUDEALL" ))
        {
            TRACE("Include=%s\n", buffer );
            for (i = 0; i <= SPY_MAX_MSGNUM; i++)
                SPY_Exclude[i] = (MessageTypeNames[i] && !strstr(buffer,MessageTypeNames[i]));
        }

        count = sizeof(buffer);
        buffer[0] = 0;
        if (!RegQueryValueExA(hkey, "SpyExclude", 0, &type, buffer, &count))
        {
            TRACE("Exclude=%s\n", buffer );
            if (!strcmp( buffer, "EXCLUDEALL" ))
                for (i = 0; i <= SPY_MAX_MSGNUM; i++) SPY_Exclude[i] = TRUE;
            else
                for (i = 0; i <= SPY_MAX_MSGNUM; i++)
                    SPY_Exclude[i] = (MessageTypeNames[i] && strstr(buffer,MessageTypeNames[i]));
        }

        SPY_ExcludeDWP = 0;
        count = sizeof(buffer);
        if(!RegQueryValueExA(hkey, "SpyExcludeDWP", 0, &type, buffer, &count))
            SPY_ExcludeDWP = atoi(buffer);

        RegCloseKey(hkey);
    }

    /* find last good entry in spy notify array and save addr for b-search */
    p = &spnfy_array[0];
    j = 0xffffffff;
    while (p->name) {
	if ((UINT)p->value > (UINT)j) {
	    ERR("Notify message array out of order\n");
	    ERR("  between values [%08x] %s and [%08x] %s\n",
		j, (p-1)->name, p->value, p->name);
	    break;
	}
	j = p->value;
	p++;
    }
    p--;
    end_spnfy_array = p;

    /* find last good entry in each common control message array
     *  and save addr for b-search.
     */
    i = 0;
    while (cc_array[i].classname) {

	j = 0x0400; /* minimum entry in array */
	q = cc_array[i].classmsg;
	while(q->name) {
	    if (q->value <= j) {
		ERR("Class message array out of order for class %s\n",
		    debugstr_w(cc_array[i].classname));
		ERR("  between values [%04x] %s and [%04x] %s\n",
		    j, (q-1)->name, q->value, q->name);
		break;
	    }
	    j = q->value;
	    q++;
	}
	q--;
	cc_array[i].lastmsg = (USER_MSG *)q;

	i++;
    }

    return 1;
}
