问题
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
回答1:
Spy++ has a huge message ID lookup table inside its source.
回答2:
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.
回答3:
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
来源:https://stackoverflow.com/questions/7252398/convert-windows-message-ids-to-text