2012-01-28 75 views
0

我一直在爲遊戲製作Window類,並且在消息泵方面遇到了問題。無限循環中的Windows消息泵

我將事件從Windows提供的消息隊列中取出併發送到它們所屬的窗口。這是翻譯和分派的功能。

從我記得的Win32編程中,翻譯和分派消息調用指定的WindowProc與參數的消息內容。因此,這裏是我指定的WindowProc ...

currWin,currhwnd和WINMAP被定義爲局部變量Window.cpp,在頂部...

不管怎樣,調用distributeSystemMessages()似乎導致無限循環。

重要提示:遊戲環路不在消息處理環路內,也不是消息處理代碼。消息處理循環應消除每幀消息隊列,將每個消息發送到它的窗口。

這裏的window.h中......

#ifndef WINDOW_H_INCLUDED 
#define WINDOW_H_INCLUDED 

#include "SystemMessage.h" 
#include <queue> 
#include <windows.h> 
using namespace std; 

///THIS FUNCTION MUST BE CALLED TO GET MESSAGES INTO WINDOW QUEUES 
void distributeSystemMessages(); 

class Window 
{ 
protected: 
    HDC hDC; 
    HWND hWnd; 
    HINSTANCE hInst; 
    HGLRC hRC; 

public: 
    queue<SystemMessage> messages; 

    Window(unsigned int width, unsigned int height, const char* name, unsigned int colorBits = 24, unsigned int depthBits = 24, unsigned int stencilBits = 0); 
    ~Window(); 

    void makeContextCurrent(); 
    void swapBuffers(); 

    unsigned int getHeight(); 
    unsigned int getWidth(); 

    int getMouseX(); 
    int getMouseY(); 

    void setSize(unsigned int width, unsigned int height); 
}; 

#endif // WINDOW_H_INCLUDED 

這裏的Window.cpp ...

#include "Window.h" 
#include <map> 
#include <cstdio> 
#include <GLee.h> 
#include <GL/gl.h> 
#include <GL/glu.h> 
using namespace std; 

HWND currhwnd; 
Window* currWin; 
map<HWND, Window*> winMap = map<HWND, Window*>(); 

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    if(currhwnd != hwnd) 
    { 
     map<HWND, Window*>::iterator i = winMap.find(hwnd); 
     if(i != winMap.end()) 
     { 
      currWin = (*i).second; 
      currhwnd = hwnd; 
     } 
     else return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 

    SystemMessage msg(hwnd, uMsg, wParam, lParam); 

    currWin->messages.push(msg); 

    return 0; 
} 

Window::Window(unsigned int width, unsigned int height, const char* name, unsigned int colorBits, unsigned int depthBits, unsigned int stencilBits) 
{ 
    //TODO: ADD TIME FUNCTIONS TO A TIMER CLASS 
    //QueryPerformanceCounter(&startTime); 
    //lastTime = startTime; 
    messages = queue<SystemMessage>(); 


    hInst = GetModuleHandle(NULL); 

    WNDCLASSEX wincl;  /* Data structure for the windowclass */ 

    /* The Window structure */ 
    wincl.hInstance = hInst; 
    wincl.lpszClassName = "Squirrel Engine Window"; 
    wincl.lpfnWndProc = MainWndProc;  /* This function is called by windows */ 
    wincl.style = CS_DBLCLKS;     /* Catch double-clicks */ 
    wincl.cbSize = sizeof (WNDCLASSEX); 

    /* Use default icon and mouse-pointer */ 
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); 
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW); 
    wincl.lpszMenuName = NULL;     /* No menu */ 
    wincl.cbClsExtra = 0;      /* No extra bytes after the window class */ 
    wincl.cbWndExtra = 0;      /* structure or the window instance */ 
    /* Use Windows's default colour as the background of the window */ 
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; 

    /* Register the window class, and if it fails quit the program */ 
    if (!RegisterClassEx (&wincl)) 
    { 
     printf("Could not register window class.\n"); 
     return; 
    } 

    /* The class is registered, let's create the program*/ 
    hWnd = CreateWindowEx (
      0,     /* Extended possibilites for variation */ 
      "Squirrel Engine Window",/* Classname */ 
      name,  /* Title Text */ 
      WS_OVERLAPPEDWINDOW, /* default window */ 
      CW_USEDEFAULT,  /* Windows decides the position */ 
      CW_USEDEFAULT,  /* where the window ends after on the screen */ 
      10,     /* The programs width */ 
      10,     /* and height in pixels */ 
      HWND_DESKTOP,  /* The window is a child-window to desktop */ 
      NULL,    /* No menu */ 
      hInst,  /* Program Instance handler */ 
      NULL     /* No Window Creation data */ 
      ); 

    RECT rcWindow; 
    RECT rcClient; 

    GetWindowRect(hWnd, &rcWindow); 
    GetClientRect(hWnd, &rcClient); 

    POINT ptDiff; 
    ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; 
    ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; 

    MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE); 

    ShowWindow (hWnd, SW_SHOW); 

    hDC = GetDC(hWnd); 

    PIXELFORMATDESCRIPTOR pfd; 
    ZeroMemory(&pfd, sizeof(pfd)); 
    pfd.nSize = sizeof(pfd); 
    pfd.nVersion = 1; 
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | 
        PFD_DOUBLEBUFFER; 
    pfd.iPixelType = PFD_TYPE_RGBA; 
    pfd.cColorBits = colorBits; 
    pfd.cDepthBits = depthBits; 
    pfd.cStencilBits = stencilBits; 
    pfd.iLayerType = PFD_MAIN_PLANE; 
    int iFormat = ChoosePixelFormat(hDC, &pfd); 
    SetPixelFormat(hDC, iFormat, &pfd); 

    hRC = wglCreateContext(hDC); 
    hDC = hDC; 

    //makeContextCurrent(); 

    winMap[hWnd] = this; 
    //TODO: Find out what this function does 
    wglSwapIntervalEXT(0); 
} 

