我在设置Windows计时器的回调/ windowproc时遇到问题。我在这个例子中想要的是控制台窗口显示三个“Timer Click!”消息然后退出。
#include "stdafx.h"
#include <strsafe.h>
#include "Windows.h"
using namespace System;
int receivedCalls = 0;
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to main window
UINT msg, // type of message
WPARAM wParam, // additional information
LPARAM lParam // additional information
)
{
switch (msg)
{
case WM_TIMER:
receivedCalls += 1;
Console::WriteLine("Timer click!");
return 0;
}
}
int main()
{
UINT result;
UINT_PTR IDT_TIMER1 = 1;
HWND hwnd = GetConsoleWindow();
result = SetTimer(hwnd,IDT_TIMER1,5000,(TIMERPROC) NULL);
if (result == 0)
{
LPTSTR lpszFunction = TEXT("SetTimer");
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
while (receivedCalls < 3) {
Sleep(100);
}
KillTimer(hwnd, IDT_TIMER1);
return 0;
}
MessageBox错误代码来自Windows页面。我收到错误代码5:访问被拒绝。我无法设置计时器的可能原因是什么?我真的需要管理员权限来设置计时器吗?如果是这样,定期检查某些内容的首选方法是什么(例如,轮询网站以获取新信息)。
答案 0 :(得分:1)
这是准确的。控制台窗口由完全不同的进程conhost.exe拥有。它充当安全边界,主要是为了确保程序不能执行从屏幕缓冲区窃取密码等操作。击败这一点,它永远不会按预期工作。实际的窗口过程内置于conhost.exe中,它不知道如何处理这些WM_TIMER消息。
你必须重新考虑这一点。就像创建自己的窗口和消息循环一样,通常在另一个线程上,以防止它干扰正常的控制台I / O.或者更容易使用CreateTimerQueueTimer(),请注意其回调在另一个线程上运行。必须这样,因为操作系统没有任何方法可以打入你的主线程。正确执行此操作的难度提供了本机Windows程序以其工作方式工作的原因。消息循环是producer-consumer problem的通用解决方案。控制台模式程序不会尝试解决它。