this slowpoke moves

Create Explorer in ListView

Unit DirWatch.pas
unit DirWatch;

interface

uses
  Windows, Messages, SysUtils, Forms, Classes;

type
  TNotifyFilter = (nfFilename, nfDirname, nfAttrib,
    nfSize, nfLastWrite, nfSecurity);
  TNotifyFilters = set of TNotifyFilter;
  TWatchThread = class; 
  TDirectoryWatch = class(TComponent)
  private
    fWindowHandle: THandle;
    fWatchThread: TWatchThread;
    fWatchSubDirs: boolean;
    fDirectory: string;
    fActive: boolean;
    fNotifyFilters: TNotifyFilters; 
    fOnChangeEvent: TNotifyEvent;
    procedure SetActive(aActive: boolean);
    procedure SetDirectory(aDir: string);
    procedure SetWatchSubDirs(aWatchSubDirs: boolean);
    procedure SetNotifyFilters(aNotifyFilters: TNotifyFilters);
    procedure WndProc(var aMsg: TMessage);
  public
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Directory: string read fDirectory write SetDirectory;
    property NotifyFilters: TNotifyFilters read fNotifyFilters write SetNotifyFilters;
    property WatchSubDirs: boolean read fWatchSubDirs write SetWatchSubDirs;
    property Active: boolean read fActive write SetActive;
    property OnChange: TNotifyEvent read fOnChangeEvent write fOnChangeEvent;
  end;
  TWatchThread = class(TThread)
  private
    fOwnerHdl: Thandle;
    fChangeNotify : THandle;
    fBreakEvent: THandle; 
    fDirectory: string;
    fWatchSubDirs: longbool;
    fNotifyFilters: dword;
    fFinished: boolean; 
  protected
    procedure SetDirectory(const Value: string);
    procedure ProcessFilenameChanges;
    procedure Execute; override;
  public
    constructor Create( OwnerHdl: THandle;
      const InitialDir: string; WatchSubDirs: boolean; NotifyFilters: dword);
    destructor Destroy; override;
    procedure Terminate;
    property Directory: string write SetDirectory;
  end;

procedure Register;

implementation

const
  NOTIFYCHANGE_MESSAGE = WM_USER + 1;

resourcestring
  sInvalidDir = 'Invalid Directory: ';

procedure Register;
begin
  RegisterComponents('Samples', [TDirectoryWatch]);
end;

function DirectoryExists(const Name: string): Boolean;
var
  Code: Integer;
begin
  Code := GetFileAttributes(PChar(Name));
  Result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
end;

constructor TDirectoryWatch.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  fNotifyFilters := [nfFilename, nfDirname, nfLastWrite];
  fDirectory := 'C:\';
  fWindowHandle := AllocateHWnd(WndProc);
end;

destructor TDirectoryWatch.Destroy;
begin
  Active := false;
  DeallocateHWnd(fWindowHandle);
  inherited Destroy;
end;

procedure TDirectoryWatch.WndProc(var aMsg: TMessage);
begin
  with aMsg do
    if Msg = NOTIFYCHANGE_MESSAGE then
    begin
      if assigned(OnChange) then OnChange(self);
    end else
      Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;

procedure TDirectoryWatch.SetNotifyFilters(aNotifyFilters: TNotifyFilters);
begin
  if aNotifyFilters = fNotifyFilters then exit;
  fNotifyFilters := aNotifyFilters;
  if assigned(fWatchThread) then
  begin
    Active := false;
    Active := true;
  end;
end;

procedure TDirectoryWatch.SetWatchSubDirs(aWatchSubDirs: boolean);
begin
  if aWatchSubDirs = fWatchSubDirs then exit;
  fWatchSubDirs := aWatchSubDirs;
  if assigned(fWatchThread) then
  begin
    Active := false;
    Active := true;
  end;
end;