Window::~Window() 
{ 
    wglDeleteContext(hRC); 
    ReleaseDC(hWnd, hDC); 
    winMap.erase(hWnd); 
    PostQuitMessage(0); 
} 

unsigned int Window::getWidth() 
{ 
    RECT rcClient; 
    GetClientRect(hWnd, &rcClient); 
    return rcClient.right; 
} 
unsigned int Window::getHeight() 
{ 
    RECT rcClient; 
    GetClientRect(hWnd, &rcClient); 
    return rcClient.bottom; 
} 

void Window::setSize(unsigned int width, unsigned int height) 
{ 
    RECT rcWindow; 
    RECT rcClient; 

    GetWindowRect(hWnd, &rcWindow); 
    GetClientRect(hWnd, &rcClient); 

    POINT ptDiff; 
    ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; 
    ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; 

    MoveWindow(hWnd,rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE); 
} 

void Window::makeContextCurrent() 
{ 
    wglMakeCurrent(hDC, hRC); 
} 

void Window::swapBuffers() 
{ 
    SwapBuffers(hDC); 
} 

int Window::getMouseX() 
{ 
    POINT p; 
    GetCursorPos(&p); 

    RECT rcWindow; 
    RECT rcClient; 

    GetWindowRect(hWnd, &rcWindow); 
    GetClientRect(hWnd, &rcClient); 

    POINT ptDiff; 
    ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; 
    ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; 


    return p.x - (rcWindow.left + ptDiff.x); 
} 
int Window::getMouseY() 
{ 
    POINT p; 
    GetCursorPos(&p); 

    RECT rcWindow; 
    RECT rcClient; 

    GetWindowRect(hWnd, &rcWindow); 
    GetClientRect(hWnd, &rcClient); 

    POINT ptDiff; 
    ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; 
    ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; 

    return p.y - (rcWindow.top + ptDiff.y); 
} 

void distributeSystemMessages() 
{ 
    MSG messages; 
    while(PeekMessage (&messages, NULL, 0, 0, PM_REMOVE)) 
    { 
     printf("MessageLoop\n"); 
     TranslateMessage(&messages); 
     DispatchMessage(&messages); 
    } 
} 

回答

2

通常情況下,你使用一個對象的架構。基本上,Windows爲每個hWnd提供本地空間的訪問權限,這些空間明確保留供您使用。你不需要任何全局變量來完成這個工作。

class Window { 
    // Can be virtual if necessary 
    LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
     // Process the message here 
    } 
    static LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
     if (Window* ptr = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))) { 
      return ptr->WindowProc(hwnd, uMsg, wParam, lParam); 
     } 
     return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
    HWND hwnd; 
public: 
    Window() { 
     hwnd = CreateWindowEx(....); 
     SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); 
     ShowWindow(...); // update the ptr 
    } 
    void ProcessMessages() { 
     MSG messages; 
     while(PeekMessage (&messages, hwnd, 0, 0, PM_REMOVE)) 
     { 
      printf("MessageLoop\n"); 
      TranslateMessage(&messages); 
      DispatchMessage(&messages); 
     } 
    } 
}; 
+0

您在CreateWindowEx中指定了哪個WindowProc?我一直無法使用該對象的方法作爲WindowProc。在這裏...爲什麼我不要在全班上課。 – Miles 2012-01-28 22:57:45

+0

@Miles:您使用靜態WindowProc。啊哈......我不應該把它們都命名爲WindowProc。我的錯。 – Puppy 2012-01-28 23:10:02

+0

但是,靜態WindowProc如何知道哪個窗口的事件隊列發送消息?這個想法是對消息進行排序。 – Miles 2012-01-28 23:11:23