Solved

ReadDirectoryChangesW asynchronous - how to trigger?

Posted on 2009-07-15
7
1,228 Views
Last Modified: 2012-06-27
I'm using Borland C++ and API's ReadDirectoryChangesW in the asynchronous way, to watch a directory for changes. I watch for rename, add delete files or folders within the directory. I hav a loop in my thread like the code you will find below. All works nice so far. .. to nice perhaps ...

The program runs for hours and all my file operations i.e deleting or programaticaly renaming hundrets of files in a split if secons handled in "section #1" correctly.

Hmm... but how to test the code in "section #2" if an asynchronous operation never happens?

My question therefore is only: How to simulate an asynchronous operation to test my code? Or better, how to trigger one?


Thanks in advance :-)
bResult = ReadDirectoryChangesW( ...);
 

if (bResult) { 
 

	// section #1

	blah ...;

	blah ...;
 

}

else {
 

	// section #2

	// code to handel the results of 

	// asynchronous operations

	

}

Open in new window

0
Comment
Question by:hasnpapa
  • 3
  • 3
7 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 24862432
How are you using the 'asynchronous' way? Are you using an 'OVERLAPPED' struct or a completion routine?
0
 
LVL 6

Accepted Solution

by:
Ravi Kalla earned 400 total points
ID: 24862531
Step1: Create 2 files "file1" and "file2"
Step2: Write a program to rename a file from "file1" if it is "file11" and "file11" if it is "file1" and put this operation in an infinite loop.
Step3: Write another program to rename a file from "file2" if it is "file22" and "file22" if it is "file2" and put this operation in an infinite loop.
Step4: Now, execute the two programs created in "Step2" and "Step3" along with the program that you have to test. This is an asynchronous operation.
0
 

Author Comment

by:hasnpapa
ID: 24863289
@Ravi:
Realy thanks a lot for this explanation. At this point I don't kwno what a asynchronous operation basicly is. Now I do :-))

@jkr:
I'm using 'OVERLAPPED' struct in "section #2" as shown in the code above :-)

	

else {

	msg = "Reaching section #2!!!!!!!!!!!!!!!";

	Synchronize(&UpdateMemo);

	DWORD dwResult = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);

	switch ( dwResult ) {

	case WAIT_OBJECT_0: // then "terminate event"

		this->Terminate();

		break;

	case WAIT_OBJECT_0 + 1: // overlapped operation finished

		bResult = GetOverlappedResult(hDir, &ov, &BytesReturned, FALSE);

		if (!bResult) { // error!

		}

		else { //results of asynchronous operation

		}

	}

}

Open in new window

0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 86

Expert Comment

by:jkr
ID: 24863340
There seems to be a misconception - the finishing of the overlapped operation is always the end of an asynchronous action...
0
 

Author Comment

by:hasnpapa
ID: 24863576
Hmm... but i works so far :-)

But, perhaps I have completely misunderstood the asynchronous data workflow ...

Would you have a look at my code please, jkr? I have mixed it up as I think, from the meager examples found tho this topic in forums and websites.

For me it is very important that I fully understand the code that I write and not to only cut&paste something and hope it will work. Do you have any further suggestions for me? Any help to learn this API stuff will be highliy appreciated ...
void __fastcall TShellChangeNotifier::Execute()

