Jeff wrote:
We have been trying to create a sample application implementing
IDropTarget but have been unsuccessful.
What kind of problems are you having? It is not a trivial interface to implement,
but it is also not a complex interface, either.
Have you tried Anders' component suite, like I suggested earlier? It handles
most of the complexities for you. The TDropFileTarget component will accept
dropped files for you.
Using the old method of implementing WM_DROPFILES allowed us to
drag files from explorer to the memo box and the file name would appear.
While WM_DROPFILES will "work" (UIPI permitting), it is limited to only accepting
dropping filenames of physical files. IDropTarget can handle those (and
CF_HDROP is not the only format that can drop files), and just about anything
else (virtual files, shell items, data streams, custom formats, etc).
Another benefit is once you have IDropTarget working, it is a small step
to enable the same IDropTarget object to handle additional shell operations,
like dropping things on your app's .exe file itself or its Taskbar buton
instead of your app's window directly.
Do you have any suggestion for what we are doing wrong with the
sample application?
As far as your IDropTarget implementation itself goes, it looks OK. But
I see several problems in how your code is managing the TDropTarget object
at runtime.
1) I would not suggest calling RegisterDragDrop() and RevokeDragDrop() from
inside of TDropTarget itself. Your TForm should be calling those instead.
Let CreateWnd() create the TDropTarget object THEN register it, and hav
DestroyWnd() revoke the object BEFORE destroying its window.
2) In addition to #1, your TForm's FDropTarget member is declared as TDropTarget,
but it needs to be declared as IDropTarget instead so the object's reference
count gets managed correctly. By declaring the variable as TDropTarget,
you are bypassing reference count management. I would also suggest making
FDropTarget be a local variable of CreateWnd() instead of a member of the
TForm at all. RegisterDragDrop() will increment the object's reference count
if successful, and RevokeDragDrop() will decrement it. You don't need to
maintain your own reference to the object since you are not accessing it
outside of CreateWnd() (except to destroy it in DestroyWnd(), which is the
wrong thing to do - let the reference count handle that for you).
constructor TDropTarget.Create(const ADragDrop: IDragDrop);
begin
inherited Create;
FDragDrop := ADragDrop;
end;
destructor TDropTarget.Destroy;
begin
inherited;
end;
...
procedure TForm1.CreateWnd;
var
LDropTarget: IDropTarget;
begin
inherited;
// ChangeWindowMessageFilterEx(Handle, WM_DROPFILES, MSGFLT_ALLOW, nil);
// ChangeWindowMessageFilterEx(Handle, WM_COPYDATA, MSGFLT_ALLOW, nil);
// ChangeWindowMessageFilterEx(Handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW,
nil);
LDropTarget := TDropTarget.Create(Self) as IDropTarget;
OleCheck(RegisterDragDrop(Handle, LDropTarget));
end;
procedure TForm1.DestroyWnd;
begin
RevokeDragDrop(Handle);
inherited;
end;
3) You also should not be calling OleInitialize() or OleUninitialize() in
your TDropTarget unit at all. That is the responsibility of individual threads
to call, and the VCL main thread also initializes OLE/COM at program startup
for you.
--
Remy Lebeau (TeamB)
Connect with Us