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

Screensaver application not turning off after the dialog box closes

本文关键字:对话框 程序 应用程序 屏幕保护      更新时间:2023-10-16

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

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

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

当您制作预览窗口时,您应该使用 WS_CHILD 代替WS_POPUP,否则您将不会收到父窗口关闭的通知。

您无需创建自己的预览窗口。您可以使用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

另外请记住不要破坏预览窗口,如果您尚未创建它。