Its easier to read if you download this file https://dl.dropboxusercontent.com/u/13278359/Making%20a%20gl%20window%20in%20Windows%20that%20is%20DLL%20Friendly.rtf
This is actually fairly easy and this technique also allows the creation of a window from a dll or just using the standard c++ main() entry functions. (make sure your projects are set to use console)
The main thing WinMain is used for is to get the hInstance, and hPrevInstance, and show Command. So without it hInstance is still very easy to get you simply use HINSTANCE hInstance=getModuleHandle(). hPrevInstance, by microsofts own admission, is always null. I do not at this time know how to get int nCmdShow so I will use SW_SHOWNORMAL
You will need to include <windows.h>, <gl/gl.h> (you may not need this), and <wglext.h>
First we need to create a windows class. Theres cool tricks you can use if you use extended windows classes but we won’t be doing anything fancy here.
<code>
WNDCLASSEX wClass={};//makes sure parameters we don’t use are NULL
wClass.cbSize=sizeof(WNDCLASSEX);//would be different if we used extra info in the extended part
wClass.style=CS_HREDRAW|CS_VREDRAW;//tells windows we want horizantal and vertical redraw
wClass.lpfnWndProc=WindowProc;//the function you want to handle windows messages
wClass.cbClsExtra=0;//forget what this is for
wClass.cbWndExtra=0;//forget what this is for
wClass.hInstance=hInstance;//that instance we just got
wClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);//custom icon
wClass.hCursor=LoadCursor(NULL, IDC_ARROW); //custom cursor
wClass.lpszMenuName=NULL; //we aren’t using a menu
wClass.lpszClassName=”WindowClass1”;//name of the class to use later during window creation, make sure it is unique
wClass.hIconSm=LoadIcon(NULL, IDI_WINLOGO);//you can use a custom icon for your window here
Next we need to register the class
if(!RegisterClassEx(&wClass))
{
//handle the error here if the class was not successfully registered
}
This lets Windows know about our window structure. Now we create the window.
HWNDcwnd=CreateWindowEx(
NULL,//the extended style sometimes if used messes stuff up just be careful
“WindowClass1”, //The name of the registered class
“I’m a window”, //The window name and also what shows up in the title bar first
WS_OVERLAPPEDWINDOW, //The style used for the window there are other settings here for fullscreen
CW_USEDEFAULT, CW_USEDEFAULT, //this is the x,y position of the window. I set it to default
dispParams->sx, dispParams->sy, //the width, height of the window
NULL, //this is the parent window
NULL, //this is the menu
hInstance, //the program instance
NULL//used to pass an lparam on msg WM_CREATE
);
if(cwnd==NULL)
{
//handle the error here if the window was not successfully created
}
ShowWindow(cwnd, SW_SHOWNORMAL);//display the window on the screen
UpdateWindow(cwnd);//force update it to make sure everything is set up
[/code]
Before I go into the creating of the gl Context let me list the setPixelFormat funtion I used.
bool setPixelFormat(HDC hDC, DisplaySettings dispParam)
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), / size /
1, / version /
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER, / support double-buffering /
PFD_TYPE_RGBA, / color type /
32, / prefered color depth /
0, 0, 0, 0, 0, 0, / color bits (ignored) /
0, / no alpha buffer /
0, / alpha bits (ignored) /
0, / no accumulation buffer /
0, 0, 0, 0, / accum bits (ignored) /
32, / depth buffer bits/
0, / stencil buffer bits /
0, / no auxiliary buffers /
PFD_MAIN_PLANE, / main layer /
0, / reserved /
0, 0, 0, / no layer, visible, damage masks/
};
int pixelFormat = ChoosePixelFormat(*hDC, &pfd);
if (pixelFormat==0)
{
returnfalse;
}
if(!SetPixelFormat(*hDC, pixelFormat, &pfd))
{
returnfalse;
}
returntrue;
}
All thats left is to create a gl Context. hDC and hRC should be global variables as you need to delete them later.
hDC=GetDC(cwnd);//gets the device context of the window (the draw surface)
if(hDC==NULL)
{
//error did not get a device context
}
if(!setPixelFormat(&hDC, dispParam))
{
//error was not able to set desired pixel format
}
hRC=wglCreateContext(hDC);//create a gl rendering context this is raw gl 1.1
//but we need it to get the context for more advanced gl
if(hRC==NULL)
{
//error did not get a gl rendering context
}
wglMakeCurrent(hDC, hRC);//attatch the rendering surface to the draw surface
PFNWGLCREATECONTEXTATTRIBSARBPROCwglCreateContextAttribsARB=(PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress(“wglCreateContextAttribsARB”);//get the function used to create higher version contexts
if(!wglCreateContextAttribsARB)
{
//error no such function
}
//gl v3.2 major=3 minor=2
int glAttribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 1,//the major gl version
WGL_CONTEXT_MINOR_VERSION_ARB, 0,//the minor gl version
WGL_CONTEXT_FLAGS_ARB, 0,//this can be used to make a forward compatible context and to set it to debug mode though 0 is normal operation
0};//0 to tell wglCreateContextAttribsARB this is the end
hRC3=NULL;//just make sure its null (may not be needed)
hRC3=wglCreateContextAttribsARB(hDC, 0, glAttribs);//creates the gl rendering context with the attributes we set.
if(hRC3==NULL)
{
//error either version is unsupported or did not get the rendering context
}
wglDeleteContext(hRC);//delete the 1.1 context
wglMakeCurrent(hDC, hRC3);//attatch the new rendering context to the draw context
For continual updating you’ll need a window proc my current bare bones one is listed below
LRESULTCALLBACK WindowProc(HWNDhwnd, UINTmsg, WPARAMwParam, LPARAMlParam)
{
caseWM_KEYDOWN:
if (wParam!=VK_ESCAPE)//allows user to close prgram by pressing esc
{
break;
}
caseWM_DESTROY:
wglMakeCurrent(hDC, NULL);//unlink the contexts
wglDeleteContext(hRC3);//delete the gl Rendering Context
PostQuitMessage(0);//close program
break;
caseWM_SIZE://sets gl up to use the new window size
screenWidth=(int) LOWORD(lParam);
screenHeight=(int) HIWORD(lParam);
glViewport(0, 0, (int) LOWORD(lParam), (int) HIWORD(lParam));
break;
default:
returnDefWindowProc( hwnd, msg, wParam, lParam );
}
return 0;
}
You’ll also need this code called somewhere in your main loop
SwapBuffers(hDC);//switches to the buffer you drew on
MSG cmsg;
while(PeekMessage(&cmsg, 0,NULL,NULL, PM_REMOVE ))
{
TranslateMessage(&cmsg);
DispatchMessage(&cmsg);
}
If you ever want to get rid of the console add this line
#pragmacomment(linker, “/SUBSYSTEM:windows /ENTRY:mainCRTStartup”)
And thats it I did adapt this code somewhat from what I have so if something doesn’t work let me know. Cheers :)










0 comments