C++ / OpenGL | "undefined reference to `_imp__ChoosePixelFormat@8`" 等

C++ / OpenGL | "undefined reference to `_imp__ChoosePixelFormat@8`" and more

我正在阅读 NeHe 的第一本 OpenGL 编程指南,当涉及到编译完成他的第一个教程的结果时,我发现自始至终都有错误。这是发生错误的整个源文件(Created in Eclipse CDT with 'opengl32' 'glaux' 'glut32' 'glu32' linked successfully):

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#define GLEW_STATIC

HGLRC hRC = NULL;
HDC hDC = NULL;
HWND hWnd = NULL;
HINSTANCE hInstance;

bool keys[256];
bool active = TRUE;
bool fullscreen = TRUE;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

GLvoid ResizeGLScene(GLsizei width, GLsizei height)
{
    if(height == 0) height = 1;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int InitGL()
{
    glShadeModel(GL_SMOOTH);
    glClearColor(0, 0, 0, 0);
    glClearDepth(1);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    return TRUE;
}

int DrawGLScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    return TRUE;
}

void KillGLWindow()
{
    if(fullscreen)
    {
        ChangeDisplaySettings(NULL, 0);
        ShowCursor(TRUE);
    }

    if(hRC)
    {
        if(!wglMakeCurrent(NULL, NULL))
        {
            MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
        }

        if(!wglDeleteContext(hRC))
        {
            MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
        }

        hRC = NULL;
    }

    if(hDC && !ReleaseDC(hWnd, hDC))
    {
        MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

        hDC = NULL;
    }

    if(hWnd && !DestroyWindow(hWnd))
    {
        MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

        hWnd = NULL;
    }

    if(!UnregisterClass("OpenGL", hInstance))
    {
        MessageBox(NULL, "Could not unregister class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

        hInstance = NULL;
    }
}

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenFlag)
{
    GLuint pixelFormat;
    WNDCLASS wc;
    DWORD dwExStyle;
    DWORD dwStyle;
    RECT windowRect;

    windowRect.left = 0;
    windowRect.right = width;
    windowRect.top = 0;
    windowRect.bottom = height;

    fullscreen = fullscreenFlag;
    hInstance = GetModuleHandle(NULL);

    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "OpenGL";

    if(!RegisterClass(&wc))
    {
        MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    if(fullscreen)
    {
        DEVMODE dmScreenSettings;

        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));

        dmScreenSettings.dmSize = sizeof(dmScreenSettings);
        dmScreenSettings.dmPelsWidth = width;
        dmScreenSettings.dmPelsHeight = height;
        dmScreenSettings.dmBitsPerPel = bits;
        dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
        {
            if(MessageBox(NULL, "The requested fullscreen mode is not supported by\nyour video card.  Use windowed mode instead?", "OpenGL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
            {
                fullscreen = FALSE;
            }
            else
            {
                MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);

                return FALSE;
            }
        }
    }

    if(fullscreen)
    {
        dwExStyle = WS_EX_APPWINDOW;
        dwStyle = WS_POPUP;

        ShowCursor(FALSE);
    }
    else
    {
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        dwStyle = WS_OVERLAPPEDWINDOW;
    }

    AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);

    if(!(hWnd = CreateWindowEx(dwExStyle,
            "OpenGL",
            title,
            WS_CLIPSIBLINGS |
            WS_CLIPCHILDREN |
            dwStyle,
            0,
            0,
            windowRect.right - windowRect.left,
            windowRect.bottom - windowRect.top,
            NULL,
            NULL,
            hInstance,
            NULL)))
        {
            KillGLWindow();

            MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONINFORMATION);

            return FALSE;
        }

    static PIXELFORMATDESCRIPTOR pfd =
    {
            sizeof(PIXELFORMATDESCRIPTOR),
            1,
            PFD_DRAW_TO_BITMAP |
            PFD_SUPPORT_OPENGL |
            PFD_DOUBLEBUFFER,
            PFD_TYPE_RGBA,
            bits,
            0, 0, 0, 0, 0, 0,
            0,
            0,
            0,
            0, 0, 0, 0,
            16,
            0,
            0,
            PFD_MAIN_PLANE,
            0,
            0, 0, 0
    };

    if(!(hDC = GetDC(hWnd)))
    {
        KillGLWindow();

        MessageBox(NULL, "Cannot create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    if(!(pixelFormat = ChoosePixelFormat(hDC, &pfd)))
    {

        ChoosePixelFormat(hDC, &pfd);
        KillGLWindow();

        MessageBox(NULL, "Cannot find a suitable pixel format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    if(!SetPixelFormat(hDC, pixelFormat, &pfd))
    {
        KillGLWindow();

        MessageBox(NULL, "Cannot set the pixel format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    if(!(hRC = wglCreateContext(hDC)))
    {
        KillGLWindow();

        MessageBox(NULL, "Cannot create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    if(!wglMakeCurrent(hDC, hRC))
    {
        KillGLWindow();

        MessageBox(NULL, "Cannot activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    ShowWindow(hWnd, SW_SHOW);
    SetForegroundWindow(hWnd);
    SetFocus(hWnd);
    ResizeGLScene(width, height);

    if(!InitGL())
    {
        KillGLWindow();

        MessageBox(NULL, "Initialization failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);

        return FALSE;
    }

    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_ACTIVATE:
        {
            if(!HIWORD(wParam))
            {
                active = TRUE;
            }
            else
            {
                active = FALSE;
            }

            return 0;
        }


        case WM_SYSCOMMAND:
        {
            switch(wParam)
            {
                case SC_SCREENSAVE:
                case SC_MONITORPOWER:

                return 0;
            }

            break;
        }

        case WM_CLOSE:
        {
            PostQuitMessage(0);

            return 0;
        }

        case WM_KEYDOWN:
        {
            keys[wParam] = TRUE;

            return 0;
        }

        case WM_KEYUP:
        {
            keys[wParam] = FALSE;

            return 0;
        }

        case WM_SIZE:
        {
            ResizeGLScene(LOWORD(lParam), HIWORD(lParam));

            return 0;
        }
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL done = FALSE;

    if(MessageBox(NULL, "Would you like to run in fullscreen mode?", "Start Fullscreen", MB_YESNO | MB_ICONQUESTION) == IDNO)
    {
        fullscreen = false;
    }

    if(!CreateGLWindow("OpenGL", 640, 480, 16, fullscreen))
    {
        return 0;
    }

    while(!done)
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if(msg.message == WM_QUIT)
            {
                done = TRUE;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        else
        {
            if(active)
            {
                if(keys[VK_ESCAPE])
                {
                    done = TRUE;
                }
                else
                {
                    DrawGLScene();
                    SwapBuffers(hDC);
                }
            }

            if(keys[VK_F1])
            {
                keys[VK_F1] = FALSE;
                KillGLWindow();

                fullscreen = !fullscreen;

                if(!CreateGLWindow("OpenGL", 640, 480, 16, fullscreen))
                {
                    return 0;
                }
            }
        }
    }

    KillGLWindow();

    return msg.wParam;
}

...这是生成的编译结果(添加了 MinGW、opengl、glut、glaux):

03:52:04 **** Incremental Build of configuration Debug for project GL ****
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\Main.o" "..\src\Main.cpp" 
..\src\Main.cpp: In function 'BOOL CreateGLWindow(char*, int, int, int, bool)':
..\src\Main.cpp:216:2: warning: narrowing conversion of 'bits' from 'int' to 'BYTE {aka unsigned char}' inside { } is ill-formed in C++11 [-Wnarrowing]
  };
  ^
..\src\Main.cpp: In function 'int WinMain(HINSTANCE, HINSTANCE, LPSTR, int)':
..\src\Main.cpp:356:55: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
  if(!CreateGLWindow("OpenGL", 640, 480, 16, fullscreen))
                                                       ^
..\src\Main.cpp:397:58: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
     if(!CreateGLWindow("OpenGL", 640, 480, 16, fullscreen))
                                                          ^
g++ -o GL.exe "src\Main.o" -lopengl32 -lglaux -lglaux -lglu32 -lfreeglut 
src\Main.o: In function `Z14CreateGLWindowPciiib':
C:\Users\Michael\Desktop\LiTHiA\C++\GL\Debug/../src/Main.cpp:227: undefined reference to `_imp__ChoosePixelFormat@8'
C:\Users\Michael\Desktop\LiTHiA\C++\GL\Debug/../src/Main.cpp:230: undefined reference to `_imp__ChoosePixelFormat@8'
C:\Users\Michael\Desktop\LiTHiA\C++\GL\Debug/../src/Main.cpp:238: undefined reference to `_imp__SetPixelFormat@12'
src\Main.o: In function `WinMain@16':
C:\Users\Michael\Desktop\LiTHiA\C++\GL\Debug/../src/Main.cpp:386: undefined reference to `_imp__SwapBuffers@4'
collect2.exe: error: ld returned 1 exit status

03:52:05 Build Finished (took 1s.598ms)

很抱歉代码太长了。任何帮助/建议?任何赞赏。提前致谢。

Link 针对 gdi32(即将 -lgdi32 添加到链接器命令行)。该库定义了函数 ChoosePixelFormatSetPixelFormatSwapBuffers,它们在链接器错误消息中被报告为未定义的引用。