procedure TDirectoryWatch.SetDirectory(aDir: string);
begin
  if aDir = '' then
  begin
    Active := false;
    fDirectory := '';
    exit;
  end;
  if (aDir[length(aDir)] <> '\') then aDir := aDir + '\'; 
  if aDir = fDirectory then exit;
  if not (csDesigning in ComponentState) and not DirectoryExists(aDir) then
    raise Exception.Create( sInvalidDir + aDir);
  fDirectory := aDir;
  if assigned(fWatchThread) then
    fWatchThread.Directory := fDirectory;
end;

procedure TDirectoryWatch.SetActive(aActive: boolean);
var
  nf: dword;
begin
  if aActive = fActive then exit;
  fActive := aActive;
  if csDesigning in ComponentState then exit;
  if fActive then
  begin
    if not DirectoryExists(fDirectory) then
    begin
      fActive := false;
      raise Exception.Create(sInvalidDir + fDirectory);
    end;
    nf := 0;
    if nfFilename in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_FILE_NAME;
    if nfDirname in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_DIR_NAME;
    if nfAttrib in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_ATTRIBUTES;
    if nfSize in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_SIZE;
    if nfLastWrite in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_LAST_WRITE;
    if nfSecurity in fNotifyFilters then
      nf := nf or FILE_NOTIFY_CHANGE_SECURITY;
    fWatchThread := TWatchThread.Create(
      fWindowHandle, fDirectory, fWatchSubDirs, nf);
  end else
  begin
    fWatchThread.Terminate;
    fWatchThread := nil;
  end;
end;

constructor TWatchThread.Create(OwnerHdl: THandle;
  const InitialDir: string; WatchSubDirs: boolean; NotifyFilters: dword);
begin
  inherited Create(True); 
  fOwnerHdl := OwnerHdl;
  if WatchSubDirs then
    cardinal(fWatchSubDirs) := 1 
  else
    fWatchSubDirs := false;
  FreeOnTerminate := true;
  Priority := tpLowest;
  fDirectory := InitialDir;
  fNotifyFilters := NotifyFilters;
  fBreakEvent := windows.CreateEvent(nil, False, False, nil);
  Resume;
end;

destructor TWatchThread.Destroy;
begin
  CloseHandle(fBreakEvent);
  inherited Destroy;
end;

procedure TWatchThread.SetDirectory(const Value: string);
begin
  if (Value = FDirectory) then exit;
  FDirectory := Value;
  SetEvent(fBreakEvent);
end;

procedure TWatchThread.Terminate;
begin
  inherited Terminate;
  SetEvent(fBreakEvent);
  while not fFinished do sleep(10); 
end;

procedure TWatchThread.Execute;
begin
  while (not Terminated) do
  begin
    fChangeNotify := FindFirstChangeNotification(pchar(fDirectory),
      fWatchSubDirs, fNotifyFilters);
    if (fChangeNotify = INVALID_HANDLE_VALUE) then
      WaitForSingleObject(fBreakEvent, INFINITE)
    else
      try
        ProcessFilenameChanges;
      finally
        FindCloseChangeNotification(fChangeNotify);
      end;
  end;
  fFinished := true;
end;

procedure TWatchThread.ProcessFilenameChanges;
var
  WaitResult : DWORD;
  HandleArray : array[0..1] of THandle;
const
  TEN_MSECS = 10;
  HUNDRED_MSECS = 100;
begin
  HandleArray[0] := fBreakEvent;
  HandleArray[1] := fChangeNotify;
  while (not Terminated) do
  begin
    WaitResult := WaitForMultipleObjects(2, @HandleArray, False, INFINITE);
    if (WaitResult = WAIT_OBJECT_0 + 1) then 
    begin
      repeat 
        FindNextChangeNotification(fChangeNotify);
      until Terminated or
        (WaitForSingleObject(fChangeNotify, TEN_MSECS) <> WAIT_OBJECT_0);
      if Terminated then break;
      PostMessage(fOwnerHdl, NOTIFYCHANGE_MESSAGE, 0, 0);
    end else 
    begin 
      while (not Terminated) and
        (WaitForSingleObject(fBreakEvent, HUNDRED_MSECS) = WAIT_OBJECT_0) do;
      break;
    end;
  end;
end;
end.
Unit1 :
uses DirWatch

private
    DirectoryWatch: TDirectoryWatch;
    procedure RefreshView(Sender: TObject);
    
type
  TDriveType = (dtUnknown, dtNoDrive, dtFloppy, dtFixed, dtNetwork, dtCDROM, dtRAM);
    
//

procedure GetDrivesList(strings: TStrings);
var
  DriveNum: Integer;
  DriveStr: array [0..3] of Char;
  DriveBits: set of 0..25;
begin
  DriveStr := '?:\'#0;
  strings.clear;
  Integer(DriveBits) := GetLogicalDrives;
  for DriveNum := 0 to 25 do
  begin
    if not (DriveNum in DriveBits) then Continue;
    DriveStr[0] := Char(DriveNum + Ord('A'));
    if TDriveType(GetDriveType(DriveStr)) = dtFixed then
      strings.Add(DriveStr);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DirectoryWatch := TDirectoryWatch.Create(self);
  DirectoryWatch.OnChange := RefreshView;
  DirectoryWatch.Directory := 'C:\';
  DirectoryWatch.Active := true;
  GetDrivesList(ComboBox1.Items);
  ComboBox1.ItemIndex := 0;
  ComboBox1Change(nil);
end;

procedure TForm1.Exit1Click(Sender: TObject);
begin
  close;
end;

procedure TForm1.RefreshView(Sender: TObject);
var
  sr: TSearchRec;
  searchResult: integer;
  lvi: TListitem;
  attr: string;
begin
  ListView1.items.clear;
  screen.Cursor := crHourglass;
  ListView1.Items.BeginUpdate;
  try
    lvi := ListView1.Items.Add;
    lvi.Caption := '..';
    lvi.Data := pointer(-2); 
    lvi.ImageIndex := 2;
    searchResult := FindFirst(DirectoryWatch.Directory+'*.*',faAnyFile,sr);
    while searchResult = 0 do
    begin
      if sr.Name[1] <> '.' then
      begin
        lvi := ListView1.Items.Add;
        if sr.Attr and FILE_ATTRIBUTE_DIRECTORY > 0 then lvi.Data := pointer(-1);
        lvi.Caption := sr.Name;
        if lvi.Data <> nil then 
          lvi.SubItems.Add('') else
          lvi.SubItems.Add(format('%1.0n Kb',[sr.Size/1024]));
        if sr.Time = 0 then
          lvi.SubItems.Add('') else
          lvi.SubItems.Add(formatdatetime(ShortDateFormat + '  ' +
            ShortTimeFormat, FileDateToDateTime(sr.Time)));
        if lvi.Data <> nil then
          lvi.ImageIndex := 1 else
          lvi.ImageIndex := 0;
        if sr.Attr and FILE_ATTRIBUTE_READONLY > 0 then
          attr := 'R' else attr := '';
        if sr.Attr and FILE_ATTRIBUTE_ARCHIVE > 0 then
          attr := attr + 'A';
        if sr.Attr and FILE_ATTRIBUTE_SYSTEM > 0 then
          attr := attr + 'S';
        if sr.Attr and FILE_ATTRIBUTE_HIDDEN > 0 then
          attr := attr + 'H';
        lvi.SubItems.Add(attr);
      end;
      searchResult := FindNext(sr);
    end;
    findClose(sr);
  finally
    ListView1.Items.EndUpdate;
    screen.Cursor := crDefault;
  end;
  Caption := 'Exploring - ' + DirectoryWatch.Directory;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  DirectoryWatch.Directory := ComboBox1.Text;
  RefreshView(nil);
end;

procedure TForm1.ListView1DblClick(Sender: TObject);
var
  lvi: TListItem;
  i: integer;
begin
  lvi := Listview1.Selected;
  if (lvi = nil) or (lvi.Data = nil) then exit;
  if lvi.Caption = '..' then
  begin
    i := length (DirectoryWatch.Directory)-1;
    if i < 3 then exit;
    while DirectoryWatch.Directory[i] <> '\' do dec(i);
    DirectoryWatch.Directory := copy(DirectoryWatch.Directory,1,i);
  end else
    DirectoryWatch.Directory :=
      DirectoryWatch.Directory + lvi.Caption;
  RefreshView(nil);
end;

procedure TForm1.ListView1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then ListView1DblClick(Sender);
end;

procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
begin
  Compare := integer(Item1.Data) - integer(Item2.Data);
  if Compare <> 0 then exit;
  Compare := CompareText(Item1.Caption, Item2.Caption);
end;

Keine Kommentare:

Kommentar veröffentlichen

Beliebte Posts

Translate