简体   繁体   中英

CreateWindow() returns nullptr and GetLastError() returns 1400

Hello I have recently decided to learn graphics programming through DirectX11 and for that I'm learning how to use the Windows API. I managed to create a window by following an online tutorial and later successfully created one by myself. However, the problem starts when I tried to make a framework to create the Window, I ran into a few errors but by studying the documentation and looking up examples most of them were solved, except for one involving the CreateWindow() function.

Whenever I try to get the handle for the window it returns nullptr, I tried getting the error code through GetLastError(), but all I get is 1400, which according to MSDN is "Invalid window handle". I don't know what I'm doing wrong and I haven't found any threads that solved the issue. It compiles successfully, but no window appears.

Window.hpp

#pragma once
#include "WindowsHeader.hpp"

class Window
{
public:

    Window(int width, int height, const char* name);
    ~Window();
    Window(const Window&) = delete;
    Window& operator=(const Window&) = delete;

private:

    class WindowClass
    {
    public:

        static const char* GetName() noexcept;
        static HINSTANCE GetInstance() noexcept;

    private:

        WindowClass() noexcept;
        ~WindowClass();
        WindowClass(const WindowClass&) = delete;
        WindowClass& operator=(const WindowClass&) = delete;

        static constexpr const char* window_class_name{ "HardwareAccelerated3D" };
        static WindowClass window_class;
        HINSTANCE hinst;
    };

    static LRESULT CALLBACK HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;
    static LRESULT CALLBACK HandleMsgInvoke(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;
    LRESULT HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept;

    int width;
    int height;
    HWND hwnd;
};

Window.cpp

#include "Window.hpp"
#include <sstream>

//Window Class

Window::WindowClass Window::WindowClass::window_class;

Window::WindowClass::WindowClass() noexcept
    : hinst(GetModuleHandle(NULL))
{
    WNDCLASSEX window_class{ {0} };
    window_class.cbSize = sizeof(window_class);
    window_class.style = CS_OWNDC;
    window_class.lpfnWndProc = &HandleMsgSetup;
    window_class.cbClsExtra = NULL;
    window_class.cbWndExtra = NULL;
    window_class.hInstance = GetInstance();
    window_class.hIcon = NULL;
    window_class.hCursor = NULL;
    window_class.hbrBackground = NULL;
    window_class.lpszMenuName = NULL;
    window_class.lpszClassName = GetName();
    window_class.hIconSm = NULL;
    RegisterClassEx(&window_class);
}

Window::WindowClass::~WindowClass()
{
    UnregisterClass(GetName(), GetInstance());
}

const char* Window::WindowClass::GetName() noexcept
{
    return window_class_name;
}

HINSTANCE Window::WindowClass::GetInstance() noexcept
{
    return window_class.hinst;
}

//Window

Window::Window(int width, int height, const char* name)
    : width(width), height(height)
{
    RECT wndrec;
    wndrec.left = 100;
    wndrec.right = wndrec.left + width;
    wndrec.top = 100;
    wndrec.bottom = wndrec.top + height;
    if (!AdjustWindowRect(&wndrec, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, false))
    {
        std::ostringstream oss;
        oss << GetLastError();
        OutputDebugString(oss.str().c_str());
    }

    hwnd = CreateWindow(WindowClass::GetName(), name, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, wndrec.right - wndrec.left, wndrec.bottom - wndrec.top, NULL,
        NULL, WindowClass::GetInstance(), this);

    if (!hwnd)
    {
        std::ostringstream oss;
        oss << GetLastError();
        OutputDebugString(oss.str().c_str());
    }

    ShowWindow(hwnd, SW_SHOWDEFAULT);
}

Window::~Window()
{
    DestroyWindow(hwnd);
}

LRESULT WINAPI Window::HandleMsgSetup(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
    if (msg == WM_NCCREATE)
    {
        const CREATESTRUCTW* const pcreate = reinterpret_cast<CREATESTRUCTW*>(lparam);
        Window* const pwnd = static_cast<Window*>(pcreate->lpCreateParams);
        SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pwnd));
        SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&Window::HandleMsgInvoke));
        return pwnd->HandleMsg(hwnd, msg, wparam, lparam);
    }
    return DefWindowProc(hwnd, msg, wparam, lparam);
}

LRESULT WINAPI Window::HandleMsgInvoke(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
    Window* const pwnd = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
    return pwnd->HandleMsg(hwnd, msg, wparam, lparam);
}

LRESULT Window::HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
    switch (msg)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wparam, lparam);
}

WinMain.cpp

#include "WindowsMessageMap.hpp"
#include "Window.hpp"

int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
    Window window(640, 480, "HardwareAccelerated3D");

    MSG msg;
    BOOL gresult;
    while (gresult = GetMessage(&msg, NULL, NULL, NULL) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if (gresult == -1)
        return -1;
    return msg.wParam;
}

WindowsHeader.hpp is just a few defines and Windows.h to avoid some windows macros, and WindowsMessageMap.hpp just prints windows messages to the debug console (I use it to see what messages are being called).

PS: this is my first post here, so feel free to point out any issues with the post itself, so that I can be more clear next time.

Thanks in advance! :-)

The hwnd you used in the code is the same as it in Window.hpp :

LRESULT Window::HandleMsg(HWND, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
    switch (msg)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wparam, lparam);
}

The last line of Window.hpp:

HWND hwnd;

When you call HandleMsg , hwnd of Window.hpp is not initialized:

在此处输入图片说明

You may use hwnd in HandleMsgSetup , just add the hwnd param like the following code:

LRESULT Window::HandleMsg(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
    switch (msg)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wparam, lparam);
}

And it works for me:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM