win32程序中WM_TIMER消息不能响应?

时间:2022-08-23 20:37:13
在做一个时钟的小程序。窗体CreateWindowEx的dwExStyle参数为WS_EX_TOOLWINDOW | WS_EX_LAYERED,dwStyle参数为WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP。在WM_CREATE中使用了函数SetTimer,然而却不能在WM_TIMER中得到响应,求大佬帮忙~
注:163行仅仅是一个断点- -,stdafx.h里有一句#include <math.h>
// Clock.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Clock.h"

#define MAX_LOADSTRING 100
#define ID_TIMER 1

// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
POINT pt, pe;
RECT rt, re;
HWND g_hWnd;
HDC windowDC;
HDC memDC;
HBITMAP memBMP;

// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void InitDC();
void RefreshDC();
void RlsDC();
void DrawClock();

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

  // TODO: 在此放置代码。
MSG msg;
HACCEL hAccelTable;

// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CLOCK, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

InitDC();

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CLOCK));

// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLOCK));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   int scrW = GetSystemMetrics(SM_CXSCREEN), scrH = GetSystemMetrics(SM_CYSCREEN);
   hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, szWindowClass, szTitle, WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP, scrW - 150, 50, 100, 100, NULL, NULL, hInstance, NULL);
   SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
   SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 0, LWA_COLORKEY);
   g_hWnd = hWnd;

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND - 处理应用程序菜单
//  WM_PAINT - 绘制主窗口
//  WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
bool isDrag = false;

