随笔-341  评论-2670  文章-0  trackbacks-0
    查了MSDN,发现Windows支持Drag and Drop的方法是四个COM:IEnumFORMATETC、IDataObject、IDropSource和IDropTarget。为了让自己做的一个代码编辑文本框里面的代码可以被拖出去拖进来,无奈之下只好实现了这四个东西。

    实现了之后,程序刚开始需要调用OldInitialize(NULL);,结束的时候调用OnUninitialize();,控件创建的时候调用RegisterDragDrop,控件结束的时候调用RevokeDragDrop。然后就可以通过这些COM来做Drag and Drop了。下面是接口的实现:

    头文件:
 1 /*******************************************************************************
 2 Vczh Library++ 2.0
 3 Vczh Coder::文本拖曳
 4 开发者:陈梓瀚
 5 
 6 接口:
 7 类:
 8   TextProvider                        :文本拖曳处理器
 9 函数:
10 *******************************************************************************/
11 #ifndef VCZHCODER_TEXTPROVIDER
12 #define VCZHCODER_TEXTPROVIDER
13 
14 #include <objidl.h>
15 #include "..\..\..\..\VL++\Library\Data\Data\VL_Data_String.h"
16 
17 using namespace vl;
18 
19 class TextProvider : public IEnumFORMATETC , public IDataObject , public IDropSource , public IDropTarget
20 {
21 protected:
22     VBool                FEnumeratorReaded;
23     FORMATETC            FAvailableFormat;
24     HGLOBAL                FGlobal;
25 
26     virtual VBool        OnDragDropGetData(VUnicodeString& String)=0;
27     virtual void        OnDragOver(VInt X , VInt Y)=0;
28     virtual void        OnDragEnter()=0;
29     virtual void        OnDragLeave()=0;
30     virtual void        OnDrop(VUnicodeString String , VInt X , VInt Y)=0;
31 public:
32     TextProvider();
33     ~TextProvider();
34 
35     VBool                Drag();
36 
37     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid , __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
38     ULONG STDMETHODCALLTYPE AddRef();
39     ULONG STDMETHODCALLTYPE Release();
40 
41     HRESULT STDMETHODCALLTYPE Next(ULONG celt , FORMATETC *rgelt , ULONG *pceltFetched);
42     HRESULT STDMETHODCALLTYPE Skip(ULONG celt);
43     HRESULT STDMETHODCALLTYPE Reset();
44     HRESULT STDMETHODCALLTYPE Clone(__RPC__deref_out_opt IEnumFORMATETC **ppenum);
45 
46     HRESULT STDMETHODCALLTYPE GetData(FORMATETC *pformatetcIn ,STGMEDIUM *pmedium);
47     HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC *pformatetc , STGMEDIUM *pmedium);
48     HRESULT STDMETHODCALLTYPE QueryGetData(__RPC__in_opt FORMATETC *pformatetc);
49     HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(__RPC__in_opt FORMATETC *pformatectIn , __RPC__out FORMATETC *pformatetcOut);
50     HRESULT STDMETHODCALLTYPE SetData(FORMATETC *pformatetc , STGMEDIUM *pmedium , BOOL fRelease);
51     HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection , __RPC__deref_out_opt IEnumFORMATETC **ppenumFormatEtc);
52     HRESULT STDMETHODCALLTYPE DAdvise(__RPC__in FORMATETC *pformatetc , DWORD advf , __RPC__in_opt IAdviseSink *pAdvSink , __RPC__out DWORD *pdwConnection);
53     HRESULT STDMETHODCALLTYPE DUnadvise(DWORD dwConnection);
54     HRESULT STDMETHODCALLTYPE EnumDAdvise(__RPC__deref_out_opt IEnumSTATDATA **ppenumAdvise);
55 
56     HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed , DWORD grfKeyState);
57     HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
58     
59     HRESULT STDMETHODCALLTYPE DragEnter(__RPC__in_opt IDataObject *pDataObj , DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect);
60     HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect);
61     HRESULT STDMETHODCALLTYPE DragLeave();
62     HRESULT STDMETHODCALLTYPE Drop(__RPC__in_opt IDataObject *pDataObj , DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect);
63 };
64 
65 #endif

    代码文件:
  1 #include <windows.h>
  2 #include "TextProvider.h"
  3 #include "..\..\..\..\VL++\Library\Windows\VL_WinMain.h"
  4 
  5 using namespace vl::windows;
  6 
  7 TextProvider::TextProvider()
  8 {
  9     FEnumeratorReaded=false;
 10     FAvailableFormat.cfFormat=CF_TEXT;
 11     FAvailableFormat.ptd=0;
 12     FAvailableFormat.dwAspect=DVASPECT_ICON;
 13     FAvailableFormat.lindex=-1;
 14     FAvailableFormat.tymed=TYMED_HGLOBAL;
 15     FGlobal=0;
 16 }
 17 
 18 TextProvider::~TextProvider()
 19 {
 20 }
 21 
 22 VBool TextProvider::Drag()
 23 {
 24     VUnicodeString String;
 25     if(!OnDragDropGetData(String))
 26     {
 27         return false;
 28     }
 29 
 30     FGlobal=GlobalAlloc(GMEM_FIXED,(String.Length()+1)*sizeof(VWChar));
 31     VMbcsString Mbcs=ToMbcs(String);
 32     memcpy((VPointer)FGlobal,Mbcs.Buffer(),Mbcs.Length()+1);
 33 
 34     DWORD Effect=DROPEFFECT_MOVE|DROPEFFECT_COPY;
 35     DWORD Result=0;
 36     if(DoDragDrop(this,this,Effect,&Result)==DRAGDROP_S_DROP)
 37     {
 38         switch(Result)
 39         {
 40         case DROPEFFECT_MOVE:
 41             return true;
 42         case DROPEFFECT_COPY:
 43             return false;
 44         default:
 45             if(FGlobal)
 46             {
 47                 GlobalFree(FGlobal);
 48                 FGlobal=0;
 49             }
 50             return false;
 51         }
 52     }
 53     else
 54     {
 55         if(FGlobal)
 56         {
 57             GlobalFree(FGlobal);
 58             FGlobal=0;
 59         }
 60         return false;
 61     }
 62 }
 63 
 64 HRESULT STDMETHODCALLTYPE TextProvider::QueryInterface(REFIID riid , __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
 65 {
 66     if(riid==IID_IUnknown)
 67     {
 68         *ppvObject=static_cast<IUnknown*>(static_cast<IDataObject*>(this));
 69     }
 70     else if(riid==IID_IEnumFORMATETC)
 71     {
 72         IEnumFORMATETC* Object=this;
 73         *ppvObject=Object;
 74     }
 75     else if(riid==IID_IDataObject)
 76     {
 77         IDataObject* Object=this;
 78         *ppvObject=Object;
 79     }
 80     else if(riid==IID_IDropSource)
 81     {
 82         IDropSource* Object=this;
 83         *ppvObject=Object;
 84     }
 85     else if(riid==IID_IDropTarget)
 86     {
 87         IDropTarget* Object=this;
 88         *ppvObject=Object;
 89     }
 90     else
 91     {
 92         *ppvObject=NULL;
 93         return E_NOINTERFACE;
 94     }
 95     return S_OK;
 96 }
 97 
 98 ULONG STDMETHODCALLTYPE TextProvider::AddRef()
 99 {
100     return 1;
101 }
102 
103 ULONG STDMETHODCALLTYPE TextProvider::Release()
104 {
105     return 1;
106 }
107 
108 HRESULT STDMETHODCALLTYPE TextProvider::Next(ULONG celt , FORMATETC *rgelt , ULONG *pceltFetched)
109 {
110     if(FEnumeratorReaded)
111     {
112         if(pceltFetched)
113         {
114             *pceltFetched=0;
115         }
116         return S_FALSE;
117     }
118     else
119     {
120         FEnumeratorReaded=true;
121         if(celt)
122         {
123             if(pceltFetched)
124             {
125                 *pceltFetched=1;
126             }
127             if(rgelt)
128             {
129                 *rgelt=FAvailableFormat;
130             }
131         }
132         return celt==1?S_OK:S_FALSE;
133     }
134 }
135 
136 HRESULT STDMETHODCALLTYPE TextProvider::Skip(ULONG celt)
137 {
138     return S_FALSE;
139 }
140 
141 HRESULT STDMETHODCALLTYPE TextProvider::Reset()
142 {
143     FEnumeratorReaded=false;
144     return S_OK;
145 }
146 
147 HRESULT STDMETHODCALLTYPE TextProvider::Clone(__RPC__deref_out_opt IEnumFORMATETC **ppenum)
148 {
149     *ppenum=static_cast<IEnumFORMATETC*>(this);
150     return S_OK;
151 }
152 
153 HRESULT STDMETHODCALLTYPE TextProvider::GetData(FORMATETC *pformatetcIn ,STGMEDIUM *pmedium)
154 {
155     if(pformatetcIn->cfFormat!=CF_TEXT || pformatetcIn->tymed!=TYMED_HGLOBAL)
156     {
157         return DV_E_FORMATETC;
158     }
159     pmedium->tymed=TYMED_HGLOBAL;
160     pmedium->hGlobal=FGlobal;
161     pmedium->pUnkForRelease=NULL;
162     FGlobal=0;
163     return S_OK;
164 }
165 
166 HRESULT STDMETHODCALLTYPE TextProvider::GetDataHere(FORMATETC *pformatetc , STGMEDIUM *pmedium)
167 {
168     return DV_E_TYMED;
169 }
170 
171 HRESULT STDMETHODCALLTYPE TextProvider::QueryGetData(__RPC__in_opt FORMATETC *pformatetc)
172 {
173     if(pformatetc->cfFormat!=CF_TEXT || pformatetc->tymed!=TYMED_HGLOBAL)
174     {
175         return DV_E_FORMATETC;
176     }
177     else
178     {
179         return S_OK;
180     }
181 }
182 
183 HRESULT STDMETHODCALLTYPE TextProvider::GetCanonicalFormatEtc(__RPC__in_opt FORMATETC *pformatectIn , __RPC__out FORMATETC *pformatetcOut)
184 {
185     *pformatetcOut=FAvailableFormat;
186     return DATA_S_SAMEFORMATETC;
187 }
188 
189 HRESULT STDMETHODCALLTYPE TextProvider::SetData(FORMATETC *pformatetc , STGMEDIUM *pmedium , BOOL fRelease)
190 {
191     return E_NOTIMPL;
192 }
193 
194 HRESULT STDMETHODCALLTYPE TextProvider::EnumFormatEtc(DWORD dwDirection , __RPC__deref_out_opt IEnumFORMATETC **ppenumFormatEtc)
195 {
196     Reset();
197     *ppenumFormatEtc=static_cast<IEnumFORMATETC*>(this);
198     return S_OK;
199 }
200 
201 HRESULT STDMETHODCALLTYPE TextProvider::DAdvise(__RPC__in FORMATETC *pformatetc , DWORD advf , __RPC__in_opt IAdviseSink *pAdvSink , __RPC__out DWORD *pdwConnection)
202 {
203     return OLE_E_ADVISENOTSUPPORTED;
204 }
205 
206 HRESULT STDMETHODCALLTYPE TextProvider::DUnadvise(DWORD dwConnection)
207 {
208     return OLE_E_ADVISENOTSUPPORTED;
209 }
210 
211 HRESULT STDMETHODCALLTYPE TextProvider::EnumDAdvise(__RPC__deref_out_opt IEnumSTATDATA **ppenumAdvise)
212 {
213     return OLE_E_ADVISENOTSUPPORTED;
214 }
215 
216 HRESULT STDMETHODCALLTYPE TextProvider::QueryContinueDrag(BOOL fEscapePressed , DWORD grfKeyState)
217 {
218     if(fEscapePressed==TRUE)
219     {
220         return DRAGDROP_S_CANCEL;
221     }
222     else if(grfKeyState&MK_LBUTTON)
223     {
224         return S_OK;
225     }
226     else
227     {
228         return DRAGDROP_S_DROP;
229     }
230 }
231 
232 HRESULT STDMETHODCALLTYPE TextProvider::GiveFeedback(DWORD dwEffect)
233 {
234     return DRAGDROP_S_USEDEFAULTCURSORS;
235 }
236 
237 HRESULT STDMETHODCALLTYPE TextProvider::DragEnter(__RPC__in_opt IDataObject *pDataObj , DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect)
238 {
239     IEnumFORMATETC* Enumerator=0;
240     VBool Found=false;
241     if(pDataObj->EnumFormatEtc(DATADIR_GET,&Enumerator)!=S_OK)return E_UNEXPECTED;
242     FORMATETC Format;
243     ULONG Fetched=0;
244     while(true)
245     {
246         Enumerator->Next(1,&Format,&Fetched);
247         if(Fetched==0)
248         {
249             break;
250         }
251         if(Format.cfFormat==CF_TEXT && Format.tymed==TYMED_HGLOBAL)
252         {
253             if(pDataObj->QueryGetData(&Format)==S_OK)
254             {
255                 Found=true;
256             }
257         }
258     }
259     Enumerator->Release();
260     if(Found)
261     {
262         *pdwEffect=grfKeyState&MK_CONTROL?DROPEFFECT_COPY:DROPEFFECT_MOVE;
263         OnDragEnter();
264     }
265     else
266     {
267         *pdwEffect=DROPEFFECT_NONE;
268     }
269     return S_OK;
270 }
271 
272 HRESULT STDMETHODCALLTYPE TextProvider::DragOver(DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect)
273 {
274     if(*pdwEffect&DROPEFFECT_COPY || *pdwEffect&DROPEFFECT_MOVE)
275     {
276         *pdwEffect=grfKeyState&MK_CONTROL?DROPEFFECT_COPY:DROPEFFECT_MOVE;
277         OnDragOver(pt.x,pt.y);
278     }
279     else
280     {
281         *pdwEffect=DROPEFFECT_NONE;
282     }
283     return S_OK;
284 }
285 
286 HRESULT STDMETHODCALLTYPE TextProvider::DragLeave()
287 {
288     OnDragLeave();
289     return S_OK;
290 }
291 
292 HRESULT STDMETHODCALLTYPE TextProvider::Drop(__RPC__in_opt IDataObject *pDataObj , DWORD grfKeyState , POINTL pt , __RPC__inout DWORD *pdwEffect)
293 {
294     STGMEDIUM Medium;
295     if(!pDataObj->GetData(&FAvailableFormat,&Medium)==S_OK)
296     {
297         ShowMessage(GetApplication()->GetMainForm(),L"拖放源不支持将数据转换成字符串,拖放失败。",GetApplication()->GetMainForm()->GetText());
298         return E_UNEXPECTED;
299     }
300     if(Medium.tymed!=TYMED_HGLOBAL)
301     {
302         ReleaseStgMedium(&Medium);
303         ShowMessage(GetApplication()->GetMainForm(),L"拖放源不支持将数据使用HGLOBAL传送,拖放失败。",GetApplication()->GetMainForm()->GetText());
304         return E_UNEXPECTED;
305     }
306     PCChar Buffer=(PCChar)GlobalLock(Medium.hGlobal);
307     VUnicodeString String=ToUnicode(Buffer);
308     GlobalUnlock(Medium.hGlobal);
309     ReleaseStgMedium(&Medium);
310     OnDrop(String,pt.x,pt.y);
311     *pdwEffect=grfKeyState&MK_CONTROL?DROPEFFECT_COPY:DROPEFFECT_MOVE;
312     return S_OK;
313 }

    写了一整天。
posted on 2009-05-29 21:17 陈梓瀚(vczh) 阅读(2963) 评论(4)  编辑 收藏 引用 所属分类: C++

评论:
# re: 使用COM实现控件内容的Drag and Drop 2009-05-29 22:36 | 沈臻豪(foxtail)
做了什么东东啊 截图秀秀  回复  更多评论
  
# re: 使用COM实现控件内容的Drag and Drop 2009-05-30 17:00 | 东方CJ
收藏一下,正需要这个  回复  更多评论
  
# re: 使用COM实现控件内容的Drag and Drop 2009-06-03 20:42 | SOS
罕见的发现你写了个具体技术的日志,另外OldInitialize是啥--,旧式初始化>_<  回复  更多评论
  
# re: 使用COM实现控件内容的Drag and Drop 2009-06-04 19:02 | 飘飘白云
@SOS

楼主笔误了,应是:

OleInitialize()
OleUninitialize()
  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理