草庐IT

c++ - CreateWindowEx 失败

coder 2024-02-24 原文

我正在学习 NeHe gamedev 教程(同时将它们更改为面向对象),但我遇到了 CreateWindowEx 演示 (http://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)/13001) 的问题/).

我试图通过 lpParam 向 WndProc 传递指向我的 Window 对象的指针(详见此处:http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/),但如果我尝试这样做,CreateWindowEx 将失败,GetLastError 返回 1400 - ERROR_INVALID_WINDOW_HANDLE。

我是 Windows API 的完全初学者,已经用尽了我所知道的解决此问题的所有方法,您能在这里指出我的错误吗? 相关代码如下:

LRESULT CALLBACK cog::WindowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
    // Member method as windowproc: http://web.archive.org/web/20051125022758/www.rpi.edu/~pudeyo/articles/wndproc/

    if(msg == WM_NCCREATE) {
        LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam;
        SetWindowLong(window, GWL_USERDATA, (long)cs->lpCreateParams);
    }

    cog::Window* w = (cog::Window*)GetWindowLong(window, GWL_USERDATA);
    if(w) {
        return w->windowProc(msg, wParam, lParam);

    } else {
        return DefWindowProc(window, msg, wParam, lParam);
    }
}

cog::Window::Window(int width, int height, int bits, bool fullscreen) :
fullscreen(fullscreen), appInstance(GetModuleHandle(NULL)), active(FALSE) {

    // Generate a rectangle corresponding to the window size
    RECT winRect = {0, 0, width, height};

    WNDCLASS winClass;
     winClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;   // Redraw On Size, And Own DC For Window.
    winClass.lpfnWndProc    = (WNDPROC) cog::WindowProc;            // WndProc Handles Messages
    winClass.cbClsExtra     = 0;                                    // No Extra Window Data
    winClass.cbWndExtra     = sizeof(this);                         // Window Data - pointer to Window object
    winClass.hInstance      = this->appInstance;                    // Set The Instance
    winClass.hIcon          = LoadIcon(NULL, IDI_WINLOGO);          // Load The Default Icon
    winClass.hCursor        = LoadCursor(NULL, IDC_ARROW);          // Load The Arrow Pointer
    winClass.hbrBackground  = NULL;                                 // No Background Required For GL
    winClass.lpszMenuName   = NULL;                                 // We Don't Want A Menu
    winClass.lpszClassName  = TEXT("OpenGL");   

    if(!RegisterClass(&winClass)) {
        throw cog::WindowException(std::string("Failed to register class"));
    }

    if(this->fullscreen) {
        DEVMODE screenSettings;
        memset(&screenSettings, 0, sizeof(DEVMODE));

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

        if(DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&screenSettings, CDS_FULLSCREEN)) {
            if(MessageBox(NULL, "Cannot start in full screen mode - start in windowed mode instead?", "OpenGL", MB_YESNO | MB_ICONEXCLAMATION)) {
                this->fullscreen = FALSE;

            } else {
                throw cog::WindowException(std::string("Refused to launch program in windowed mode"));

            }
        }
    }

    DWORD winExStyle;
    DWORD winStyle;
    if(fullscreen) {
        winExStyle = WS_EX_APPWINDOW;
        winStyle = WS_POPUP;
        ShowCursor(FALSE);

    } else {
        winExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        winStyle = WS_OVERLAPPEDWINDOW;
    }

    AdjustWindowRectEx(&winRect, winStyle, FALSE, winExStyle);

    /*
     * !! BLOWS UP AT THIS CALL - WindowException triggered
     */
    if(!(this->window = CreateWindowEx(
    winExStyle,
    TEXT("OpenGL"),
    TEXT("OpenGL Testing"),
    winStyle,
    0, 0,
    winRect.right - winRect.left,
    winRect.bottom - winRect.top,
    NULL,
    NULL,
    this->appInstance,
    this))) {
        throw cog::WindowException(std::string("Failed to create window"));
    }

    // ... cut here ...
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE lPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    cog::Window* w = NULL;

    try {
        w = new cog::Window(100, 100, 16, TRUE);

        // ... cut here ...

    } catch(cog::Exception e) {
        MessageBox(NULL, e.what(), "Exception Raised", MB_OK | MB_ICONEXCLAMATION);
    }

    if(w) {
        delete w;
    }
}

成员windowProc:

LRESULT CALLBACK cog::Window::windowProc(UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
    case WM_ACTIVATE:
        if(HIWORD(wParam)) {
            this->active = FALSE;

        } else {
            this->active = TRUE;
        }

        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:
        this->keys[wParam] = TRUE;
        break;

    case WM_KEYUP:
        this->keys[wParam] = FALSE;
        break;

    case WM_SIZE:
        this->resize(LOWORD(lParam), HIWORD(lParam));
        return 0;

    default:
        break;
    }

    return DefWindowProc(this->window, msg, wParam, lParam);
}

最佳答案

您请求全屏显示是否会导致问题? w = new cog::Window(100, 100, 16, TRUE);

如果有帮助,这在我的代码库中有效:

