Use OLE to drag and drop data between different programs

zhaozj2021-02-16  48

Use OLE to drag and drop data between different programs (OLE DRAG AND DROP)

Difficulty: ★★★ ☆☆

First knowledge: delphi / interface / Win32 / ole or com

Digging data from a program to another (typically drag text) is no new, many shared software support this feature (such as floating window features such as famous Flashget, Netants). The author always wants this feature in his own software. After a period of information search, some understanding, but most of these documents use C description. So, good things (not good, j) I don't dare to enjoy it. After organizing, I will write it out with Delphi's implementation method, and simply explain the OLE DRAG AND DROP mechanism.

The so-called OLE DRAG AND DROP can know what it means to be translated, it makes different programs (or the same program) interact by moving data with each other. In this regard, Windows has made a very complex work in this later. Fortunately, we don't have to worry about its complexity, Windows has provided us with two quite critical interfaces: idropsource, idroptarget, we only use these two The interface can easily implement OLE DRAG AND DROP, the former is implemented by the data source program that allows drag and dropping your data, and the latter is implemented by the data target program that allows reception of drag and drop data. In this article, we only discuss the latter, because we only want to receive data from other programs to drag and drop, and the former has been implemented by most programs (such as IE, Windows Help System, etc. If you want to know more about IDROPSOURCE See the Win32 SDK Help File).

Next we simply understand how Windows is dragged and dropped later, then we implement an example of the IDROPTARGET (regarding the API and formats in the program). Windows calls an important dodragdrop function in the background to detect interfaces and calls with our implementation, which is the step of working on this function:

• When we start to drag data to a form that can receive data, DoDragDrop first checks if the form under the mouse is registered as a form that can be received (registered via the RegisterDragDrop API, the function has two parameters, the first one For the handle of the form to register, the second is a object pointer to the class that implements the IDROPTARGET. In our form, it does not need to receive any dragged data to liberate the registration, it only has one parameter It is the form handle to be released. Another important point is to successfully call these functions. We must use Oleinitialize (NIL) at the end of the program to initialize Ole Library.)

• If the form can receive drag, DodragDrop adjusts the DrageNter method of the idropTarget interface. This method returns an effect Dweffect through a reference parameter, which can have different values ​​(decided by checking iDataObject), you can Find these values ​​in the help, which represents the operation of copying, shearing, etc. (referring to a program for IdropSource), and the specific you will see in the code below. The DodragDrop is then passed to idropsource by calling idropsource :: GiveFeedback.

