使用COM实现控件内容的Drag and Drop

使用COM实现控件内容的Drag and Drop
    查了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  }

    写了一整天。

你可能感兴趣的:(使用COM实现控件内容的Drag and Drop)