TWebBrowser OLE Drag Drop

Posted on 2004-09-09
Last Modified: 2010-04-05
How do I override the default OLE drag drop behaviour for a TWebBrowser?

I am using the TWebrowser component as a HTML editor by putting it in edit mode.  I like the fact that I can drag HTML from IE into it. But, When I drag a link, or a html file, it opens the document, replacing the contents with the new file.  I would like to speficy my own behaviour when files are dropped, but use the existing behaviour when html is dropped.

It looks like I need to create a new Interface that inherits from the IDropTarget Interface that TWebBrowser uses, but I have no Idea how to do this.

I have figured out how to replace the IDropTarget interface, by doing the following:

CustDoc: ICustomDoc;
hr : HResult;
  hr := WebBrowser1.Document.QueryInterface(ICustomDoc, CustDoc);
  if hr = $00000000 {S_OK} then

DocHostUIHandler is an instance of this class, which allows overriding the regular UI operations:

TDocHostUIHandler = class(TComObject, IDocHostUIHandler)

One of the methods of this class is GetDropTarget, which allows you to specify an alternate IDropTarget interface.  I have been able
disable and enable drag drop by editing the contents.  So, I think that all I need to do is replace ppDropTarget with my own interface? How do I create this interface, so that I can inherit some of the existing behaviour?

function TDocHostUIHandler.IDocHostUIHandler_GetDropTarget(const pDropTarget: IDropTarget;
  out ppDropTarget: IDropTarget): HRESULT;
 //Enables Drag drop;
  Result := S_OK;
  //Disables drop
  //Result := S_FALSE;

Question by:wolsen
1 Comment
LVL 33

Accepted Solution

