ReadDirectoryChangesW asynchronous - how to trigger?

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

hasnpapaAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
How are you using the 'asynchronous' way? Are you using an 'OVERLAPPED' struct or a completion routine?
0
Ravi KallaTechnology LeadCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
hasnpapaAuthor Commented:
@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
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

jkrCommented:
There seems to be a misconception - the finishing of the overlapped operation is always the end of an asynchronous action...
0
hasnpapaAuthor Commented:
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
jkrCommented:
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
hasnpapaAuthor Commented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.