我正在尝试用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;
}
答案 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_TIMER
、WM_CREATE
、WM_QUIT
。
还记得不要破坏预览窗口,如果你还没有创建它。