Slick812 earned 125 total points
ID: 12060591
hello  wolsen, , I have done a little with the IDropTarget Interface, I am mostly posting here because no one else has. I can not explain the IDropTarget Interface since, there are many factors and methods, it controls the cursors shown for a drag over, and queries for drop data types that are accepted or not, I do not handle any of that in my code. . .
Here is a BASIC and about as simple as you can get IDropTarget class. . . There are MANY types of Drop Data, they are usually typed by a Clip board format, like CF_HDROP  , CF_TEXT  and  CF_IDLIST , I do not know the CF_  type for HTML or Links . . .
The following code only does the CF_HDROP  format, sorry I do not have time now to clean it up , (take out un-used code) - -


  TDropTarget = class(TInterfacedObject, IDropTarget)
   function DragEnter(const DataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; stdcall;
   function DragOver(grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; stdcall;
   function DragLeave: HResult; stdcall;
   function Drop(const DataObj: IDataObject; grfKeyState: Integer; pt: TPoint; var dwEffect: Integer): HResult; stdcall;


// TDropTarget = = = = = = = = = = = = = = = = = = = = = = = =
// the first three functions do not do anything, just return a default NOERROR and the system does the default handling

function TDropTarget.DragEnter(const DataObj: IDataObject; grfKeyState: Longint;
                               pt: TPoint; var dwEffect: Longint): HResult;
//DataObj.EnumFormatEtc(dwDuirection, IEnumFormatetc);
 Result := NOERROR;

function TDropTarget.DragOver(grfKeyState: Longint; pt: TPoint;
                              var dwEffect: Longint): HResult;
 Result := NOERROR;

function TDropTarget.DragLeave: HResult;
 Result := NOERROR;

function TDropTarget.Drop(const DataObj: IDataObject; grfKeyState: Longint;
                          pt: TPoint; var dwEffect: Longint): HResult;
 Enum : IEnumFormatEtc;
 Link : PChar;
 Dummy : Integer;
 Format : TFormatEtc;
 Medium : TStgMedium;
 {FileStr,} FileStr1: String;
 DropFiles: PDropFiles;
 //ShiftState: Byte;

  {function GetFilesFromHGlobal(const HGlob: HGlobal; Files: String): boolean;
  DropFiles: PDropFiles;
  Filename: PChar;
  DropFiles := PDropFiles(GlobalLock(HGlob));
  Files := 'Low';
  //FileStr1 := 'Low';
    Filename := PChar(DropFiles) + DropFiles^.pFiles;
    while (Filename^ <> #0) do
      if (DropFiles^.fWide) then // -> NT4 & Asian compatibility
        Files := Files+','+PWideChar(FileName);
        inc(Filename, (Length(PWideChar(FileName)) + 1) * 2);
      end else
        Files := Files+','+FileName;
        FileStr1 := FileStr1 +','+FileName;
        inc(Filename, Length(Filename) + 1);

  Result := (Length(Files) > 0);

{function KeysToShiftState(Keys: Word): Byte;
// did not need key dowm info
  Result := Zero;
  if Keys and MK_SHIFT <> Zero then Result := One;
  if Keys and MK_CONTROL <> Zero then Result := Result or 2;
  if Keys and MK_LBUTTON <> Zero then Result := Result or 4;
  if Keys and MK_RBUTTON <> Zero then Result := Result or 8;
  if Keys and MK_MBUTTON <> Zero then Result := Result or 16;
  //if GetKeyState(VK_MENU) < 0 then Result := Result or 32;

{this does very little, just gets the file name from the DropFiles, a pointer to
 the TDropFiles in ShlObj.pas  , I only needed a single file name, I only do ONE kind
 of drop data, CF_HDROP, but there are many more}

Result := S_OK;

if DataObj.EnumFormatEtc(DATADIR_GET, Enum) <> S_OK then Exit;

 while Enum.Next(One, Format, @Dummy) = S_OK do
 begin // Enum.Next
 //ComStr := ComStr+' '+ Int2Str(Format.cfFormat);
 //SetWindowText(hWordEdit, Pchar(ComStr));

 if Format.cfFormat = CF_HDROP then
   if DataObj.GetData(Format, Medium) = S_OK then
     begin  // GetData
     //ShiftState := KeysToShiftState(grfKeyState);
      if (medium.tymed = TYMED_HGLOBAL) then
        begin // TYMED_HGLOBAL
       //GetFilesFromHGlobal(medium.HGlobal, FileStr);
       DropFiles := PDropFiles(GlobalLock(medium.HGlobal));
       Link := PChar(DropFiles) + DropFiles^.pFiles;
       while (Link^ <> #0) do
         begin // Link <> 0
         if (DropFiles^.fWide) then // -> NT4 & Asian compatibility
           begin // fWide
           FileStr1 := FileStr1+PWideChar(Link);
           inc(Link, (Length(PWideChar(Link)) + One) * Two);
           end else // fWide
           FileStr1 := FileStr1 +Link;
           inc(Link, PCharLength(Link) + One);
           end; // else fWide
         end; // Link <> 0

       end; // TYMED_HGLOBAL
      //Don't forget to clean-up!
      end; // finally
     end;  // GetData
  if Length(FileStr1) > 6 then
    if FileExists(FileStr1) then
    if LoadIColFile(FileStr1) > mOne then
 end; // Enum.Next


// TDropTarget finish  = = = = = = = = = =  = =

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

I have no Idea how to incorperate this in to a web browser for editing, and know nothing about the  IDocHostUIHandler_GetDropTarge  function. . ,
I use this code to give my API custom control drop file handling -

DropTar: TDropTarget;

if OleInitialize(nil) = S_OK then
  RegisterDragDrop(hScrollGrid, DropTar);
// hScrollGrid is the control Handle

- - - - - - - - - - - - - - - - - - - -

there is also an API function  RevokeDragDrop( ) which will Turn OFF the IDropTarget Interface for a control, I do not have time to try it, but you may be able to change the IDtopTarget for your window with -

RegisterDragDrop(WebBrowser.Handle, DropTar);

but there may be complications with an application as complex as the IE browser!, , like I said I have not tried it.

also, I wonder if you know of the ActiveX control DHTMLEdit, which is a system activeX that is for HTML Editing, and is in the  DHTMLEDLib_TLB.pas and is suppose to be good for an HTML editor, if you can figure out how to use it

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi procedure  - Unsatisfied forward or external declaration. 2 142
Magic Software info 18 125
Need Help Delphi 2010 CheckBox1 Stored value in memo 13 57
Base1 Encode/Decode 3 68
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Sending a Secure fax is easy with eFax Corporate ( First, just open a new email message. In the To field, type your recipient's fax number You can even send a secure international fax — just include t…
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now