⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 0,1410,26545,00.html

📁 C++builder学习资料C++builder
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<HTML>



<HEAD>



<TITLE>Using COM to Accept Interprocess Drag and Drop operations</TITLE>



</HEAD>

<BODY>



<A NAME="top"></A>

<table>

<TR>

   <td>

<P>

<SPAN CLASS="title3">Using COM to Accept Interprocess Drag and Drop operations</SPAN> 

 

		- by Borland Developer Support Staff 

<BLOCKQUOTE CLASS="abstract"> 

  <p><B>Abstract:</B>This article describes how to implement an OLE Drop Target.</p> 

    </BLOCKQUOTE> 

  </table> 

<a name="top"></a> 

<table width="100%" border=0 cellpadding=5 cellspacing=0> 

<tr><td  valign=center align=middle> 

<font face="Arial Black">

Accepting Drag and Drop Operations from Other Processes</font></td></tr> 

<tr><td align=left><br> 

 <table cellpadding="0" cellspacing="0" border="1"> 

<tr><td align=middle>Table Of Contents</td></tr> 

<tr><td><A style="text-decoration: none;" href="#objective" onMouseover="window.status='Objective';return true" onMouseOut="window.status='';return true;">Objective</a></td></tr> 

<tr><td><A style="text-decoration: none;" href="#ovr" onMouseover="window.status='Overview';return true" onMouseOut="window.status='';return true;">Overview/Diagram</a></td></tr> 

<tr><td><A style="text-decoration: none;" href="#exp" onMouseover="window.status='Explanation';return true" onMouseOut="window.status='';return true;">Explanation</a></td></tr> 

<tr><td><A style="text-decoration: none;" href="#code" onMouseover="window.status='Code';return true" onMouseOut="window.status='';return true;">Code</a></td></tr> 

</table><br> 

 

</td></tr> 

 

<tr><td align = left> 

<a name="objective"></a><A class=loginLink href="#top"><font face="Arial">Objective</font></a> 

</td></tr> 

 

<tr><td> 

<p> 

<big>I</big>n this article, I will seek to explain how to make your application accept files dropped from other 

processes. For this document, I assume you have some knowledge of the following concepts: 

<ul> 

<li>C++Builder</li> 

<li>COM/OLE</li> 

<li>Win32 API</li> 

</ul> 

</p> 

</td></tr> 

 

<tr><td align = left> 

<a name="ovr"></a><A class=loginLink href="#top"><font face="Arial">Overview and Diagrams</font></a>  

</td></tr>  

  

<tr><td>  

  

<p><big>D</big>rag and drop operations are one of the core features of Win32 "user-friendliness."   

Dragging and dropping objects, files, icons, and other things makes an application easy to use and visually  

pleasing. One particularly powerful feature of Win32 drag and drop is to be able to drag items between programs,  

i.e. dragging a picture out of IE onto your form.</p>  

<p>Inter-process drag-and-drop is accomplished by implementing certain COM interfaces depending on what services  

your application requires. In order to for the user to be able to drag objects off your application, you must  

implement <code>IDropSource</code>. To accept files, implement <code>IDropTarget</code>. In this article, I will  

focus mainly on the use and implementation of <code>IDropTarget</code>, but in order to provide better understanding,  

I will explain in brief the operation of <code>IDropSource</code>.</p>  

  

<p>Here is an overview diagram of what occurs during an inter-process drag and drop operation:<br>  

<img src="images/dragdrop.jpg" width="520" height="367"></p>  

  

<p>As you can see, the "Server" (the drag source) provides an <code>IDropSource</code> interface to the system.  

The system also gets the data from the server wrapped in an <code>IDataObject</code> interface. When the user  

drags the mouse over the drop target, the system calls methods on both target and source interfaces to execute the  

transfer of data.</p>  

  

<p>For the purposes of this article, we really only need to concern ourselves with <code>IDropTarget</code>. Here  

are the methods of <code>IDropTarget</code> (in vtable order) which we will have to implement to allow drops in   

our application:<br><br>  

<table width=80% align=center border=1 cellpadding=3 cellspacing=0>  

<tr bgcolor=#cfcfcf><th><b>Method</b></th><th><b>Description</b></th></tr>  