HWND impl::window_impl::create_window_(
    window_impl* window // associated window object
) {
    auto const INSTANCE = ::GetModuleHandleW(L"");

    WNDCLASSEXW const wc = {
        sizeof(WNDCLASSEXW),
        CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
        window_impl::top_level_wnd_proc_,
        0,
        0,
        INSTANCE,
        nullptr,
        ::LoadCursorW(nullptr, MAKEINTRESOURCE(IDC_ARROW)),
        nullptr,
        nullptr,
        CLASS_NAME,
        nullptr
    };

    ::RegisterClassExW(&wc); // ignore return value

    auto const result = ::CreateWindowExW(
        0,
        CLASS_NAME,
        L"window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        (HWND)nullptr ,
        (HMENU)nullptr,
        INSTANCE,
        window
    );

    return result;
}

[编辑] 我认为您对 CreateWindowExW 的调用的参数顺序错误——特别是实例参数。您是否使用 STRICT 进行编译?它应该检测到这种问题。

[编辑] 没有直接关系,但是当编译为 64 位代码时您的实现将不起作用,并且它不会检查可能的错误——您应该使用类似的东西:

//--------------------------------------------------------------------------
//! Get the userdata for the window given by @c hwnd (our window object).
//! @throw bklib::platform::windows_exception
//--------------------------------------------------------------------------
impl::window_impl* get_window_ptr(HWND hwnd) {
    ::SetLastError(0);
    auto const result = ::GetWindowLongPtrW(hwnd, GWLP_USERDATA);

    if (result == 0) {
        auto const e = ::GetLastError();
        if (e) {
            BOOST_THROW_EXCEPTION(bklib::platform::windows_exception()
                << bklib::platform::windows_error_code(e)
            );
        }
    }

    return reinterpret_cast<impl::window_impl*>(result);
}

//--------------------------------------------------------------------------
//! Set the userdata for the window given by @c hwnd to be our
//! window object.
//! @throw bklib::platform::windows_exception
//--------------------------------------------------------------------------
void set_window_ptr(HWND hwnd, impl::window_impl* ptr) {
    ::SetLastError(0);
    auto const result = ::SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(ptr));

    if (result == 0) {
        auto const e = ::GetLastError();
        if (e) {
            BOOST_THROW_EXCEPTION(bklib::platform::windows_exception()
                << bklib::platform::windows_error_code(e)
            );
        }
    }
}

[edit] 更多代码以防有帮助

//------------------------------------------------------------------------------
//! Top level window procedure which forwards messages to the appropriate
//! impl::window_impl instance.
//! @throw noexcept
//!     Swallows all exceptions at the API boundary.
//------------------------------------------------------------------------------
LRESULT CALLBACK impl::window_impl::top_level_wnd_proc_(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) try {
    // set the instance pointer for the window given by hwnd if it was just created
    if (msg == WM_NCCREATE) {
        auto const cs =
            reinterpret_cast<CREATESTRUCTW const*>(lParam);
        auto const window_ptr =
            reinterpret_cast<window_impl*>(cs->lpCreateParams);

        set_window_ptr(hwnd, window_ptr);
    }

    // the window object to forward the message to
    auto const window = get_window_ptr(hwnd);

    if (window) {
        return window->window_proc_(hwnd, msg, wParam, lParam);
    } else {
        // it's possible we will receive some messages beofre WM_NCCREATE;
        // use the default handler
        return ::DefWindowProcW(hwnd, msg, wParam, lParam);
    }
} catch (std::exception&) {
    ::PostQuitMessage(-1);
    return 0;
} catch (...) {
    ::PostQuitMessage(-1);
    return 0;
}

//------------------------------------------------------------------------------
//! Called by the top level window proc. Dispatches messages to their
//! appropriate handler function.
//------------------------------------------------------------------------------
LRESULT impl::window_impl::window_proc_(
    HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) {
    return ::DefWindowProcW(hwnd, msg, wParam, lParam);
}

//------------------------------------------------------------------------------
void impl::window_impl::create() {
    handle_ = create_window_(this);
}

//------------------------------------------------------------------------------
void impl::window_impl::show(bool visible) {
    ::ShowWindow(handle_, SW_SHOWDEFAULT);
    ::InvalidateRect(handle_, nullptr, FALSE);
    ::UpdateWindow(handle_);
}

关于c++ - CreateWindowEx 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14026875/

有关c++ - CreateWindowEx 失败的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 即使失败也继续进行多主机测试 - 2

    我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  5. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

    我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

  8. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

  9. ruby-on-rails - Ruby 流量控制 : throw an exception, 返回 nil 还是让它失败? - 2

    我在思考流量控制的最佳实践。我应该走哪条路?1)不要检查任何东西并让程序失败(更清晰的代码,自然的错误消息):defself.fetch(feed_id)feed=Feed.find(feed_id)feed.fetchend2)通过返回nil静默失败(但是,“CleanCode”说,你永远不应该返回null):defself.fetch(feed_id)returnunlessfeed_idfeed=Feed.find(feed_id)returnunlessfeedfeed.fetchend3)抛出异常(因为不按id查找feed是异常的):defself.fetch(feed_id

  10. ruby - gem 规范失败 - 2

    我正在为毕业设计开发GEM,TravisCI构建不断失败。这是我在Travis上的链接:https://travis-ci.org/ricardobond/perpetuus/builds/8709218构建错误是:$bundleexecrakerakeaborted!Don'tknowhowtobuildtask'default'/home/travis/.rvm/gems/ruby-1.9.3-p448/bin/ruby_noexec_wrapper:14:in`eval'/home/travis/.rvm/gems/ruby-1.9.3-p448/bin/ruby_noexec_

随机推荐