⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dwatchdlg.cpp

📁 监控文件目录的VC程序
💻 CPP
字号:
// dwatchDlg.cpp : implementation file
//

#include "stdafx.h"
#include "winsvc.h"	// Fuer Admi-Test
#include "dwatch.h"
#include "optionsdialog.h"
#include "dwatchDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// Undokumentierte Funktion aus ntdll.dll
// Parameters
// ----------
// 1. FileHandle
// 2. EventHandle (OPTIONAL)
// 3. &ApcRoutine (OPTIONAL)
// 4. &ApcContext (OPTIONAL)
// 5. &IO_STATUS_BLOCK (2 DWORDS)
// 6. &buffer (FILE_NOTIFY_INFORMATION)
// 7. BufferLength
// 8. Flags
// 9. BOOL -> Subdirectories ueberwachen oder nicht
extern "C"
DWORD __stdcall NtNotifyChangeDirectoryFile (HANDLE, HANDLE, PVOID, PVOID, PVOID, PVOID, DWORD, DWORD, BOOL);

// Watch-Handles
HANDLE watchhandle[8];
// Watch-Info fuer den jeweiligen Thread
DWORD threadinfo[8];
// MFC-Threads
CWinThread *threads[8];
// Thread-synchronisation
CRITICAL_SECTION csection;


////////////////////////////////////////////////////////////////////////////
// EXTRA THREADS --- not class members

// Wartet die initialisierung dieser App ab
// ... und laesst dann die Options-Box erscheinen
// Ausserdem wird die Groesse des Fensters eingestellt
void WaitFunc (CDwatchDlg *cdw)
{
	WaitForInputIdle (GetCurrentProcess(), 10000);
	HWND hwnd = cdw->GetSafeHwnd();
	SetWindowPos (hwnd, NULL, 0, 0, 600, 300, SWP_NOMOVE | SWP_NOZORDER); 
	SendMessage (hwnd, WM_CONTEXTMENU, 0, 0L); 
}

// Sorgt dafuer, dass das ListCtrl wieder sichtbar wird
void VisibilityFunc (CDwatchDlg *cdw)
{
	SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_IDLE);
	Sleep (2000);
	for (;;)
	{
		Sleep (2000);
		if (cdw->m_listctrl.GetSafeHwnd() && cdw->m_visibility == FALSE)
		{
			cdw->m_listctrl.SendMessage (WM_SETREDRAW, TRUE, 0L);
			cdw->m_listctrl.InvalidateRect (NULL);
			cdw->m_listctrl.UpdateWindow();
			cdw->m_visibility = TRUE;
		}
	}
}

// Jeder einzelne "Watch" wird als Thread ausgef黨rt
void Threadfunc (CDwatchDlg *cdw)
{
	// Thread findet sich selbst
	int s;
	int tnum = -1;
	for (s=0; s<8; s++)
	{
		if (threads[s])
		{
			if (threads[s]->m_nThreadID == GetCurrentThreadId())
			{
				tnum = s;
				break;
			}
		}
	}
	// WatchHandle oeffnen
	watchhandle[tnum] = CreateFile (cdw->m_options.m_dirname,
									FILE_LIST_DIRECTORY,
									FILE_SHARE_READ | FILE_SHARE_WRITE,
									NULL,
									OPEN_EXISTING,
									FILE_FLAG_BACKUP_SEMANTICS,
									NULL);
	BYTE buffer[1024];
	DWORD io_status_block[2];
	for (;;)
	{
		ZeroMemory (buffer, sizeof (buffer));
		NtNotifyChangeDirectoryFile (watchhandle[tnum], 
									 NULL,
									 NULL,
									 NULL,
									 &io_status_block,
									 &buffer,
									 sizeof (buffer),
									 threadinfo[tnum],
									 TRUE);
		WaitForSingleObject (watchhandle[tnum], INFINITE);
		EnterCriticalSection (&csection);
		cdw->SetEntry (tnum, (FILE_NOTIFY_INFORMATION*)buffer);
		LeaveCriticalSection (&csection);
	}	
}





/////////////////////////////////////////////////////////////////////////////
// HelperFuncs