<tr><td><code>QueryInterface</code></td><td>Return supported interfaces (in this case, <code>IDropTarget</code> and  

<code>IUnknown</code>).</td></tr>  

<tr><td><code>AddRef</code></td><td>Increment reference count.</td></tr>  

<tr><td><code>Release</code></td><td>Decrement reference count.</td></tr>  

</table><br>  

<table width=80% align=center border=1 cellpadding=3 cellspacing=0>  

<tr bgcolor=#cfcfcf><th><b>Method</b></th><th><b>Description</b></th></tr>  

<tr><td><code>DragEnter</code></td><td>Called when the drag operation <b>enters</b> the drop target area.</td></tr>  

<tr><td><code>DragOver</code></td><td>Called when the drag operation <b>moves</b> over the target area.</td></tr>  

<tr><td><code>DragLeave</code></td><td>Called when the drag operation <b>leaves</b> the target area.</td></tr>  

<tr><td><code>Drop</code></td><td>Called when an object is <b>dropped</b> on the target area.</td></tr>  

</table>  

  

<p>These are the methods we have to implement to make our application an available drop target, but we're not completely  

finished yet. There is one more thing we must do. We have to use the <code>RegisterDragDrop</code> and  

<code>RevokeDragDrop</code> functions to let the system know we're ready to accept drops. It remains  

up to our implementation to determine what kind of objects we allow.</p>  

  

</td></tr>  

  

<tr><td align = left>  

<a name="exp"></a><A class=loginLink href="#top"><font face="Arial">Explanation</font></a> 

</td></tr> 

 

<tr><td> 

<p> 

<big>L</big>et's jump into implementing our drop target. We will implement this as a component that can be dropped 

on a form and attached to any visual control. Here are our first two classes: <code>TDropTargetImpl</code> and 

<code>TGenericVCLDropTarget</code>. <code>TDropTargetImpl</code> is pretty simple, all it does is call back to the  

<code>TGenericVCLDropTarget</code> that owns it, so any drop target implementation can deal with it however it wants 

(i.e text droptarget, bitmap droptarget, etc.). TDropTargetImpl will implement <code>QueryInterface, AddRef</code>, and 

<code>Release</code>, but nothing else. <code>TGenericDropTarget</code> will be pretty much abstract as well. It will 

contain a property of type <code>TWinControl</code> that we'll use as our target to register with the system. 

</p> 

<p> 

The class that does the real work for our example is <code>TTextDropTarget</code>. This class will derive from 

<code>TGenericVCLDropTarget</code> and will contain the necessary functions for getting the drop. 

Most of the code is pretty self-explanatory. I will focus on the two methods that are really important to us. 

The first is the DragEnter method. This is where we determine if we want to allow the drop or not.<br> 

<br> 

<table border=1 bgcolor=#cfcfcf cellpadding=3 cellspacing=0> 

<tr><td> 

<pre><code>HRESULT <b>__stdcall</b> TTextDropTarget::DragEnter(IDataObject *pDataObject,

                      DWORD grfKeyState, _POINTL pt, DWORD *pdwEffect)

{

  FORMATETC fe;

  setFE(fe,CF_TEXT,TYMED_HGLOBAL); <font color="#0000AA"><i>// fill in structure for text</i></font>

  HRESULT hres = pDataObject-&gt;QueryGetData(&amp;fe); <font color="#0000AA"><i>//do we like what this dataobject has?</i></font>

  <b>if</b> (SUCCEEDED(hres) &amp;&amp; FOnDragEnter)

  {

    <font color="#0000AA"><i>/*the QueryGetData method returns an HRESULT

    depending on whether or not we could

    actually get the data if we tried. If we

    return a failing HRESULT here, the droptarget

    will not allow the drop*/</i></font>

    <font color="#0000AA"><i>//here's where we determine the keystates, etc. for the event</i></font>

    TShiftState ss;

    ss.Clear();

    <b>if</b> (grfKeyState &amp; MK_CONTROL)

      ss = ss &lt;&lt; ssCtrl;

    <b>if</b> (grfKeyState &amp; MK_ALT)

      ss = ss &lt;&lt; ssAlt;

    <b>if</b> (grfKeyState &amp; MK_SHIFT)

      ss = ss &lt;&lt; ssShift;

    <b>if</b> (grfKeyState &amp; MK_LBUTTON)

      ss = ss &lt;&lt; ssLeft;

    <b>if</b> (grfKeyState &amp; MK_MBUTTON)

      ss = ss &lt;&lt; ssMiddle;

    <b>if</b> (grfKeyState &amp; MK_RBUTTON)

      ss = ss &lt;&lt; ssRight;

    FOnDragEnter(TargetControl,pt.x,pt.y,ss);

  }

  <b>return</b> hres;

}</code></pre> 

