Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ReadDirectoryChangesW ?

264 views
Skip to first unread message

asdf

unread,
Oct 25, 2000, 3:00:00 AM10/25/00
to

Hi!

I'm trying to monitor a folder for file changes using ReadDirectoryChangesW.
The problem with the code below is that TestFunc never gets called.

Does anyone know how to use ReadDirectoryChangesW asynchonously with a
completion routine?

Thanks


VOID WINAPI TestFunc(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered,
LPOVERLAPPED lpOverlapped)
{
...
}

void Test()
{
...
hDir = CreateFile(m_sPath, FILE_LIST_DIRECTORY, FILE_SHARE_READ |
FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);

DWORD dwNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE;
ReadDirectoryChangesW(hDir, chBuf, DIR_BUF_SIZE, TRUE, dwNotifyFilter,
&dwBytesRet,
&ol, (LPOVERLAPPED_COMPLETION_ROUTINE)(&TestFunc));
...
}

Mattias Sjögren

unread,
Oct 25, 2000, 3:00:00 AM10/25/00
to

Please don't multipost your messages. Especially not to VB groups when
you write your code in C++.


Matt

============================================
Mattias Sjögren - mattiass @ hem.passagen.se
CodeHound - Free VB Search Engine
http://www.codehound.com

Charles Herrington

unread,
Dec 12, 2000, 4:28:41 PM12/12/00
to
Has anyone successfully used ReadDirectoryChangesW in VB? I am attempting
to use it now with the completion routine as well and I am getting the error
998 - Invalid access to memory location.

Here is how I am trying to use it:

Private mlDirectoryHandle As Long
Private mlNotifyInfo As FILE_NOTIFY_INFORMATION
Private mlBytesReturned As Long
Private mlOverlapped As OVERLAPPED

Public Function BeginWatchDirectory(ByVal sPath As String) As Boolean

Dim lHandle As Long
Dim lRet As Long

mlDirectoryHandle = CreateFile(sPath, FILE_LIST_DIRECTORY,
FILE_SHARE_READ Or FILE_SHARE_DELETE, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS Or FILE_FLAG_OVERLAPPED, 0)
If Not mlDirectoryHandle = INVALID_HANDLE_VALUE Then
lRet = ReadDirectoryChangesW(mlDirectoryHandle, mlNotifyInfo,
Len(mlNotifyInfo), True, FILE_NOTIFY_CHANGE_FILE_NAME, mlBytesReturned,
mlOverlapped, AddressOf ChangeRoutine)
Debug.Print "ReadDirectoryChangesW returned " & lRet & "
LastDllError: " & Err.LastDllError
End If

End Function

Private Sub ChangeRoutine()

Debug.Print "Completion routine called"

End Sub

Can anyone tell me where I went wrong? Thanks.

Mattias Sjögren <mattiass.do...@hem.passagen.se> wrote in message
news:39f70fea...@msnews.microsoft.com...

Randy Birch

unread,
Dec 12, 2000, 6:54:32 PM12/12/00
to
> Private Sub ChangeRoutine()

According to the MSDN, the declaration for the I/O completion routine
requires accepting three parameters :

dwErrorCode (Long)
dwNumberOfBytesTransfered (Long)
lpOverlapped (OVERLAPPED struct if used, or a Long if not)

Me thinks too it should be Public, in a BAS module.

Public Sub ChangeRoutine (dwErrorCode As Long, _
dwNumberOfBytesTransfered As Long,
_
lpOverlapped As XXXXX )

For initial testing, you can change all overlapped use to nulls (0&),
declare the member in the API As Long (instead of OVERLAPPED), and use As
Long in the completion routine's last param.


--

Randy Birch
MVP Visual Basic

Take the vb.net poll at:
http://www.mvps.org/vbnet/
http://www.mvps.org/ccrp/

"Charles Herrington" <chu...@pandavoice.com> wrote in message
news:uhRTtIIZAHA.1260@tkmsftngp05...
: Has anyone successfully used ReadDirectoryChangesW in VB? I am attempting

: Mattias Sjvgren <mattiass.do...@hem.passagen.se> wrote in message


: news:39f70fea...@msnews.microsoft.com...
: >
: > Please don't multipost your messages. Especially not to VB groups when
: > you write your code in C++.
: >
: >
: > Matt
: >
: > ============================================

