查了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) 阅读(3030)
评论(4) 编辑 收藏 引用 所属分类:
C++