(Free)GLUTのWindow Procedureをこっそり入れかえる

GLUTはライブラリ内でWindowのあれこれを隠蔽しているため、そのままだとメニューを入れたり、別途コントロールを突っ込んだりすることがそのままでは難しいです。
ですが、あらゆるWindow Handleを奪いとる事ができるWindowsでは、EnumWindowsというAPIを使用する事により、Window Procedureを挿げ替える事が可能です。

WNDPROC OriginalWindowProcedure = NULL; // オリジナルのWindow Procedureの保存用

/**
 * カスタムWindowProcedure
 */
LRESULT CALLBACK
GLUTApplicationWindowProc(HWND AWindowHandle, UINT AMsg, WPARAM AWParam, LPARAM ALParam)
{
  switch (AMsg)
    {
    case WM_DESTROY:
      exit(0); // -mwindowsオプションでビルドすると、そのままではプロセスが死なないため、WM_DESTROY時にexit()をcallする.
      break;
    default:
      if (OriginalWindowProcedure)
        {
          return CallWindowProc(OriginalWindowProcedure,
                                AWindowHandle,
                                AMsg,
                                AWParam,
                                ALParam);
        }
      else
        {
          return DefWindowProc(AWindowHandle,
                               AMsg,
                               AWParam,
                               ALParam);
        }
      glutPostRedisplay();
      break;
    }

  return 0;
}

//Window Procedureを入れ替えるためのコールバック
BOOL CALLBACK
SetWindowProc(HWND AWindowHandle, LPARAM ALParam)
{
  //引数のWindowHandleからインスタンスを取得する.
  HANDLE ModuleHandle = reinterpret_cast<HANDLE>(GetWindowLongPtr(AWindowHandle,
                                                                  GWL_HINSTANCE));

  //自プロセスにより生成されたウィンドウであるならそのウィンドウハンドルを奪う
  if (GetModuleHandle(NULL) == ModuleHandle)
    {
      NarrowChar ClassName[256]; //256は適当 多分正規のサイズが規定されているはず

      //WindowHandleのWindowClass名を取得して、それが置き換えたい対象のWindowClass名であるなら、Window Procedureを入れ替える.
      GetClassName(AWindowHandle,
                   reinterpret_cast<LPWSTR>(ClassName),
                   256);

      //ウィンドウクラス名がGLUTのものであったら、そのウィンドウプロシージャを奪う
      // GLUTなら"GLUT"、FreeGLUTなら"FREEGLUT"
      if (strncmp(ClassName, "FREEGLUT", strlen(ClassName)) == 0)
        {
          //オリジナルのWindowProcedureは保存しておきましょう。
          OriginalWindowProcedure = reinterpret_cast<WNDPROC>(GetWindowLongPtr(AWindowHandle,
                                                                               GWL_WNDPROC));

          //Window Procesure を挿げ替える!!!
          SetWindowLongPtr(AWindowHandle,
                           GWL_WNDPROC,
                           reinterpret_cast<LONG>(GLUTApplicationWindowProc));

          //メインメニューを付けてみる.
          HMENU Menu = LoadMenu(GetModuleHandle(NULL),
                                MAKEINTRESOURCE(IDR_GLMAINMENU));

          if (Menu)
            {
              SetMenu(AWindowHandle,
                      Menu);
            }
          return false;
        }
    }

  return true;
}

int
main(int argc, char* argv[])
{
  //あらゆる初期化をしましょう
  Application.Initialize();

  //Window Procedureを挿げ替えるために、EnumWindowsをcall
  EnumWindows(SetWindowProc,
              0);


  Application.Run();

  return 0;
}