: > Mattias Sjvgren - mattiass @ hem.passagen.se

:
:


Charles Herrington

unread,
Dec 13, 2000, 12:08:52 PM12/13/00
to
I made the changes you suggested and I am still getting the same error
(998). Here is what my code looks like now:

Private Declare Function ReadDirectoryChangesW Lib "kernel32" (ByVal hHandle
As Long, lpBuffer As FILE_NOTIFY_INFORMATION, nBufferLength As Long,
bWatchSubTree As Long, dwNotifyFilter As Long, lpBytesReturned As Long,
ByRef lpOverlapped As Long, lpCompletionRoutine As Long) As Long

Public Function BeginWatchDirectory(ByVal sPath As String) As Boolean

Dim lHandle As Long
Dim lRet As Long

'Get a handle to the directory
mlDirectoryHandle = CreateFile(sPath, FILE_LIST_DIRECTORY, _
FILE_SHARE_READ Or FILE_SHARE_DELETE, 0, OPEN_EXISTING, _
FILE_FLAG_BACKUP_SEMANTICS Or FILE_FLAG_OVERLAPPED, 0)

'Check to see if the handle is valid


If Not mlDirectoryHandle = INVALID_HANDLE_VALUE Then

'Request a change notification
lRet = ReadDirectoryChangesW(mlDirectoryHandle, mlNotifyInfo, _
Len(mlNotifyInfo), True, FILE_NOTIFY_CHANGE_FILE_NAME, _
mlBytesReturned, 0&, AddressOf ChangeRoutine)

'Print the results of the request to the debug window
Debug.Print "ReadDirectoryChangesW returned " & lRet & _
" LastDllError: " & Err.LastDllError

'If the request was not successfull, close the handle to the
directory
If lRet = 0 Then CloseHandle mlDirectoryHandle

End If

End Function

Public Sub ChangeRoutine(dwErrorCode As Long, _
dwNumberOfBytesTransfered As Long, lpOverlapped As Long)

Debug.Print "Completion routine called"

End Sub

I would greatly appreciate any help anyone can give.

Randy Birch <r...@mvps.org> wrote in message
news:#lih0aJZAHA.712@tkmsftngp04...

Randy Birch

unread,
Dec 13, 2000, 8:53:02 PM12/13/00
to
Try ByVal for the three returned params in the completion routine.

Post your declares and constants as well, please.

--

Randy Birch
MVP Visual Basic

"Charles Herrington" <chu...@pandavoice.com> wrote in message

news:OZ22bcSZAHA.448@tkmsftngp02...
: I made the changes you suggested and I am still getting the same error

: > :
: >
: >
:
:


Charles Herrington

unread,
Dec 14, 2000, 9:36:58 AM12/14/00
to
Thanks for the suggestion but I am still getting the same problem. Here is
all the code from my BAS module. Thanks again for the help.

Option Explicit

Public Type FILE_NOTIFY_INFORMATION
NextEntryOffset As Long
Action As Long
FileNameLength As Long
FileName As String
End Type

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

Private Declare Function ReadDirectoryChangesW Lib "kernel32" (ByVal hHandle
As Long, lpBuffer As FILE_NOTIFY_INFORMATION, nBufferLength As Long,
bWatchSubTree As Long, dwNotifyFilter As Long, lpBytesReturned As Long,
ByRef lpOverlapped As Long, lpCompletionRoutine As Long) 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
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long)
As Long

Private Const FILE_NOTIFY_CHANGE_FILE_NAME = &H1
Private Const FILE_NOTIFY_CHANGE_DIR_NAME = &H2
Private Const FILE_NOTIFY_CHANGE_ATTRIBUTES = &H4
Private Const FILE_NOTIFY_CHANGE_SIZE = &H8
Private Const FILE_NOTIFY_CHANGE_LAST_WRITE = &H10
Private Const FILE_NOTIFY_CHANGE_SECURITY = &H100
Private Const INVALID_HANDLE_VALUE = -1

Private Const FILE_LIST_DIRECTORY = (&H1)
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_DELETE = &H4
Private Const OPEN_EXISTING = 3
Private Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Private Const FILE_FLAG_OVERLAPPED = &H40000000

