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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

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…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.

776 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