Este snippet muestra una clase de ventana completa, incluyendo el problemático wndProc, que es es algo complicado incluir en la clase debido a que se tiene que pasar como parametro lpfnWndProc al WNDCLASS. Esto es debido a que no se puede pasar un puntero a una función miembro de una clase a menos de que sea estática o que el puntero vaya a ser usado en el contexto de un objeto de una clase, que sigue sin arreglar el problema. La solución que me ha parecido mas viable es la que se muestra en este hilo de gamedev.net, en la que se usa una función miembro estática que sirve de dummy para la verdadera función interna de la clase, comunicandose entre ambas vias el area de datos de usuario HWND de 32-bit, por donde se envía una referencia del objeto CVentana.

Para ver mas detalladamente el problema en la página The Function Pointer Tutorials esta que son y como usar los punteros a funciones en c++, este es un artículo de msdn como crear un puntero a función miembro y en linuxquality hay otro.

ventana.h

C++:
  1. #ifndef _CVENTANA_C_
  2. #define _CVENTANA_C_
  3.  
  4. #include <windows.h>
  5. #include <gl\gl.h>
  6. #include <gl\glu.h>
  7. #include <gl\glaux.h>
  8.  
  9.  
  10.  
  11. #define INACTIVO     0  //Quiere decir que el objeto CVentana no tiene una ventana asociada, esta "vacio"
  12. #define ACTIVO       1  //El objeto tiene una ventana funcional asociada
  13. #define ESTADO_ERROR 2  //Durante la creacion o destrucccion del objeto se presentó un error
  14.  
  15. class CVentana
  16. {
  17. protected:
  18.      static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  19.      LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
  20. private:
  21.     int estado;
  22. public:
  23.     WNDCLASS  wnd;
  24.     HWND      hwnd;
  25.     MSG       msg;
  26.     HINSTANCE hinstance;
  27.     HDC       hdc;
  28.     HGLRC     hrc;
  29.     bool fullscreen;
  30.     int alto;
  31.     int ancho;
  32.  
  33.     //Constructor, inicializa el estado del objeto
  34.     CVentana()  {
  35.                     estado=INACTIVO;
  36.                 };
  37.  
  38.     int Crear_Ventana(int _ancho,int _alto,int pos_x,int pos_y,bool _fullscreen,int profundidad_color);
  39.  
  40.     //Cambia el tamaño de la ventna de gl
  41.     void Cambiar_Tamano_GL(GLsizei ancho, GLsizei alto);
  42.  
  43.     //Inicializa gl, se usa en la creacion de la ventana
  44.     bool Inicializar_GL(GLvoid);
  45.  
  46.     //Funcion que libera los recursos de la ventana
  47.     void Destruir_Ventana(void) ;
  48.  
  49.     //Ciclo de observacion de mensajes, el único mensaje especial que toma es WM_QUIT,de encontrarlo retorna
  50.     //true, si no, manda el mensaje al winproc()
  51.     bool Ciclo_Mensaje(void);
  52.  
  53.     //Acceso al estado del objeto
  54.     int Obtener_Estado(void){return estado;};
  55.  
  56.     //Limpia el objeto en caso de ESTADO_ERROR,y lo devuelve a INACTIVO
  57.     //OJO, no es segura la liberacion de memoria
  58.     void Limpiar_Objeto(void);
  59.  
  60. };
  61.  
  62. #endif
  63.  
  64. /*El codigo típico para abrir una ventana y que corra, etc es algo como
  65. #pragma comment(lib, "opengl32.lib")
  66. #pragma comment(lib, "glu32.lib")
  67. #pragma comment(lib, "glaux.lib")
  68. int WINAPI WinMain( HINSTANCE    hInstance,HINSTANCE hPrevInstance,LPSTR    lpCmdLine,int nCmdShow)
  69. {
  70.     CVentana    myVentana;
  71.     if(myVentana.Crear_Ventana(640,480,200,200,false,32) == ESTADO_ERROR)
  72.     {
  73.         MessageBox(NULL,"Error en la creacion de la ventana","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  74.     }
  75.     else
  76.     {
  77.         glClearColor(0.5f,0.5f,0.5f,0.5f);
  78.         while(myVentana.Ciclo_Mensaje()==false)
  79.         {
  80.             glLoadIdentity();
  81.             gluLookAt(0.0f,0.0f,19.0f,   0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
  82.             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  83.             SwapBuffers(myVentana.hdc);
  84.         }
  85.     }
  86. }
  87. */

