几点心得
1.在多媒体定时器的响应函数中不能使用DestroyWindow函数。
因为多媒体定时器实际是内部开了一个线程,在该线程中调用定时器的回调函数。
而MSDN告诉我们:
A thread cannot use DestroyWindow to destroy a window created by a different thread.
所有就有上面的结论了。那么,如果确实要调用怎么办呢? 比如用多媒体定时器来控制一个窗口的生存时间,到了一定的秒数就关闭窗口。
应该用sendmessage。
{
TIMECAPS tc;
if(::timeGetDevCaps(&tc,sizeof(TIMECAPS)) == TIMERR_NOERROR)//查询设备能力。
{
m_timerRes = min(max(tc.wPeriodMin,1),tc.wPeriodMax);
if(::timeBeginPeriod(m_timerRes)==TIMERR_NOERROR)//设定定时器精度。
{
MMRESULT result= ::timeSetEvent(uDelay,m_timerRes,TimerProc,(DWORD)this, TIME_PERIODIC);
if (result != NULL)//设置成功,定时器开始起作用。
{
m_timerId = (UINT)result;
return TRUE;
}
}
}
return FALSE;
}
下面是响应函数:
{
::SendMessage(m_pThis->m_hWnd,WM_MY_TimeTick,0,0);
// if(m_pThis->m_LiveTime==0)
// {
//注意,这里不能直接调DestroyWindow,因为不在同一个线程中.
// }
}
注意:WM_MY_TimeTick是一个自定义的消息。可以在响应该消息是调用DestroyWindow。SendMessage函数为什么可以成功呢,因为该函数没有要求在同一个线程中(实际上连同一个进程都没要求,可以安全的发送消息到另一个进程的窗口,很多情况下会失败是因为地址空间的关系)。它之所以不要求,是因为该函数自己会处理线程切换等事务。
2、服务的类型和子进程的类型
如果服务注册为非交互式的,然后在其中产生子进程。那么子进程可以使用窗口吗(即是否能是一个GUI程序)?答案是非也。
这个问题大概根窗口站(window station)相关吧。窗口站包含了桌面,桌面包含了窗口。windows将可见的窗口站命名为WinSta0,其余的窗口站都是不可见的。
除非另行指定,windows子系统将所有运行在本地系统账户下的服务与一个非可见窗口站:Service-0x0-3e7$关联起来。所有非交互式服务都共享此窗口站。
凡是指定了某个账户(非本地系统账户)的服务,都运行在一个独立的非可见窗口站中。
总结:如果是非交互式的服务,则其子进程也在同一个窗口站(该窗口站不可见)运行,因此子进程的窗口也是不可见的。
以上内容,详见《深入解析windows操作系统第4版》p221。
3、如何屏蔽Ctrl+alt+del
简单的说,hook winlogon.exe进程中的SAS 窗口的窗口过程。在其中拦截该组合键即可。主要步骤是:
1. 打开winlogon.exe进程。这个又分为: a.取进程id. b.提升权限。 c.打开进程.
2.写该进程的内存。 写入一些数据,为加载DLL做准备。
3.创建远程线程,让winlogon加载一个dll。
4.DLL的主函数中,替换winlogon的SAS窗口过程。注意,该窗口在桌面Winlogon下,必须先打开该桌面,才能枚举窗口。
注:2,3,4也可以完全不使用dll,直接把代码写入winlogon进程,这就需要几个占位函数以便计算各函数的代码长度。
或者,使用DLL,但只是加入代码,并不在dll主函数中做hook窗口的工作。而是创建远程线程,执行该dll中的代码。
相关的代码网上很容易找,不过自己做的话还是会碰到一些细节问题。只要基本概念有了,找到代码然后修改是很容易的。