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.