I am trying to write a Template manager for office template files. Instead of a lot of VBA macros in each template I plan to let the manager do the job. A document can be started either from office app menu "file/new", or dblclicking the template, or a link from LAN to the template. I have written this thread code to monitor the last access of files in the template folder (szDirName).


ThreadProc PROC uses edi esi Param:DWORD
LOCAL lpBytesReturned:dword

invoke CreateFile,addr szDirName,GENERIC_READ,FILE_SHARE_DELETE or FILE_SHARE_READ,0,\
OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0
mov hDir,eax
invoke ReadDirectoryChangesW,hDir,addr buf,sizeof buf,TRUE,FILE_NOTIFY_CHANGE_LAST_ACCESS,\
addr lpBytesReturned,0,0
.if eax==0
invoke MessageBox,0,0,0,MB_OK
.else
xor ecx,ecx
@@:
add edi,ecx
lea edi,buf
mov esi,.FILE_NOTIFY_INFORMATION.Action
.if esi==FILE_ACTION_MODIFIED
invoke SetDlgItemText,hDlg,EDT_1,CAStr(addr .FILE_NOTIFY_INFORMATION.FileName)
.elseif esi==0
invoke CloseHandle,hDir
ret
.endif
mov ecx,.FILE_NOTIFY_INFORMATION.NextEntryOffset
.if ecx==0
invoke RtlZeroMemory,addr buf,sizeof buf
jmp ThreadProc
.endif
jmp @B
.endif

    ret
ThreadProc ENDP


However you must wait at least one hour before a new update of last access is done. Any ideas how to solve this problem.

Best regards
Posted on 2006-05-09 15:32:19 by minor28
minor28,

Attached is a FASM program source which uses ReadDirectoryChangesW in a thread, which constatly monitors for Create, Modify, Delete, Move To, & Move From.  It seems to work well.  The program creates a little dialog with buttons for each of the monitored events, and then displays a ListView of the detected activity.

hth,

farrier
Attachments:
Posted on 2006-05-09 17:11:10 by farrier
Thanks farrier,

Your code works in a similar way as mine.

My problem is not the code itself but the fact the system doesn't update file LastAccess not earlier then one hour after latest update of the file. ReadDirectoryChangesW will stay in wait mode for this specific file up to one hour before a new event will be triggered.

My program must be notified immediately without any delay.
Posted on 2006-05-10 00:55:45 by minor28
minor28,

I don't understand your problem.  In the program I gave you, the modify button will open the test file, set the file pointer to the end of the file, and write many bytes, then close the file.  The ListView is updated immediately, and just as fast as I can click the button.  I thought that is what you were having trouble wtih.

?

You don't have to use the buttons of the program I gave you to test my application.  Just change the directory to watch--it monitors the folder which the program resides in--or just put this program in the folder containing the files you wish to monitor.

hth,

farrier
Posted on 2006-05-10 04:30:09 by farrier
As it is now I have a lot of office templates (*.dot, *.xlt, *.pot etc.) with VBA macros. To open a new document the user fill in a userform with data to be inserted to the document.

My project is aimed to take over all VBA macro work. No VBA macros in the templates. When a user opens a template my program must be notified in due time to open a "UserForm" to do the old macro work.

I am in the beginning of the work so my first step is to solve the notifying problem. As far as I know the only useful filter is FILE_NOTIFY_CHANGE_LAST_ACCESS (for *.dot files I can use the recovery file as notifying event but not the others). The initiativ to start the process comes from the template.

My code works fine if the template in question not is accessed within one hour after last access. That's because of limitation in the filesystem updating of LastAccess.

I don't know if this makes the problem more clear to understand.
Posted on 2006-05-10 07:00:11 by minor28
Hm, you shouldn't depend on LAST_ACCESS - I tend to turn that filesystem feature off as I find it useless, and it slows down things. I'm not sure all systems support it anyway (ie., if your LAN shared files are really hosted on a unix box).

Getting these kinds of notifications on windows file shares can be a pain anyway - just like file locking can.
Posted on 2006-05-10 07:03:40 by f0dder
i may be way off here, but how about using FindFirstChangeNotification ...
Posted on 2006-05-10 09:36:34 by evlncrn8
minor28,

If you check only for FILE_NOTIFY_CHANGE_LAST_ACCESS I'm not sure how that works, if you want to be notified if the file is opened my program won't do that.  It will check for Create, Delete, Modify, MoveFrom, & MoveTo.

If you try what I suggested before--putting my fc.exe in any directory, run it and watch the ListView--change on line in FC.asm, line 249, change:

.if

to

if .T.

It will then show all Notificaitons.

f0dder,

