欢迎各位大家关注本人微信公众号:程序员JC,小程序:RobotJC 里面包含很多本人之前做的小案例(包含源码以及资源),也许这里有你想要的东西哦。
这篇文章其实几周前,我就想写了。但是鉴于我个人的一些事情,导致我没有心思和心情去写。但是,之后我想想不应该这样继续下去。所以借这篇文章机会,我衷心希望各位看到这篇文章的朋友,能生活的像题图上写的一样,“纵使生活跌倒一百次,也要一百零一次地站起来”。因为好的心态生活真的很重要。好了,不讲大道理了,哈哈。开始说正事了。
我为什么会写这个程序?
首先,说明一下,我是一个晚睡晚起的程序员(哈哈,不知道各位同僚的程序员作息如何)。加上疫情期间一直在家待着,这种晚睡晚起的习惯愈演愈烈(睡的更晚,起的更晚),而且缺乏各种锻炼。不像之前上班,尽管的睡的很晚,但是第二天会因为上班有时会强制自己早睡而且每天饮食正常,会跑步锻炼。我也意识到自己的这个问题,也想过改正,但是每到晚上就会非常精神,而且还有很多理由说服自己,是不是就像民间里流传的寒号鸟故事,哈哈。
我也具体分析过,导致我晚睡的最直接因素主要有两个,一个是手机,一个电脑。所以从我一个程序员角度出发,有没有什么办法能让我写一个程序,在指定的时间段内强制关机手机和电脑,而且在指定的时间段内容只要一开机就会关机(大概就是这么情况,对了千万不要留一手后路,如果留了也会去说服自己每次走后路,至少我会这样,嘿嘿。如果有必要的特殊情况需要在这段指定的时间段内要是用手机或设备,这时可以给条后路,但是一定要麻烦,不能太过容易,因为我个人觉得如果十分必要,再麻烦也会去处理的)。
但是,需要考虑实际的是,我目前只能从电脑进行实时,但是在手机上我没有进行深入研究。我私底下也会去研究这方面的技术,如果各位同僚知道如何操作,也可以各位分享一下,谢谢!接下来,我都是讲如何从电脑实现我上述需求。
将白话需求转成技术需求?
这里,我只说个大概,然后列出几点核心技术需求。如果要想写的程序有较高的权限,所以用户不是很容易找到程序的源头,也不容易把程序杀掉。而且在关机前几分钟要有提示信息,防止用户数据丢失。
需求一:无任务栏图标弹窗倒计时提示?防止用户直接关闭,也不能遮盖其他应用程序。
需求二:从任务管理器隐藏程序,服务程序形式?防止用户直接
从任务管理器杀掉进程。
需求三:轮询服务、监听服务以及提示应用进程?轮询服务是防止监听服务异常,监听服务是防止提示应用程序异常,但是关机等执行命令依然在监听服务执行。
需求四:安装及卸载程序?安装初始化,卸载释放。
需求具体实现?
这里先说明一下,本程序一共包含5个进程,分别是安装进程(管理员权限)、卸载进程(管理员权限)、轮询服务进程(管理员权限、服务程序)、监听服务进程(服务程序)以及提示窗口进程。以下只给出部分源码,末尾会给出源码链接地址。
安装进程:只可安装一次,如需重复安装,必须先卸载。这个阶段可以添加计划,其中系统计划标题不可修改,只可修改时段。这个进程会创建并且启动轮询服务进程和监听服务进程。
卸载进程:会停止及删除轮询服务进程和监听服务进程。如果此前执行过安装进程,则执行该进程后,即可重新执行安装进程。
轮询服务进程:循环检测监听服务进程状态,如果被卸载,则执行安装及启动操作;如果被停止,则执行启动操作。
监听服务进程:读取计划项数据,循环检测计划状态,计划一旦触发则轮询提示窗口进程状态。如果未启动,则执行启动操作。
提示窗口进程:该窗口进程是运行在桌面之上,图标之下,是因为只能起一个提示作用,不可覆盖其他程序(类似广告)。隐藏任务栏图标,主要为了防止用户直接关闭。
需求一:无任务栏图标弹窗倒计时提示?
这里我就不对Win32窗口程序操作进行详细说明了,主要包含注册窗口RegisterClass、创建窗口CreateWindow以及消息轮询回调DefWindowProc几个步骤。忘记了的或者不清楚的请自行学习。
要想任务栏不显示引用程序图标,创建窗口需要使用API CreateWindowEx,第一个参数引入WS_EX_TOOLWINDOW以及第二个参数引入WS_POPUP即可,则可实现任务栏图标隐藏。
要想实现窗口透明化、任意形状窗口或者广告形式的弹窗,在创建窗口需要使用API CreateWindowEx,第一个参数引入WS_EX_LAYERED以及第二个参数引入WS_POPUP即可,之后需要调用API过滤窗口背景颜色。这里如果我选的窗口背景颜色是纯白色,则需要执行下面的代码则可实现窗口滤色。
//第一个参数,窗口句柄
//第二个参数,窗口背景颜色
//第三个参数, [0,1]/[0-255]
//第四个参数,LWA_COLORKEY/LWA_ALPHA
SetLayeredWindowAttributes(g_hWindow, RGB(255, 255, 255), 1, LWA_COLORKEY);
窗口绘制操作,这里如果要想实现任意形状的窗口绘制。则需要对矢量图进行操作(诸如:.PNG和.gif之类的)。我这里使用的Win32GDI+,因为GDI+可以操作PNG及GIF的矢量图。之所以不使用Win32GDI,使用GDI只可操作位图(BMP),比较局限,但是效率会比GDI+高很多。先粗略说明一下,如果需要是使用GDI+,需要最开始初始化一下,然后最后在进行释放。见下:
INT APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, INT nCmdShow)
{
//初始化
ULONG_PTR gdiplusStartupToken;
GdiplusStartupInput gdiInput;
GdiplusStartup(&gdiplusStartupToken, &gdiInput, NULL);
/* 执行逻辑(start) */
/* 执行逻辑(end) */
//释放
GdiplusShutdown(gdiplusStartupToken);
return 0;
}
截图前后对比:
需求二:从任务管理器隐藏程序,服务程序形式?
如需实现服务程序,不能像开发传统的Win32窗口程序或者控制台程序。不过也有点类似,主函数main就行,不需要WinMain。这里关心一下SERVICE_TABLE_ENTRY这个结构,结构里的程序包含服务名和入口函数,这个结构填充完后,需要使用API StartServiceCtrlDispatcher执行,然后该应用程序就是服务程序了。
入口函数是int func(int argc, const char *argv[]),参数就是main函数的入口参数。在入口函数中还需要实现SERVICE_STATUS这个结构。这个结构填充完后,需要调用API RegisterServiceCtrlHandler 和 SetServiceStatus 程序编译成功后,也是以exe后缀形式存在,启动之后不可在任务管理器中找到该服务程序,只能在服务管理器中能查看,见下图:
需求三:轮询服务、监听服务以及提示应用进程?
轮询服务、监听服务以及提示应用进程都是在同一个层级目录下,不可随意移动位置。但是这里有个问题,因为安装进程和卸载进程是在上面三个进程的上一级目录,而安装进程会直接安装并启动轮询服务和监听服务进程,这里就会出现工作路径问题。所以需要在每个应用程序最开始需要显示设置进程工作路径,调用API SetCurrentDirectory即可。具体路径结构见下:
需求四:安装及卸载程序?
这里的安装及卸载都是需要管理员权限的。考虑到服务程序没法直接卸载,所以这里提供了卸载程序。需要说明的是,安装程序的时候会写入计划项数据,并且会调用科大讯飞三方库并合成相关的提示音。
总结
到这里,该程序的核心需求及其难点均已实现。这里可能有的同僚会问这里广告弹窗是怎么回事,好像没有提到?的确,是没有提到。这里我说的只是一种方式。上述的服务程序窗口形式就是目前大多windows系统上的广告弹出形式,我这里想要表述的只是形式而已。只要弄懂了我上述说的服务程序及提示,便可实现弹窗。祝各位感兴趣的同僚早日实现哈!加油!
这里最后需要说明一下的事,尽管在电脑上,实现了我的上述需求。但是在实际当中,并没什么卵用。我还是晚睡晚起,哈哈。所以说打铁还需自身硬啊。这个是值得我反思的问题,不过从技术上我也算多学习了一样。嘿嘿。
最后附上源码地址:
链接:https://pan.baidu.com/s/1sj1iLKLs0fb2seUXjVa5Aw
提取码:rtjv