Private mlDirectoryHandle As Long
Public glNotifyInfo As FILE_NOTIFY_INFORMATION
Public glBytesReturned As Long
Private mlOverlapped As OVERLAPPED

Public Function BeginWatchDirectory(ByVal sPath As String) As Boolean

Dim lHandle As Long
Dim lRet As Long

'Get a handle to the directory


mlDirectoryHandle = CreateFile(sPath, FILE_LIST_DIRECTORY, _
FILE_SHARE_READ Or FILE_SHARE_DELETE, 0, OPEN_EXISTING, _
FILE_FLAG_BACKUP_SEMANTICS Or FILE_FLAG_OVERLAPPED, 0)

'Check to see if the handle is valid
If Not mlDirectoryHandle = INVALID_HANDLE_VALUE Then

'Request a change notification
lRet = ReadDirectoryChangesW(mlDirectoryHandle, glNotifyInfo, _
Len(glNotifyInfo), True, FILE_NOTIFY_CHANGE_FILE_NAME, _
glBytesReturned, 0&, AddressOf ChangeRoutine)

'Print the results of the request to the debug window
Debug.Print "ReadDirectoryChangesW returned " & lRet & _
" LastDllError: " & Err.LastDllError

'If the request was not successfull, close the handle to the
directory
If lRet = 0 Then CloseHandle mlDirectoryHandle

End If

End Function

Public Sub ChangeRoutine(ByVal dwErrorCode As Long, _
ByVal dwNumberOfBytesTransfered As Long, ByVal lpOverlapped As Long)

Debug.Print "Completion routine called"

End Sub


Randy Birch <r...@mvps.org> wrote in message

news:OO2PtBXZAHA.2216@tkmsftngp02...

Randy Birch

unread,
Dec 14, 2000, 11:21:19 PM12/14/00
to

Give this a whack.

I did some additional reading in the msdn, and the completion routine will
not fire unless a "waitable state" api has been called (see comment below ).
Since this is synchronous, not asynchronous, this code simply monitors the
folder and finishes on the first change. But it will show you how to do some
of the necessary footwork. Paste the code below into a new project .. there
are some significant changes from your declares.

--

Randy Birch
MVP Visual Basic


'-----------------
The FileIOCompletionRoutine function is an application-defined callback
function used with the ReadFileEx and WriteFileEx functions. It is called
when the asynchronous input and output (I/O) operation is completed or
canceled and the calling thread is in an alertable state (using the SleepEx,
MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx, or
WaitForMultipleObjectsEx function with the fAlertable flag set to TRUE).

'-----------------

Option Explicit

Public hFile As Long

Public Declare Function ReadDirectoryChangesW Lib "kernel32" _
(ByVal hHandle As Long, _
ByVal lpBuffer As Long, _
ByVal nBufferLength 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 Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Dest As Any, _
Source As Any, _
ByVal nbytes As Long)

Private Declare Function lstrlenW Lib "kernel32" _
(ByVal lpString As Long) As Long

Private Declare Function StrLen Lib "kernel32" _
Alias "lstrlenW" _
(ByVal lpString As Long) As Long

Public Declare Function GlobalAlloc Lib "kernel32" _
(ByVal wFlags As Long, ByVal dwBytes As Long) As Long

Public Declare Function GlobalFree Lib "kernel32" _
(ByVal hMem As Long) As Long

Public Const GMEM_FIXED = &H0

Public 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

Public Const FILE_NOTIFY_CHANGE_FILE_NAME = &H1
Public Const FILE_NOTIFY_CHANGE_DIR_NAME = &H2
Public Const FILE_NOTIFY_CHANGE_ATTRIBUTES = &H4
Public Const FILE_NOTIFY_CHANGE_SIZE = &H8
Public Const FILE_NOTIFY_CHANGE_LAST_WRITE = &H10
Public Const FILE_NOTIFY_CHANGE_SECURITY = &H100
Public Const INVALID_HANDLE_VALUE = -1

Public Const FILE_LIST_DIRECTORY = (&H1)
Public Const FILE_SHARE_READ = &H1
Public Const FILE_SHARE_WRITE = &H2
Public Const FILE_SHARE_DELETE = &H4
Public Const OPEN_EXISTING = 3
Public Const FILE_FLAG_BACKUP_SEMANTICS = &H2000000
Public Const FILE_FLAG_OVERLAPPED = &H40000000