{

	HANDLE hEvents[2];

	OVERLAPPED ov;

	memset(&ov, 0, sizeof(ov));

	BOOL bResult;

	DWORD dwError;

	DWORD BytesReturned;

	size_t nBufSize = 32*1024;

	FILE_NOTIFY_INFORMATION* pBuffer = (FILE_NOTIFY_INFORMATION*)calloc(1, nBufSize);

	FILE_NOTIFY_INFORMATION* pBufferCurrent;
 

	ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

	hEvents[0] = ov.hEvent;

	hEvents[1] = Form2->m_StopEvent; // stop thread event
 

	HANDLE hDir = CreateFile(MonitorDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL);
 

	while (!Terminated) {

		bResult = ReadDirectoryChangesW(hDir, pBuffer, nBufSize, TRUE, FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME, &BytesReturned, &ov, NULL);

		if (bResult) {

			DWORD dwResult = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);

			if (dwResult == WAIT_OBJECT_0) {

				pBufferCurrent = pBuffer;

				do {

					AnsiString filename = AnsiString(pBufferCurrent->FileName).SubString(0, pBufferCurrent->FileNameLength / 2);

					if (pBufferCurrent->Action == FILE_ACTION_ADDED) {

						msg += "Add: "; msg += filename;

					}

					else if (pBufferCurrent->Action == FILE_ACTION_REMOVED) {

						msg += "Removed: "; msg += filename;

					}

					else if (pBufferCurrent->Action == FILE_ACTION_MODIFIED) {

						msg += "Modified: "; msg += filename;

					}

					else if (pBufferCurrent->Action == FILE_ACTION_RENAMED_OLD_NAME) {

						msg = "Old-Name: "; msg += filename;

						Synchronize(&UpdateMemo);

						pBufferCurrent = (FILE_NOTIFY_INFORMATION*)(((DWORD)pBufferCurrent) + pBufferCurrent->NextEntryOffset);

						msg = "New-Name: ";

						msg += AnsiString(pBufferCurrent->FileName).SubString(0, pBufferCurrent->FileNameLength / 2);

						Synchronize(&UpdateMemo);

					}

					//else if (pBufferCurrent->Action == FILE_ACTION_RENAMED_NEW_NAME) {

					//	msg += "NEW-Name: ";

					//	msg += filename;

					//}

					if (pBufferCurrent->NextEntryOffset) {

						pBufferCurrent = (FILE_NOTIFY_INFORMATION*)(((DWORD)pBufferCurrent) + pBufferCurrent->NextEntryOffset);

						msg += " ... Walk on Buffer";

						Synchronize(&UpdateMemo);

					}

					else {

						pBufferCurrent = NULL;

					}

				} while (pBufferCurrent != NULL);

			}

			else if (dwResult == WAIT_OBJECT_0 + 1) {  the "terminat event"

				this->Terminate();

			}

		}

	}

	else {

		msg = "Reaching section #2!!!!!!!!!!!!!!!";

		Synchronize(&UpdateMemo);

		DWORD dwResult = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);

		switch ( dwResult ) {

			case WAIT_OBJECT_0: // the "terminate event"

				this->Terminate();

				break;

			case WAIT_OBJECT_0 + 1: // overlapped operation finished

				bResult = GetOverlappedResult(hDir, &ov, &BytesReturned, FALSE);

				if (!bResult) { // error!

				}

			else { //results of asynchronous operation

			}

		}

	}		

	CloseHandle( hDir );

	free(pBuffer);

}

Open in new window

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 100 total points
ID: 24863779
Let me put it like that - there is no reason to use an OVERLAPPED struct in your code at all, you could just leave it out. You have a single thread of execution, and waiting for the event to be signalled right after calling that function makes little sense. It would be less CPU consuming to wait for a handle created by 'FindFirstChangeNotification()' (http://msdn.microsoft.com/en-us/library/aa364417.aspx) and then call 'ReadDirectoryChangesW()', e.g. like
    HANDLE  hNotify;

    DWORD   dwResult;
 

    hNotify =   FindFirstChangeNotification     (   MonitorDirectory,

                                                    TRUE,

                                                    FILE_NOTIFY_CHANGE_SIZE

                                                );
 

    hEvents[0] = hNotify;

    hEvents[1] = Form2->m_StopEvent; // stop thread event
 

    HANDLE hDir = CreateFile(

                          MonitorDirectory,                   // pointer to the file name

                          FILE_LIST_DIRECTORY,                // access (read-write) mode

                          FILE_SHARE_READ|FILE_SHARE_DELETE,  // share mode

                          NULL,                               // security descriptor

                          OPEN_EXISTING,                      // how to create

                          FILE_FLAG_BACKUP_SEMANTICS,         // file attributes

                          NULL                                // file with attributes to copy

                        );
 

    TCHAR acBuf[1024];
 

    DWORD dwRet;
 

    for (   ;;)

        {

            DWORD dwResult = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
 
 

            ReadDirectoryChangesW(hDir,(LPVOID) acBuf,1024,FALSE,FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_CREATION,&dwRet,NULL,NULL);
 

            FILE_NOTIFY_INFORMATION* pInfo = (FILE_NOTIFY_INFORMATION*) acBuf;
 

            //...
 

            FindNextChangeNotification  (   hNotify);

        };
 

    CloseHandle(hDir);

Open in new window

0
 

Author Comment

by:hasnpapa
ID: 24864223
In my very first atempt, I had a short code like the showen by you, using the synchronous way.

But soon I figured out, that ReadDirectoryChangesW blocks the Termination of the thread and so the Close() of the whole Programm, while it is waiting for the next event.

Well, I cut&paste ;-) your code and compile it.
Now, as the same effect as im my first atempt, the thread cannot be terminated on command, because the ReadDirectoryChangesW is waiting for its event. If I let ReadDirectoryChangesW work asynchronously ... yes, then it will be "terminatable".

0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

930 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now