unit FileDropper;
{ If the component is placed on the form, it will enable dropping
  files from windows explorer onto the form (OnDrop event should be then
  handled) or onto the TListBox, TEdit or TMemo components. Such DispControl
  must be assigned to TFileDropper.DispControl property. Then the full filename
  will be added (to TListBox, TMemo) or will replace the content (TEdit) of the
  DispControl if the file is dropped on it. }
{
  (C) 2000 - 2003 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://chromulan.org
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}


interface

uses
  Windows, Messages, ShellApi, SysUtils, Classes, Controls, StdCtrls, Forms;

type
  TOnDropFile = procedure(const AFileName: string) of object;

  TFileDropper = class(TComponent)
  private
    { Private declarations }
    FOldWndMethod : TWndMethod;
    FWindow: TWinControl;
    FControl: TWinControl;{tedit}
    FOnDropFile: TOnDropFile;
    procedure SubClassWndProc(var Message: TMessage);
    function GetListBox: TListBox;
    function GetMemo: TMemo;
    function GetEdit: TEdit;
    procedure SetWindow(AWindow: TWinControl);
    procedure SetControl(AControl: TWinControl);
    procedure WMDropFiles(var Msg: TMessage);
  protected
    { Protected declarations }
    procedure Loaded; override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property ListBox: TListBox read GetListBox;
    property Memo: TMemo read GetMemo;
    property Edit: TEdit read GetEdit;
  published
    { Published declarations }
    property OnDropFile: TOnDropFile read FOnDropFile write FOnDropFile;
    property DispControl: TWinControl read FControl write SetControl;
    property Window: TWinControl read FWindow write SetWindow;
  end;

procedure Register;

implementation

{TFileDropper.}
procedure TFileDropper.WMDropFiles(var Msg: TMessage);
var
  hDrop    : THandle;
  FileName : array[0..254] of Char;
  iFiles   : integer;
  i        : integer;
begin
  hDrop  := Msg.WParam;
  iFiles := DragQueryFile(hDrop, $FFFFFFFF, FileName, 254);
  for i := 0 to iFiles - 1 do
  begin
    DragQueryFile(hDrop, i, FileName, 254);
    if Assigned(FOnDropFile) then begin
      FOnDropFile(FileName);
    end;
    if ListBox <> nil then begin
      ListBox.Items.Add(FileName);
    end;
    if Memo <> nil then begin
      Memo.Lines.Add(FileName); 
    end;
    if Edit <> nil then begin
      Edit.Text := FileName;
    end;
    //if Items.IndexOf(FileName) = -1
    //then Items.Add(FileName);
  end;
  DragFinish(hDrop);
end;

function TFileDropper.GetListBox: TListBox;
begin
  if DispControl is TListBox then
    Result := TListBox(DispControl)
  else
    Result := nil;
end;

function TFileDropper.GetMemo: TMemo;
begin
  if DispControl is TMemo then
    Result := TMemo(DispControl)
  else
    Result := nil;
end;

function TFileDropper.GetEdit: TEdit;
begin
  if DispControl is TEdit then
    Result := TEdit(DispControl)
  else
    Result := nil;
end;

procedure TFileDropper.SubClassWndProc(var Message: TMessage);
begin
  (*
  If ( (sm <> smOff) and  ( Message.Msg = WM_LBUTTONDOWN ) )
     {or
     ( Message.Msg = WM_Message ) } then
  begin
    if Message.Msg <> 0 then
      FOldWndMethod(Message);
  end else
  *)
  if Message.Msg = WM_DropFiles then begin
    WMDropFiles(Message);
    // FOldWndMethod(Message);
  end else begin
    FOldWndMethod(Message);
  end;
end;

procedure TFileDropper.SetControl(AControl: TWinControl);
begin
  if (AControl = nil) or
     (AControl is TListBox) or
     (AControl is TMemo) or
     (AControl is TEdit)
  then begin
    FControl := AControl;
  end else begin
    raise Exception.Create('Only TListBox, TMemo and TEdit are allowed');
  end;
end;

constructor TFileDropper.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  if Owner is TForm then begin
    Window := TWinControl(Owner);
  end;
end;

procedure TFileDropper.Loaded;
begin
  inherited;
  if (Window = nil) and (Owner is TForm) then
    Window := TWinControl(Owner);
end;

procedure TFileDropper.SetWindow(AWindow: TWinControl);
begin
  if FWindow = AWindow then
    exit;
  if FWindow <> nil then begin
    //DragAcceptFiles(FWindow.Handle, false);
    FWindow.WindowProc := FOldWndMethod;
    FWindow := nil;
  end;
  if AWindow <> nil then begin
    FWindow := AWindow;
    FOldWndMethod := FWindow.WindowProc;
    FWindow.WindowProc := SubClassWndProc;
    DragAcceptFiles(FWindow.Handle, True);
  end;
end;

destructor TFileDropper.Destroy;
begin
  Window := nil;
  inherited Destroy;
end;
{/TFileDropper.}

procedure Register;
begin
  RegisterComponents('File Utils', [TFileDropper]);
end;

end.