// Einen Eintrag im ListCtrl setzen.... wird vom jeweiligen Thread gemacht
// ...buffer zeigt auf eine	struct -> FILE_NOTIFY_INFORMATION
// TIME-CRITICAL !!!!
void CDwatchDlg::SetEntry (int num, FILE_NOTIFY_INFORMATION *buffer)
{
	// Local vars
	static SYSTEMTIME st;
	static char string[256];
	static int numitems;
	static char *action;
	static int s;

	// ListCtrl abschalten, damit die Threads schneller sind...
	if (m_visibility)
	{
		m_visibility = FALSE;
		m_listctrl.SendMessage (WM_SETREDRAW, FALSE, 0L);
	}

	numitems = m_listctrl.GetItemCount();
	// Zeit eintragen
	GetLocalTime (&st);
	sprintf (string, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
	m_listctrl.InsertItem (numitems, string);
	// Thread-info eintragen
	m_listctrl.SetItemText (numitems, 1, m_infotxt[num]);
	// Aktion eintragen
	switch (buffer->Action)
	{
		case FILE_ACTION_ADDED:
		action = "++ created ++";
		break;

		case FILE_ACTION_REMOVED:
		action = "-- removed --";
		break;

		case FILE_ACTION_MODIFIED:
		action = "< modified >";
		break;

		case FILE_ACTION_RENAMED_OLD_NAME:
		action = "renaming...";
		break;

		case FILE_ACTION_RENAMED_NEW_NAME:
		action = "...renamed";
		break;

		default:
		action = "Unknown";
		break;
	}
	m_listctrl.SetItemText (numitems, 2, action);
	// File/Directory-Namen eintragen
	for (s=0; s<(int)buffer->FileNameLength; s++)
		string[s] = (char)buffer->FileName[s];
	string[s+1] = (char)0;
	m_listctrl.SetItemText (numitems, 3, string);

	// Eventuell alles noch einmal
	if (buffer->NextEntryOffset)
		SetEntry (num, (FILE_NOTIFY_INFORMATION*)((BYTE*)buffer + buffer->NextEntryOffset));
}


// Threads Killen und zugehoerige Watchhandles schliessen
// ... und Critical-Section-Objekt erneuern
void CDwatchDlg::KillAllThreads (void)
{
	int s;
	for (s=0; s<8; s++)
	{
		if (threads[s])
		{
			HANDLE hthread = threads[s]->m_hThread;
			TerminateThread (hthread, 0);
			delete threads[s];
			CloseHandle (hthread);
			CloseHandle (watchhandle[s]);
			threads[s] = NULL;
		}
	}	
	DeleteCriticalSection (&csection);
	InitializeCriticalSection (&csection);
}

// Titelzeile aktualisieren
void CDwatchDlg::UpdateTitle (BOOL flag)
{
	CString cs = "Directory Watchdog";
	if (flag)
		cs = cs + " <" + m_options.m_dirname + ">";
	else
		cs = cs + " <stopped>";
	SetWindowText (cs);
}

/////////////////////////////////////////////////////////////////////////////
// CDwatchDlg dialog

CDwatchDlg::CDwatchDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDwatchDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDwatchDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT

	// Auf Admi testen
	SC_HANDLE sch = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (!sch)
	{
		MessageBox ("You must log on as an administrator to use this tool...", 
					"Sorry", 
					MB_ICONSTOP);
		ExitProcess (0);
	}
	CloseServiceHandle (sch);
	
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	// CWinThread-Pointers und Watchhandles loeschen
	int s;
	for (s=0; s<8; s++)
	{
		threads[s] = NULL;
		watchhandle[s] = NULL;
	}

	// Critical Section anlegen
	InitializeCriticalSection (&csection);

	// WatchInfo-Flags laden
	threadinfo[0] = FILE_NOTIFY_CHANGE_LAST_ACCESS;
	threadinfo[1] = FILE_NOTIFY_CHANGE_ATTRIBUTES;
	threadinfo[2] = FILE_NOTIFY_CHANGE_DIR_NAME;
	threadinfo[3] = FILE_NOTIFY_CHANGE_FILE_NAME;
	threadinfo[4] = FILE_NOTIFY_CHANGE_SECURITY;
	threadinfo[5] = FILE_NOTIFY_CHANGE_SIZE;
	threadinfo[6] = FILE_NOTIFY_CHANGE_CREATION;
	threadinfo[7] = FILE_NOTIFY_CHANGE_LAST_WRITE;

	// WatchInfo-Texte laden
	m_infotxt[0] = "Read";
	m_infotxt[1] = "Attributes";
	m_infotxt[2] = "Directory";
	m_infotxt[3] = "File";
	m_infotxt[4] = "Security";
	m_infotxt[5] = "Size";
	m_infotxt[6] = "TimeStamp";
	m_infotxt[7] = "Write";
	
	m_visibility = TRUE;
	
	// Nachtr鋑liche Initialisierung starten
	AfxBeginThread ((AFX_THREADPROC)WaitFunc, this);

	// ListCtrl-Updater starten
	m_updater = AfxBeginThread ((AFX_THREADPROC)VisibilityFunc, this);
}

void CDwatchDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDwatchDlg)
	DDX_Control(pDX, IDC_LIST1, m_listctrl);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDwatchDlg, CDialog)
	//{{AFX_MSG_MAP(CDwatchDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_SIZE()
	ON_WM_CONTEXTMENU()
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDwatchDlg message handlers

BOOL CDwatchDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	
	// ListControl vorbereiten
	char *ColTxt[] = { "Time", "File Access", "Action", "Filename"};
	int i;
	LV_COLUMN lvc;
	lvc.mask=LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
	lvc.iSubItem=-1;
	for(i=0; i<4; i++)
	{
		lvc.pszText = ColTxt[i];
		lvc.fmt = LVCFMT_LEFT;
		m_listctrl.InsertColumn (i,&lvc);
	}

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CDwatchDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CDwatchDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

// ListCtrl anpassen
void CDwatchDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	
	if (m_listctrl.GetSafeHwnd())
	{
		int ptx = cx/6;
		m_listctrl.MoveWindow (0,0, cx, cy);
		m_listctrl.SetColumnWidth (0, ptx);
		m_listctrl.SetColumnWidth (1, ptx);
		m_listctrl.SetColumnWidth (2, ptx);
		m_listctrl.SetColumnWidth (3, cx-ptx-ptx-ptx);
	}
}

void CDwatchDlg::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	switch (m_options.DoModal())
	{
		// Threads starten, alte Killen
		// Die komische Prozedur von wegen Thread suspended createn und
		// dann zu resumen ist noetig, damit die CWinThread-Pointer gueltige
		// Werte haben, wenn die Threads loslegen.....
		case 0:
		KillAllThreads();
		UpdateTitle (TRUE);
		if (m_options.m_access)
		{
			threads[0] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[0]->ResumeThread();
		}
		if (m_options.m_attributes)
		{
			threads[1] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[1]->ResumeThread();
		}
		if (m_options.m_dirnames)
		{
			threads[2] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[2]->ResumeThread();
		}
		if (m_options.m_filenames)
		{
			threads[3] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[3]->ResumeThread();
		}
		if (m_options.m_security)
		{
			threads[4] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[4]->ResumeThread();
		}
		if (m_options.m_size)
		{
			threads[5] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[5]->ResumeThread();
		}
		if (m_options.m_tstamp)
		{
			threads[6] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[6]->ResumeThread();
		}
		if (m_options.m_write)
		{
			threads[7] = AfxBeginThread ((AFX_THREADPROC)Threadfunc, 
										this, 
										THREAD_PRIORITY_TIME_CRITICAL, 
										0, 
										CREATE_SUSPENDED);
			threads[7]->ResumeThread();
		}
		break;

		// Threads stoppen/loeschen
		case 1:
		KillAllThreads();
		UpdateTitle (FALSE);
		break;
		
		// Display loeschen
		case 2:
		m_listctrl.DeleteAllItems();
		break;

		// Absaven
		case 3:
		{
			CFileDialog cf (FALSE, NULL, "*.*");
			cf.m_ofn.Flags &= ~OFN_EXPLORER;
			if (cf.DoModal() == IDOK)
			{	
				CString cs = cf.GetPathName();
				CFile cfile(cs, CFile::modeCreate | CFile::modeWrite);
				cs.Format ("Directory scan of: %s\n\n", m_options.m_dirname);
				cfile.Write (cs, cs.GetLength());
				int s;
				for (s=0; s<m_listctrl.GetItemCount(); s++)
				{
					cs.Format ("%-20s %-20s %-20s %s\n", 
								m_listctrl.GetItemText (s, 0),
								m_listctrl.GetItemText (s, 1),
								m_listctrl.GetItemText (s, 2),
								m_listctrl.GetItemText (s, 3));
					cfile.Write (cs, cs.GetLength()); 
				}
				cfile.Close();
			}
		}
		break;
	
	}
}

// Threads killen, sonst Haenger!!!
void CDwatchDlg::OnClose() 
{
	KillAllThreads();
	TerminateThread (m_updater->m_hThread, 0);
	delete m_updater;
	CDialog::OnClose();
}

// Return-Taste -> Options-Dialog starten
void CDwatchDlg::OnOK()
{
	OnContextMenu (NULL, 0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -