views:

78

answers:

3

I have

procedure TMainForm.FormCreate(Sender: TObject);
begin
DragAcceptFiles (Handle, True ) ; 
end ;

but the form does not accept dragged files - no drop cursor, no firing of WM_DROPFILES message.

I had the following construct in my FormShow event (for a different reason - there was code I wanted to execute only once after the form was created, and FormShow was firing more than once during initialisation) :

procedure TMainForm.FormShow(Sender: TObject);

begin
if (not FRunOnce) then  // as FormShow can be called twice - if Form.Position assigned to
    begin
    DragAcceptFiles (Handle, True ) ; 
    FRunOnce := True ;
    end ;
end ;

DragAcceptFiles (Handle, True ) in the position shown still doesn't work. If I move it to the top of the routine (so it executes twice), it does work:

procedure TMainForm.FormShow(Sender: TObject);

begin
DragAcceptFiles (Handle, True ) ; 
if (not FRunOnce) then  // as FormShow can be called twice - if Form.Position assigned to
    begin
    FRunOnce := True ;
    end ;
end ;

All the example code I have found seems to call DragAccept during OnCreate. My experiments suggest this is too early, as is the first fire of OnShow. I'm sure something is wrong with my code elsewhere but what might be causing this?

+1  A: 

The FormShow event firing more than once in your application is a sign that the handle of the form is destroyed and recreated at least once, most probably because you change one of the properties that requires the window handle to be recreated. Changing the stay-on-topness is one example.

If the handle is recreated then the new one will of course not receive any messages the previous handle was registered to receive.

What you need to do is to call DragAcceptFiles() after the final handle has been created, or (as that may be hard to do) indeed multiple times.

mghie
I think this is the key. I hadn't appreciated that the handle might be different throughout the life of the form.
+1  A: 

I have found that issues like this are easily handled by a custom message that you post to yourself in the FormCreate. For example:

CONST
  wm_FirstRun = WM_USER + 101;


TYPE
  TForm1 = class(TForm)
  :
    Procedure wmFirstRun(var Msg:tMessage); message wm_FirstRun;
    procedure FormCreate(Sender: TObject); 
  :
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // other initialization code
  PostMessage(handle,wm_FirstRun,0,0);
end;

Procedure TForm1.wmFirstRun(var Msg:tMessage);
begin
  // handle the code here that will run once the form is processing messages
end;

The trigger mechanism is the PostMessage, so whenever you invoke that command it will invoke your custom message routine. Of course if that is the case then I would call it something other than wmFirstRun.

skamradt
SO are you saying that putting the dragacceptFiles in this message handler will ensure that it is called after the oncreate and onshow events?
Yes...but only once since it was requested in the onCreate.
skamradt
I notice that some answers have disappeared. Who does this and why?
Some people will remove their answers if they no longer feel it relevant to the problem to avoid down votes.
skamradt
+6  A: 

Any TWinControl's HWND can be created and recreated multiple times during its lifetime. The best place to call DragAcceptFiles() is in overriden CreateWnd() and DestroyWnd() methods so that you can (re)register during all (re)creations and unregister during all destructions, eg:

procedure TMainForm.CreateWnd;
begin 
  inherited;
  DragAcceptFiles(Handle, True);  
end;

procedure TMainForm.DestroyWnd;
begin 
  DragAcceptFiles(Handle, False);
  inherited;
end;
Remy Lebeau - TeamB
This is the cleanest approach. Many thanks.