无法创建子窗口,句柄无效

时间:2019-07-15 21:21:04

标签: c++ winapi

我想用OpenGL在单个窗口中查看图形并能够插入按钮。
例如:屏幕按钮的一半,另一半-图形。
创建子窗口,但在CreateOpenGLChildWindow()函数中创建子窗口时出现错误1400。主程序窗口已正确创建,并且hWnd(子窗口为hWndParent)正确。但是CreateWindow()函数中的CreateOpenGLChildWindow()不会创建窗口。
怎么了?

对于如此糟糕的代码和问题的解释,我深表歉意。

我的代码:

#include <Windows.h>
#include <GL/GL.h>
#include <GL/GLU.h>
#include <strsafe.h>

#pragma comment(lib, "OpenGL32.lib")

void ErrorExit(LPTSTR lpszFunction)
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)& lpMsgBuf,
        0, NULL);

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"),
        lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw);
}

HWND CreateOpenGLChildWindow(wchar_t* title, int x, int y, int width, int height,
    BYTE type, DWORD flags, HWND hWndParent)
{
    int         pf;
    HDC         hDC;
    HWND        hWnd;
    PIXELFORMATDESCRIPTOR pfd;
    //error here
    hWnd = CreateWindow(
        L"OpenGL",
        title,
        CS_OWNDC | WS_CLIPSIBLINGS,
        x,
        y,
        width,
        height,
        hWndParent,
        NULL,
        NULL,
        NULL
    );

    if (!hWnd) {
        MessageBox(NULL, L"CreateWindow() failed:  Cannot create a window.",
            L"Error", MB_OK);
        ErrorExit((LPTSTR)L"CreateWindow");
        return NULL;
    }

    hDC = GetDC(hWnd);

    /* there is no guarantee that the contents of the stack that become
       the pfd are zeroed, therefore _make sure_ to clear these bits. */
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | flags;
    pfd.iPixelType = type;
    pfd.cColorBits = 32;

    pf = ChoosePixelFormat(hDC, &pfd);
    if (pf == 0) {
        MessageBox(NULL, L"ChoosePixelFormat() failed:  "
            "Cannot find a suitable pixel format.", L"Error", MB_OK);
        return 0;
    }

    if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
        MessageBox(NULL, L"SetPixelFormat() failed:  "
            "Cannot set format specified.", L"Error", MB_OK);
        return 0;
    }

    DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    ReleaseDC(hWnd, hDC);

    return hWnd;

}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
wchar_t WinName[] = L"MainFrame";

int WINAPI WinMain(
    HINSTANCE This,
    HINSTANCE Prev,
    LPSTR cmd,
    int mode
)
{
    HDC hDC;                /* device context */
    HGLRC hRC;              /* opengl context */

    HWND hWnd;
    MSG msg;
    WNDCLASS wc;
    wc.hInstance = This;
    wc.lpszClassName = WinName;
    wc.lpfnWndProc = WndProc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = NULL;
    wc.cbWndExtra = NULL;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    if (!RegisterClass(&wc)) return NULL;
    int windowWidth = 800;
    int windowHeight = 800;
    int screenWidth = GetSystemMetrics(SM_CXSCREEN);
    int screenHeight = GetSystemMetrics(SM_CYSCREEN);
    hWnd = CreateWindow(
        WinName,
        L"Title",
        WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX,
        (screenWidth - windowWidth) / 2,
        (screenHeight - windowHeight) / 2,
        windowWidth,
        windowHeight,
        HWND_DESKTOP,
        NULL,
        This,
        NULL
    );

    if (!hWnd)
    {
        MessageBox(NULL, L"MAIN HWND ERROR!!!",
            L"Error", MB_OK);
        ErrorExit((LPTSTR)L"CreateWindow");
        exit(1);
    }

    HWND childOpenGLWindowHWND = CreateOpenGLChildWindow(
        WinName,
        0,
        0,
        600,
        800,
        NULL,
        NULL,
        hWnd
    );

    if (!childOpenGLWindowHWND)
        MessageBox(NULL, L"Child window init error", L"Error", MB_OK);

    hDC = GetDC(hWnd);
    hRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, hRC);

    SendMessage(hWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS), NULL);
    ShowWindow(hWnd, mode);
    while (GetMessage(&msg, NULL, NULL, NULL))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    wglMakeCurrent(NULL, NULL);
    ReleaseDC(hWnd, hDC);
    wglDeleteContext(hRC);
    DestroyWindow(hWnd);

    return msg.wParam;

    //return NULL;
}

void display()
{
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();
}

LRESULT CALLBACK WndProc(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam
)
{

    PAINTSTRUCT ps;

    switch (message)
    {
    case WM_PAINT:
        display();
        BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(NULL);
        break;
    default: return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return NULL;
}

1 个答案:

答案 0 :(得分:3)

GetLastError()中的CreateWindow()之后立即呼叫CreateOpenGLChildWindow()。您将收到错误1407(ERROR_CANNOT_FIND_WND_CLASS)。

hWnd = CreateWindow(
    L"OpenGL",
    title,
    CS_OWNDC | WS_CLIPSIBLINGS,
    x,
    y,
    width,
    height,
    hWndParent,
    NULL,
    NULL,
    NULL
);

if (!hWnd) {
    DWORD dw = GetLastError();//error code: 1407
    MessageBox(NULL, L"CreateWindow() failed:  Cannot create a window.",
        L"Error", MB_OK);
    ErrorExit((LPTSTR)L"CreateWindow");
    return NULL;
}

这表示类名L"OpenGL"未注册。您需要像注册主窗口一样注册子窗口类。

CS_OWNDC是类样式,而不是窗口样式。 To assign a style to a window class, assign the style to the style member of the WNDCLASSEX structure

创建子窗口时,您需要添加WS_CHILD样式。