Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

how to solve this ? 2

Status
Not open for further replies.

ATHUEL

Technical User
Sep 23, 2002
29
US
HI,
I have this piece of code that wait until a file is inside of a folder

"Do While present = False

present = file_in_folder(temppath)

DoEvents

Loop"

but I realize that in the mindtime the usage of the cpu is 100%.I don't experience any problem using other applications when this code is running, but that amount of cpu usage doesn't look right.
Any idea on how can i do the same task?
There is any way of acomplish this using API calls?

 
You could add a timer in order to avoid checking for the file all the time.
Then you set the interval (e.g. myTimer.Interval=10000).
The Interval is set in milliseconds, so the above mentioned interval will produce a wait of 10 seconds.
So your code will look like this:
Code:
myTimer.Interval=10000
myTimer.Enabled=True
Do While not present
present = file_in_folder(temppath)
DoEvents
Loop
myTimer.enabled=False

Regards,
Andy

Andreas Galambos
EDP / Technical Support Specialist
(andreas.galambos@bowneglobal.de)
HP:
 
Or use an API sleep call

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)




Do While present = False

present = file_in_folder(temppath)

DoEvents

Sleep 1000 ' 1 second
Loop
 
Thanks for your posts but I'm looking for other solution. The problem is that í need to catch the file as soon it is inside the folder, because that file is part of other aplication, and once it is not longer needed it's deleted. so i have really few milliseconds to acomplish my task. At this moment, and with my aproach it work fine but, as I said, it doesn't look the better solution.
 
Scan through the threads for a few days back - I think someone asked (and had answered) a question about doing this by hooks with the API...

mmilan
 
oh, alright then...


I'll take the bait!

Isn't this FindFirstChangeNotification / FindNextChangeNotification sort of thing? I guess there might be some threading too?

or have I missed something basic?

Take Care

Matt
If at first you don't succeed, skydiving is not for you.
 
Right Matt!

I remember that thread and I found it:
thread705-613325
Check out the code provided there. This function will help you without blocking your entire ressources.

Andy

Andreas Galambos
EDP / Technical Support Specialist
(andreas.galambos@bowneglobal.de)
HP:
 
>Isn't this FindFirstChangeNotification / FindNextChangeNotification sort of thing? I guess there might be some threading too?


Yep! Although I'm tending towards using ReadDirectoryChangesW which has the advantage over the ChangeNotification calls that it tells you exactly which file has changed and what the change is.

Now, in theory, there is a number of asynchronous ways of calling ReadDirectoryChangesW which means the call doesn't block. However, you seem to lose the filename and action info when you do so, thus losing the advanage over the ChangeNotification calls.

So, right now I have a solution involving a synchronous, blocking ReadDirectoryChangesW spawned in its own thread - but I'm trying to get at least one of the asynchronous methods to work as expected...
 
aaah well,

I'll watch and wait then!

Take Care

Matt
If at first you don't succeed, skydiving is not for you.
 
strongm

Can you offer me some help!

I am trying to play with this ReadDirectoryChangesW

I've got the handle to the directory, but keep getting an error returned from ReadDirectOryChangesW.

This error err.lastdll is 998 "Invalid Access to memory Location"

I suspect that my API declaration is wrong

Code:
Public Declare Function ReadDirectoryChangesW Lib"kernel32" (hDirectory aslong, Buffer() as byte, dwBufLen as long, bWatchSubTree as long, dwFilter as long, dwBytesReturned as long, pOverlap aslong, pFuncOverlap as long) as long

Any clue? BTW W2K SP3

Thanks

Take Care

Matt
If at first you don't succeed, skydiving is not for you.
 
I'm using two declarations in my tests, one for synchronous operation, the other for async:

Private Declare Function ReadDirectoryChangesW Lib "kernel32" (ByVal hHandle As Long, ByVal lpBuffer As String, ByVal nBufferLen As Long, ByVal bWatchSubtree As Long, ByVal dwNotifyFilter As Long, lpBytesReturned As Long, ByVal lpOverlapped As Long, ByVal lpCompletionRoutine As Long) As Long
Private Declare Function ReadAsync Lib "kernel32" Alias "ReadDirectoryChangesW" (ByVal hHandle As Long, ByVal lpBuffer As String, ByVal nBufferLen As Long, ByVal bWatchSubtree As Long, ByVal dwNotifyFilter As Long, lpBytesReturned As Long, lpOverlapped As OVERLAPPED, ByVal lpCompletionRoutine As Long) As Long
 
And I've got the non-blocking, asynchronous, non-threaded version up and running now. Just need to clean the code a little, and then I'll post it
 
>just need to clean the code a little

Whats that, removing wombats?

I have had some success with the synchronous version, but I am having stability problems:
I get sharing violations when I try to alter files in the watched directory and lock-ups too that kill VB!

AFAICS, there is no special clean up required other than calling close handle. Is that correct?

Take Care

Matt
If at first you don't succeed, skydiving is not for you.
 
>>just need to clean the code a little
>Whats that, removing wombats?

Just bathing, blow drying, and combing them...
 
>Whats that, removing wombats?

:)

Funny you should say that. There is indeed a wombat in the code as it stands...maybe I'll leave it in there...
 
Yep, but that just wraps the FindFirstChangeNotification / FindNextChangeNotification calls, as discussed earlier, which still have the problem that whilst you know that an event occurred you don't know which file caused it - so you have to do another (or series of other) expensive file access calls. Hence the discussion above on using ReadFileChangesW, which avoids this drawback.

thread222-576673 contains my example of the blocking, synchronous version of thsi call, and below is an async version (the example will require a form with two command buttons, and a module)