· Next, DodragDROP calls the Dragover, Dragleave method such as the IDROPTARGET interface according to the status of the mouse, and the entire process is to implement the status of the mouse in the loop. If you change the drag target, it will detect new goals again. And repeat the above process, if you press and hold the other key at the same time on the keyboard, it will call IDROPSource :: queryContinueDrag and change the keyboard status code (you can detect the changed value by the GrfKeyState parameter in Dragenter, Dragovert, and Continue to repeat the above procedure after it works according to it. · When we finally release the mouse, DodragDrop will call the idroptarget's DROP method. It returns dweffect last time, and finally according to DWEFFECT we can get the data in iDataObject in this method, and complete the complete drag and drop operation. The following figure illustrates the process of dragging and drop:

So much above, in fact, Windows works for us in the background, we just know about this process, let's take an example to implement a MEMO that can be accepted, there is only one TMEMO, please Note in the code. Let's first see some necessary initialization and end operations that need to do when the program main window creates and undo:

Constructor TFORM1.CREATE (Aowner: Tcomponent);

Begin

Inherited Create (Aowner);

Oleinitialize (NIL);

DragandDropole: = tdraganddropole.create;

// TDRAGANDDROPOLE is a class we have to implement the IDROPTARGET interface

END;

DESTRUCTOR TFORM1.DESTROY;

Begin

DragandDropole.free;

OleunInitialize;

inherited;

END;

Let's take a look at the key TDragandDropole implementation. First, he should implement the iUnknown interface. This is a basic interface to implement a reference count. Friends who are familiar with COM should know this interface and its implementation method, only give it to implement it. The code does not make a detailed description, mainly pay attention to the iDropTarget implementation method:

The first is the declaration of TDRagandDropole:

Type

TDRAGANDDROPOLE = Class (TOBJECT, IUNKNOWN, IDROPTARGET)

Private

Candrop: hResult;

Fe: tFormatetc; // data format, in the implementation part gives a detailed description

FREFCOUNT: INTEGER; / / Reference Count

protected

{IUnkown}

Function _addref: integer; stdcall;

Function _Release: integer; stdcall;

Function QueryInterface (Const IID: Tguid; Out Obj): hResult; stdcall;

{IdropTarget}

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;

public

Constructor crete;

DESTRUCTOR DESTROY; OVERRIDE;

END;

Here is the implementation part, first initialize the part:

Constructor tdraganddropole.create;

Begin

FREFCOUNT: = 0;

Registerdragdrop (Form1.Memo1.Handle, Self); // The function mentioned above

END;

Destructor TdragandDropole.destroy;

Begin

Revokedragdrop (Form1.Memo1.Handle);

inherited;

END;

Next, IUNKNOWN, no more detailed description:

Function TDRAGANDDROPOLE._ADDREF: Integer;

Begin

Result: = interlockedDecrement (freecount);

IF result = 0 THEN DESTROY;

END;

Function TDRAGANDDROPOLE._RELEASE: Integer;

Begin

Result: = interlockedIncrement (freecount);

END;

Function TDRAGANDDROPOLE.QUERYINTERFACE (Const IID: Tguid;

Out obj): hResult;

Begin

IF GetInterface (IID, OBJ) THEN

Result: = S_OK

Else Result: = E_NOINTERFACE;

END;

The most important IDROPTARGET implementation:

Function TDRAGANDDROPOLE.DRAGENTER (Const DataObj);

GrfKeyState: Integer; PT: Tpoint; var DWEffect: integer: hResult;

Begin

Result: = E_FAIL;

Candrop: = E_FAIL;

IF assigned (dataobj) THEN

Begin

With Fe Do

Begin

CFFORMAT: = CF_Text;

PTD: = NIL;

Dwaspect: = dvaspect_content;

LINDEX: = - 1;

TYMED: = TYMED_HGLOBAL;

END;

// Everyone sees from above is a conversion format that we process timely use of memory data.

/ / Here it represents the data format as a text, and stores it into a piece

// Global memory area (TYMED: = TYMED_HGLOBAL), more formats please in Win32

// Search TFormatetc in Help

CANDROP: = DataObj.QuerygetData (Fe); / / Check data according to the format specified by Fe

Result: = CANDROP;

IF not failed (result) THEN

DWEFFECT: = DROPEFFECT_COPY

Else Dweffect: = dropeffect_none;

/ (Note that we set up DWEFFECT, more values, please see Win32 Help

END;

END;

Function TDRAGANDDROPOLE.DRAGLEAVE: HRESULT;

Begin

Result: = S_OK;

END;

Function TDRAGANDDROPOLE.DRAGOVER (GRFKEYSTATE: Integer; PT: Tpoint;

VAR DWEFFECT: Integer: HRESULT;

Begin

Result: = S_OK;

// We don't need to do the rest here, of course, you can complete your own method according to your needs.

END;

Function TDRAGANDDROPOLE.DROP (Const DataObj: iDataObject)

GrfKeyState: Integer; PT: Tpoint; var DWEffect: integer: hResult;

VAR

Medium: STGMEDIUM;

HDATA: HGLOBAL;

Begin

Result: = E_FAIL;

IF not failed (Candrop) THEN

Begin

Result: = DataObj.getdata (Fe, Medium);

/ / Put the data into a global area of ​​memory according to the FE format, pay attention to Medium

HDATA: = Hglobal (GlobalLock (Medium.hglobal);

// GLOBALLOCK locks this area and returns a pointer to it

Form1.Memo1.text: = pchar (hdata);

GlobalUnlock (HDATA); // Contact lock

GlobalFree (HDATA); // Release

END;

END;

Now we can test it. This article is only probably introduced to OLE DRAG AND DROP, as long as it is carefully studied, you can achieve more complex operations.

转载请注明原文地址:https://www.9cbs.com/read-27349.html

New Post(0)