See the question and my original answer on StackOverflow

There are multiple ways to fix this.

First, you could use the official message loop from Using Messages and Message Queues, so replace your while(TRUE) ... by this:

BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
    if (bRet == -1)
        // handle the error and possibly exit
        // don't put Render() here

And then do your render loop in WM_PAINT. This is what you wanted to do but one important detail is as doc says:

Return value An application returns zero if it processes this message.

So replace your WM_PAINT handling by this:

case WM_PAINT:
  return 0; // we handle it

What it means to Windows is in fact you never validate your update region so Windows keeps sending the WM_PAINT message.

Another solution (more common in DirectX gaming loops) is to keep Render in your current message loop and handle WM_PAINT just validating the region, like this, so Windows won't send it forever:

case WM_PAINT:
  HDC hdc = BeginPaint(hWnd, &ps);
  EndPaint(hWnd, &ps);
return 0;

And change your current Input::GetKeyRaw(Key key) implementation because it runs another message loop which causes weird things. Move WM_KEYDOWN handling in the main loop, and simply store the keyboard state somewhere so you can use it in Render().