</td></tr> 

</table><br> 

 

The crucial line is the QueryGetData call. This basically makes or breaks the drag and drop operation. Our drop  

target will only allow the drop if DragEnter returns S_OK. Notice also the setFE call. This is just a macro I wrote  

that makes it easy to fill in FORMATETC structure. This is the same kind of thing as when dealing with clipboard data.  

For debugging purposes, or if you want to make a certain kind of drop target but don't know what type(s) to accept,  

here is a code snippet that shows you how to enumerate the incoming FORMATETC types. (This would be put under DragEnter).<br><br>  

<table border=1 bgcolor=#cfcfcf cellpadding=3 cellspacing=0>  

<tr><td>  

<pre><code>

IEnumFORMATETC *pefe;

FORMATETC fe;



pDataObject-&gt;EnumFormatEtc(DATADIR_GET,&amp;pefe);

<b>unsigned</b> <b>long</b> fetch;

<b>do</b> {

  pefe-&gt;Next(1,&amp;fe,&amp;fetch);

  <font color="#0000AA"><i>//do stuff with fe</i></font>

} <b>while</b> (fetch);

pefe-&gt;Release();

</code></pre>  

</td></tr>  

</table>  

<p>Next is the <code>Drop</code> method. This is where we actually pull the data over and give it to our  

application. In this case, I just use an event called OnDrop that gets an AnsiString containing the text.<br><br>  

<table border=1 bgcolor=#cfcfcf cellpadding=3 cellspacing=0>  

<tr><td>  

<pre><code>

HRESULT <b>__stdcall</b> TTextDropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState,

                    _POINTL pt, DWORD *pdwEffect)

{

  <font color="#0000AA"><i>//here's where we do all the stuff that's important.</i></font>

  <b>if</b> (FOnDrop)

  {

    FORMATETC fe;

    STGMEDIUM stg;

    HRESULT hres;

    String dropstr;

    setFE(fe,CF_TEXT,TYMED_HGLOBAL);

    hres = pDataObject-&gt;GetData(&amp;fe,&amp;stg);

    <font color="#0000AA"><i>//GetData returns us data in a storage medium structure.</i></font>

    <b>if</b> (SUCCEEDED(hres))

    {

      dropstr = String((<b>char</b> *)GlobalLock(stg.hGlobal),GlobalSize(stg.hGlobal));

      GlobalUnlock(stg.hGlobal);

      ReleaseStgMedium(&amp;stg);

      TShiftState ss;

      ss.Clear();

      <b>if</b> (grfKeyState &amp; MK_CONTROL)

        ss = ss &lt;&lt; ssCtrl;

      <b>if</b> (grfKeyState &amp; MK_ALT)

        ss = ss &lt;&lt; ssAlt;

      <b>if</b> (grfKeyState &amp; MK_SHIFT)

        ss = ss &lt;&lt; ssShift;

      <b>if</b> (grfKeyState &amp; MK_LBUTTON)

        ss = ss &lt;&lt; ssLeft;

      <b>if</b> (grfKeyState &amp; MK_MBUTTON)

        ss = ss &lt;&lt; ssMiddle;

      <b>if</b> (grfKeyState &amp; MK_RBUTTON)

        ss = ss &lt;&lt; ssRight;

      FOnDrop(TargetControl,pt.x,pt.y,ss,dropstr);

    }

    <b>return</b> hres;

  }

  <b>else</b> <b>return</b> S_OK;

}



</code></pre>  

</td></tr>  

</table>  

<p>This should be pretty straight-forward. We call GetData and fill a STGMEDIUM. We then fill the AnsiString  

from the global memory block contained in the STGMEDIUM, and release the STGMEDIUM.</p>  

