【问题标题】:Class already exists类已经存在
【发布时间】:2016-05-13 13:30:31
【问题描述】:

在我的项目中,我有 2 个类:“Window”和“Context”。 'Window' 类使用 WinAPI 实例化一个 Window 并且一切正常。 例如。此代码按预期工作:

Window win("Hello,", 600, 400);
Window win2("World!", 600, 400);

“上下文”类创建一个 OpenGL 4.0 上下文。为了做到这一点, 它需要创建一个临时窗口和一个临时上下文来检索所有 OpenGL 4.0 指针,而这反过来又需要创建一个 OpenGL 4.0 上下文。 例如。这段代码也可以:

Window win("Context", 600, 400);
Context ctx(win);

一切正常。

但是,我正在重构代码。由于一个窗口只能有一个上下文,我决定,窗口应该管理上下文,因此它应该实例化并自己删除它。但这会导致我出现奇怪的错误。

// Constructor of window
// We're at the end of the constructor
if(true == bOWnContext)
    pContext = internal::Context(*this);
}; // Constructor ends here

执行应用程序时出现异常/错误:“类已注册。” 这很奇怪,因为以下代码对我有用:

Window winA(...);
Window winB(...);
// or
Context ctx(winA);
// This works like a charm

有同事建议,我应该只注册一次窗口类, 所以我在构造函数中尝试了以下内容:

    static bool bRegistered = false;
    if(false == bRegistered){
    WNDCLASSEX  wc      = {};
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.hInstance        = GetModuleHandle(nullptr);
    wc.lpfnWndProc      = internal::WndProc;
    wc.lpszClassName    = pTitle;
    wc.style            = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;

    if(0 == RegisterClassEx(&wc)){
        //
        //  The exception class will contain the error code and
        //  a error discription.
        //
        std::error_code err_code(GetLastError(), std::system_category());
        throw std::system_error(err_code);
    }
    bRegistered = true;
    }

但是,这给了我另一个错误“找不到窗口类”。

谁能启发我,为什么我的代码不起作用?

【问题讨论】:

  • 您的窗口类没有类名。它不能被引用。不确定您在调用 CreateWindow[Ex] 时提供的窗口类名称。只要将代码编译成 DLL,GetModuleHandle(nullptr) 也是一个等待发生的错误。无论如何,您提供的代码不是类注册失败并显示“已注册”错误消息的地方。
  • 窗口类名等于我在构造函数中提供的窗口名。现在我明白为什么会出现“找不到窗口类”错误了。 GetModuleHandle(nullptr) 有什么问题?我已经将它编译成一个 DLL 并且它可以工作。唯一失败的是,如果我在另一个窗口中创建一个新窗口。
  • 哦,你是对的,你提供了一个类名。 GetModuleHandle(nullptr) 有什么问题:它将模块句柄返回给 EXE,而不是 DLL。但实现窗口过程的是DLL。查找正确模块句柄的包罗万象的解决方案:Accessing the current module’s HINSTANCE from a static library.
  • 感谢您的提示。我现在正在使用模块的 HINSTANCE。正如链接中所建议的那样。可悲的是,这并不能解决我的问题:(
  • 先生,您之前的评论给了我一个想法,现在它就像魅力一样。谢谢,伙计!

标签: c++ windows winapi opengl


【解决方案1】:

你的假设是错误的:

…由于一个窗口只能有一个上下文,…

没有。

可以有任意数量的上下文,实际上上下文并不绑定到特定的窗口。

只要窗口的像素格式与上下文的像素格式匹配,您就可以使上下文在窗口上成为当前的。如果您有多个线程,您可以同时在 same 窗口上创建不同的上下文(假设上下文与窗口的像素格式兼容)。

【讨论】:

  • 哦,这可能是设计问题。我认为上下文与 DC 相关联。
  • @Julien:是的。但是每个窗口可以有任意数量的设备上下文。
  • 考虑到Window Class定义了'CS_OWNDC',不是每个Window只有一个吗?
  • @Julien:窗口有一个主 DC,但您可以随时创建对它的附加引用。例如 BeginPaint,EndPaint 正是这样做的。更重要的是,设备上下文与 OpenGL 渲染上下文不同。因此,每个窗口可以有多个 DC(所有共享窗口像素格式),并且可以有多个 OpenGL 渲染上下文,可以任意绑定和反弹,因为它们不绑定到特定窗口或 DC。
  • @Julien:CS_OWNDC 类样式只是一种优化:它要求窗口管理器永远不要从其 DC 缓存中清除具有此类样式的窗口的 DC。因此,每当您为此窗口调用 GetDCBeginPaint 时,您都会获得相同的 DC。这并不意味着一个窗口 - 通常 - 不能与多个 DC 相关联。
【解决方案2】:

所以问题是,该类被多次注册。我对这个问题的第一个解决方案是尝试引用一个可能不存在的类。 我的工作解决方案创建一个类并通过以下方式记住它的引用:

    static const char*    pcClassName;
    if(nullptr == pcClassName){
        WNDCLASSEX  wc      = {};
        wc.cbSize           = sizeof(WNDCLASSEX);
        wc.hInstance        = ((HINSTANCE)&__ImageBase);
        wc.lpfnWndProc      = internal::WndProc;
        wc.lpszClassName    = pTitle;
        wc.style            = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;

        if(0 == RegisterClassEx(&wc)){
            //
            //  The exception class will contain the error code and
            //  a error description.
            //
            std::error_code err_code(GetLastError(), std::system_category());
            throw std::system_error(err_code);
        }
        pcClassName = pTitle;
    }

类名用于后面实际创建窗口时引用窗口类。例如。像这样:

    pHandle->handle = CreateWindowEx(
        bFullscreen ? WS_EX_APPWINDOW : NULL,
        pcClassName,
        pTitle,
        bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW,    // NOTE: Perhaps I'll create a window config struct?
        GetSystemMetrics(SM_CXSCREEN) / 2,
        GetSystemMetrics(SM_CYSCREEN) / 2,
        clientArea.right    - clientArea.left,
        clientArea.bottom   - clientArea.top,
        nullptr,    // We're not having a parent window
        nullptr,    // nor a win32 menu.
        ((HINSTANCE)&__ImageBase),
        pHandle    // Is needed for the router 'WndProc'.
    );

但是,由于我将此代码编译为 DLL,因此我使用 @IInspectable 解决方案来检索正确的“HINSTANCE”。 有关更多详细信息,请查看他的评论。

__ImageBase 定义如下:

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-23
    • 2019-02-22
    • 1970-01-01
    • 2018-10-21
    • 1970-01-01
    • 2018-10-03
    • 2019-04-10
    • 2018-11-15
    相关资源
    最近更新 更多