【问题标题】:detecting windows shell changes检测 Windows 外壳更改
【发布时间】:2009-10-13 19:12:23
【问题描述】:

我对使用 C Builder 的了解非常有限,您能否给我一个示例或指出如何在 Delphi 中使用 FindNextChangeNotification 的教程,或者如果可能的话,如何在 delphi 中使用 C 组件?

【问题讨论】:

  • 我会使用 ReadDirectoryChangesW 而不是 FindFirstChangeNotification 和 FindNextChangeNotification(除非你真的需要支持 Windows 95/98/SE/Me)。

标签: c delphi winapi notifications


【解决方案1】:

一种选择是使用TJvChangeNotify 组件,JVCL 支持 Delphi 和 C++ Builder。

另一个选项是使用SHChangeNotifyRegister 函数。 看这个链接Monitoring System Shell Changes using Delphi

再见。

【讨论】:

    【解决方案2】:

    ReadDirectoryChanges 似乎是我正在寻找的功能。这是我尝试使用mghie的代码Why does ReadDirectoryChangesW omit events?

    我的目标是监视您将在 Unit1 中看到的目录/路径或文件。我只想在检测到位置发生变化时弹出一个简单的显示消息对话框。我找不到我应该在哪里传递我的通知程序或功能。 Unit2 仅保存来自 mghie 的未更改代码。当我编译这个项目并在目录中进行简单的更改时,什么也没有发生。我是否正确使用了 ReadDirectoryChanges?

    这里是 Unit1:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Unit2;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
      fthread:TWatcherthread;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    //start directory or file watch here
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
       fThread := TWatcherThread.Create('C:\Users\abe\Desktop\statcious\mitsu\Demo\abc.txt');
    
    end;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
       if fThread <> nil then begin
        TWatcherThread(fThread).Shutdown;
        fThread.Free;
      end;
    end;
    
    end.
    

    这里是第二单元:

    unit Unit2;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TWatcherThread = class(TThread)
      private
        fChangeHandle: THandle;
        fDirHandle: THandle;
        fShutdownHandle: THandle;
      protected
        procedure Execute; override;
      public
        constructor Create(ADirectoryToWatch: string);
        destructor Destroy; override;
    
        procedure Shutdown;
    
      end;
    
    type
      TForm2 = class(TForm)
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form2: TForm2;
    
    implementation
    
    {$R *.dfm}
    
    constructor TWatcherThread.Create(ADirectoryToWatch: string);
    const
      FILE_LIST_DIRECTORY = 1;
    begin
      inherited Create(TRUE);
      fChangeHandle := CreateEvent(nil, FALSE, FALSE, nil);
      fDirHandle := CreateFile(PChar(ADirectoryToWatch),
        FILE_LIST_DIRECTORY or GENERIC_READ,
        FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
        nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
      fShutdownHandle := CreateEvent(nil, FALSE, FALSE, nil);
      Resume;
    end;
    
    destructor TWatcherThread.Destroy;
    begin
      if fDirHandle <> INVALID_HANDLE_VALUE then
        CloseHandle(fDirHandle);
      if fChangeHandle <> 0 then
        CloseHandle(fChangeHandle);
      if fShutdownHandle <> 0 then
        CloseHandle(fShutdownHandle);
      inherited Destroy;
    end;
    
    procedure TWatcherThread.Execute;
    type
      PFileNotifyInformation = ^TFileNotifyInformation;
      TFileNotifyInformation = record
        NextEntryOffset: DWORD;
        Action: DWORD;
        FileNameLength: DWORD;
        FileName: WideChar;
      end;
    const
      BufferLength = 65536;
    var
      Filter, BytesRead: DWORD;
      InfoPointer: PFileNotifyInformation;
      Offset, NextOffset: DWORD;
      Buffer: array[0..BufferLength - 1] of byte;
      Overlap: TOverlapped;
      Events: array[0..1] of THandle;
      WaitResult: DWORD;
      FileName, s: string;
    begin
      if fDirHandle <> INVALID_HANDLE_VALUE then begin
        Filter := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME
          or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE;
    
        FillChar(Overlap, SizeOf(TOverlapped), 0);
        Overlap.hEvent := fChangeHandle;
    
        Events[0] := fChangeHandle;
        Events[1] := fShutdownHandle;
    
        while not Terminated do begin
          if ReadDirectoryChangesW (fDirHandle, @Buffer[0], BufferLength, TRUE,
            Filter, @BytesRead, @Overlap, nil)
          then begin
            WaitResult := WaitForMultipleObjects(2, @Events[0], FALSE, INFINITE);
            if WaitResult = WAIT_OBJECT_0 then begin
              InfoPointer := @Buffer[0];
              Offset := 0;
              repeat
                NextOffset := InfoPointer.NextEntryOffset;
                FileName := WideCharLenToString(@InfoPointer.FileName,
                  InfoPointer.FileNameLength);
                SetLength(FileName, StrLen(PChar(FileName)));
                s := Format('[%d] Action: %.8xh, File: "%s"',
                   [Offset, InfoPointer.Action, FileName]);
                OutputDebugString(PChar(s));
                PByte(InfoPointer) := PByte(DWORD(InfoPointer) + NextOffset);
                Offset := Offset + NextOffset;
              until NextOffset = 0;
            end;
          end;
        end;
      end;
    end;
    
    procedure TWatcherThread.Shutdown;
    begin
      Terminate;
      if fShutdownHandle <> 0 then
        SetEvent(fShutdownHandle);
    end;
    
    end.
    

    【讨论】:

    • 所有代码请使用 4 个空格的缩进,否则任何人都无法阅读。
    • 为什么要在线程中而不是在主程序中执行此操作?也许主程序在发现任何变化之前就关闭了。另外,什么设置了“终止”变量?
    猜你喜欢
    • 2011-09-26
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2019-04-27
    • 2010-09-07
    相关资源
    最近更新 更多