监控文件夹内容的改变,主要是用到一个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需要使用管理员权限