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
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
1 Comment
LVL 34

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

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Correct Component for Shopping Cart. 2 121
Making delphi communicate with a c# service 16 124
Find and Replace Stream with 0s 8 73
Convert MS Word document to a PDF file 9 115
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit If you want to manage em…

726 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