switch (message)
{
case WM_CREATE:
SetTimer(hWnd, ID_TIMER, 100, NULL);
break;
case WM_TIMER:
int p;
p = 0;
RefreshDC();
break;
case WM_LBUTTONDOWN:
SetCapture(hWnd);
GetCursorPos(&pt);
GetWindowRect(hWnd, &rt);
re.right = rt.right - rt.left;
re.bottom = rt.bottom - rt.top;
break;
case WM_MOUSEMOVE:
GetCursorPos(&pe);
if (wParam == MK_LBUTTON)
{
re.left = rt.left + (pe.x - pt.x);
re.top = rt.top + (pe.y - pt.y);
MoveWindow(hWnd, re.left, re.top, re.right, re.bottom, true);
}
break;
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
SendMessage(hWnd, WM_DESTROY, 0, 0);
break;
case WM_PAINT:
BitBlt(windowDC, 0, 0, 100, 100, memDC, 0, 0, SRCCOPY);
break;
case WM_DESTROY:
KillTimer(hWnd, ID_TIMER);
RlsDC();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

void InitDC()
{
windowDC = GetDC(g_hWnd);
memDC = CreateCompatibleDC(windowDC);
memBMP = CreateCompatibleBitmap(windowDC, 100, 100);
SelectObject(memDC, memBMP);
BitBlt(memDC, 0, 0, 100, 100, windowDC, 0, 0, SRCCOPY);
RefreshDC();
}

void RefreshDC()
{
DrawClock();
BLENDFUNCTION bf;
bf.BlendOp = 0;
bf.BlendFlags = 0;
bf.AlphaFormat = 1;
bf.SourceConstantAlpha = 255;
RECT rtWin;
GetWindowRect(g_hWnd, &rtWin);
POINT ptWin = {rtWin.left, rtWin.top};
SIZE szWin = {100, 100};
POINT ptSrc = {0, 0};
UpdateLayeredWindow(g_hWnd, windowDC, &ptWin, &szWin, memDC, &ptSrc, 0, &bf, ULW_ALPHA);
}

void RlsDC()
{
if (!memBMP)
DeleteObject(memBMP);
if (!memDC)
DeleteDC(memDC);
if (!windowDC)
ReleaseDC(g_hWnd, windowDC);
}

void DrawClock()
{
RECT rtWin;
GetWindowRect(g_hWnd, &rtWin);
FillRect(memDC, &rtWin, (HBRUSH)GetStockObject(WHITE_BRUSH));
HPEN penBorder = CreatePen(PS_SOLID, 4, RGB(0, 0, 0));
HPEN penOld = (HPEN)SelectObject(memDC, penBorder);
HBRUSH brsCir = CreateSolidBrush(RGB(192, 192, 192));
HBRUSH brsOld = (HBRUSH)SelectObject(memDC, brsCir);
Ellipse(memDC, 1, 1, 99, 99);
SelectObject(memDC, penOld);
DeleteObject(penBorder);
SelectObject(memDC, brsOld);
DeleteObject(brsCir);
double dx, dy;
const double pi = atan(1.0) * 4;
for (int i = 0; i < 12; i++)
{
dx = 50 * sin((double)i / 12 * 2 * pi); dy = 50 * cos((double)i / 12 * 2 * pi);
MoveToEx(memDC, (int)(50 + dx), (int)(50 - dy), NULL);
dx = 38 * sin((double)i / 12 * 2 * pi); dy = 38 * cos((double)i / 12 * 2 * pi);
LineTo(memDC, (int)(50 + dx), (int)(50 - dy));
}
SYSTEMTIME time;
GetLocalTime(&time);
int hour = time.wHour, minute = time.wMinute, second = time.wSecond;
HPEN penHour = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
penOld = (HPEN)SelectObject(memDC, penHour);
MoveToEx(memDC, 50, 50, NULL);
dx = 22 * sin((hour % 12 + (double)minute / 60 + (double)second / 3600) / 12 * 2 * pi); dy = 22 * cos((hour % 12 + (double)minute / 60 + (double)second / 3600) / 12 * 2 * pi);
LineTo(memDC, (int)(50 + dx), (int)(50 - dy));
SelectObject(memDC, penOld);
DeleteObject(penHour);
HPEN penMinute = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
penOld = (HPEN)SelectObject(memDC, penMinute);
MoveToEx(memDC, 50, 50, NULL);
dx = 32 * sin((minute + (double)second / 60) / 60 * 2 * pi); dy = 32 * cos((minute + (double)second / 60) / 60 * 2 * pi);
LineTo(memDC, (int)(50 + dx), (int)(50 - dy));
SelectObject(memDC, penOld);
DeleteObject(penMinute);
HPEN penSecond = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
penOld = (HPEN)SelectObject(memDC, penSecond);
MoveToEx(memDC, 50, 50, NULL);
dx = 42 * sin((double)second / 60 * 2 * pi); dy = 42 * cos((double)second / 60 * 2 * pi);
LineTo(memDC, (int)(50 + dx), (int)(50 - dy));
SelectObject(memDC, penOld);
DeleteObject(penSecond);
}

6 个解决方案

#1


WM_TIMER 响应函数中设置个断点, 看看有没有执行到这里

#2


引用 1 楼 zgl7903 的回复:
WM_TIMER 响应函数中设置个断点, 看看有没有执行到这里

163行设置了,没有执行- -

#3


你的 WM_PAINT 中没有 BeginPaint 和 EndPaint ,因此WM_PAINT 消息再被反复触发, 
只要消息队列中有消息, WM_TIMER 就不会被派送

干脆 直接在WM_PAINT 中调用  DrawClock
DrawClock();
BitBlt(windowDC, 0, 0, 100, 100, memDC, 0, 0, SRCCOPY);

#4


 case WM_CREATE:
        SetTimer(hWnd, ID_TIMER, 100, aaa);
        break;




LPVoid* aaa()
{
;
}

#5


引用 3 楼 zgl7903 的回复:
你的 WM_PAINT 中没有 BeginPaint 和 EndPaint ,因此WM_PAINT 消息再被反复触发, 
只要消息队列中有消息, WM_TIMER 就不会被派送

干脆 直接在WM_PAINT 中调用  DrawClock
DrawClock();
BitBlt(windowDC, 0, 0, 100, 100, memDC, 0, 0, SRCCOPY);
搞定了~另外DrawClock语句必须在WM_TIMER中,如果在WM_PAINT中则并不能随时绘制。

#6


版主您好!
关于winapi的调用我是新手,我有个问题.
为啥要把句柄、设备环境弄为全局变量?我看书上都是局部。

#1


WM_TIMER 响应函数中设置个断点, 看看有没有执行到这里

#2


引用 1 楼 zgl7903 的回复:
WM_TIMER 响应函数中设置个断点, 看看有没有执行到这里

163行设置了,没有执行- -

#3


你的 WM_PAINT 中没有 BeginPaint 和 EndPaint ,因此WM_PAINT 消息再被反复触发, 
只要消息队列中有消息, WM_TIMER 就不会被派送

干脆 直接在WM_PAINT 中调用  DrawClock
DrawClock();
BitBlt(windowDC, 0, 0, 100, 100, memDC, 0, 0, SRCCOPY);

#4


 case WM_CREATE:
        SetTimer(hWnd, ID_TIMER, 100, aaa);
        break;




LPVoid* aaa()
{
;
}

#5


引用 3 楼 zgl7903 的回复:
你的 WM_PAINT 中没有 BeginPaint 和 EndPaint ,因此WM_PAINT 消息再被反复触发, 
只要消息队列中有消息, WM_TIMER 就不会被派送

干脆 直接在WM_PAINT 中调用  DrawClock
DrawClock();
BitBlt(windowDC, 0, 0, 100, 100, memDC, 0, 0, SRCCOPY);
搞定了~另外DrawClock语句必须在WM_TIMER中,如果在WM_PAINT中则并不能随时绘制。

#6


版主您好!
关于winapi的调用我是新手,我有个问题.
为啥要把句柄、设备环境弄为全局变量?我看书上都是局部。