I've tried my program on my three computer network and it seems to work fine if I specify

evlncrn8,

The advantage of ReadDirectoryChangesW over FindFirstChangeNotification is that it will report back the name of the file which triggered the Notification.

farrier
Posted on 2006-05-10 10:18:15 by farrier
farrier,
I can't compile FASM why I can't test it. Create, Delete, MoveFrom and MoveTo is of no use with templates. Modify is the only action and the only thing that is modified is LastAccess.

About FindFirstChangeNotification, no applicable filter is available.

f0dder, I don't think my users are skilled enough to know how to disable filesystem LastAccess.

My conclusion is that I have to find another way to achieve the function.

Thanks for your support.
Posted on 2006-05-10 11:56:06 by minor28

f0dder, I don't think my users are skilled enough to know how to disable filesystem LastAccess.

:-)

Even if they aren't, you might have to consider issues like indexing services and whatnot  - so I don't think it's a very reliable way to check if "a user has opened the template document". And it sounds very weird that you only get notifications once an hour!
Posted on 2006-05-10 12:21:06 by f0dder
If you open explorer and add Date Accessed to the listview you can read the date and time when the file was last accessed. Put the mousepointer over a file and a tooltip will turn up with file data. Refresh the listview with F5 and Date Accessed will change. Do the same again a couple of minitutes later. The tooltip will pop up but the Date Accessed will not be updated. It will not be updated even if you open the file. It takes one hour until the file is ready for updating.
Posted on 2006-05-10 13:14:32 by minor28
Weird!

If it's not a bug, perhaps Microsoft added that feature to not cause too much performance problems?
Posted on 2006-05-10 13:21:00 by f0dder
It seems to be intentionally, exactly 60 minutes. Yes probably performance with regard to the rather circumstantial way but yet available possibility to disable the function.
Posted on 2006-05-10 13:42:51 by minor28
minor28,

If you can trust me, I have attached an executable of the FC program.  Just put it in the directory you want to monitor, and run it.  It will open with a ListView and some buttons.  Forget about the buttons, and just make the changes you wish to get notifications for.

The code is written in "MASM" style and should be easy enough to translate.  You should really give FASM a try.  http://flatassembler.net/download.php

hth,

farrier
Attachments:
Posted on 2006-05-10 17:05:24 by farrier

NTFS typically updates a file's attribute on disk if the current Last Access Time in memory differs by more than an hour from the Last Access Time stored on disk, or when all in-memory references to that file are gone, whichever is more recent. For example, if a file's current Last Access Time is 1:00 P.M., and you read the file at 1:30 P.M., NTFS does not update the Last Access Time. If you read the file again at 2:00 P.M., NTFS updates the Last Access Time in the file's attribute to reflect 2:00 P.M. because the file's attribute shows 1:00 P.M. and the in-memory Last Access Time shows 2:00 P.M.
Posted on 2006-05-10 18:00:07 by arafel
Thanks farrier,

I have tested your program. It works in the same way as mine.  I must find another way.
Posted on 2006-05-11 00:24:08 by minor28
minor28,

Is it possible that when you get the first notification after--activating your monitor program--you could modify the file in some trivial way to trigger a modification notification.  The modification could be something trivial and not affecting the use of the template.  If that is a problem, you could immediately undo your modifications back to the original.  This may allow the access notification to be triggered every time.

Just a thought.

farrier
Posted on 2006-05-12 00:00:55 by farrier
Has anyone looked at this...

SHChangeNotifyRegister

It is only available in later versions of Shell32 but is available as an ordinal from Win95.

SHChangeNotifyRegister ordinal 2
SHChangeNotifyDeregister ordinal 4
SHChangeNotifyUpdateEntryList ordinal 5

Donkey
Posted on 2006-05-16 03:57:44 by donkey
Hi donkey,

SHChangeNotifyRegister might work. I will make a deeper test later. Seems to be some more event notifications than ReadDirectoryChangesW and FindFirstChangeNotification.

With this code I got a lot of notification messages.

invoke SHGetSpecialFolderLocation,0,CSIDL_DESKTOP,addr ppidl
.if eax==S_OK
mov eax,ppidl
mov ps.pidl,eax
mov ps.bWatchSubFolders,TRUE
;SHCNRF_InterruptLevel Or SHCNRF_RecursiveInterrupt = 1h + 1000h
invoke SHChangeNotifyRegister,hWin,9003h, SHCNE_ALLEVENTS Or SHCNE_INTERRUPT,\
WM_USER + 5,1,addr ps
.if eax>0
mov regID,eax
.endif
.endif
Posted on 2006-05-23 12:22:33 by minor28