<p>This is really all there is to it. If you wanted to make a drop target that accepted images, you would  

really only have to adjust DragEnter and Drop to deal with the format type. Enjoy.</p>  

</td></tr>  

  

<tr><td align = left>  

<a name="code"></a><A class=loginLink href="#top"><font face="Arial">Code</font></a> 

</td></tr> 

 

<tr><td> 

<p>Here is the complete code for the TTExtDropTarget component.</p> 

<p><table border=1 width=90% cellpadding=3 cellspacing=0> 

<tr bgcolor=blue><td><font color=white>GenericVCLDropTarget.h</font></td></tr> 

<tr><td> 

<pre><code>

<font color="#0000AA"><i>//---------------------------------------------------------------------------</i></font>



<font color="202020">#ifndef GenericVCLDropTargetH</font>

<font color="202020">#define GenericVCLDropTargetH</font>

<font color="#0000AA"><i>//---------------------------------------------------------------------------</i></font>

<font color="202020">#include &lt;SysUtils.hpp&gt;</font>

<font color="202020">#include &lt;Controls.hpp&gt;</font>

<font color="202020">#include &lt;Classes.hpp&gt;</font>

<font color="202020">#include &lt;Forms.hpp&gt;</font>

<font color="202020">#include &lt;oleidl.h&gt;</font>

<font color="#0000AA"><i>//---------------------------------------------------------------------------</i></font>

<font color="#0000AA"><i>//this macro makes filling in a FORMATETC structure easy</i></font>

<font color="202020">#define setFE(fe, cf, med)  </font>

   ((fe).cfFormat=cf, 

    (fe).dwAspect=DVASPECT_CONTENT, 

    (fe).ptd=NULL, 

    (fe).tymed=med, 

    (fe).lindex=-1)



<b>class</b> PACKAGE TGenericVCLDropTarget : <b>public</b> TComponent

{

  <b>friend</b> <b>class</b> TDropTargetImpl;

<b>private</b>:

  TDropTargetImpl *m_dt;

  TWinControl *m_DropTarget;

  <b>bool</b> registered;

<b>protected</b>:

  <b>void</b> <b>__fastcall</b> SetDropTarget(TWinControl *target);

  <b>virtual</b> HRESULT <b>__stdcall</b> DragEnter(IDataObject *pDataObject,

                      DWORD grfKeyState, _POINTL pt, DWORD *pdwEffect)=0;

  <b>virtual</b> HRESULT <b>__stdcall</b> DragOver(DWORD grfKeyState, _POINTL pt,

                      DWORD *pdwEffect)=0;

  <b>virtual</b> HRESULT <b>__stdcall</b> DragLeave()=0;

  <b>virtual</b> HRESULT <b>__stdcall</b> Drop(IDataObject *pDataObject, DWORD grfKeyState,

                      _POINTL pt, DWORD *pdwEffect)=0;

  <b>__property</b> TWinControl *TargetControl = {read=m_DropTarget, write=SetDropTarget};

  <b>__property</b> <b>bool</b> Registered = {read=registered};

<b>public</b>:

  <b>__fastcall</b> TGenericVCLDropTarget(TComponent* Owner);

  <b>__fastcall</b> ~TGenericVCLDropTarget();

<b>__published</b>:

};



<b>class</b> TDropTargetImpl : <b>public</b> IDropTarget

{

<b>private</b>:

  ULONG ref_count;

  TGenericVCLDropTarget *backptr;

<b>public</b>:

  TDropTargetImpl(TGenericVCLDropTarget *obj) { ref_count=0; backptr=obj; }

  HRESULT <b>__stdcall</b> QueryInterface(REFIID riid, <b>void</b> **ppv);

  ULONG <b>__stdcall</b> AddRef() { InterlockedIncrement((<b>long</b> *)&amp;ref_count); <b>return</b> ref_count; }

  ULONG <b>__stdcall</b> Release() { <b>if</b> (InterlockedDecrement((<b>long</b> *)&amp;ref_count) &lt;= 0)

                                  <b>delete</b> <b>this</b>;

                              <b>return</b> ref_count; }

  HRESULT <b>__stdcall</b> DragEnter(IDataObject *pDataObject,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -