We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

File Notification using ReadDirectoryChanges API

pswenson
pswenson asked
on
Medium Priority
2,928 Views
Last Modified: 2012-06-27
I'm trying to get the ReadDirectoryChangesW call for Win NT to work (it is not supported for Win 95).  Below is the code.  Has anyone implemented it successufully in Delphi?  If so could you post the code?  In the code below, the call to GetQueuedCompletionStatus holds until a file change is made in the c:\temp2 directory.  That's cool, but I can't figure out how to decode the information returned.  The code is based on an example from MSDN.


interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

const
  FILE_LIST_DIRECTORY = $0001;
  MAX_PATH = 80;
  MAX_BUFFER = 4096;
type
  PDirectoryInfo = ^TDirectoryInfo;

  PBuffer = ^TBuffer;
  TBuffer = array [0..MAX_BUFFER - 1] of Char;

  TDirectoryInfo = record
    hDir: THandle;
    lpszDirName: array [0..MAX_PATH - 1] of WChar;
    lpBuffer: array [0..MAX_BUFFER - 1] of Char;
    dwBufLength: DWORD;
    Overlapped: POverlapped;
  end;

  PFileNotifyInformation = ^TFileNotifyInformation;
  TFileNotifyInformation = record
    NextEntryOffset: DWord;
    Action: DWord;
    FileNameLength: DWord;
    FileName: WideChar;
  end;

type
  TForm3 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.DFM}

procedure TForm3.Button1Click(Sender: TObject);
var
  ChangeBuffer: PFileNotifyInformation;
  fni: PFileNotifyInformation;
  Info, NumBytes, Offset, LastError: DWord;
  DirHandle, CompletionPort: THandle;
  Overlapped: POverlapped;
  Queue, ReadResult: BOOL;
  BytesReturned: PDWord;
  PFileNotifyInfo: PFileNotifyInformation;
begin
  New(ChangeBuffer);

  New(Overlapped);

  DirHandle := CreateFile(PChar('c:\temp2')
                          , FILE_LIST_DIRECTORY
                          , (FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE)
                          , nil
                          , OPEN_EXISTING
                          , FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED
                          , 0);

  if DirHandle = INVALID_HANDLE_VALUE then begin
    ShowMessage('Unable to get handle to directory c:\temp2');
    exit;
  end;

  try
    CompletionPort := CreateIOCompletionPort(DirHandle, 0, 5, 0);
    try
      SetLastError(0);
      ReadResult := ReadDirectoryChangesW(DirHandle
                           , ChangeBuffer
                           , SizeOf(ChangeBuffer)
                           , LongBool(TRUE)
                           , FILE_NOTIFY_CHANGE_LAST_WRITE
                           , BytesReturned
                           , Overlapped
                           , 0);

      LastError := GetLastError;
      if not ReadResult then begin
        ShowMessage(SysErrorMessage(LastError));
        exit;
      end;

      repeat
        Queue := GetQueuedCompletionStatus(CompletionPort
                                         , NumBytes
                                         , Info
                                         , Overlapped
                                         , INFINITE);
        LastError := GetLastError;
        if not Queue then begin
          ShowMessage(Format('GetQueuedCompletionStatus Error %d', [LastError]));
          exit;
        end;

        if Info > 0 then begin
          fni := ChangeBuffer;
          repeat
            OffSet := byte(fni) + fni^.NextEntryOffset;
            fni:= Ptr(Offset);
          until Offset < 1;
        end;

        ReadDirectoryChangesW(DirHandle
                             , ChangeBuffer
                             , SizeOf(ChangeBuffer)
                             , LongBool(FALSE)
                             , FILE_NOTIFY_CHANGE_LAST_WRITE
                             , BytesReturned
                             , Overlapped
                             , 0);

      until Info < 1;

      Dispose(ChangeBuffer);
    finally
      PostQueuedCompletionStatus(CompletionPort, 0, 0, 0);
    end;
  finally
    CloseHandle(DirHandle);
  end;
end;


end.
Comment
Watch Question

Commented:
what do you want to know?
Commented:
Unlock this solution with a free trial preview.
(No credit card required)
Get Preview

Author

Commented:
How did you know the component was at the site?  Is there a directory somewhere?

Commented:
pswenson,

 I was searching for some information about ReadDirectoryChangesW, because I was interested too in this problem. I couldn't find anything usefull, so as last resort I used a searchengine (what normally doesn't help a lot) and by holy there it pointed me out to Delphi Super Page. (Invisible components of D3)

But, DSP has also a search engine. But normally, these specific functions aren't implemented in custom source codes. That's why I didn't checked for components at DSP.

Regards, Zif.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a free trial preview!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.