Paste the following into the form:
[tt]
Option Explicit

Private Sub Command1_Click()
FileWatch "c:\temp", "test.txt"
End Sub

Private Sub Command2_Click()
Cancelled = True
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
' Make sure we don't have any pending waits...
Cancelled = True
Do Until hFolder = 0
DoEvents
Loop
End Sub
[/tt]
And the following into the module:
[tt]

Option Explicit

' Declaration for async version of ReadDirectoryChangesW
Private Declare Function ReadAsync Lib "kernel32" Alias "ReadDirectoryChangesW" (ByVal hHandle As Long, lpBuffer As Any, ByVal nBufferLen As Long, ByVal bWatchSubtree As Long, ByVal dwNotifyFilter As Long, lpBytesReturned As Long, lpOverlapped As OVERLAPPED, ByVal lpCompletionRoutine As Long) As Long

Private Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (ByVal lpEventAttributes As Long, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As String) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long

Public Declare Function TerminateThread Lib "kernel32" (ByVal hThread As Long, ByVal dwExitCode As Long) As Long
Private Declare Function WaitForSingleObjectEx Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long, ByVal bAlertable As Long) As Long


Public Type OVERLAPPED
Internal As Long
InternalHigh As Long
Offset As Long
OffsetHigh As Long
hEvent As Long
End Type

Public Enum WaitState
WAIT_FAILED = -1
WAIT_OBJECT_0 = 0
WAIT_ABANDONED = &H80
WAIT_IO_COMPLETION = &HC0
WAIT_TIMEOUT = &H102
End Enum

Public Enum FileAction
FILE_ACTION_ADDED = &H1
FILE_ACTION_REMOVED = &H2
FILE_ACTION_MODIFIED = &H3
FILE_ACTION_RENAMED_OLD_NAME = &H4
FILE_ACTION_RENAMED_NEW_NAME = &H5
End Enum

Public Enum NotificationFilters
FILE_NOTIFY_CHANGE_FILE_NAME = 1
FILE_NOTIFY_CHANGE_DIR_NAME = &H2
FILE_NOTIFY_CHANGE_ATTRIBUTES = &H4
FILE_NOTIFY_CHANGE_SIZE = &H8
FILE_NOTIFY_CHANGE_LAST_WRITE = &H10
FILE_NOTIFY_CHANGE_LAST_ACCESS = &H20
FILE_NOTIFY_CHANGE_CREATION = &H40
FILE_NOTIFY_CHANGE_SECURITY = &H100
End Enum

Public Type FILE_NOTIFY_INFORMATION
NextEntryOffset As Long
Action As Long
FileNameLength As Long
Filename(255) As Byte
End Type

Const FILE_LIST_DIRECTORY = 1
Const GENERIC_WRITE = &H40000000
Const GENERIC_READ = &H80000000
Const FILE_SHARE_DELETE = 4
Const FILE_SHARE_READ = 1
Const OPEN_EXISTING = 3
Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Const FILE_FLAG_OVERLAPPED = &H40000000

Public cBuffer(1024) As Byte
Public Cancelled As Boolean
Public hEvent As Long
Public OL As OVERLAPPED
Public strFileWatch As String
Public hFolder As Long

Public Sub FileIOCompletionRoutine(ByVal dwErrorCode As Long, ByVal dwNumberofBytes As Long, lpOverlapped As OVERLAPPED)
Dim wombat As FILE_NOTIFY_INFORMATION ' the infamous wombat!
Dim strFilename As String

If dwNumberofBytes Then ' did we get anything?
CopyMemory wombat, cBuffer(0), dwNumberofBytes
strFilename = Left(CStr(wombat.Filename), wombat.FileNameLength / 2)

Select Case wombat.Action
Case FILE_ACTION_ADDED
If strFilename = strFileWatch Then
MsgBox strFilename & " added to monitored folder"
Cancelled = True
End If
Case FILE_ACTION_MODIFIED
Case FILE_ACTION_REMOVED
Case FILE_ACTION_RENAMED_NEW_NAME
Case FILE_ACTION_RENAMED_OLD_NAME
Case Else
End Select
End If


End Sub

Public Sub FileWatch(ByVal cFolder As String, ByVal strFile As String)
Dim nFilter As Long
Dim nReturned As Long
Dim WaitResult As Long
Dim mykey As Long
Dim ByteCount As Long

strFileWatch = strFile
Cancelled = False
' Create our own event, and stick it in the OVERLAPPED structure so that
' we can link it to our asynch ReadDirectoryChagesW
hEvent = CreateEvent(0&, False, False, "vbReadAsyncEvent")
OL.hEvent = hEvent

' Get handle to nominated folder
hFolder = CreateFile(cFolder, FILE_LIST_DIRECTORY, FILE_SHARE_READ + FILE_SHARE_DELETE, 0&, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS + FILE_FLAG_OVERLAPPED, 0)
' Filter the type of file events we want to monitor
nFilter = FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_LAST_WRITE + FILE_NOTIFY_CHANGE_CREATION

' Keep looping until user cancels
Do
' set up the async call
ReadAsync hFolder, cBuffer(0), 1024, False, nFilter, nReturned, OL, AddressOf FileIOCompletionRoutine ' 0&
Do
' Wait for event or timeout to occur
WaitResult = WaitForSingleObjectEx(hEvent, 100, True)
DoEvents ' Yield to OS
Loop Until (WaitResult = WAIT_IO_COMPLETION) Or (Cancelled = True)
Loop Until Cancelled

' Clean up as we go
CloseHandle hEvent
CloseHandle OL.hEvent
CloseHandle hFolder
hFolder = 0

End Sub

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top