类已经存在

时间:2016-05-13 13:30:31

标签: c++ windows winapi opengl

在我的项目中,我有两个类:'Window'和'Context'。 “Window”类使用WinAPI实例化一个窗口,一切正常。 例如。这段代码按照假设:

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

类'Context'创建一个OpenGL 4.0 Context。为了做到这一点, 它需要创建一个临时窗口和一个临时上下文来检索所有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;
    }

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

有人可以启发我,为什么我的代码不起作用?

2 个答案:

答案 0 :(得分:0)

你开始做错了假设:

  

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

不。

可以有任意数量的上下文,实际上上下文与特定窗口无关。

只要窗口的pixelformat与上下文的pixelformat匹配,就可以在窗口中使上下文变为当前。如果你有几个线程,你可以同时在相同的窗口上创建不同的上下文当前(假设上下文与窗口的pixelformat兼容)。

答案 1 :(得分:0)

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

    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;