1 #include "CtrlCore.h"
2 
3 #ifdef GUI_WIN
4 
5 namespace Upp {
6 
7 #ifdef COMPILER_CLANG
8 #define CLANG_NOTHROW __attribute__((nothrow))
9 #else
10 #define CLANG_NOTHROW
11 #endif
12 
13 
14 #define LLOG(x)  // DLOG(x)
15 
16 int  GetClipboardFormatCode(const char *format_id);
17 
ToWin32CF(const char * s)18 int ToWin32CF(const char *s)
19 {
20 	return GetClipboardFormatCode(s);
21 }
22 
FromWin32CF(int cf)23 String FromWin32CF(int cf)
24 {
25 	GuiLock __;
26 	if(cf == CF_TEXT)
27 		return "text";
28 	if(cf == CF_UNICODETEXT)
29 		return "wtext";
30 	if(cf == CF_DIB)
31 		return "dib";
32 #ifndef PLATFORM_WINCE
33 	if(cf == CF_HDROP)
34 		return "files";
35 #endif
36 	char h[256];
37 	GetClipboardFormatNameA(cf, h, 255);
38 	return h;
39 }
40 
ToFORMATETC(const char * s)41 FORMATETC ToFORMATETC(const char *s)
42 {
43 	FORMATETC fmtetc;
44 	fmtetc.cfFormat = ToWin32CF(s);
45 	fmtetc.dwAspect = DVASPECT_CONTENT;
46 	fmtetc.lindex = -1;
47 	fmtetc.ptd = NULL;
48 	fmtetc.tymed = TYMED_HGLOBAL;
49 	return fmtetc;
50 }
51 
AsString(POINTL p)52 String AsString(POINTL p)
53 {
54 	return String().Cat() << "[" << p.x << ", " << p.y << "]";
55 }
56 
57 struct UDropTarget : public IDropTarget {
58 	ULONG         rc;
59 	LPDATAOBJECT  data;
60 	Ptr<Ctrl>     ctrl;
61 	Index<String> fmt;
62 
63 	STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
STDMETHOD_Upp::UDropTarget64 	STDMETHOD_(ULONG, AddRef)(void)  { return ++rc; }
STDMETHOD_Upp::UDropTarget65 	STDMETHOD_(ULONG, Release)(void) { if(--rc == 0) { delete this; return 0; } return rc; }
66 
67 	STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
68 	STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
69 	STDMETHOD(DragLeave)();
70 	STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);
71 
72 	void DnD(POINTL p, bool drop, DWORD *effect, DWORD keys);
73 	void FreeData();
74 	void Repeat();
75 	void EndDrag();
76 	String Get(const char *fmt) const;
77 
UDropTargetUpp::UDropTarget78 	UDropTarget() { rc = 1; data = NULL; }
79 	~UDropTarget();
80 };
81 
Has(UDropTarget * dt,const char * fmt)82 bool Has(UDropTarget *dt, const char *fmt)
83 {
84 	return dt->fmt.Find(fmt) >= 0;
85 }
86 
Get(UDropTarget * dt,const char * fmt)87 String Get(UDropTarget *dt, const char *fmt)
88 {
89 	return dt->Get(fmt);
90 }
91 
QueryInterface(REFIID iid,void ** ppv)92 STDMETHODIMP CLANG_NOTHROW UDropTarget::QueryInterface(REFIID iid, void ** ppv)
93 {
94 	if(iid == IID_IUnknown || iid == IID_IDropTarget) {
95 		*ppv = this;
96 		AddRef();
97 		return S_OK;
98 	}
99 	*ppv = NULL;
100 	return E_NOINTERFACE;
101 }
102 
Get(const char * fmt) const103 String UDropTarget::Get(const char *fmt) const
104 {
105 	FORMATETC fmtetc = ToFORMATETC(fmt);
106 	STGMEDIUM s;
107 	if(data->GetData(&fmtetc, &s) == S_OK && s.tymed == TYMED_HGLOBAL) {
108 		char *val = (char *)GlobalLock(s.hGlobal);
109 		String data(val, (int)GlobalSize(s.hGlobal));
110 		GlobalUnlock(s.hGlobal);
111 		ReleaseStgMedium(&s);
112 		return data;
113     }
114 	return Null;
115 }
116 
DnD(POINTL pl,bool drop,DWORD * effect,DWORD keys)117 void UDropTarget::DnD(POINTL pl, bool drop, DWORD *effect, DWORD keys)
118 {
119 	GuiLock __;
120 	LLOG("DnD effect: " << *effect);
121 	dword e = *effect;
122 	*effect = DROPEFFECT_NONE;
123 	if(!ctrl)
124 		return;
125 	PasteClip d;
126 	d.dt = this;
127 	d.paste = drop;
128 	d.accepted = false;
129 	d.allowed = 0;
130 	d.action = 0;
131 	if(e & DROPEFFECT_COPY) {
132 		LLOG("DnD DROPEFFECT_COPY");
133 		d.allowed = DND_COPY;
134 		d.action = DND_COPY;
135 	}
136 	if(e & DROPEFFECT_MOVE) {
137 		LLOG("DnD DROPEFFECT_MOVE");
138 		d.allowed |= DND_MOVE;
139 		if(Ctrl::GetDragAndDropSource())
140 			d.action = DND_MOVE;
141 	}
142 	LLOG("DnD keys & MK_CONTROL:" << (keys & MK_CONTROL));
143 	if((keys & MK_CONTROL) && (d.allowed & DND_COPY))
144 		d.action = DND_COPY;
145 	if((keys & (MK_ALT|MK_SHIFT)) && (d.allowed & DND_MOVE))
146 		d.action = DND_MOVE;
147 	ctrl->DnD(Point(pl.x, pl.y), d);
148 	if(d.IsAccepted()) {
149 		LLOG("DnD accepted, action: " << (int)d.action);
150 		if(d.action == DND_MOVE)
151 			*effect = DROPEFFECT_MOVE;
152 		if(d.action == DND_COPY)
153 			*effect = DROPEFFECT_COPY;
154 	}
155 }
156 
Repeat()157 void UDropTarget::Repeat()
158 {
159 	Ctrl::DnDRepeat();
160 }
161 
DragEnter(LPDATAOBJECT pDataObj,DWORD grfKeyState,POINTL pt,LPDWORD pdwEffect)162 STDMETHODIMP CLANG_NOTHROW UDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
163 {
164 	GuiLock __;
165 	LLOG("DragEnter " << pt);
166 	data = pDataObj;
167 	data->AddRef();
168 	fmt.Clear();
169 	IEnumFORMATETC *fe;
170 	if(!ctrl || pDataObj->EnumFormatEtc(DATADIR_GET, &fe) != NOERROR) {
171 		*pdwEffect = DROPEFFECT_NONE;
172 		return NOERROR;
173 	}
174 	FORMATETC fmtetc;
175 	while(fe->Next(1, &fmtetc, 0) == S_OK) {
176 		fmt.FindAdd(FromWin32CF(fmtetc.cfFormat));
177 		if(fmtetc.ptd)
178 			CoTaskMemFree(fmtetc.ptd);
179 	}
180 	LLOG("DragEnter fmt: " << fmt);
181 	fe->Release();
182 	DnD(pt, false, pdwEffect, grfKeyState);
183 	return NOERROR;
184 }
185 
186 
DragOver(DWORD grfKeyState,POINTL pt,LPDWORD pdwEffect)187 STDMETHODIMP CLANG_NOTHROW UDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
188 {
189 	LLOG("DragOver " << pt << " keys: " << grfKeyState);
190 	DnD(pt, false, pdwEffect, grfKeyState);
191 	return NOERROR;
192 }
193 
FreeData()194 void UDropTarget::FreeData()
195 {
196 	if(data) {
197 		data->Release();
198 		data = NULL;
199 	}
200 }
201 
EndDrag()202 void UDropTarget::EndDrag()
203 {
204 	Ctrl::DnDLeave();
205 }
206 
DragLeave()207 STDMETHODIMP CLANG_NOTHROW UDropTarget::DragLeave()
208 {
209 	LLOG("DragLeave");
210 	EndDrag();
211 	FreeData();
212 	return NOERROR;
213 }
214 
Drop(LPDATAOBJECT,DWORD grfKeyState,POINTL pt,LPDWORD pdwEffect)215 STDMETHODIMP CLANG_NOTHROW UDropTarget::Drop(LPDATAOBJECT, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
216 {
217 	LLOG("Drop");
218 	if(Ctrl::GetDragAndDropSource())
219 		Ctrl::OverrideCursor(Null);
220 	DnD(pt, true, pdwEffect, grfKeyState);
221 	EndDrag();
222 	FreeData();
223 	return NOERROR;
224 }
225 
~UDropTarget()226 UDropTarget::~UDropTarget()
227 {
228 	if(data) data->Release();
229 	EndDrag();
230 }
231 
232 // --------------------------------------------------------------------------------------------
233 
234 Ptr<Ctrl> sDnDSource;
235 
GetDragAndDropSource()236 Ctrl * Ctrl::GetDragAndDropSource()
237 {
238 	return sDnDSource;
239 }
240 
241 struct  UDataObject : public IDataObject {
242 	ULONG                       rc;
243 	dword                       effect;
244 	VectorMap<String, ClipData> data;
245 
246 	STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
STDMETHOD_Upp::UDataObject247 	STDMETHOD_(ULONG, AddRef)(void)  { return ++rc; }
STDMETHOD_Upp::UDataObject248 	STDMETHOD_(ULONG, Release)(void) { if(--rc == 0) { delete this; return 0; } return rc; }
249 
250 	STDMETHOD(GetData)(FORMATETC *fmtetc, STGMEDIUM *medium);
251 	STDMETHOD(GetDataHere)(FORMATETC *, STGMEDIUM *);
252 	STDMETHOD(QueryGetData)(FORMATETC *fmtetc);
253 	STDMETHOD(GetCanonicalFormatEtc)(FORMATETC *, FORMATETC *pformatetcOut);
254 	STDMETHOD(SetData)(FORMATETC *fmtetc, STGMEDIUM *medium, BOOL release);
255 	STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ief);
256 	STDMETHOD(DAdvise)(FORMATETC *, DWORD, IAdviseSink *, DWORD *);
257 	STDMETHOD(DUnadvise)(DWORD);
258 	STDMETHOD(EnumDAdvise)(LPENUMSTATDATA *);
259 
UDataObjectUpp::UDataObject260 	UDataObject() { rc = 1; effect = 0; }
261 };
262 
263 struct UEnumFORMATETC : public IEnumFORMATETC {
264 	ULONG        rc;
265 	int          ii;
266 	UDataObject *data;
267 
268 	STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);
STDMETHOD_Upp::UEnumFORMATETC269 	STDMETHOD_(ULONG, AddRef)(void)  { return ++rc; }
STDMETHOD_Upp::UEnumFORMATETC270 	STDMETHOD_(ULONG, Release)(void) { if(--rc == 0) { delete this; return 0; } return rc; }
271 
272 	STDMETHOD(Next)(ULONG n, FORMATETC *fmtetc, ULONG *fetched);
273 	STDMETHOD(Skip)(ULONG n);
274 	STDMETHOD(Reset)(void);
275 	STDMETHOD(Clone)(IEnumFORMATETC **newEnum);
276 
UEnumFORMATETCUpp::UEnumFORMATETC277 	UEnumFORMATETC()  { ii = 0; rc = 1; }
~UEnumFORMATETCUpp::UEnumFORMATETC278 	~UEnumFORMATETC() { data->Release(); }
279 };
280 
281 struct UDropSource : public IDropSource {
282 	ULONG rc;
283 	Image no, move, copy;
284 
285 	STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj);
STDMETHOD_Upp::UDropSource286 	STDMETHOD_(ULONG, AddRef)(void)  { return ++rc; }
STDMETHOD_Upp::UDropSource287 	STDMETHOD_(ULONG, Release)(void) { if(--rc == 0) { delete this; return 0; } return rc; }
288 
289 	STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
290 	STDMETHOD(GiveFeedback)(DWORD dwEffect);
291 
UDropSourceUpp::UDropSource292 	UDropSource() { rc = 1; }
293 };
294 
QueryInterface(REFIID iid,void ** ppv)295 STDMETHODIMP CLANG_NOTHROW UDataObject::QueryInterface(REFIID iid, void ** ppv)
296 {
297 	if(iid == IID_IUnknown || iid == IID_IDataObject) {
298 		*ppv = this;
299 		AddRef();
300 		return S_OK;
301 	}
302 	*ppv = NULL;
303 	return E_NOINTERFACE;
304 }
305 
SetMedium(STGMEDIUM * medium,const String & data)306 void SetMedium(STGMEDIUM *medium, const String& data)
307 {
308 	int sz = data.GetCount();
309 	HGLOBAL hData = GlobalAlloc(0, sz + 4);
310 	if (hData) {
311 		char *ptr = (char *) GlobalLock(hData);
312 		memcpy(ptr, ~data, sz);
313 		memset(ptr + sz, 0, 4);
314 		GlobalUnlock(hData);
315 		medium->tymed = TYMED_HGLOBAL;
316 		medium->hGlobal = hData;
317 		medium->pUnkForRelease = 0;
318 	}
319 }
320 
GetData(FORMATETC * fmtetc,STGMEDIUM * medium)321 STDMETHODIMP CLANG_NOTHROW UDataObject::GetData(FORMATETC *fmtetc, STGMEDIUM *medium)
322 {
323 	String fmt = FromWin32CF(fmtetc->cfFormat);
324 	ClipData *s = data.FindPtr(fmt);
325 	if(s) {
326 		String q = s->Render();
327 		SetMedium(medium, q.GetCount() ? q : sDnDSource ? sDnDSource->GetDropData(fmt) : String());
328 		return S_OK;
329 	}
330 	return DV_E_FORMATETC;
331 }
332 
GetDataHere(FORMATETC *,STGMEDIUM *)333 STDMETHODIMP CLANG_NOTHROW UDataObject::GetDataHere(FORMATETC *, STGMEDIUM *)
334 {
335     return DV_E_FORMATETC;
336 }
337 
QueryGetData(FORMATETC * fmtetc)338 STDMETHODIMP CLANG_NOTHROW UDataObject::QueryGetData(FORMATETC *fmtetc)
339 {
340 	return data.Find(FromWin32CF(fmtetc->cfFormat)) >= 0 ? S_OK : DV_E_FORMATETC;
341 }
342 
GetCanonicalFormatEtc(FORMATETC *,FORMATETC * pformatetcOut)343 STDMETHODIMP CLANG_NOTHROW UDataObject::GetCanonicalFormatEtc(FORMATETC *, FORMATETC *pformatetcOut)
344 {
345     pformatetcOut->ptd = NULL;
346     return E_NOTIMPL;
347 }
348 
349 #ifdef PLATFORM_WINCE
350 static int CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(_T("Performed DropEffect"));
351 #else
352 static int CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat("Performed DropEffect");
353 #endif
354 
SetData(FORMATETC * fmtetc,STGMEDIUM * medium,BOOL release)355 STDMETHODIMP CLANG_NOTHROW UDataObject::SetData(FORMATETC *fmtetc, STGMEDIUM *medium, BOOL release)
356 {
357 	if(fmtetc->cfFormat == CF_PERFORMEDDROPEFFECT && medium->tymed == TYMED_HGLOBAL) {
358         DWORD *val = (DWORD*)GlobalLock(medium->hGlobal);
359         effect = *val;
360         GlobalUnlock(medium->hGlobal);
361         if(release)
362             ReleaseStgMedium(medium);
363         return S_OK;
364     }
365 	return E_NOTIMPL;
366 }
367 
EnumFormatEtc(DWORD dwDirection,IEnumFORMATETC ** ief)368 STDMETHODIMP CLANG_NOTHROW UDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ief)
369 {
370 	UEnumFORMATETC *ef = new UEnumFORMATETC;
371 	ef->data = this;
372 	AddRef();
373 	*ief = ef;
374 	return S_OK;
375 }
376 
DAdvise(FORMATETC *,DWORD,IAdviseSink *,DWORD *)377 STDMETHODIMP CLANG_NOTHROW UDataObject::DAdvise(FORMATETC *, DWORD, IAdviseSink *, DWORD *)
378 {
379 	return OLE_E_ADVISENOTSUPPORTED;
380 }
381 
382 
DUnadvise(DWORD)383 STDMETHODIMP CLANG_NOTHROW UDataObject::DUnadvise(DWORD)
384 {
385 	return OLE_E_ADVISENOTSUPPORTED;
386 }
387 
EnumDAdvise(LPENUMSTATDATA FAR *)388 STDMETHODIMP CLANG_NOTHROW UDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
389 {
390 	return OLE_E_ADVISENOTSUPPORTED;
391 }
392 
QueryInterface(REFIID riid,void FAR * FAR * ppvObj)393 STDMETHODIMP CLANG_NOTHROW UEnumFORMATETC::QueryInterface(REFIID riid, void FAR* FAR* ppvObj)
394 {
395 	if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) {
396 		*ppvObj = this;
397 		AddRef();
398 		return NOERROR;
399     }
400 	*ppvObj = NULL;
401 	return ResultFromScode(E_NOINTERFACE);
402 }
403 
Next(ULONG n,FORMATETC * t,ULONG * fetched)404 STDMETHODIMP CLANG_NOTHROW UEnumFORMATETC::Next(ULONG n, FORMATETC *t, ULONG *fetched) {
405 	if(t == NULL)
406 		return E_INVALIDARG;
407 	if(fetched) *fetched = 0;
408 	while(ii < data->data.GetCount() && n > 0) {
409 		if(fetched) (*fetched)++;
410 		n--;
411 		*t++ = ToFORMATETC(data->data.GetKey(ii++));
412 	}
413 	return n ? S_FALSE : NOERROR;
414 }
415 
Skip(ULONG n)416 STDMETHODIMP CLANG_NOTHROW UEnumFORMATETC::Skip(ULONG n) {
417 	ii += n;
418 	if(ii >= data->data.GetCount())
419 		return S_FALSE;
420 	return NOERROR;
421 }
422 
Reset()423 STDMETHODIMP CLANG_NOTHROW UEnumFORMATETC::Reset()
424 {
425     ii = 0;
426     return NOERROR;
427 }
428 
Clone(IEnumFORMATETC ** newEnum)429 STDMETHODIMP CLANG_NOTHROW UEnumFORMATETC::Clone(IEnumFORMATETC **newEnum)
430 {
431 	if(newEnum == NULL)
432 		return E_INVALIDARG;
433 	UEnumFORMATETC *ef = new UEnumFORMATETC;
434 	ef->data = data;
435 	data->AddRef();
436 	ef->ii = ii;
437 	*newEnum = ef;
438 	return NOERROR;
439 }
440 
QueryInterface(REFIID riid,void ** ppvObj)441 STDMETHODIMP CLANG_NOTHROW UDropSource::QueryInterface(REFIID riid, void **ppvObj)
442 {
443 	if (riid == IID_IUnknown || riid == IID_IDropSource) {
444 		*ppvObj = this;
445 		AddRef();
446 		return NOERROR;
447 	}
448 	*ppvObj = NULL;
449 	return ResultFromScode(E_NOINTERFACE);
450 }
451 
QueryContinueDrag(BOOL fEscapePressed,DWORD grfKeyState)452 STDMETHODIMP CLANG_NOTHROW UDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
453 {
454 	if(fEscapePressed)
455 		return DRAGDROP_S_CANCEL;
456 	else
457 	if(!(grfKeyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)))
458 		return DRAGDROP_S_DROP;
459 	Ctrl::ProcessEvents();
460 	return NOERROR;
461 }
462 
GiveFeedback(DWORD dwEffect)463 STDMETHODIMP CLANG_NOTHROW UDropSource::GiveFeedback(DWORD dwEffect)
464 {
465 	LLOG("GiveFeedback");
466 	Image m = IsNull(move) ? copy : move;
467 	if((dwEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY) {
468 		LLOG("GiveFeedback COPY");
469 		if(!IsNull(copy)) m = copy;
470 	}
471 	else
472 	if((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE) {
473 		LLOG("GiveFeedback MOVE");
474 		if(!IsNull(move)) m = move;
475 	}
476 	else
477 		m = no;
478 	Ctrl::OverrideCursor(m);
479 	Ctrl::SetMouseCursor(m);
480 	return S_OK;
481 }
482 
483 Image MakeDragImage(const Image& arrow, Image sample);
484 
MakeDragImage(const Image & arrow,const Image & arrow98,Image sample)485 Image MakeDragImage(const Image& arrow, const Image& arrow98, Image sample)
486 {
487 	if(IsWin2K())
488 		return MakeDragImage(arrow, sample);
489 	else
490 		return arrow98;
491 }
492 
DoDragAndDrop(const char * fmts,const Image & sample,dword actions,const VectorMap<String,ClipData> & data)493 int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions,
494                         const VectorMap<String, ClipData>& data)
495 {
496 	UDataObject *obj = new UDataObject;
497 	obj->data <<= data;
498 	if(fmts) {
499 		Vector<String> f = Split(fmts, ';');
500 		for(int i = 0; i < f.GetCount(); i++)
501 			obj->data.GetAdd(f[i]);
502 	}
503 	UDropSource *dsrc = new UDropSource;
504 	DWORD result = 0;
505 	Image m = Ctrl::OverrideCursor(CtrlCoreImg::DndMove());
506 	dsrc->no = MakeDragImage(CtrlCoreImg::DndNone(), CtrlCoreImg::DndNone98(), sample);
507 	if(actions & DND_COPY)
508 		dsrc->copy = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndCopy(), CtrlCoreImg::DndCopy98(), sample);
509 	if(actions & DND_MOVE)
510 		dsrc->move = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndMove(), CtrlCoreImg::DndMove98(), sample);
511 	sDnDSource = this;
512 	int level = LeaveGuiMutexAll();
513 	HRESULT r = DoDragDrop(obj, dsrc,
514 	                       (actions & DND_COPY ? DROPEFFECT_COPY : 0) |
515 	                       (actions & DND_MOVE ? DROPEFFECT_MOVE : 0), &result);
516 	EnterGuiMutex(level);
517 	DWORD re = obj->effect;
518 	obj->Release();
519 	dsrc->Release();
520 	OverrideCursor(m);
521 	SyncCaret();
522 	CheckMouseCtrl();
523 	KillRepeat();
524 	sDnDSource = NULL;
525 	if(r == DRAGDROP_S_DROP) {
526 		if(((result | re) & DROPEFFECT_MOVE) == DROPEFFECT_MOVE && (actions & DND_MOVE))
527 			return DND_MOVE;
528 		if(((result | re) & DROPEFFECT_COPY) == DROPEFFECT_COPY && (actions & DND_COPY))
529 			return DND_COPY;
530     }
531 	return DND_NONE;
532 }
533 
ReleaseUDropTarget(UDropTarget * dt)534 void ReleaseUDropTarget(UDropTarget *dt)
535 {
536 	dt->Release();
537 }
538 
NewUDropTarget(Ctrl * ctrl)539 UDropTarget *NewUDropTarget(Ctrl *ctrl)
540 {
541 	UDropTarget *dt = new UDropTarget;
542 	dt->ctrl = ctrl;
543 	return dt;
544 }
545 
SetSelectionSource(const char * fmts)546 void Ctrl::SetSelectionSource(const char *fmts) {}
547 
548 }
549 
550 #endif
551