Board index » delphi » Implementing IDropTarget?

Implementing IDropTarget?

Hi,

I must be making a very stupid mistake: I am unable to get IDropTarget
to work. Always when calling RegisterDragDrop I get an (OLE) error
stating that there is too little memory for this operation.

The complete code I am using can be found below. There is no type
library, just a plain new application with the below modifications.

What am I doing wrong? I am just looking for the most simplistic
example that lets me RegisterDragDrop something (later implementing
IDropSource).

TIA
Stefan

*******************

uses
  ActiveX, ComObj, ComServ,
  .... <standard >;

type
  TForm1 = class(TForm, IDropTarget)
    Button1: TButton;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);

  public
    function IDropTarget.DragOver = _DragOver; // kill compiler
warning

    function DragEnter(const dataObj: IDataObject; grfKeyState:
Longint;
      pt: TPoint; var dwEffect: Longint): HResult; stdcall;
    function _DragOver(grfKeyState: Longint; pt: TPoint;
      var dwEffect: Longint): HResult; stdcall;
    function DragLeave: HResult; stdcall;
    function Drop(const dataObj: IDataObject; grfKeyState: Longint;
pt: TPoint;
      var dwEffect: Longint): HResult; stdcall;

  end;

{ implementation section - just stubbed to get everything to compile }

procedure TForm1.Button1Click(Sender: TObject);
begin
  OleCheck( RegisterDragDrop(Self.Handle, Self) );
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  OleCheck( RevokeDragDrop(Self.Handle) );
end;

{ Interface definition }

function TForm1.DragEnter(const dataObj: IDataObject; grfKeyState:
Longint;
  pt: TPoint; var dwEffect: Longint): HResult;
begin
  Result := S_OK;
end;

{ _DragOver aliased to IDropTarget.DragOver }

function TForm1._DragOver(grfKeyState: Longint; pt: TPoint;
  var dwEffect: Longint): HResult;
begin
  Result := S_OK;
end;

function TForm1.DragLeave: HResult;
begin
  Result := S_OK;
end;

function TForm1.Drop(const dataObj: IDataObject; grfKeyState: Longint;
pt: TPoint;
  var dwEffect: Longint): HResult;
begin
  Result := S_OK;
end;

--
mailto:Stefan.Hoffmeister (at) Uni-Passau.de
http://kakadu.rz.uni-passau.de/~w4hoff01/
    PGP public key at homepage

 

Re:Implementing IDropTarget?


Hello,

Off of the top of my head, I think you need to first lock
the drop target class using the CoLockObjectExternal API
before you call calling RegisterDragDrop.

And don't forget to unlock your object using the same
CoLockObjectExternal API when you're done with the IDropTarget
implementor class.
--
Binh Ly
Brickhouse Data Systems, Inc
http://www.brickhouse.com

Stefan Hoffmeister <no.spam.ple...@see.signature> wrote in article
<34b75ad1.15734...@forums.borland.com>...

Quote
> Hi,

> I must be making a very stupid mistake: I am unable to get IDropTarget
> to work. Always when calling RegisterDragDrop I get an (OLE) error
> stating that there is too little memory for this operation.

> The complete code I am using can be found below. There is no type
> library, just a plain new application with the below modifications.

> What am I doing wrong? I am just looking for the most simplistic
> example that lets me RegisterDragDrop something (later implementing
> IDropSource).

> TIA
> Stefan

> *******************

> uses
>   ActiveX, ComObj, ComServ,
>   .... <standard >;

> type
>   TForm1 = class(TForm, IDropTarget)
>     Button1: TButton;
>     Button2: TButton;
>     procedure Button2Click(Sender: TObject);
>     procedure Button1Click(Sender: TObject);

>   public
>     function IDropTarget.DragOver = _DragOver; // kill compiler
> warning

>     function DragEnter(const dataObj: IDataObject; grfKeyState:
> Longint;
>       pt: TPoint; var dwEffect: Longint): HResult; stdcall;
>     function _DragOver(grfKeyState: Longint; pt: TPoint;
>       var dwEffect: Longint): HResult; stdcall;
>     function DragLeave: HResult; stdcall;
>     function Drop(const dataObj: IDataObject; grfKeyState: Longint;
> pt: TPoint;
>       var dwEffect: Longint): HResult; stdcall;

>   end;

> { implementation section - just stubbed to get everything to compile }

> procedure TForm1.Button1Click(Sender: TObject);
> begin
>   OleCheck( RegisterDragDrop(Self.Handle, Self) );
> end;

> procedure TForm1.Button2Click(Sender: TObject);
> begin
>   OleCheck( RevokeDragDrop(Self.Handle) );
> end;

> { Interface definition }

> function TForm1.DragEnter(const dataObj: IDataObject; grfKeyState:
> Longint;
>   pt: TPoint; var dwEffect: Longint): HResult;
> begin
>   Result := S_OK;
> end;

> { _DragOver aliased to IDropTarget.DragOver }

> function TForm1._DragOver(grfKeyState: Longint; pt: TPoint;
>   var dwEffect: Longint): HResult;
> begin
>   Result := S_OK;
> end;

> function TForm1.DragLeave: HResult;
> begin
>   Result := S_OK;
> end;

> function TForm1.Drop(const dataObj: IDataObject; grfKeyState: Longint;
> pt: TPoint;
>   var dwEffect: Longint): HResult;
> begin
>   Result := S_OK;
> end;

> --
> mailto:Stefan.Hoffmeister (at) Uni-Passau.de
> http://kakadu.rz.uni-passau.de/~w4hoff01/
>     PGP public key at homepage

Re:Implementing IDropTarget?


Quote
: "bly" <b...@castle.net> wrote:
>Off of the top of my head, I think you need to first lock
>the drop target class using the CoLockObjectExternal API
>before you call calling RegisterDragDrop.

>And don't forget to unlock your object using the same
>CoLockObjectExternal API when you're done with the IDropTarget
>implementor class.

I tried adding the lock

  OleCheck( CoLockObjectExternal(Self, true, false) ); // lock

and the unlock at the appropriate places, after having added IUnknown
to the form's class:

  TForm1 = class(TForm, IUnknown, IDropTarget)

Strangely I am now crashing with a nil pointer access somewhere in the
access to the IUnknown interface: a simple assignment "someinterface
:= self" at least crashes...

Any ideas what I am missing here?

Stefan
--
mailto:Stefan.Hoffmeister (at) Uni-Passau.de
http://kakadu.rz.uni-passau.de/~w4hoff01/
    PGP public key at homepage

Re:Implementing IDropTarget?


Remember to do OLEInitialise(nil) in your units initialization
and OleUnInitialize in the finalization. Once these are in, everything
should work just fine.

The CoLockObjectExternal should go in the form's OnCreate method
and the corresponding CoLockObjectExternal (release) in the
OnDestroy.

Cheers,

            _  _______________________________  _
           / )|        David Brock            |( \
          / / |      dbr...@cqm.co.uk         | \ \
        _( (_ |  _  Paisley - Scotland     _  | _) )_
       (((\ \)|_/ )_______________________( \_|(/ /)))
       (\\\\ \_/ /                         \ \_/ ////)
        \       /                           \       /
         \    _/                             \_    /
         /   /                                 \   \

Quote

>Any ideas what I am missing here?

>Stefan
>--
>mailto:Stefan.Hoffmeister (at) Uni-Passau.de
>http://kakadu.rz.uni-passau.de/~w4hoff01/
>    PGP public key at homepage

Re:Implementing IDropTarget?


You can't add IUnknown to TForm without implementing it, unfortunately.
There's an "it would be a bug if it weren't a design decision" issue
with TForm (TCustomForm actually) -- it implements _some_ COM stuff, to
(I think) support ActiveForms.  you didn't get an error for failing to
implement the IUnknown methods in your TForm1 class because of that --
but you've got to re-implement them because you need them to work
differently than the ones in TCustomForm.

An alternative is to implement something you could call TInterfacedForm,
which would be     TInterfacedForm = class(TForm, IUnknown)
and which has Addref/Release/QI implemented, then descend from that.

I'm not sure I know why you added IUnknown to the form's class; that's
what caused the trouble.  Did you have a compile error if you didn't do
so?

!^NavFont02F02A20004HIA31C60

Re:Implementing IDropTarget?


Quote
: jmerrill_nos...@mnsinc.com (jmerrill_nos...@mnsinc.com) wrote:
>You can't add IUnknown to TForm without implementing it, unfortunately.
>There's an "it would be a bug if it weren't a design decision" issue
>with TForm (TCustomForm actually) -- it implements _some_ COM stuff, to
>(I think) support ActiveForms.  

It's implemented in TComponent - and I should have had a look at the
implementation earlier - thanks a lot for the pointer!

Quote
>you didn't get an error for failing to
>implement the IUnknown methods in your TForm1 class because of that --

My reasoning was: it's there, so it's fully implemented; there was no
indication in the TComponent._AddRef etc. documentation whatsoever
that these needed to be re-implemented.

Is there sample code anywhere that shows how to do it right? Currently
I return E_NOINTERFACE and a refcount of 0 each time (thanks to Edwin
Hagen for the code) - anything wrong with that?

Quote
>but you've got to re-implement them because you need them to work
>differently than the ones in TCustomForm.

>An alternative is to implement something you could call TInterfacedForm,
>which would be     TInterfacedForm = class(TForm, IUnknown)
>and which has Addref/Release/QI implemented, then descend from that.

Right, that would be much cleaner - I just tried to get something up
and running...

Quote
>I'm not sure I know why you added IUnknown to the form's class; that's
>what caused the trouble.  Did you have a compile error if you didn't do
>so?

Yes. It was suggested to also use "CoLockObjectExternal", which needs
IUnknown, to solve my problem. This appears not to be necessary, so
IUnknown has been removed from the class declaration...

All in all my problem boiled down to:

1) I did not call OleInitialize and OleUninitialize
   --> caused OleSysError -> "Not enough storage is available..."

2) I did *not* re-implement the IUnknown interface as I thought that
it already had been implemented; it turned out that the existing
implementation is useless (not ready-to-use).
   --> caused AV to nil pointer

--
mailto:Stefan.Hoffmeister (at) Uni-Passau.de
http://kakadu.rz.uni-passau.de/~w4hoff01/
    PGP public key at homepage

Re:Implementing IDropTarget?


Stefan,

  Are you trying to implement IDropTarget so
that you can drop files onto your form (or
a component on your form) and process them
in some manner (open, add to a list or treeview)?

  If so, save yourself some valuable time and
go to the Delphi Super Page and do a search
for the author "Angus Johnson" or his contribution,
"dndfiles.zip".

  Or, you might try this directly:

  http://SunSITE.icm.edu.pl/delphi/ftp/d20free/dndfiles.zip

There are two, very well-written components, one
implementing the drag source, and the other the drag target.
Properties for the important functionality allow you
to write the event handling.  There's a demo with
it that shows everything.  A very well-done contribution.

Paul Furbacher

Other Threads