功能:实现一个windows守护进程,设置有自定义图标,启动后隐藏黑窗口,获取exe所在目录,并设置开机自启动(需要以管理员权限运行)。如果需要打包成可执行的安装包程序,见另一篇博客:https://blog.csdn.net/qq_24977505/article/details/106415058。
隐藏控制台窗口:main函数前添加
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) 即可。
设置自定义图标:Damon.exe设置heworld.ico图标,HelloWorld.exe没有
1、需要先自制一个ico格式图标,点开http://www.bitbug.net/ 上传图片即可做好。
2、将图标放到代码路径下,在vs项目中添加.rc文件(选中项目->右键添加->新建项->资源文件.rc->确定)。
3、到源文件目录记事本打开这个.rc文件,末尾添加 IDI_ICON1 ICON DISCARDABLE "heworld.ico" ,heworld.ico是第一步自作好的ico文件,一定要同在源文件目录下。
4、重新编译即可。
设置开机自启动代码如下:
#include
#include
#include
#include
// 设置黑窗隐藏
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
// 需要守护的进程可执行文件,和daemon.exe放一起
#define PROCCESS_NAME "HelloWorld.exe"
char g_workPath[MAX_PATH] = { 0 };
void WriteLogFile(char *msg);
BOOL SetSelfStart()
{
//获取程序完整名称
char pName[MAX_PATH] = { 0 };
GetModuleFileNameA(NULL, pName, MAX_PATH);
HKEY hKey = NULL;
LONG lRet = NULL;
const char * regeditPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\";
if (ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE, regeditPath, 0, KEY_ALL_ACCESS, &hKey))
{
return FALSE;
}
if (ERROR_SUCCESS != RegSetValueExA(hKey, "Heworld", 0, REG_SZ, (const unsigned char*)pName, strlen(pName) + sizeof(char)))
{
return FALSE;
}
RegCloseKey(hKey);
WriteLogFile("守护进程开机自启动成功\n");
return TRUE;
}
void GetWorkPath(char *argv)//获取exe所在目录
{
char drive[4];
char subdir[MAX_PATH];
char fn[MAX_PATH];
char exten[MAX_PATH];
_splitpath_s(argv, drive, subdir, fn, exten);
sprintf_s(g_workPath, "%s%s", drive, subdir);
}
int main(int argc, char *argv[])
{
GetWorkPath(argv[0]);
if (!SetSelfStart())
{
WriteLogFile("守护进程开机自启动失败\n");
}
STARTUPINFOA si;
PROCESS_INFORMATION pi;
//初始化
ZeroMemory(&si, sizeof(si));
si.wShowWindow = SW_HIDE;
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
//构造cmd执行守护进程的字符串
static char fileName[MAX_PATH] = { 0 };
snprintf(fileName, MAX_PATH, "%s%s", g_workPath, PROCCESS_NAME);
do {
if (!CreateProcessA(NULL, fileName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
WriteLogFile("守护进程启动失败,程序即将退出\n");
return -1;
}
WriteLogFile("守护进程成功\n");
WaitForSingleObject(pi.hProcess, INFINITE);
WriteLogFile("守护进程退出......\n");
//关闭进程和句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Sleep(2000);
} while (true);
return 0;
}
const char *GetNowStr()
{
static char nowstr[64];
time_t nowTime = 0;
time(&nowTime);
struct tm tmNow;
localtime_s(&tmNow, &nowTime);
sprintf_s(nowstr, "%02d%02d_%02d%02d%02d", tmNow.tm_mon + 1, tmNow.tm_mday,
tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
return nowstr;
}
void WriteLogFile(char *msg)
{
static int writeLine = 0;
static FILE* fp = NULL;
if (fp == NULL)
{
char buf[1024];
sprintf_s(buf, "%s%s", g_workPath, "daemon.log");
fopen_s(&fp, buf, "w");
if (fp == NULL)
{
printf("open log file fail\n");
return;
}
}
static char header[128];
sprintf_s(header, "[%s]:", GetNowStr());
fwrite(header, 1, strlen(header), fp);
fwrite(msg, 1, strlen(msg), fp);
fflush(fp);
printf(msg);
if (50000 < writeLine++)
{
fp = NULL;
writeLine = 0;
}
}