Public Function BeginWatchDirectory(ByVal sPath As String) As Long

Dim dynBuffer As Long
Dim dynBufferSize As Long
Dim lpBytesReturned As Long
Dim c As Long

'Get a handle to the directory

hFile = CreateFile(sPath, _
FILE_LIST_DIRECTORY, _
FILE_SHARE_READ Or _
FILE_SHARE_WRITE Or _
FILE_SHARE_DELETE, _
0&, _
OPEN_EXISTING, _
FILE_FLAG_BACKUP_SEMANTICS, _
0&)

'Check to see if the handle is valid

If Not hFile = INVALID_HANDLE_VALUE Then

'set a size for the data returned
'and allocate memory for it
dynBufferSize = 4096
dynBuffer = GlobalAlloc(GMEM_FIXED, dynBufferSize)

'pass this to the API. The app now waits for
'a change (is unresponsive)
Call ReadDirectoryChangesW(hFile, _
dynBuffer, _
dynBufferSize, _
0&, _
FILE_NOTIFY_CHANGE_FILE_NAME, _
lpBytesReturned, _
0&, _
0&) 'AddressOf ChangeRoutine)

'Print results to the debug window
Debug.Print "RDC LastDllError " & _
Err.LastDllError & _
" " & Err.Description

Debug.Print "RDC lpBytesReturned " & lpBytesReturned

'if lpReturned = 0, then the buffer was too small.
'if its > 0, there is data. The call returns
'two sets of data on a file rename- the
'original filename and the new filename.
'The loop below takes care of extracting
'additional data if NextOffset indicates
'there is more.
If lpBytesReturned > 0 Then

'some working vars
Dim ptrNext As Long
Dim ptrNextOffset As Long
Dim ptrAction As Long
Dim ptrFileLen As Long
Dim ptrFileName As String
Dim cnt As Long

'since ptrNextOffset in the Do Loop
'points to the *next* block of data
'following the one being processed,
'we need a way to remember where the
'current offest was, in order to use
'Copymem. ptrNext fills this need.
ptrNext = 0

Do

cnt = cnt + 1
Debug.Print "Pass " & cnt

'copy the values from the buffer
'into longs. Since the data was
'returned smooshed into a single
'Long, we offset each extracted
'Long var by 4 bytes.
CopyMemory ptrNextOffset, ByVal dynBuffer + ptrNext, 4
CopyMemory ptrAction, ByVal dynBuffer + ptrNext + 4, 4
CopyMemory ptrFileLen, ByVal dynBuffer + ptrNext + 8, 4

Debug.Print " ptrNextOffset " & ptrNextOffset
Debug.Print " ptrAction " & ptrAction
Debug.Print " ptrFileLen " & ptrFileLen

'now copy the string
Debug.Print " ptrToByteString " & _
GetPointerToByteStringW(dynBuffer + ptrNext + 12)

ptrNext = ptrNextOffset

Loop Until ptrNextOffset = 0

End If

'free the memory and close the file
Call GlobalFree(dynBuffer)

If hFile <> 0 Then CloseHandle hFile

End If

End Function

Private Function GetPointerToByteStringW(lpString As Long) As String

Dim buff() As Byte
Dim nsize As Long

If lpString Then

'its Unicode, so mult. by 2
nsize = lstrlenW(lpString) * 2

If nsize Then
ReDim buff(0 To (nsize - 1)) As Byte
CopyMemory buff(0), ByVal lpString, nsize
GetPointerToByteStringW = buff
End If

End If

End Function

Public Function ChangeRoutine(ByVal dwErrorCode As Long, _
ByVal dwBytesTransfered As Long, _
ByVal lpOverlapped As Long) As Long

'actually not called !
Debug.Print "Completion routine called: " & _
"dwErrorCode" = dwErrorCode & vbNewLine & _
"dwBytesTransfered" = dwBytesTransfered & vbNewLine & _
"lpOverlapped" = lpOverlapped

End Function

vladisl...@gmail.com

unread,
Feb 23, 2015, 6:01:43 PM2/23/15
to
среда, 25 октября 2000 г., 10:00:00 UTC+3 пользователь asdf написал:
Your buffer MUST BE DWORD (4bytes) aligned !!! Try...
0 new messages