How do I allow negative numbers with the ES_NUMBER edit control style?

Raymond Chen


The ES_NUMBER edit control style limits typed input to digits, but what if you also want to accept negative numbers? How can we extend¹ ES_NUMBER to accept the minus sign?

The ES_NUMBER edit control style works by altering the behavior of the edit control when it receives a WM_CHAR. You can do that too!

Subclass the edit control and handle the WM_CHAR message by checking whether the character is a digit or a minus sign. If not, then beep and return. Otherwise, let the message through.

LRESULT CALLBACK SignedIntegerSubclassProc(
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR uIdSubclass,
    DWORD_PTR dwRefData)
 switch (uMsg) {
  RemoveWindowSubclass(hwnd, SignedIntegerSubclassProc, uIdSubclass);

 case WM_CHAR:
   wchar_t ch = (wchar_t)wParam;
   if (ch < L' ') break;                // let control character through
   else if (ch == L'-') break;          // let hyphen-minus through
   else if (ch == L'\x2212') break;     // let Unicode minus sign through
   else if (IsUnicodeDigit(ch)) break;  // let digit through
   MessageBeep(0);                      // otherwise invalid
   return 0;

 return DefSubclassProc(hwnd, uMsg, wParam, lParam);

BOOL EnforceSignedIntegerEdit(HWND hwnd)
 return SetWindowSubclass(hwnd, SignedIntegerSubclassProc, 0, 0);

If the user entered a character, then we let it through if it is one of the following:

  • A control character, to permit Ctrl+A, Ctrl+C, Bksp, Tab, and so on.
  • Unicode character U+002D HYPHEN-MINUS, which is what most people think of as a minus sign.
  • Unicode character U+2212 MINUS SIGN, which is a true minus sign.

¹ As noted in the documentation, the ES_NUMBER edit control style doesn’t prevent the user from putting non-digits into the edit control by other means, like pasting with Ctrl+V. The exercise is to extend the existing behavior of the ES_NUMBER style, not to fix it to cover all the other scenarios. Our technique has the same defects as ES_NUMBER, but at least it’s the same defects.


Comments are closed. Login to edit/delete your existing comments