Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Windows Message IDs to Text

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

like image 802
SparkyNZ Avatar asked Aug 31 '11 03:08

SparkyNZ


3 Answers

Spy++ has a huge message ID lookup table inside its source.

like image 54
Raymond Chen Avatar answered Nov 16 '22 22:11

Raymond Chen


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.

like image 32
Sahil Singh Avatar answered Nov 16 '22 21:11

Sahil Singh


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
like image 33
John Foster Avatar answered Nov 16 '22 21:11

John Foster