ventana.cpp

C++:
  1. #include "ventana.h"
  2.  
  3.  
  4.  
  5. LRESULT CALLBACK CVentana::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  6. {
  7.     CVentana* pParent;
  8.  
  9.    // Get pointer to window
  10.    if(uMsg == WM_CREATE)
  11.    {
  12.       pParent = (CVentana*)((LPCREATESTRUCT)lParam)->lpCreateParams;
  13.       SetWindowLongPtr(hWnd,GWL_USERDATA,(LONG_PTR)pParent);
  14.    }
  15.    else
  16.    {
  17.       pParent = (CVentana*)GetWindowLongPtr(hWnd,GWL_USERDATA);
  18.       if(!pParent) return DefWindowProc(hWnd,uMsg,wParam,lParam);
  19.    }
  20.  
  21.    pParent->hwnd = hWnd;
  22.    return pParent->WndProc(uMsg,wParam,lParam);
  23. }
  24.  
  25. LRESULT CVentana::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  26. {
  27.     switch (uMsg)                  // Evalua los mensajes entrantes
  28.     {
  29.         case WM_SYSCOMMAND:       // Intercepta comandos del sistema
  30.         {
  31.             switch (wParam)       // Verifica el mensaje
  32.             {
  33.                 case SC_SCREENSAVE:     // screensaver intentando aparecer
  34.                 case SC_MONITORPOWER:            // Monitor entrando a modo bajo consumo energia
  35.                 return 0;                     // evitar que ocurra
  36.             }
  37.             break;                  // salir
  38.         }
  39.  
  40.         case WM_CLOSE:                // Un mensaje de salida
  41.         {
  42.         PostQuitMessage(0);               // Enviando un mensaje de salida
  43. //      destruir_ventana();             
  44.            return 0;               
  45.         }
  46.     }
  47.  
  48.     return DefWindowProc(hwnd,uMsg,wParam,lParam)//Interprete por defecto de windows;
  49. }
  50.  
  51. int CVentana::Crear_Ventana(int _ancho,int _alto,int pos_x,int pos_y,bool _fullscreen,int profundidad_color)
  52. {
  53.     if(estado == INACTIVO)
  54.     {
  55.         DWORD dwExStyle;
  56.         DWORD dwStyle;
  57.         RECT  window_rect;
  58.         GLuint PixelFormat;
  59.    
  60.         fullscreen=_fullscreen;
  61.         ancho=_ancho;   //Se copia el alto y el ancho para mantenerlo como variables globales
  62.         alto=_alto;     //alto
  63.    
  64.      window_rect.left=(long)0;       
  65.         window_rect.right=(long)ancho;  //Se inicializa el rect_angulo de la ventana 
  66.         window_rect.top=(long)0;       
  67.         window_rect.bottom=(long)alto; 
  68.       
  69.         
  70.         hinstance = GetModuleHandle(NULL);
  71.         
  72.         wnd.style          =CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 
  73.         wnd.lpfnWndProc    = (WNDPROC) StaticWndProc;   //El principal reto de la clase, incluir el wndProc dentro de la clase
  74.         wnd.cbClsExtra     =0;
  75.         wnd.cbWndExtra     =0;
  76.         wnd.hInstance      =hinstance;
  77.         wnd.hIcon          =LoadIcon(NULL,IDI_WINLOGO);
  78.         wnd.hCursor        =LoadCursor(NULL,IDC_ARROW);
  79.         wnd.hbrBackground  =NULL;
  80.         wnd.lpszMenuName   =NULL;
  81.         wnd.lpszClassName  ="pick";
  82.         
  83.         if(!RegisterClass(&wnd)) //Se registra la clase y se verifican ESTADO_ERRORes
  84.         {
  85.             MessageBox(NULL,"Falla al registrar la clase de la ventana.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  86.             estado=ESTADO_ERROR;
  87.             return estado;
  88.         }
  89.         
  90.         if(fullscreen) //se verifica el parametro fullscreen y se ajustan los parametros
  91.         {
  92.             DEVMODE dmScreenSettings;                        
  93.             memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
  94.             dmScreenSettings.dmSize=sizeof(dmScreenSettings);      
  95.             dmScreenSettings.dmPelsWidth    = ancho;               
  96.             dmScreenSettings.dmPelsHeight   = alto;           
  97.             dmScreenSettings.dmBitsPerPel   = profundidad_color;            
  98.             dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
  99.    
  100.             if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)//se pide el cambio a fullscreen y se verifica ESTADO_ERRORes
  101.             {
  102.                 if (MessageBox(NULL,"El modo No es soportado por la tarjeta | opengl, pasar a modo window?","Ventana gl",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
  103.                 {
  104.                     fullscreen=FALSE;      
  105.                 }
  106.                 else
  107.                 {
  108.                     MessageBox(NULL,"El programa se cerrará.","ESTADO_ERROR",MB_OK|MB_ICONSTOP); //no se pudo cambiar el modo grafico a pantalla completa
  109.                     estado=ESTADO_ERROR;
  110.                     return estado;
  111.                 }
  112.             }
  113.         }   
  114.         if(fullscreen)//si el parametro fullscreen sigue siendo true
  115.         {
  116.             dwExStyle=WS_EX_APPWINDOW;
  117.             dwStyle=WS_POPUP;
  118.             pos_x=0;
  119.             pos_y=0;
  120.             ShowCursor(FALSE);
  121.         }
  122.         else  // si no se solicita una ventana en modo normal
  123.         {
  124.             dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  125.             dwStyle=WS_OVERLAPPEDWINDOW;
  126.         }
  127.         AdjustWindowRectEx(&window_rect, dwStyle, FALSE, dwExStyle); //se ajusta el tamaño y estilo del borde 
  128.         
  129.         if (!(hwnd=CreateWindowEx(  dwExStyle,                     //Funcion de creacion de la ventana con verificacion de ESTADO_ERROR               
  130.                                     "pick",     
  131.                                     "pick",     
  132.                                     dwStyle |                     
  133.                                     WS_CLIPSIBLINGS |               
  134.                                     WS_CLIPCHILDREN,                   
  135.                                     pos_x, pos_y,                  
  136.                                     window_rect.right-window_rect.left
  137.                                     window_rect.bottom-window_rect.top
  138.                                     NULL,                        
  139.                                     NULL,                        
  140.                                     hinstance,             
  141.                                     this))) //Este NULL cambiarlo por this AHORA       
  142.         {
  143.             Destruir_Ventana();   //Si fallo se destruye la ventana y se muestra mensaje de ESTADO_ERROR                                         
  144.             MessageBox(NULL,"ESTADO_ERROR de creacion de la ventana.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  145.             estado=ESTADO_ERROR;
  146.             return estado;
  147.         }
  148.        
  149.         static  PIXELFORMATDESCRIPTOR pfd=     //se eligen los parametros del pixel format descriptor   
  150.         {
  151.             sizeof(PIXELFORMATDESCRIPTOR),       
  152.             1,                     
  153.             PFD_DRAW_TO_WINDOW |                       
  154.             PFD_SUPPORT_OPENGL |                //creacion de una ventana doble buffer, rgba, con el       
  155.             PFD_DOUBLEBUFFER,               //parametro profundidad_color que recibe la funcion       
  156.             PFD_TYPE_RGBA,            //se solicita compatible con gl,etc,etc      
  157.             profundidad_color,             
  158.             0, 0, 0, 0, 0, 0,                     
  159.             0,                     
  160.             0,                     
  161.             0,                     
  162.             0, 0, 0, 0,         
  163.             16,         //profundidad del buffer stencil  
  164.             0,                     
  165.             0,                     
  166.             PFD_MAIN_PLANE,        
  167.             0,                     
  168.             0, 0, 0          
  169.         };
  170.        
  171.         if (!(hdc=GetDC(hwnd))) //se solicita un dc para la ventana         
  172.         {
  173.             this->Destruir_Ventana();         //si falla mensaje de ESTADO_ERROR y destruye la ventana         
  174.             MessageBox(NULL,"No se pudo crear un contexto gl.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  175.             estado=ESTADO_ERROR;
  176.             return estado;
  177.         }
  178.    
  179.         if (!(PixelFormat=ChoosePixelFormat(hdc,&pfd))) //se solicitan los parametros para el dc con el pdf
  180.         {
  181.             this->Destruir_Ventana();                  //si falla mensaje de ESTADO_ERROR y destruye la ventana
  182.             MessageBox(NULL,"No se pudo encontrar el formato de pixeles.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  183.             estado=ESTADO_ERROR;
  184.             return estado;
  185.         }
  186.    
  187.         if(!SetPixelFormat(hdc,PixelFormat,&pfd))      //se establecen los parametros para el dc
  188.         {
  189.             this->Destruir_Ventana();            //si falla mensaje de ESTADO_ERROR y destruye la ventana      
  190.             MessageBox(NULL,"No se pudo establecer el formato de pixeles.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  191.             estado=ESTADO_ERROR;
  192.             return estado;
  193.         }
  194.    
  195.         if (!(hrc=wglCreateContext(hdc)))              //creacion del contexto de Opengl contenido en el hglrc hrc 
  196.         {
  197.             this->Destruir_Ventana();                  //si falla mensaje de ESTADO_ERROR y destruye la ventana
  198.             MessageBox(NULL,"No se pudo establecer un contexto gl.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  199.             estado=ESTADO_ERROR;
  200.             return estado;
  201.         }
  202.    
  203.         if(!wglMakeCurrent(hdc,hrc))                    //Se trata de activar el contexto gl hrc
  204.         {
  205.             this->Destruir_Ventana();                        //si falla mensaje de ESTADO_ERROR y destruye la ventana
  206.             MessageBox(NULL,"No se pudo activar el contexto gl.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  207.             estado=ESTADO_ERROR;
  208.             return estado;         
  209.         }
  210.    
  211.         ShowWindow(hwnd,SW_SHOW);         //se muestra la ventana ya creada
  212.         SetForegroundWindow(hwnd);     
  213.         SetFocus(hwnd);      //se pide foco del usuario sobre la ventana
  214.        
  215.         estado=ACTIVO;  // Se concluyo exitosamente la creacion de la ventana
  216.        
  217.         Cambiar_Tamano_GL(ancho,alto);      //se ajusta el hrc de gl a la ventana
  218.    
  219.         if (!Inicializar_GL())                  // Inicializacion de opengl
  220.         {
  221.             this->Destruir_Ventana();                        //si falla mensaje de ESTADO_ERROR y destruye la ventana
  222.             MessageBox(NULL,"Inicializacion fallida.","ESTADO_ERROR",MB_OK|MB_ICONEXCLAMATION);
  223.             estado=ESTADO_ERROR;
  224.             return estado;           
  225.         }
  226.     }
  227.     return estado;
  228.  
  229. }
  230.  
  231.  
  232.  
  233. void CVentana::Cambiar_Tamano_GL(GLsizei ancho, GLsizei alto)   //funcion que cambia el viewport de gl segun ancho,alto
  234. {
  235.     if(estado == ACTIVO)
  236.     {
  237.         if (alto==0)                                   
  238.         {
  239.             alto=1;          
  240.         }
  241.         glViewport(0,0,ancho,alto);   
  242.         glMatrixMode(GL_PROJECTION);
  243.         glLoadIdentity();         
  244.         gluPerspective(45.0f,(GLfloat)ancho/(GLfloat)alto,0.1f,100.0f);
  245.         glMatrixMode(GL_MODELVIEW);       
  246.         glLoadIdentity();                           
  247.     }
  248. }
  249.  
  250. bool CVentana::Inicializar_GL(GLvoid)         //Funcion de inicializacion de Opengl interna de la libreria, para propositos mas especificos, cambiar los parametros por fuera de esta funcion                   
  251. {
  252.  
  253.         glShadeModel(GL_SMOOTH);                           
  254.         glClearColor(0.0f, 0.0f, 0.0f, 0.5f);            
  255.         glClearDepth(1.0f);         
  256.         glEnable(GL_DEPTH_TEST);                           
  257.         glDepthFunc(GL_LEQUAL);        
  258.         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  259.         return TRUE;                                   
  260.  
  261. }
  262.  
  263.  
  264.  
  265. //Funcion de Destruccion de ventana y liberacion de recursos
  266. void CVentana::Destruir_Ventana(void)                        
  267. {
  268.     if(estado== ACTIVO)
  269.     {
  270.         if (fullscreen)          // Esta la ventana en modo fullscreen
  271.         {
  272.             ChangeDisplaySettings(NULL,0);          // Se regresa al modo normal de Windows
  273.             ShowCursor(TRUE);                        // Se muestra el puntero del mouse
  274.         }
  275.  
  276.         if (hrc)                                            // Si se establecio un  contexto de render
  277.         {   
  278.             if (!wglMakeCurrent(NULL,NULL))     // Se hace "actual"
  279.             {
  280.                 MessageBox(NULL,"Liberacion de rc y dc fallo.","SHUTDOWN ESTADO_ERROR",MB_OK | MB_ICONINFORMATION);
  281.                 estado=ESTADO_ERROR;
  282.             }
  283.