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
Solved

How to access and read dragged text?

Posted on 1998-08-20
12
546 Views
Last Modified: 2010-04-04
If I select text from some other application and then drag
it to drop it into my RichEdit-control, how I can access and read this text before it will display in my control?
OnDragDrop doesn't effect.
0
Comment
Question by:raunol
  • 6
  • 3
  • 2
  • +1
12 Comments
 
LVL 10

Expert Comment

by:viktornet
ID: 1337336
Oh, kinda difficult task!

Regards,
Viktor
0
 
LVL 4

Expert Comment

by:d003303
ID: 1337337
Yo,
you will have to implement OLE drag and drop services. Use the RegisterDragDrop function to register your rich edit as a drop target and provide an implementation of IDropTarget as an interface. In its DragEnter implementation, you ca nquery the clipboard format of the IDataObject and read its content with the GetData method.

Slash/d003303
0
 

Author Comment

by:raunol
ID: 1337338
d003303,

Thank's for the hint. I grade it,if You can solve what's wrong here:


First I made TDropTarget type:

Uses ole2

Type

TDropTarget=Class(iDropTarget)
Public
   function Drop(DataObj:IDataObject; rfKeyState:Longint;
                 const pt: TPoint; var dwEffect:Longint):Hresult;
                 override;

   function DragOver(grfKeyState: Longint; const pt: TPoint;
                    var dwEffect: Longint): HResult;override;
End;

TMyRich=Class(TCustomRichEdit)
public
      DropTarget:TDropTarget;

End

Then I put this into the MyRich's WM_CREATE handler: RegisterDragDrop(handle,DropTarget);

When I now test it and drag text from an other edit-application to my control, nothing will happen - no effects will disapear
under functions TdropTarget.Drop or TDropTarget.DragOver ??
 
- Rauno -
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 8

Expert Comment

by:ZifNab
ID: 1337339
just an idea.. why not when selecting, copying it to the clipboard? (Or isn't this also already done, just for dragging and dropping to another application?) Zif?. The clipboard can be easely entered from delphi.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1337340
OK,
you don't have any effects because the RichEdit control is already registered as a Drag/Drop target when you call RegisterDragDrop, take a look at the return value. You can re-register it with RevokeDragDrop and then call RegisterDragDrop again. But, all RichEdit internal Drag/Drop events do not work anymore :-(

I'm currently looking for a way to get the previous IDropTarget of a registered drop target window, so you can proxy/stub the whole thing in your implementation.

Slash/d003303
0
 

Author Comment

by:raunol
ID: 1337341
d003303,

"no effects will appear" I should had written ;-)
(My english is not good)

Yes, I notised the function returned E_INVALIDARG.
I changed it a little and then it returned
DRAGDROP_E_ALREADYREGISTERED.

I also tried this RevokeDragDrop, but it caused
always error.


ZifNaf,

If I drag text from an other application to my
control, for example from WordPad, the text isn't
there in the clipboard.

There is the SelectionChange procedure in the RichEdit.
I dropped dragged text different position when the
SelectionChange activated. Under the procedure I
opened the ClipBoard and red the contents, but dragged
text wasn't there. There was some other text copied
before.

Obviously, due to OLE operation, I think the
text is stored somewhere in iDropTarged. But how to
get out it from there, before it will display in my control?
I want to do this, because I want to change the style of the
text (size and so on) before it will display.

- Rauno


0
 
LVL 4

Accepted Solution

by:
d003303 earned 200 total points
ID: 1337342
Yep, got it.
Here's the code. Create a form, drop a richedit onto is and apply this code:

// BOC

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, ActiveX;

type

  TForm1 = class(TForm)
    RichEdit1: TRichEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure OnTextDropped(Sender: TObject);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

const CF_RichTextFormat = 49226;

type

  TDropTargetProxy = class(TInterfacedObject, IDropTarget)
  private
    FOriginalTarget : IDropTarget;
    FOnTextDropped  : TNotifyEvent;
  public
    constructor Create(TargetToProxy: IDropTarget);
    destructor Destroy; override;
    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;
    // manipulation interface
    property OnTextDropped: TNotifyEvent read FOnTextDropped write FOnTextDropped;
  end;

  TDataObjectProxy = class(TInterfacedObject, IDataObject)
  private
    FOriginalDataObject : IDataObject;
    FDroppedText,
    FReplacedText       : PChar;
    FReplacedTextSize   : LongInt;
    FOnTextDropped      : TNotifyEvent;
  public
    constructor Create(DataObjectToProxy: IDataObject);
    destructor Destroy; override;
    function GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium):
      HResult; stdcall;
    function GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium):
      HResult; stdcall;
    function QueryGetData(const formatetc: TFormatEtc): HResult;
      stdcall;
    function GetCanonicalFormatEtc(const formatetc: TFormatEtc;
      out formatetcOut: TFormatEtc): HResult; stdcall;
    function SetData(const formatetc: TFormatEtc; var medium: TStgMedium;
      fRelease: BOOL): HResult; stdcall;
    function EnumFormatEtc(dwDirection: Longint; out enumFormatEtc:
      IEnumFormatEtc): HResult; stdcall;
    function DAdvise(const formatetc: TFormatEtc; advf: Longint;
      const advSink: IAdviseSink; out dwConnection: Longint): HResult; stdcall;
    function DUnadvise(dwConnection: Longint): HResult; stdcall;
    function EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
      stdcall;
    // manipulation interface
    procedure ReplaceDroppedText(NewText: PChar; NewTextSize: LongInt);
    property DroppedText: PChar read FDroppedText;
  end;

