TWebBrowser OLE Drag Drop

Posted on 2004-09-09
Medium Priority
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 500 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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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 is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month13 days, 23 hours left to enroll

801 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