创建windows系统服务监控一个文件夹的内容改变

监控文件夹内容的改变,主要是用到一个api: ReadDirectoryChangesW ,这个api只能用来处理宽字节,但是我建项目的时候用的是没有修改character set 用的是ansi  所以写项目程序的过程中需要使用ansi到Unicode的变换(这个是想使用WideCharToMultiByte,MultiByteToWideChar这两个API),,但是由于多次使用这种变换,导致程序完成后有一个bug,时有时无,找了好久都没有找到。

最后又重新编写了程序,把character set 设置成宽字节,bug就暂时没有了, 能够正常运行了。

这个小练习主要就是学习使用几个api.

这个exe使用ini文件,确定监控文件夹的位置和log生成的路径。

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <string>


char where_to_save_log[MAX_PATH];
char where_to_monitior[MAX_PATH];
bool bRun = false;
std::string m_ini_path;


SERVICE_STATUS servicestatus;
SERVICE_STATUS_HANDLE hStatus;

class monitior_file_change
{
private:
	char folder[1024];

public:
	char notify[1024];
	bool watch_state;
	int input_folder();
	void do_text_deal(std::string p);
	int monitior_file();
};

void to_do_something();
int WriteToLog(char* str);
std::string get_ini_path();
bool searchFile();

void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WINAPI ServiceMain(int argc, char** argv);
void WINAPI ControlHandler(DWORD request);
int WriteToLog(char* str);
void WatchDirectory(LPTSTR);


int WriteToLog(char* str)
{
	FILE* pfile;
	fopen_s(&pfile, where_to_save_log, "a+");

	if (pfile == NULL)
		return -1;

	fprintf_s(pfile, "%s\n", str);
	fclose(pfile);

	return 0;

}
#include "Header.h"

std::string get_ini_path()
{
	char exefullpath[MAX_PATH];
	std::string strPath = "";
	GetModuleFileName(NULL,exefullpath, MAX_PATH);
	strPath = (std::string)exefullpath;
	int pos = strPath.find_last_of('\\', strPath.length());

	return strPath.substr(0, pos);

}

bool searchFile()
{
	HANDLE hFile = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATA pNextInfo;

	std::string p = get_ini_path();
	std::string m1 = "\\*.ini";
	p = p + m1;

	hFile = FindFirstFile(p.c_str(), &pNextInfo);

	if (INVALID_HANDLE_VALUE == hFile)
	{
		return FALSE;
	}

	std::string inipath;
	if (pNextInfo.cFileName[0] != '.')
	{
		inipath = pNextInfo.cFileName;
	}
	while (FindNextFile(hFile, &pNextInfo))
	{
		if (pNextInfo.cFileName[0] != '.')
			continue;
		inipath = pNextInfo.cFileName;
		
	}
	int pos = p.find_last_of('\\', p.length());
	std::string p1 = p.substr(0, pos+1);

	m_ini_path = p1 + inipath;
	return true;

}

/////////////////////////////////////////////////////获得ini文件的绝对路径。

int monitior_file_change::input_folder()
{
	 GetPrivateProfileString("SECTION", "Where_to_save_log", "No Text", where_to_save_log, MAX_PATH, m_ini_path.c_str());
	 GetPrivateProfileStringA("SECTION", "Where_to_monitior", "No Text1", where_to_monitior, MAX_PATH, m_ini_path.c_str());

	 return 0;

}

int monitior_file_change::monitior_file()
{
	HANDLE handle_directory = CreateFile(where_to_monitior,
		FILE_LIST_DIRECTORY,
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_BACKUP_SEMANTICS,
		NULL);

	if (handle_directory == INVALID_HANDLE_VALUE)
	{
		DWORD ERROR_DIR = GetLastError();
		WriteToLog("Open dir Error!\n");
	}
	char notify[1024];

	DWORD cbBytes;
	BOOL watch_state;
	FILE_NOTIFY_INFORMATION *pNotify = (FILE_NOTIFY_INFORMATION *)notify;
	while (1)
	{
		memset(notify, 0, 1024);

		watch_state = ReadDirectoryChangesW(handle_directory,
			¬ify,
			sizeof(notify),
			TRUE,
			FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME,
			&cbBytes,
			NULL,
			NULL);		
		char message[1024];
		if (GetLastError() == ERROR_INVALID_FUNCTION)
		{
			sprintf_s(message, "system do not support.\n");
			WriteToLog(message);
		}
		
		else if (watch_state == 0)
		{
			sprintf_s(message, "monitior.\n");
			WriteToLog(message);
		}
		
		else if (GetLastError() == ERROR_NOTIFY_ENUM_DIR)
		{
			sprintf_s(message, "out of memory.\n");
			WriteToLog(message);
		}

		else
		{
			std::string file_name;
			
			PSTR ps = new CHAR[126];
			WideCharToMultiByte(0, 0, pNotify->FileName, -1, ps, 126, NULL, NULL);
			file_name = std::string(ps);
			delete[] ps;
		
		
			char szTimeBuf[64] = { 0X00 };
			SYSTEMTIME today;
			char message[1024];
			::GetLocalTime(&today);
			sprintf_s(szTimeBuf, "%.2d:%.2d:%.2d.%.3d", today.wHour, today.wMinute, today.wSecond, today.wMilliseconds);
	
			switch (pNotify->Action)
			{
			case FILE_ACTION_ADDED:
				sprintf_s(message, "%s  New Folder:%s\n", szTimeBuf, file_name.c_str());
				WriteToLog(message);
				do_text_deal(file_name);
				break;
			case FILE_ACTION_MODIFIED:
				sprintf_s(message, "%s  The file was modified. This can be a change in the time stamp or attributes.\n", szTimeBuf);
				WriteToLog(message);
				break;
			case FILE_ACTION_REMOVED:
				sprintf_s(message, "%s  The file was removed from the directory.\n", szTimeBuf);
				WriteToLog(message);
				break;
			case FILE_ACTION_RENAMED_OLD_NAME:
				sprintf_s(message, "%s  The file was renamed and this is the old name .\n", szTimeBuf);
				WriteToLog(message);
				break;
			default:
				sprintf_s(message, "Unknown command.\n");
				WriteToLog(message);
			}
		}
	}
	::CloseHandle(handle_directory);



}

void monitior_file_change::do_text_deal(std::string p)
{
	std::string suf = p.substr(p.find_last_of('.') + 1);
	if (suf == "txt" || suf == "csv")
		WriteToLog("file is end,can do some deal");
}







void to_do_something()
{
	searchFile();
	monitior_file_change m1;
	m1.input_folder();

	m1.monitior_file();
	return ;
}

//*********************************************************************************************************************

void WINAPI ServiceMain(int argc, char** argv)
{
	servicestatus.dwServiceType = SERVICE_WIN32;
	servicestatus.dwCurrentState = SERVICE_START_PENDING;
	servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;

	servicestatus.dwWin32ExitCode = 0;
	servicestatus.dwServiceSpecificExitCode = 0;
	servicestatus.dwCheckPoint = 0;
	servicestatus.dwWaitHint = 0;

	hStatus = ::RegisterServiceCtrlHandler("testservice", ControlHandler);
	if (hStatus == 0)
	{
		WriteToLog("RegisterServiceCtrlHandler failed");
		return;
	}
	else
		WriteToLog("RegisterServiceCtrlHandler success");



	servicestatus.dwCurrentState = SERVICE_RUNNING;

	SetServiceStatus(hStatus, &servicestatus);

	bRun = true;

	while (bRun)
	{
		to_do_something();//监控文件夹想做的事情
	}

	WriteToLog("service stopped");
}

void RefreshDirectory(LPTSTR lpDir)
{
	_tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}

void RefreshTree(LPTSTR lpDrive)
{
	_tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
}



void WINAPI ControlHandler(DWORD request)
{
	switch (request)
	{
	case SERVICE_CONTROL_STOP:
		bRun = false;
		servicestatus.dwCurrentState = SERVICE_STOPPED;
		break;

	case SERVICE_CONTROL_SHUTDOWN:
		bRun = false;
		servicestatus.dwCurrentState = SERVICE_STOPPED;
		break;

	default:
		break;
	}

	SetServiceStatus(hStatus, &servicestatus);
}

void main()
{
	SERVICE_TABLE_ENTRY Entrytable[2];

	Entrytable[0].lpServiceName = "testservice";
	Entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

	Entrytable[1].lpServiceName = NULL;
	Entrytable[1].lpServiceProc = NULL;

	StartServiceCtrlDispatcher(Entrytable);
}
打开cmd 使用以下语句写入后台服务:
sc create testservciename binPath= "xxx.exe" 
sc start testservciename
/////
如果不想用了可以使用以下语句
sc stop testservciename
sc delete testservciename

PS : cmd需要使用管理员权限




猜你喜欢

转载自blog.csdn.net/york6/article/details/79023894
今日推荐