对话框关闭后屏幕保护程序应用程序未关闭

时间:2012-07-07 15:17:39

标签: c++ memory-leaks screensaver

我正在尝试用C ++编写屏幕保护程序。我已经实现了预览窗口,但我发现它没有关闭,因为我打开了任务管理器,我看到3个“bounce.scr”实例打开,显然是从预览窗口打开。不要误解我的意思。我花了好几个小时试图让它关闭,例如检查窗口是否可见,以及父窗口,使用带有SC_CLOSE的WM_SYSTEMCOMMAND。屏幕保护对话框关闭后,它仍然不会关闭。这是代码:

很抱歉,如果它很难阅读,但我并没有真正评论我的代码。

    #include <windows.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/timeb.h>

    struct BALL
    {
        float posX;
        float posY;
        float posZ;
        float velX;
        float velY;
        float velZ;
        float size;
        float colorR;
        float colorG;
        float colorB;
    };



    float state;

    void SetupPixelFormat(HDC hDC)
    {
            int nPixelFormat;

            static PIXELFORMATDESCRIPTOR pfd = {
                    sizeof(PIXELFORMATDESCRIPTOR),          
                    1,                                      
                    PFD_DRAW_TO_WINDOW |                    
                    PFD_SUPPORT_OPENGL |                    
                    PFD_DOUBLEBUFFER,                       
                    PFD_TYPE_RGBA,                          
                    32,                                     
                    0, 0, 0, 0, 0, 0,                       
                    0,                                      
                    0,                                      
                    0,                                      
                    0, 0, 0, 0,                             
                    16,                                     
                    0,                                      
                    0,                                      
                    PFD_MAIN_PLANE,                         
                    0,                                      
                    0, 0, 0 };                              

                    nPixelFormat = ChoosePixelFormat(hDC, &pfd);

                    SetPixelFormat(hDC, nPixelFormat, &pfd);
    }

    HDC scr_hdc;
    bool done;
    bool isPreview;
    int timeFromStart = 0;
    int prevX = 0;
    int prevY = 0;

    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static HGLRC hRC;
        static HDC hDC;

        int width, height;

        if (!IsWindowVisible(GetParent(hwnd)) && timeFromStart >= 5 && isPreview)
        {
            message = WM_CLOSE;
        }

        switch(message)
        {
            case WM_CREATE:
                hDC = GetDC(hwnd);
                scr_hdc = hDC;
                SetupPixelFormat(hDC);

                hRC = wglCreateContext(hDC);
                wglMakeCurrent(hDC, hRC);

                return 0;
                break;
            case WM_KEYDOWN:
            case WM_MOUSEMOVE:
                if (isPreview) break;
            case WM_SYSCOMMAND:
                if (isPreview) 
                    { if (wParam == SC_CLOSE) { } else { break; } }
            case WM_CLOSE:
                int x = LOWORD(lParam);
                int y = HIWORD(lParam);
                if (timeFromStart >= 5)
                {
                    if ((x != prevX && y != prevX) || message != WM_MOUSEMOVE)
                    {
                        wglMakeCurrent(hDC, NULL);
                        wglDeleteContext(hRC);
                        done = true;
                        //PostQuitMessage(0);
                    }
                }
                else
                {
                    timeFromStart++;
                }
                prevX = x;
                prevY = y;
                return 0;
                break;
        }
        return (DefWindowProc(hwnd, message, wParam, lParam));
    }

    int screensaver(HINSTANCE hInstance, int balls, HWND parent)
    {
        WNDCLASSEX windowClass;
        HWND hwnd;
        HWND desktopHWND;
        MSG msg;
        DWORD dwExStyle;
        DWORD dwStyle;
        RECT windowRect;
        RECT desktopRect;

        if (parent)
        {
            GetClientRect(parent, &windowRect);
            windowRect.left = 0L;
            windowRect.top = 0L;
            isPreview = true;
        }
        else
        {
            desktopHWND = GetDesktopWindow();
            GetWindowRect(desktopHWND, &desktopRect);

            windowRect.left = 0L;
            windowRect.right = desktopRect.right;
            windowRect.top = 0L;
            windowRect.bottom = desktopRect.bottom;
            isPreview = false;
        }

        windowClass.cbSize = sizeof(WNDCLASSEX);
        windowClass.style = CS_HREDRAW | CS_VREDRAW;
        windowClass.lpfnWndProc = WndProc;
        windowClass.cbClsExtra = 0;
        windowClass.cbWndExtra = 0;
        windowClass.hInstance = hInstance;
        windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        windowClass.hbrBackground = NULL;
        windowClass.lpszMenuName = NULL;
        windowClass.lpszClassName = "ScreensaverClass";
        windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

        if (!RegisterClassEx(&windowClass))
        {
            return 0;
        }

        //SetCapture();

        /*DEVMODE dmScreenSettings;
        memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
        dmScreenSettings.dmSize = sizeof(dmScreenSettings);
        dmScreenSettings.dmPelsWidth = 800;
        dmScreenSettings.dmPelsHeight = 600;
        dmScreenSettings.dmBitsPerPel = 32;
        dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

        ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN != DISP_CHANGE_SUCCESSFUL); */

        dwExStyle = WS_EX_APPWINDOW;
        dwStyle = WS_POPUP;
        if (!parent)
        {
            ShowCursor(FALSE);
        }

        AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);

        hwnd = CreateWindowEx(NULL, "ScreensaverClass",
                              "Screensaver",
                              dwStyle |
                              WS_CLIPCHILDREN |
                              WS_CLIPSIBLINGS,
                              0, 0,
                              windowRect.right - windowRect.left,
                              windowRect.bottom - windowRect.top,
                              NULL,
                              NULL,
                              hInstance,
                              NULL);
        if (!hwnd)
        {
            return 0;
        }

        if (parent)
        {
            SetParent(hwnd, parent);

            SetWindowLong(hwnd, -16, GetWindowLong(hwnd, -16) | 0x40000000);
        }

        ShowWindow(hwnd, SW_SHOW);
        UpdateWindow(hwnd);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(79, (float)windowRect.right / (float)windowRect.bottom, .03f, 100);
        glMatrixMode(GL_MODELVIEW);

        glDepthFunc(GL_LEQUAL);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glEnable(GL_COLOR_MATERIAL);

        GLuint room = glGenLists(1);
        glNewList(room, GL_COMPILE);
        glBegin(GL_QUADS);
        glColor4f(1,1,1,1);
        glNormal3f(0,0,-1); // North Side
        glVertex3i(0, 50, 50);
        glVertex3i(50, 50, 50);
        glVertex3i(50, 0, 50);
        glVertex3i(0, 0, 50);
        glNormal3f(-1,0,0); // East Side
        glVertex3i(50, 50, 50);
        glVertex3i(50, 50, 0);
        glVertex3i(50, 0, 0);
        glVertex3i(50, 0, 50);
        glNormal3f(0,0,1); // South Side
        glVertex3i(50, 50, 0);
        glVertex3i(0, 50, 0);
        glVertex3i(0, 0, 0);
        glVertex3i(50, 0, 0);
        glNormal3f(1,0,0); // West Side
        glVertex3i(0, 50, 0);
        glVertex3i(0, 50, 50);
        glVertex3i(0, 0, 50);
        glVertex3i(0, 0, 0);
        glNormal3f(0,-1,0); // Top Side
        glVertex3i(0, 50, 0);
        glVertex3i(50, 50, 0);
        glVertex3i(50, 50, 50);
        glVertex3i(0, 50, 50);
        glNormal3f(0,1,0); // Bottom Side
        glVertex3i(0, 0, 50);
        glVertex3i(50, 0, 50);
        glVertex3i(50, 0, 0);
        glVertex3i(0, 0, 0);
        glEnd();
        glEndList();

        GLuint ball = glGenLists(1);
        glNewList(ball, GL_COMPILE);
        GLUquadric *s = gluNewQuadric();
        gluSphere(s, 1, 10, 10);

        glEndList();

        struct BALL* ballsList = (struct BALL*)calloc(balls, sizeof(struct BALL));

        for (int i = 0; i < balls; i++) 
        {
            ballsList[i].posX = (float)(rand()%50);
            ballsList[i].posY = (float)(rand()%50);
            ballsList[i].posZ = (float)(rand()%50);
            ballsList[i].velX = ((float)rand() / (float)RAND_MAX) - .5f;
            ballsList[i].velY = ((float)rand() / (float)RAND_MAX) - .5f;
            ballsList[i].velZ = ((float)rand() / (float)RAND_MAX) - .5f;
            ballsList[i].size = (float)rand() / (float)RAND_MAX;
            ballsList[i].colorR = (float)rand() / (float)RAND_MAX;
            ballsList[i].colorG = (float)rand() / (float)RAND_MAX;
            ballsList[i].colorB = (float)rand() / (float)RAND_MAX;
        }

        SetTimer(hwnd, 31, 50, (TIMERPROC) NULL);

        struct timeb timeobj;
        long lasttimestamp;
        long thistimestamp;
        float framemultiplier;

        ftime(&timeobj);
        lasttimestamp = (long)timeobj.time * 1000L + timeobj.millitm;

        done = false;

        state = 3;
        float yaw = 0;

        while (!done)
        {
            PeekMessage(&msg, hwnd, NULL, NULL, PM_REMOVE);

            if (msg.message == WM_QUIT)
            {
                state = 1;
                done = true;
            }
            else
            {
                if (msg.message == WM_TIMER)
                {

                ftime(&timeobj);
                thistimestamp = timeobj.time * 1000L + timeobj.millitm;
                framemultiplier = (float)(thistimestamp - lasttimestamp) / 50;

                yaw += framemultiplier;

                glClearColor(0,0,0,1);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                glLoadIdentity();
                glRotatef(yaw,0,1,0);
                glTranslatef(-25,-25,-25);

                glCallList(room);

                for (int i = 0; i < balls; i++)
                {
                    struct BALL *b = &ballsList[i];
                    b->posX += (b->velX * framemultiplier);
                    b->posY += (b->velY * framemultiplier);
                    b->posZ += (b->velZ * framemultiplier);

                    if (b->posX < b->size)
                    {
                        b->velX = -b->velX;
                        b->posX = b->size;
                    }
                    if (b->posY < b->size)
                    {
                        b->velY = -b->velY;
                        b->posY = b->size;
                    }
                    if (b->posZ < b->size)
                    {
                        b->velZ = -b->velZ;
                        b->posZ = b->size;
                    }
                    float fms = 50 - b->size;
                    if (b->posX > fms)
                    {
                        b->velX = -b->velX;
                        b->posX = fms;
                    }
                    if (b->posY > fms)
                    {
                        b->velY = -b->velY;
                        b->posY = fms;
                    }
                    if (b->posZ > fms)
                    {
                        b->velZ = -b->velZ;
                        b->posZ = fms;
                    }

                    b->velY -= .01f * framemultiplier;

                    glColor3f(b->colorR, b->colorG, b->colorB);
                    glPushMatrix();
                    glTranslatef(b->posX, b->posY, b->posZ);
                    glScalef(b->size, b->size, b->size);
                    glCallList(ball);
                    glPopMatrix();
                    lasttimestamp = thistimestamp;
                }

                SwapBuffers(scr_hdc);
                }

                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        /*ChangeDisplaySettings(NULL, 0);*/
        ShowCursor(TRUE);
        //ReleaseCapture();

        KillTimer(hwnd, 31);

        free(ballsList);

        return msg.wParam;
    }

    int APIENTRY WinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPSTR     lpCmdLine,
                         int       nCmdShow)
    {
        if (strstr(lpCmdLine, "/s"))
        {
            return screensaver(hInstance, 30, NULL);
        }
        else if (strstr(lpCmdLine, "/p"))
        {
            HWND ptr = (HWND)atoi(lpCmdLine + 3);
            screensaver(hInstance, 30, ptr);
        }
        return 0;
    }

2 个答案:

答案 0 :(得分:0)

当您创建预览窗口时,您应该使用WS_CHILD而不是WS_POPUP,否则您将不会收到关闭父窗口的通知。

答案 1 :(得分:0)

您无需创建自己的预览窗口。 您可以使用 Windows 为您创建的一个。

if( parent ){
    hwnd= parent;
}else{
    hwnd= CreateWindow ...
}
hDC= GetDC(hwnd);
SetupPixelFormat(hDC);
hRC= wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);

然后在渲染 SwapBuffers 的检查结果之后。如果失败,那么用户已经关闭了预览,窗口被破坏了,是时候退出了。

if( !SwapBuffers(scr_hdc) )
    break;
}

请记住,您的 WndProc 未附加到该窗口。因此,当您处于预览状态时,将不会出现 WM_TIMERWM_CREATEWM_QUIT

还记得不要破坏预览窗口,如果你还没有创建它。