constructor TDropTargetProxy.Create(TargetToProxy: IDropTarget);
begin
  inherited Create;
  FOriginalTarget := TargetToProxy;
  FOriginalTarget._AddRef;
end;

destructor TDropTargetProxy.Destroy;
begin
  FOriginalTarget._Release;
  inherited Destroy;
end;

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

function TDropTargetProxy.DragOver(grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult;
begin
  Result := FOriginalTarget.DragOver(grfKeyState, pt, dwEffect);
end;

function TDropTargetProxy.DragLeave: HResult;
begin
  Result := FOriginalTarget.DragLeave;
end;

function TDropTargetProxy.Drop(const dataObj: IDataObject; grfKeyState: Longint; pt: TPoint; var dwEffect: Longint): HResult;
var DataObjectProxy : TDataObjectProxy;
begin
  // create proxy data object
  DataObjectProxy := TDataObjectProxy.Create(dataObj);
  DataObjectProxy.FOnTextDropped := FOnTextDropped;
  DataObjectProxy._AddRef;
  // pass proxy data object to caller
  Result := FOriginalTarget.Drop(DataObjectProxy, grfKeyState, pt, dwEffect);
  DataObjectProxy._Release;
end;

constructor TDataObjectProxy.Create(DataObjectToProxy: IDataObject);
begin
  inherited Create;
  FOriginalDataObject := DataObjectToProxy;
  FOriginalDataObject._AddRef;
  FDroppedText := nil;
  FReplacedText := nil;
end;

destructor TDataObjectProxy.Destroy;
begin
  FOriginalDataObject._Release;
  inherited Destroy;
end;

function TDataObjectProxy.GetData(const formatetcIn: TFormatEtc; out medium: TStgMedium): HResult;
var MemPointer    : Pointer;
    RichText      : PChar;
    TextLen       : LongInt;
begin
  Result := FOriginalDataObject.GetData(formatetcIn, medium);

  // check for RichEdit format
  if (Succeeded(Result))
    and (formatetcIn.cfFormat = CF_RichTextFormat)
    and (formatetcIn.tymed = TYMED_HGLOBAL) then
   begin
     // here's the point to manipulate the data !

     TextLen := GlobalSize(Medium.hGlobal) + 1;
     MemPointer := GlobalLock(Medium.hGlobal);
     GetMem(RichText, TextLen);
     FillChar(RichText[0], TextLen, 0);
     try
       StrLCopy(RichText, MemPointer, TextLen - 1);
       FDroppedText := RichText;
       if Assigned(FOnTextDropped)
        then FOnTextDropped(Self);
     finally
       FreeMem(RichText, TextLen);
       GlobalUnlock(Medium.hGlobal);
     end;

     FDroppedText := nil;
     if FReplacedText = nil
      then Exit;

     GlobalReAlloc(Medium.hGlobal, FReplacedTextSize, GMEM_MOVEABLE);
     MemPointer := GlobalLock(Medium.hGlobal);
     try
       StrCopy(MemPointer, FReplacedText);
     finally
       FreeMem(FReplacedText, FReplacedTextSize);
       FReplacedText := nil;
       GlobalUnlock(Medium.hGlobal);
     end;
   end;
end;

function TDataObjectProxy.GetDataHere(const formatetc: TFormatEtc; out medium: TStgMedium):HResult;
begin
  Result := FOriginalDataObject.GetDataHere(formatetc, medium);
end;

function TDataObjectProxy.QueryGetData(const formatetc: TFormatEtc): HResult;
begin
  Result := FOriginalDataObject.QueryGetData(formatetc);
end;

function TDataObjectProxy.GetCanonicalFormatEtc(const formatetc: TFormatEtc; out formatetcOut: TFormatEtc): HResult;
begin
  Result := FOriginalDataObject.GetCanonicalFormatEtc(formatetc, formatetcOut);
end;

function TDataObjectProxy.SetData(const formatetc: TFormatEtc; var medium: TStgMedium; fRelease: BOOL): HResult;
begin
  Result := FOriginalDataObject.SetData(formatetc, medium, fRelease);
end;

function TDataObjectProxy.EnumFormatEtc(dwDirection: Longint; out enumFormatEtc: IEnumFormatEtc): HResult;
begin
  Result := FOriginalDataObject.EnumFormatEtc(dwDirection, enumFormatEtc);
end;

function TDataObjectProxy.DAdvise(const formatetc: TFormatEtc; advf: Longint; const advSink: IAdviseSink; out dwConnection: Longint): HResult;
begin
  Result := FOriginalDataObject.DAdvise(formatetc, advf, advSink, dwConnection);
end;

function TDataObjectProxy.DUnadvise(dwConnection: Longint): HResult;
begin
  Result := FOriginalDataObject.DUnadvise(dwConnection);
end;

function TDataObjectProxy.EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
begin
  Result := FOriginalDataObject.EnumDAdvise(enumAdvise);
end;

procedure TDataObjectProxy.ReplaceDroppedText(NewText: PChar; NewTextSize: LongInt);
begin
  if FDroppedText = nil
   then Exit;
  FReplacedTextSize := NewTextSize;
  GetMem(FReplacedText, FReplacedTextSize);
  StrLCopy(FReplacedText, NewText, FReplacedTextSize);
end;

////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormCreate(Sender: TObject);
var PropHandle         : THandle;
    DropTarget         : TDropTargetProxy;
    RichEditDropTarget : IDropTarget;
    RegisterResult : LongInt;
    ErrorStr : string;
begin
  // get original drop target
  PropHandle := GetProp(RichEdit1.Handle, 'OleDropTargetInterface');

  // look if existant
  if PropHandle = 0
   then Exit;

  // create proxy drop target instance
  RichEditDropTarget := IDropTarget(Pointer(PropHandle));
  DropTarget := TDropTargetProxy.Create(RichEditDropTarget);
  DropTarget.OnTextDropped := OnTextDropped;

  // unregister original drop target
  RevokeDragDrop(RichEdit1.Handle);

  // ... and register our proxy one
  RegisterResult := RegisterDragDrop(RichEdit1.Handle, DropTarget as IDropTarget);

  // error check
  if (RegisterResult <> S_OK) and (RegisterResult <> DRAGDROP_E_ALREADYREGISTERED) then
   begin
     case RegisterResult of
       DRAGDROP_E_INVALIDHWND : ErrorStr := 'Invalid window handle';
       E_OUTOFMEMORY : ErrorStr := 'Out of memory';
     end;
     DropTarget.Free;
     raise Exception.Create(ErrorStr);
   end;
end;

procedure TForm1.OnTextDropped(Sender : TObject);
//(RichText: PChar; var NewText: PChar; var NewTextLen: LongInt);
// insert string contains trailing '}', overriden by a #0 in code
const InsertString: PChar = ' >through Slash''s proxy<}';
var DataObject: TDataObjectProxy;
    NewTextLen: LongInt;
    NewText,
    StrPointer: PChar;
begin
  if Sender is TDataObjectProxy then
   begin
     DataObject := (Sender as TDataObjectProxy);
     // length + terminator + insertion string
     NewTextLen := StrLen(DataObject.DroppedText) + 1 + StrLen(InsertString);
     GetMem(NewText, NewTextLen);
     FillChar(NewText[0], NewTextLen, 0);

     // find closing bracket
     StrPointer := StrRScan(DataObject.DroppedText, '}');
     // cut off original string
     StrPointer[0] := #0;
     StrCopy(NewText, DataObject.DroppedText);
     StrCat(NewText, InsertString);
     DataObject.ReplaceDroppedText(NewText, NewTextLen);
     FreeMem(NewText, NewTextLen);
   end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  RevokeDragDrop(RichEdit1.Handle);
end;

end.

// EOC

This can easily be implemented into any richedit derivant. What is does is to obtain the previous IDropTarget interfave of the richedit and replaces it with its own. When the data is written over (see source), you can manipulate is however you like.

Have fun,
Slash/d003303
0
 

Author Comment

by:raunol
ID: 1337343
Thanks for Your kindness, the code looks fine,
but I have still broblems. I think, the code is for
Delphi3 or 4, and I have Delphi 2 :-(

I don't find ActiveX unit for me, but obviously OLE2 unit
works as well, becouse there is all what are used in the
code - except TInterfacedObject. But Class-clause respects
only one descent so I must remove TInterfacedObject anyway.

Also I must make some other changes. There is some "out" type
in the code or it is bug (e.g. out medium) I changed it "Var".
Also I must change "Const" types to "Var", because
functions (e.g. GetData) don't respect Class constants
as variable. Then I change _Addref And _release without "_" Addref And Release.

That's all. After those changes Delphi2 compiled the code.
But If I try to run the program, it breaks off in the RegisterDragDrop-function which is under the
FormCreate -event, and causes run-time error 210
that means: "Object not initialized". What to do?

- Rauno  -
0
 
LVL 4

Expert Comment

by:d003303
ID: 1337344
I still got a Delphi 2 installed somewhere, I'll port you the code. Hang on.

Slash/d003303
0
 
LVL 4

Expert Comment

by:d003303
ID: 1337345
hum, hum, hum. I re-designed the objects for D2 and it will not run properly. Bad, bad. I keep on diggin...
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1337346
d003303, If you keep digging, you'll end up in China :-).
0
 
LVL 4

Expert Comment

by:d003303
ID: 1337347
...or in New Zealand...
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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

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 The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

809 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