2016-05-13 168 views
0

在我的项目中,我有2个类:'窗口'和'上下文'。 类'窗口'使用WinAPI实例化一个窗口,一切工作正常。 例如此代码的工作原理如下:类已经存在

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

'Context'类创建一个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 

一些collegue的建议,我应该只有一次注册窗口类, 所以我尝试在构造函数如下:

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; 
    } 

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

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

+1

你的窗口类没有类名。它不能被引用。不知道你在调用CreateWindow [Ex]'时提供的窗口类名称。 GetModuleHandle(nullptr)'是一个等待发生的错误,只要将代码编译成DLL即可。无论如何,您提供的代码不是类注册失败的地方,并带有*“已注册”*错误消息。 – IInspectable

+0

窗口类名称等于我在构造函数中提供的窗口的名称。现在我明白为什么出现'找不到窗口类'的错误。 GetModuleHandle(nullptr)有什么问题?我已经编译成一个DLL,它的工作原理。唯一的失败是,如果我在另一个窗口内创建一个新窗口。 – Julien

+1

哦,你说得对,你提供的是一个班级名称。 'GetModuleHandle(nullptr)'有什么问题:它将模块句柄返回给EXE,而不是DLL。但它是实现窗口过程的DLL。包罗万象的解决方案,找到正确的模块句柄:从静态库访问当前模块的HINSTANCE(https://blogs.msdn.microsoft.com/oldnewthing/20041025-00/?p=37483)。 – IInspectable

回答

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,我用取回权“HINSTANCE” @IInspectable解决方案。 欲了解更多详情,请查看他的评论。

__ImageBase定义如下:

EXTERN_C IMAGE_DOS_HEADER __ImageBase; 
1

你开始一个错误的假设:

… Since a window can have only one context at all, …

都能跟得上。

可以有上下文的,事实上上下文没有绑定到特定窗口的任意数目。

只要窗口的像素格式相匹配的背景下,你可以使窗口上下文电流。如果您有多个线程,您可以同时在同一个窗口(在上下文与窗口的像素格式兼容的情况下)在不同的上下文中显示不同的上下文。

+0

哦,那可能是一个。设计的问题,我想到了一个上下文绑直流 – Julien

+0

@Julien:它不过是有可能的设备上下文的任意数量的每一个窗口 – IInspectable

+0

是不是有每个窗口只有一个,考虑到定义窗口类“。 ?CS_OWNDC“ – Julien