很多时候,我们都会遇到编写后台运行程序的问题。编写后台运行程序的主要工作并不在接口上,而是在其作为服务器程序所完成的实际工作上。由于编写过不少后台工作程序,最初总是为程序的后台工作接口而苦恼不已。在这里,我贴出相关的代码,相信根据此设计,读者可以轻易地把它应用到自己的后台程序中去。
假设程序名称为startup,那么程序启动的接口为:
Startup: 启动该程序
Startup -v: 查看该程序的版本
Startup -d: 启动该程序,并将调试信息打印到debug文件中
Startup -h: 以后台方式启动应用程序
Startup -k: 停止后台应用程序的运行
Startup -l: 重新读取应用程序的配置文件
配置文件(startup.ini)的格式如下:
[SERVER]
DEBUG = 1
完整的实现如下:
Startup.h
#ifndef _STARTUP_H_
#define _STARTUP_H_

#define MAX_MSG_SIZE 1500
#define MAX_BUFFER_LEN 1024
#define MIN_BUFFER_LEN 256
#define MAX_FILE_NAME_LEN MAX_BUFFER_LEN

#define CFG_PATH "Startup.ini"

void loadConfig();
void mprintf(const char *pszFormat,...);

#endif
Startup.cpp
#include "Startup.h"
#include <stdlib.h>
#include <Windows.h>

#include <iostream>

using namespace std;

HANDLE hExitHandle = 0;
HANDLE hLoadHandle = 0;
int nDbgInfoPrt = 0;

int main(int argc, char* argv[])

...{
if (argc > 2)

...{
cout << "Error, print "Startup -help" for usage." << endl;
return 0;
}

if (argc == 2 && strcmp(argv[1], "-help") == 0)

...{
cout << "Usage: Startup for starting up test." << endl;
cout << "-------------------------------------------" << endl;
cout << "Startup: Start the application." << endl;
cout << "Startup -v: View the version." << endl;
cout << "Startup -d: Start the application in debug mode." << endl;
cout << "Startup -h: Start the application in hide mode." << endl;
cout << "Startup -k: Stop the application running in hide mode." << endl;
cout << "Startup -l: Reload the config when running in hide mode." << endl;
return 0;
}

if (argc == 2 && strcmp(argv[1], "-v") == 0)

...{
cout << "Startup v1.0 for starting up test" << endl;
return 0;
}

if (argc == 2 && strcmp(argv[1], "-d") == 0)

...{
nDbgInfoPrt = true;
mprintf("Run application in debug mode!");
}

if (argc == 2 && strcmp(argv[1], "-h" ) == 0)

...{
//Run the program background

char szPath[MAX_PATH] = ...{ 0 };
STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

GetModuleFileName(NULL, (LPWCH)szPath, MAX_PATH);
if (!CreateProcess(NULL, // No module name (use command line).
(LPWSTR)szPath, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
CREATE_NO_WINDOW, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi) // Pointer to PROCESS_INFORMATION structure.
)

...{
cout << "Failed in starting application, error code: " << GetLastError() << endl;
}

return 0;
}

if (argc == 2 && strcmp(argv[1], "-k") == 0)

...{
hExitHandle = OpenEvent(EVENT_ALL_ACCESS, FALSE, (LPCWSTR)"StartupKill");
if (NULL == hExitHandle)

...{
mprintf("Can't open kill event");
return 0;
}

SetEvent(hExitHandle);
return 0;
}

if (argc == 2 && strcmp(argv[1], "-l") == 0)

...{
hLoadHandle = OpenEvent(EVENT_ALL_ACCESS, FALSE, (LPCWSTR)"StartupLoad");
if (NULL == hLoadHandle)

...{
mprintf("Can't open load event");
return 0;
}

SetEvent(hLoadHandle);
return 0;
}

hExitHandle = CreateEvent(NULL, TRUE, FALSE, (LPCWSTR)"StartupKill");
if (NULL == hExitHandle)

...{
mprintf("Can't create kill event");
return 0;
}

hLoadHandle = CreateEvent(NULL, TRUE, FALSE, (LPCWSTR)"StartupLoad");
if (NULL == hLoadHandle)

...{
mprintf("Can't create load event");
return 0;
}

if (GetLastError() == ERROR_ALREADY_EXISTS)

...{
cout << "Application has already started." << endl;
return 0;
}

// load the configure information
loadConfig();

for ( ; ; )

...{
if (WaitForSingleObject(hExitHandle, 0) != WAIT_TIMEOUT)

...{
break;
}

if (WaitForSingleObject(hLoadHandle, 0) != WAIT_TIMEOUT)

...{
loadConfig();
}
// TODO: do something here
mprintf("The program is alive!");

Sleep(1000);
}

CloseHandle(hExitHandle);
CloseHandle(hLoadHandle);

return 0;
}


/**////////////////////////////////////////////////////
//
// Description: load the configure from .ini file
//
// Parameter:
// void ==
//
// Return:
// void ==
//

/**////////////////////////////////////////////////////
void loadConfig()

...{
// Get the configure info from Startup.ini
nDbgInfoPrt = GetPrivateProfileInt((LPCWSTR)"SERVER", (LPCWSTR)"DEBUG", 0, (LPCWSTR)CFG_PATH);
}



/**////////////////////////////////////////////////////
//
// Description: print the msg
//
// Parameter:
// const char *pszFormat ==
//
// Return:
// void ==
//

/**////////////////////////////////////////////////////
void mprintf(const char *pszFormat,...)

...{
if (!nDbgInfoPrt)

...{
return;
}

va_list vaArg;
va_start(vaArg, pszFormat);


char szDbgInfo[MAX_BUFFER_LEN + 1] = ...{0, };
vsprintf_s(szDbgInfo, pszFormat, vaArg);

va_end(vaArg);

cout << szDbgInfo << endl;
}
