Is there a hidden/undocumented API call within Windows that will convert a message ID (e.g. WM_COMMAND) into text?
I have seen suggestions on how to achieve this using macros and switch statements (which is a bit of a joke!) but surely there is a run-time means of doing this?
I can't use Spy++ for the scenario I'm trying to debug and I don't want to create a huge table of command IDs and there text - even if it is via a macro. There must be a way to do this - surely Spy++ doesn't have a huge message ID lookup table inside its source???
Cheers Sparky
Spy++ has a huge message ID lookup table inside its source.
In visual studio, you can add uMsg,wm
in command window or immediate window to get the string representation of the message ID given by uMsg
.
source : http://www.codeguru.com/cpp/v-s/debug/article.php/c1267/Convert-message-ID-to-a-string.htm (comments section)
PS: This is same link as mentioned in jack's answer. A user had commented there on the link. This technique has helped me very much in debugging Windows messages (no modification and recompilation of code is required), and therefore merits a separate answer.
Hereafter is code to convert WM_ and other Win32 message codes to text. Includes options to ignore certain messages (eg. WM_MOUSEMOVE) and to dump a list of messages received at the end. (NB: This list only goes up to 1024 (WM_USER) due to the 30K limit on this box. Also there are many duplicates in the list thereafter.)
// Usage -----
#include "win_msg.h"
void ShowMessageText(UINT msg)
{
wchar_t str[1024];
wchar_t* win_msgtext = (wchar_t*)GetMessageText(msg);
if (win_msgtext)
{
//printf(L"WndProc: msg = %x (%s)\n", msg, win_msgtext);
wsprintf(str, L"WndProc: msg = %x (%s)\n", msg, win_msgtext);
OutputDebugString(str);
}
}
To list messages used (and generate an 'ignore' list) call:
ShowUsedMessages();
// win_msg.h file ----------
#define SHOW_USED_MESSAGES 1
wchar_t* GetMessageText(unsigned int msg);
#ifdef SHOW_USED_MESSAGES
void ShowUsedMessages(void);
#endif
// win_msg.cpp -----------
#include "stdafx.h"
#include "win_msg.h"
// List here messages to ignore (-1 signifies end of list)
// if -999 occurs at the start of the list, ALL messages except these are ignored (ie. inverts)
//int msgs_to_ignore[] = { -1 };
int msgs_to_ignore[] = {//-999,
0x20, 0x84, 0xA0, 0x113, 0x200
};
// 0x0020 - WM_SETCURSOR (45)
// 0x0084 - WM_NCHITTEST (26)
// 0x0113 - WM_TIMER (46)
// 0x0135 - WM_CTLCOLORBTN (8)
// 0x0200 - WM_MOUSEFIRST (26)
typedef struct {
unsigned int code;
wchar_t* text;
} XMSGITEM;
// These from https://wiki.winehq.org/List_Of_Windows_Messages
XMSGITEM xmsglist[] =
{
{ 0, L"WM_NULL"},
{ 1, L"WM_CREATE" },
{ 2, L"WM_DESTROY" },
{ 3, L"WM_MOVE" },
{ 5, L"WM_SIZE" },
{ 6, L"WM_ACTIVATE" },
{ 7, L"WM_SETFOCUS" },
{ 8, L"WM_KILLFOCUS" },
{ 10, L"WM_ENABLE" },
{ 11, L"WM_SETREDRAW" },
{ 12, L"WM_SETTEXT" },
{ 13, L"WM_GETTEXT" },
{ 14, L"WM_GETTEXTLENGTH" },
{ 15, L"WM_PAINT" },
{ 16, L"WM_CLOSE" },
{ 17, L"WM_QUERYENDSESSION" },
{ 18, L"WM_QUIT" },
{ 19, L"WM_QUERYOPEN" },
{ 20, L"WM_ERASEBKGND" },
{ 21, L"WM_SYSCOLORCHANGE" },
{ 22, L"WM_ENDSESSION" },
{ 24, L"WM_SHOWWINDOW" },
{ 25, L"WM_CTLCOLOR" },
{ 26, L"WM_WININICHANGE" },
{ 27, L"WM_DEVMODECHANGE" },
{ 28, L"WM_ACTIVATEAPP" },
{ 29, L"WM_FONTCHANGE" },
{ 30, L"WM_TIMECHANGE" },
{ 31, L"WM_CANCELMODE" },
{ 32, L"WM_SETCURSOR" },
{ 33, L"WM_MOUSEACTIVATE" },
{ 34, L"WM_CHILDACTIVATE" },
{ 35, L"WM_QUEUESYNC" },
{ 36, L"WM_GETMINMAXINFO" },
{ 38, L"WM_PAINTICON" },
{ 39, L"WM_ICONERASEBKGND" },
{ 40, L"WM_NEXTDLGCTL" },
{ 42, L"WM_SPOOLERSTATUS" },
{ 43, L"WM_DRAWITEM" },
{ 44, L"WM_MEASUREITEM" },
{ 45, L"WM_DELETEITEM" },
{ 46, L"WM_VKEYTOITEM" },
{ 47, L"WM_CHARTOITEM" },
{ 48, L"WM_SETFONT" },
{ 49, L"WM_GETFONT" },
{ 50, L"WM_SETHOTKEY" },
{ 51, L"WM_GETHOTKEY" },
{ 55, L"WM_QUERYDRAGICON" },
{ 57, L"WM_COMPAREITEM" },
{ 61, L"WM_GETOBJECT" },
{ 65, L"WM_COMPACTING" },
{ 68, L"WM_COMMNOTIFY" },
{ 70, L"WM_WINDOWPOSCHANGING" },
{ 71, L"WM_WINDOWPOSCHANGED" },
{ 72, L"WM_POWER" },
{ 73, L"WM_COPYGLOBALDATA" },
{ 74, L"WM_COPYDATA" },
{ 75, L"WM_CANCELJOURNAL" },
{ 78, L"WM_NOTIFY" },
{ 80, L"WM_INPUTLANGCHANGEREQUEST" },
{ 81, L"WM_INPUTLANGCHANGE" },
{ 82, L"WM_TCARD" },
{ 83, L"WM_HELP" },
{ 84, L"WM_USERCHANGED" },
{ 85, L"WM_NOTIFYFORMAT" },
{ 123, L"WM_CONTEXTMENU" },
{ 124, L"WM_STYLECHANGING" },
{ 125, L"WM_STYLECHANGED" },
{ 126, L"WM_DISPLAYCHANGE" },
{ 127, L"WM_GETICON" },
{ 128, L"WM_SETICON" },
{ 129, L"WM_NCCREATE" },
{ 130, L"WM_NCDESTROY" },
{ 131, L"WM_NCCALCSIZE" },
{ 132, L"WM_NCHITTEST" },
{ 133, L"WM_NCPAINT" },
{ 134, L"WM_NCACTIVATE" },
{ 135, L"WM_GETDLGCODE" },
{ 136, L"WM_SYNCPAINT" },
{ 160, L"WM_NCMOUSEMOVE" },
{ 161, L"WM_NCLBUTTONDOWN" },
{ 162, L"WM_NCLBUTTONUP" },
{ 163, L"WM_NCLBUTTONDBLCLK" },
{ 164, L"WM_NCRBUTTONDOWN" },
{ 165, L"WM_NCRBUTTONUP" },
{ 166, L"WM_NCRBUTTONDBLCLK" },
{ 167, L"WM_NCMBUTTONDOWN" },
{ 168, L"WM_NCMBUTTONUP" },
{ 169, L"WM_NCMBUTTONDBLCLK" },
{ 171, L"WM_NCXBUTTONDOWN" },
{ 172, L"WM_NCXBUTTONUP" },
{ 173, L"WM_NCXBUTTONDBLCLK" },
{ 176, L"EM_GETSEL" },
{ 177, L"EM_SETSEL" },
{ 178, L"EM_GETRECT" },
{ 179, L"EM_SETRECT" },
{ 180, L"EM_SETRECTNP" },
{ 181, L"EM_SCROLL" },
{ 182, L"EM_LINESCROLL" },
{ 183, L"EM_SCROLLCARET" },
{ 185, L"EM_GETMODIFY" },
{ 187, L"EM_SETMODIFY" },
{ 188, L"EM_GETLINECOUNT" },
{ 189, L"EM_LINEINDEX" },
{ 190, L"EM_SETHANDLE" },
{ 191, L"EM_GETHANDLE" },
{ 192, L"EM_GETTHUMB" },
{ 193, L"EM_LINELENGTH" },
{ 194, L"EM_REPLACESEL" },
{ 195, L"EM_SETFONT" },
{ 196, L"EM_GETLINE" },
{ 197, L"EM_LIMITTEXT" },
{ 197, L"EM_SETLIMITTEXT" },
{ 198, L"EM_CANUNDO" },
{ 199, L"EM_UNDO" },
{ 200, L"EM_FMTLINES" },
{ 201, L"EM_LINEFROMCHAR" },
{ 202, L"EM_SETWORDBREAK" },
{ 203, L"EM_SETTABSTOPS" },
{ 204, L"EM_SETPASSWORDCHAR" },
{ 205, L"EM_EMPTYUNDOBUFFER" },
{ 206, L"EM_GETFIRSTVISIBLELINE" },
{ 207, L"EM_SETREADONLY" },
{ 209, L"EM_SETWORDBREAKPROC" },
{ 209, L"EM_GETWORDBREAKPROC" },
{ 210, L"EM_GETPASSWORDCHAR" },
{ 211, L"EM_SETMARGINS" },
{ 212, L"EM_GETMARGINS" },
{ 213, L"EM_GETLIMITTEXT" },
{ 214, L"EM_POSFROMCHAR" },
{ 215, L"EM_CHARFROMPOS" },
{ 216, L"EM_SETIMESTATUS" },
{ 217, L"EM_GETIMESTATUS" },
{ 224, L"SBM_SETPOS" },
{ 225, L"SBM_GETPOS" },
{ 226, L"SBM_SETRANGE" },
{ 227, L"SBM_GETRANGE" },
{ 228, L"SBM_ENABLE_ARROWS" },
{ 230, L"SBM_SETRANGEREDRAW" },
{ 233, L"SBM_SETSCROLLINFO" },
{ 234, L"SBM_GETSCROLLINFO" },
{ 235, L"SBM_GETSCROLLBARINFO" },
{ 240, L"BM_GETCHECK" },
{ 241, L"BM_SETCHECK" },
{ 242, L"BM_GETSTATE" },
{ 243, L"BM_SETSTATE" },
{ 244, L"BM_SETSTYLE" },
{ 245, L"BM_CLICK" },
{ 246, L"BM_GETIMAGE" },
{ 247, L"BM_SETIMAGE" },
{ 248, L"BM_SETDONTCLICK" },
{ 255, L"WM_INPUT" },
{ 256, L"WM_KEYDOWN" },
{ 256, L"WM_KEYFIRST" },
{ 257, L"WM_KEYUP" },
{ 258, L"WM_CHAR" },
{ 259, L"WM_DEADCHAR" },
{ 260, L"WM_SYSKEYDOWN" },
{ 261, L"WM_SYSKEYUP" },
{ 262, L"WM_SYSCHAR" },
{ 263, L"WM_SYSDEADCHAR" },
{ 264, L"WM_KEYLAST" },
{ 265, L"WM_UNICHAR" },
{ 265, L"WM_WNT_CONVERTREQUESTEX" },
{ 266, L"WM_CONVERTREQUEST" },
{ 267, L"WM_CONVERTRESULT" },
{ 268, L"WM_INTERIM" },
{ 269, L"WM_IME_STARTCOMPOSITION" },
{ 270, L"WM_IME_ENDCOMPOSITION" },
{ 271, L"WM_IME_COMPOSITION" },
{ 271, L"WM_IME_KEYLAST" },
{ 272, L"WM_INITDIALOG" },
{ 273, L"WM_COMMAND" },
{ 274, L"WM_SYSCOMMAND" },
{ 275, L"WM_TIMER" },
{ 276, L"WM_HSCROLL" },
{ 277, L"WM_VSCROLL" },
{ 278, L"WM_INITMENU" },
{ 279, L"WM_INITMENUPOPUP" },
{ 280, L"WM_SYSTIMER" },
{ 287, L"WM_MENUSELECT" },
{ 288, L"WM_MENUCHAR" },
{ 289, L"WM_ENTERIDLE" },
{ 290, L"WM_MENURBUTTONUP" },
{ 291, L"WM_MENUDRAG" },
{ 292, L"WM_MENUGETOBJECT" },
{ 293, L"WM_UNINITMENUPOPUP" },
{ 294, L"WM_MENUCOMMAND" },
{ 295, L"WM_CHANGEUISTATE" },
{ 296, L"WM_UPDATEUISTATE" },
{ 297, L"WM_QUERYUISTATE" },
{ 306, L"WM_CTLCOLORMSGBOX" },
{ 307, L"WM_CTLCOLOREDIT" },
{ 308, L"WM_CTLCOLORLISTBOX" },
{ 309, L"WM_CTLCOLORBTN" },
{ 310, L"WM_CTLCOLORDLG" },
{ 311, L"WM_CTLCOLORSCROLLBAR" },
{ 312, L"WM_CTLCOLORSTATIC" },
{ 512, L"WM_MOUSEFIRST" },
{ 512, L"WM_MOUSEMOVE" },
{ 513, L"WM_LBUTTONDOWN" },
{ 514, L"WM_LBUTTONUP" },
{ 515, L"WM_LBUTTONDBLCLK" },
{ 516, L"WM_RBUTTONDOWN" },
{ 517, L"WM_RBUTTONUP" },
{ 518, L"WM_RBUTTONDBLCLK" },
{ 519, L"WM_MBUTTONDOWN" },
{ 520, L"WM_MBUTTONUP" },
{ 521, L"WM_MBUTTONDBLCLK" },
{ 521, L"WM_MOUSELAST" },
{ 522, L"WM_MOUSEWHEEL" },
{ 523, L"WM_XBUTTONDOWN" },
{ 524, L"WM_XBUTTONUP" },
{ 525, L"WM_XBUTTONDBLCLK" },
{ 528, L"WM_PARENTNOTIFY" },
{ 529, L"WM_ENTERMENULOOP" },
{ 530, L"WM_EXITMENULOOP" },
{ 531, L"WM_NEXTMENU" },
{ 532, L"WM_SIZING" },
{ 533, L"WM_CAPTURECHANGED" },
{ 534, L"WM_MOVING" },
{ 536, L"WM_POWERBROADCAST" },
{ 537, L"WM_DEVICECHANGE" },
{ 544, L"WM_MDICREATE" },
{ 545, L"WM_MDIDESTROY" },
{ 546, L"WM_MDIACTIVATE" },
{ 547, L"WM_MDIRESTORE" },
{ 548, L"WM_MDINEXT" },
{ 549, L"WM_MDIMAXIMIZE" },
{ 550, L"WM_MDITILE" },
{ 551, L"WM_MDICASCADE" },
{ 552, L"WM_MDIICONARRANGE" },
{ 553, L"WM_MDIGETACTIVE" },
{ 560, L"WM_MDISETMENU" },
{ 561, L"WM_ENTERSIZEMOVE" },
{ 562, L"WM_EXITSIZEMOVE" },
{ 563, L"WM_DROPFILES" },
{ 564, L"WM_MDIREFRESHMENU" },
{ 640, L"WM_IME_REPORT" },
{ 641, L"WM_IME_SETCONTEXT" },
{ 642, L"WM_IME_NOTIFY" },
{ 643, L"WM_IME_CONTROL" },
{ 644, L"WM_IME_COMPOSITIONFULL" },
{ 645, L"WM_IME_SELECT" },
{ 646, L"WM_IME_CHAR" },
{ 648, L"WM_IME_REQUEST" },
{ 656, L"WM_IMEKEYDOWN" },
{ 656, L"WM_IME_KEYDOWN" },
{ 657, L"WM_IMEKEYUP" },
{ 657, L"WM_IME_KEYUP" },
{ 672, L"WM_NCMOUSEHOVER" },
{ 673, L"WM_MOUSEHOVER" },
{ 674, L"WM_NCMOUSELEAVE" },
{ 675, L"WM_MOUSELEAVE" },
{ 768, L"WM_CUT" },
{ 769, L"WM_COPY" },
{ 770, L"WM_PASTE" },
{ 771, L"WM_CLEAR" },
{ 772, L"WM_UNDO" },
{ 773, L"WM_RENDERFORMAT" },
{ 774, L"WM_RENDERALLFORMATS" },
{ 775, L"WM_DESTROYCLIPBOARD" },
{ 776, L"WM_DRAWCLIPBOARD" },
{ 777, L"WM_PAINTCLIPBOARD" },
{ 778, L"WM_VSCROLLCLIPBOARD" },
{ 779, L"WM_SIZECLIPBOARD" },
{ 780, L"WM_ASKCBFORMATNAME" },
{ 781, L"WM_CHANGECBCHAIN" },
{ 782, L"WM_HSCROLLCLIPBOARD" },
{ 783, L"WM_QUERYNEWPALETTE" },
{ 784, L"WM_PALETTEISCHANGING" },
{ 785, L"WM_PALETTECHANGED" },
{ 786, L"WM_HOTKEY" },
{ 791, L"WM_PRINT" },
{ 792, L"WM_PRINTCLIENT" },
{ 793, L"WM_APPCOMMAND" },
{ 856, L"WM_HANDHELDFIRST" },
{ 863, L"WM_HANDHELDLAST" },
{ 864, L"WM_AFXFIRST" },
{ 895, L"WM_AFXLAST" },
{ 896, L"WM_PENWINFIRST" },
{ 897, L"WM_RCRESULT" },
{ 898, L"WM_HOOKRCRESULT" },
{ 899, L"WM_GLOBALRCCHANGE" },
{ 899, L"WM_PENMISCINFO" },
{ 900, L"WM_SKB" },
{ 901, L"WM_HEDITCTL" },
{ 901, L"WM_PENCTL" },
{ 902, L"WM_PENMISC" },
{ 903, L"WM_CTLINIT" },
{ 904, L"WM_PENEVENT" },
{ 911, L"WM_PENWINLAST" },
{ 1024, L"WM_USER" }
};
// 1003 messages
#define NUM_XMSGS (sizeof(xmsglist) / sizeof(XMSGITEM))
bool ignore_msg[NUM_XMSGS];
static int xmsgs_initialized = 0;
#ifdef SHOW_USED_MESSAGES
int used_freq[NUM_XMSGS];
#endif
//-------------------------------------------------
// returns -1 if not found
int msgid_to_index(unsigned int msg)
{
static unsigned int first, cur, last; //138nS
//register unsigned int first,cur,last; //173nS
// Use bchop to find message code
first = 0;
last = NUM_XMSGS;
while (1)
{
cur = (first + last) / 2;
if (msg < xmsglist[cur].code)
{
if (cur == last)
return (-1); // not found
else
last = cur;
}
else
{
if (msg == xmsglist[cur].code) //found
{
return (cur);
}
if (cur == first)
return (-1); // not found
else
first = cur;
}
}
}
//-------------------------------------------------
#define MAX_XMIGNORES (sizeof(msgs_to_ignore) / sizeof(int))
void initialise_xmsgs(void)
{
int msg,index;
bool invert = 0;
if (msgs_to_ignore[0] == -999) invert = 1;
for (int i = 0; i < NUM_XMSGS; i++)
{
ignore_msg[i] = invert;
#ifdef SHOW_USED_MESSAGES
used_freq[i] = 0;
#endif
}
for (int i = 0; i < MAX_XMIGNORES; i++)
{
msg = msgs_to_ignore[i];
if (msg == -1) break;
index = msgid_to_index(msg);
if (index != -1)
{
if (index < NUM_XMSGS)
{
ignore_msg[index] = invert ^ 1;
}
else
{
index = NUM_XMSGS;
}
}
}
xmsgs_initialized = 1;
}
//-------------------------------------------------
wchar_t* GetMessageText(unsigned int msg)
{
int index;
// Setup ignore list on first call
if (!xmsgs_initialized)
{
initialise_xmsgs();
}
index = msgid_to_index(msg);
if (index == -1) return (NULL);//not found - bad msg id
#ifdef SHOW_USED_MESSAGES
used_freq[index]++;
#endif
if (ignore_msg[index])
{
return (NULL);
}
return (xmsglist[index].text);
}
//-------------------------------------------------
#ifdef SHOW_USED_MESSAGES
void ShowUsedMessages(void)
{
wchar_t str[1024];
wchar_t* p = str;
int count = 0;
int lastmsg;
// Find last message - to exclude ',' at end
for (int i = 0; i < NUM_XMSGS; i++)
{
if (used_freq[i]) lastmsg = i;
}
// Pass 1 - output table for inclusion
OutputDebugString(L"\nint msgs_to_ignore[] = {\n");
for (int i = 0; i < NUM_XMSGS; i++)
{
if (used_freq[i])
{
p += wsprintf(p, L"0x%X", xmsglist[i].code);
count++;
if (i == lastmsg)
count = 8;
else
*p++ = ',';
if (count >= 8)
{
*p++ = '\n';
*p++ = '\0';
OutputDebugString(str);
p = str;
count = 0;
}
}
}
OutputDebugString(L"};\n");
// Pass 2 - add message text and frequencies
for (int i = 0; i < NUM_XMSGS; i++)
{
if (used_freq[i])
{
wsprintf(str, L"// 0x%04X - %s (%d)\n", xmsglist[i].code, xmsglist[i].text, used_freq[i]);
OutputDebugString(str);
}
}
}
#endif
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With