1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok (pbartok@novell.com)
24 // Srikanth Madikeri (csri_1986@yahoo.com) - Win32 Drop files.
30 using System.Collections;
32 using System.Reflection;
33 using System.Reflection.Emit;
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization;
38 namespace System.Windows.Forms {
39 internal class Win32DnD {
40 #region Local Variables
41 private const uint DATADIR_GET = 1;
42 private const uint S_OK = 0x00000000;
43 private const uint S_FALSE = 0x00000001;
44 private const uint DRAGDROP_S_DROP = 0x00040100;
45 private const uint DRAGDROP_S_CANCEL = 0x00040101;
46 private const uint DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
47 private const uint E_NOTIMPL = unchecked((uint)0x80004001);
48 private const uint E_NOINTERFACE = unchecked((uint)0x80004002);
49 private const uint E_FAIL = unchecked((uint)0x80004005);
50 private const uint OLE_E_ADVISENOTSUPPORTED = unchecked((uint)0x80040003);
51 private const uint DV_E_FORMATETC = unchecked((uint)0x80040064);
53 // To call function pointers
54 //private static object[] GetDataArgs;
56 // IDataObject Delegates
57 private static QueryInterfaceDelegate DOQueryInterface;
58 private static AddRefDelegate DOAddRef;
59 private static ReleaseDelegate DORelease;
60 private static GetDataDelegate GetData;
61 private static GetDataHereDelegate GetDataHere;
62 private static QueryGetDataDelegate QueryGetData;
63 private static GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
64 private static SetDataDelegate SetData;
65 private static EnumFormatEtcDelegate EnumFormatEtc;
66 private static DAdviseDelegate DAdvise;
67 private static DUnadviseDelegate DUnadvise;
68 private static EnumDAdviseDelegate EnumDAdvise;
70 // IDropSource Delegates
71 private static QueryInterfaceDelegate DSQueryInterface;
72 private static AddRefDelegate DSAddRef;
73 private static ReleaseDelegate DSRelease;
74 private static QueryContinueDragDelegate QueryContinueDrag;
75 private static GiveFeedbackDelegate GiveFeedback;
77 // IDropTarget Delegates
78 private static QueryInterfaceDelegate DTQueryInterface;
79 private static AddRefDelegate DTAddRef;
80 private static ReleaseDelegate DTRelease;
81 private static DragEnterDelegate DragEnter;
82 private static DragOverDelegate DragOver;
83 private static DragLeaveDelegate DragLeave;
84 private static DropDelegate Drop;
86 private static DragEventArgs DragDropEventArgs;
87 private static GiveFeedbackEventArgs DragFeedbackEventArgs;
88 private static QueryContinueDragEventArgs DragContinueEventArgs;
89 private static ArrayList DragFormats;
90 private static FORMATETC[] DragFormatArray;
91 private static ArrayList DragMediums;
92 #endregion // Local Variables
94 #region Delegate Definitions
96 internal delegate uint QueryInterfaceDelegate(IntPtr @this, ref Guid riid, IntPtr ppvObject);
97 internal delegate uint AddRefDelegate(IntPtr @this);
98 internal delegate uint ReleaseDelegate(IntPtr @this);
101 internal delegate uint GetDataDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pmedium);
102 internal delegate uint GetDataHereDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium);
103 internal delegate uint QueryGetDataDelegate(IntPtr @this, ref FORMATETC pformatetc);
104 internal delegate uint GetCanonicalFormatEtcDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut);
105 internal delegate uint SetDataDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release);
106 internal delegate uint EnumFormatEtcDelegate(IntPtr @this, uint direction, IntPtr ppenumFormatEtc);
107 internal delegate uint DAdviseDelegate(IntPtr @this, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection);
108 internal delegate uint DUnadviseDelegate(IntPtr @this, uint pdwConnection);
109 internal delegate uint EnumDAdviseDelegate(IntPtr @this, IntPtr ppenumAdvise);
112 internal delegate uint QueryContinueDragDelegate(IntPtr @this, bool fEscapePressed, uint grfkeyState);
113 internal delegate uint GiveFeedbackDelegate(IntPtr @this, uint pdwEffect);
116 internal delegate uint DragEnterDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
117 internal delegate uint DragOverDelegate(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
118 internal delegate uint DragLeaveDelegate(IntPtr @this);
119 internal delegate uint DropDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
120 #endregion // Delegate Definitions
122 [StructLayout(LayoutKind.Sequential)]
123 internal struct FORMATETC {
124 [MarshalAs(UnmanagedType.U2)]
125 internal ClipboardFormats cfFormat;
127 internal DVASPECT dwAspect;
129 internal TYMED tymed;
132 [StructLayout(LayoutKind.Sequential)]
133 internal struct STGMEDIUM {
134 internal TYMED tymed;
135 internal IntPtr hHandle;
136 internal IntPtr pUnkForRelease;
139 [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
140 internal struct DROPFILES {
141 internal uint pFiles;
146 internal string pText;
149 internal enum DVASPECT {
150 DVASPECT_CONTENT = 1,
151 DVASPECT_THUMBNAIL = 2,
153 DVASPECT_DOCPRINT = 8
156 internal enum TYMED {
167 private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
168 private static readonly Guid IID_IDataObject = new Guid("0000010e-0000-0000-C000-000000000046");
169 private static readonly Guid IID_IDropSource = new Guid("00000121-0000-0000-C000-000000000046");
170 private static readonly Guid IID_IDropTarget = new Guid("00000122-0000-0000-C000-000000000046");
174 // Required for all other OLE functions to work
175 Win32OleInitialize(IntPtr.Zero);
178 DragDropEventArgs = new DragEventArgs(new DataObject(DataFormats.FileDrop, new string[0]), 0, 0, 0, DragDropEffects.None, DragDropEffects.None);
179 DragFeedbackEventArgs = new GiveFeedbackEventArgs(DragDropEffects.None, true);
180 DragContinueEventArgs = new QueryContinueDragEventArgs(0, false, DragAction.Continue);
181 DragFormats = new ArrayList();
182 DragFormatArray = new FORMATETC[0];
183 DragMediums = new ArrayList();
187 DOQueryInterface = new QueryInterfaceDelegate(ComIDataObject.QueryInterface);
188 DOAddRef = new AddRefDelegate(ComIDataObject.AddRef);
189 DORelease = new ReleaseDelegate(ComIDataObject.Release);
190 GetData = new GetDataDelegate(ComIDataObject.GetData);
191 GetDataHere = new GetDataHereDelegate(ComIDataObject.GetDataHere);
192 QueryGetData = new QueryGetDataDelegate(ComIDataObject.QueryGetData);
193 GetCanonicalFormatEtc = new GetCanonicalFormatEtcDelegate(ComIDataObject.GetCanonicalFormatEtc);
194 SetData = new SetDataDelegate(ComIDataObject.SetData);
195 EnumFormatEtc = new EnumFormatEtcDelegate(ComIDataObject.EnumFormatEtc);
196 DAdvise = new DAdviseDelegate(ComIDataObject.DAdvise);
197 DUnadvise = new DUnadviseDelegate(ComIDataObject.DUnadvise);
198 EnumDAdvise = new EnumDAdviseDelegate(ComIDataObject.EnumDAdvise);
201 DSQueryInterface = new QueryInterfaceDelegate(ComIDropSource.QueryInterface);
202 DSAddRef = new AddRefDelegate(ComIDropSource.AddRef);
203 DSRelease = new ReleaseDelegate(ComIDropSource.Release);
204 QueryContinueDrag = new QueryContinueDragDelegate(ComIDropSource.QueryContinueDrag);
205 GiveFeedback = new GiveFeedbackDelegate(ComIDropSource.GiveFeedback);
208 DTQueryInterface = new QueryInterfaceDelegate(ComIDropTarget.QueryInterface);
209 DTAddRef = new AddRefDelegate(ComIDropTarget.AddRef);
210 DTRelease = new ReleaseDelegate(ComIDropTarget.Release);
211 DragEnter = new DragEnterDelegate(ComIDropTarget.DragEnter);
212 DragOver = new DragOverDelegate(ComIDropTarget.DragOver);
213 DragLeave = new DragLeaveDelegate(ComIDropTarget.DragLeave);
214 Drop = new DropDelegate(ComIDropTarget.Drop);
217 internal class ComIDataObject {
218 [StructLayout(LayoutKind.Sequential)]
219 internal struct DataObjectStruct {
220 internal IntPtr vtbl;
221 internal QueryInterfaceDelegate QueryInterface;
222 internal AddRefDelegate AddRef;
223 internal ReleaseDelegate Release;
224 internal GetDataDelegate GetData;
225 internal GetDataHereDelegate GetDataHere;
226 internal QueryGetDataDelegate QueryGetData;
227 internal GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
228 internal SetDataDelegate SetData;
229 internal EnumFormatEtcDelegate EnumFormatEtc;
230 internal DAdviseDelegate DAdvise;
231 internal DUnadviseDelegate DUnadvise;
232 internal EnumDAdviseDelegate EnumDAdvise;
235 internal static IntPtr GetUnmanaged() {
236 DataObjectStruct data_object;
237 IntPtr data_object_ptr;
240 data_object = new DataObjectStruct();
242 data_object.QueryInterface = Win32DnD.DOQueryInterface;
243 data_object.AddRef = Win32DnD.DOAddRef;
244 data_object.Release = Win32DnD.DORelease;
245 data_object.GetData = Win32DnD.GetData;
246 data_object.GetDataHere = Win32DnD.GetDataHere;
247 data_object.QueryGetData = Win32DnD.QueryGetData;
248 data_object.GetCanonicalFormatEtc = Win32DnD.GetCanonicalFormatEtc;
249 data_object.SetData = Win32DnD.SetData;
250 data_object.EnumFormatEtc = Win32DnD.EnumFormatEtc;
251 data_object.DAdvise = Win32DnD.DAdvise;
252 data_object.DUnadvise = Win32DnD.DUnadvise;
253 data_object.EnumDAdvise = Win32DnD.EnumDAdvise;
255 data_object_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DataObjectStruct)));
256 Marshal.StructureToPtr(data_object, data_object_ptr, false);
258 // Update vtbl pointer
259 offset = data_object_ptr.ToInt64();
260 offset += Marshal.SizeOf(typeof(IntPtr));
261 Marshal.WriteIntPtr(data_object_ptr, new IntPtr(offset));
263 return data_object_ptr;
266 internal static void ReleaseUnmanaged(IntPtr data_object_ptr) {
267 Marshal.FreeHGlobal(data_object_ptr);
270 internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
272 if (IID_IUnknown.Equals(riid) || IID_IDataObject.Equals(riid)) {
273 Marshal.WriteIntPtr(ppvObject, @this);
278 catch (Exception e) {
279 Console.WriteLine("Got exception {0}", e.Message);
282 Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
283 return E_NOINTERFACE;
286 internal static uint AddRef(IntPtr @this) {
287 // We only use this for DnD, try and fake it
291 internal static uint Release(IntPtr @this) {
292 // We only use this for DnD, try and fake it
296 internal static STGMEDIUM medium = new STGMEDIUM();
297 internal static uint GetData(IntPtr this_, ref FORMATETC pformatetcIn, IntPtr pmedium) {
300 index = FindFormat(pformatetcIn);
302 medium.tymed = TYMED.TYMED_HGLOBAL;
303 medium.hHandle = XplatUIWin32.DupGlobalMem(((STGMEDIUM)DragMediums[index]).hHandle);
304 medium.pUnkForRelease = IntPtr.Zero;
306 Marshal.StructureToPtr(medium, pmedium, false);
308 catch (Exception e) {
309 Console.WriteLine("Error: {0}", e.Message);
314 return DV_E_FORMATETC;
317 internal static uint GetDataHere(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium) {
318 return DV_E_FORMATETC;
321 internal static uint QueryGetData(IntPtr @this, ref FORMATETC pformatetc) {
322 if (FindFormat(pformatetc) != -1) {
325 return DV_E_FORMATETC;
328 internal static uint GetCanonicalFormatEtc(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut) {
329 Marshal.WriteIntPtr(pformatetcOut, Marshal.SizeOf(typeof(IntPtr)), IntPtr.Zero);
333 internal static uint SetData(IntPtr this_, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release) {
337 internal static uint EnumFormatEtc(IntPtr this_, uint direction, IntPtr ppenumFormatEtc) {
338 if (direction == DATADIR_GET) {
341 ppenum_ptr = IntPtr.Zero;
342 DragFormatArray = new FORMATETC[DragFormats.Count];
344 for (int i = 0; i < DragFormats.Count; i++) {
345 DragFormatArray[i] = (FORMATETC)DragFormats[i];
347 Win32SHCreateStdEnumFmtEtc((uint)DragFormatArray.Length, DragFormatArray, ref ppenum_ptr);
348 Marshal.WriteIntPtr(ppenumFormatEtc, ppenum_ptr);
354 internal static uint DAdvise(IntPtr this_, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
355 return OLE_E_ADVISENOTSUPPORTED;
358 internal static uint DUnadvise(IntPtr this_, uint pdwConnection) {
359 return OLE_E_ADVISENOTSUPPORTED;
362 internal static uint EnumDAdvise(IntPtr this_, IntPtr ppenumAdvise) {
363 return OLE_E_ADVISENOTSUPPORTED;
367 internal class ComIDataObjectUnmanaged {
368 [StructLayout(LayoutKind.Sequential)]
369 internal struct IDataObjectUnmanaged {
370 internal IntPtr QueryInterface;
371 internal IntPtr AddRef;
372 internal IntPtr Release;
373 internal IntPtr GetData;
374 internal IntPtr GetDataHere;
375 internal IntPtr QueryGetData;
376 internal IntPtr GetCanonicalFormatEtc;
377 internal IntPtr SetData;
378 internal IntPtr EnumFormatEtc;
379 internal IntPtr DAdvise;
380 internal IntPtr DUnadvise;
381 internal IntPtr EnumDAdvise;
384 private static bool Initialized;
385 private static MethodInfo GetDataMethod;
386 //private static MethodInfo GetDataHereMethod;
387 private static MethodInfo QueryGetDataMethod;
388 //private static MethodInfo GetCanonicalFormatEtcMethod;
389 //private static MethodInfo SetDataMethod;
390 //private static MethodInfo EnumFormatEtcMethod;
391 //private static MethodInfo DAdviseMethod;
392 //private static MethodInfo DUnadviseMethod;
393 //private static MethodInfo EnumDAdviseMethod;
394 private static object[] MethodArguments;
396 private IDataObjectUnmanaged vtbl;
397 private IntPtr @this;
399 internal ComIDataObjectUnmanaged(IntPtr data_object_ptr) {
404 vtbl = new IDataObjectUnmanaged();
405 @this = data_object_ptr;
407 vtbl = (IDataObjectUnmanaged)Marshal.PtrToStructure(Marshal.ReadIntPtr(data_object_ptr), typeof(IDataObjectUnmanaged));
410 catch (Exception e) {
411 Console.WriteLine("Exception {0}", e.Message);
415 private static void Initialize() {
416 AssemblyName assembly;
417 AssemblyBuilder assembly_builder;
423 assembly = new AssemblyName();
424 assembly.Name = "XplatUIWin32.FuncPtrInterface";
425 assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
427 MethodArguments = new object[6];
428 GetDataMethod = CreateFuncPtrInterface(assembly_builder, "GetData", typeof(uint), 3);
429 //GetDataHereMethod = CreateFuncPtrInterface(assembly_builder, "GetDataHere", typeof(uint), 3);
430 QueryGetDataMethod = CreateFuncPtrInterface(assembly_builder, "QueryGetData", typeof(uint), 2);
431 //GetCanonicalFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "GetCanonicalFormatEtc", typeof(uint), 3);
432 //SetDataMethod = CreateFuncPtrInterface(assembly_builder, "SetData", typeof(uint), 4);
433 //EnumFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "EnumFormatEtc", typeof(uint), 3);
434 //DAdviseMethod = CreateFuncPtrInterface(assembly_builder, "DAdvise", typeof(uint), 5);
435 //DUnadviseMethod = CreateFuncPtrInterface(assembly_builder, "DUnadvise", typeof(uint), 2);
436 //EnumDAdviseMethod = CreateFuncPtrInterface(assembly_builder, "EnumDAdvise", typeof(uint), 2);
441 internal uint QueryInterface(Guid riid, IntPtr ppvObject) {
445 riid_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
446 Marshal.StructureToPtr(riid, riid_ptr, false);
448 MethodArguments[0] = vtbl.QueryInterface;
449 MethodArguments[1] = this.@this;
450 MethodArguments[2] = riid_ptr;
451 MethodArguments[3] = ppvObject;
454 ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
457 catch (Exception e) {
458 Console.WriteLine("Caught exception {0}", e.Message);
462 Marshal.FreeHGlobal(riid_ptr);
467 internal uint AddRef() {
468 // We only use this for DnD, try and fake it
472 internal uint Release() {
473 // We only use this for DnD, try and fake it
477 internal uint GetData(FORMATETC pformatetcIn, ref STGMEDIUM pmedium) {
479 IntPtr pformatetcIn_ptr;
482 pformatetcIn_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
483 Marshal.StructureToPtr(pformatetcIn, pformatetcIn_ptr, false);
485 pmedium_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STGMEDIUM)));
487 MethodArguments[0] = vtbl.GetData;
488 MethodArguments[1] = this.@this;
489 MethodArguments[2] = pformatetcIn_ptr;
490 MethodArguments[3] = pmedium_ptr;
493 ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
494 Marshal.PtrToStructure(pmedium_ptr, pmedium);
497 catch (Exception e) {
498 Console.WriteLine("Caught exception {0}", e.Message);
502 Marshal.FreeHGlobal(pformatetcIn_ptr);
503 Marshal.FreeHGlobal(pmedium_ptr);
508 internal uint GetDataHere(FORMATETC pformatetc, ref STGMEDIUM pmedium) {
512 internal uint QueryGetData(FORMATETC pformatetc) {
514 IntPtr pformatetc_ptr;
516 pformatetc_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
517 Marshal.StructureToPtr(pformatetc, pformatetc_ptr, false);
519 MethodArguments[0] = vtbl.GetData;
520 MethodArguments[1] = this.@this;
521 MethodArguments[2] = pformatetc_ptr;
524 ret = (uint)QueryGetDataMethod.Invoke(null, MethodArguments);
527 catch (Exception e) {
528 Console.WriteLine("Caught exception {0}", e.Message);
532 Marshal.FreeHGlobal(pformatetc_ptr);
537 internal uint GetCanonicalFormatEtc(FORMATETC pformatetcIn, ref FORMATETC pformatetcOut) {
541 internal uint SetData(FORMATETC pformatetc, STGMEDIUM pmedium, bool release) {
545 internal uint EnumFormatEtc(uint direction, IntPtr ppenumFormatEtc) {
549 internal uint DAdvise(FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
550 return OLE_E_ADVISENOTSUPPORTED;
553 internal uint DUnadvise(uint pdwConnection) {
554 return OLE_E_ADVISENOTSUPPORTED;
557 internal uint EnumDAdvise(IntPtr ppenumAdvise) {
558 return OLE_E_ADVISENOTSUPPORTED;
563 internal class ComIDropSource {
564 [StructLayout(LayoutKind.Sequential)]
565 internal struct IDropSource {
566 internal IntPtr vtbl;
567 internal IntPtr Window;
568 internal QueryInterfaceDelegate QueryInterface;
569 internal AddRefDelegate AddRef;
570 internal ReleaseDelegate Release;
571 internal QueryContinueDragDelegate QueryContinueDrag;
572 internal GiveFeedbackDelegate GiveFeedback;
575 internal static IntPtr GetUnmanaged(IntPtr Window) {
576 IDropSource drop_source;
577 IntPtr drop_source_ptr;
580 drop_source = new IDropSource();
581 drop_source.QueryInterface = Win32DnD.DSQueryInterface;
582 drop_source.AddRef = Win32DnD.DSAddRef;
583 drop_source.Release = Win32DnD.DSRelease;
584 drop_source.QueryContinueDrag = Win32DnD.QueryContinueDrag;
585 drop_source.GiveFeedback = Win32DnD.GiveFeedback;
586 drop_source.Window = Window;
588 drop_source_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_source));
589 Marshal.StructureToPtr(drop_source, drop_source_ptr, false);
591 // Update vtbl pointer
592 offset = drop_source_ptr.ToInt64();
593 offset += 2 * Marshal.SizeOf(typeof(IntPtr));
594 Marshal.WriteIntPtr(drop_source_ptr, new IntPtr(offset));
596 return drop_source_ptr;
599 internal static void ReleaseUnmanaged(IntPtr drop_source_ptr) {
600 Marshal.FreeHGlobal(drop_source_ptr);
603 internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
605 if (IID_IUnknown.Equals(riid) || IID_IDropSource.Equals(riid)) {
606 Marshal.WriteIntPtr(ppvObject, @this);
611 catch (Exception e) {
612 Console.WriteLine("Got exception {0}", e.Message);
615 Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
616 return E_NOINTERFACE;
619 internal static uint AddRef(IntPtr @this) {
620 // We only use this for DnD, try and fake it
624 internal static uint Release(IntPtr @this) {
625 // We only use this for DnD, try and fake it
629 internal static uint QueryContinueDrag(IntPtr @this, bool fEscapePressed, uint grfkeyState) {
632 window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
634 // LAMESPEC? - according to MSDN, when the any mousebutton is *pressed* it defaults to Drop.
635 // According to COM customary behaviour it's the other way round; which is what we do here
636 if (fEscapePressed) {
637 DragContinueEventArgs.drag_action = DragAction.Cancel;
638 } else if ((grfkeyState & (1+2+16)) == 0) { // Left, middle and right mouse button not pressed
639 DragContinueEventArgs.drag_action = DragAction.Drop;
641 DragContinueEventArgs.drag_action = DragAction.Continue;
644 DragContinueEventArgs.escape_pressed = fEscapePressed;
645 DragContinueEventArgs.key_state = (int)grfkeyState;
647 Control.FromHandle(window).DndContinueDrag(DragContinueEventArgs);
649 if (DragContinueEventArgs.drag_action == DragAction.Cancel) {
650 return DRAGDROP_S_CANCEL;
651 } else if (DragContinueEventArgs.drag_action == DragAction.Drop) {
652 return DRAGDROP_S_DROP;
657 internal static uint GiveFeedback(IntPtr @this, uint pdwEffect) {
660 window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
662 DragFeedbackEventArgs.effect = (DragDropEffects)pdwEffect;
663 DragFeedbackEventArgs.use_default_cursors = true;
665 Control.FromHandle(window).DndFeedback(DragFeedbackEventArgs);
667 if (DragFeedbackEventArgs.use_default_cursors) {
668 return DRAGDROP_S_USEDEFAULTCURSORS;
674 internal class ComIDropTarget {
675 [StructLayout(LayoutKind.Sequential)]
676 internal struct IDropTarget {
677 internal IntPtr vtbl;
678 internal IntPtr Window;
679 internal QueryInterfaceDelegate QueryInterface;
680 internal AddRefDelegate AddRef;
681 internal ReleaseDelegate Release;
683 internal DragEnterDelegate DragEnter;
684 internal DragOverDelegate DragOver;
685 internal DragLeaveDelegate DragLeave;
686 internal DropDelegate Drop;
689 internal static IntPtr GetUnmanaged(IntPtr Window) {
690 IDropTarget drop_target;
691 IntPtr drop_target_ptr;
694 drop_target = new IDropTarget();
695 drop_target.QueryInterface = Win32DnD.DTQueryInterface;
696 drop_target.AddRef = Win32DnD.DTAddRef;
697 drop_target.Release = Win32DnD.DTRelease;
698 drop_target.DragEnter = Win32DnD.DragEnter;
699 drop_target.DragOver = Win32DnD.DragOver;
700 drop_target.DragLeave = Win32DnD.DragLeave;
701 drop_target.Drop = Win32DnD.Drop;
702 drop_target.Window = Window;
704 drop_target_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_target));
705 Marshal.StructureToPtr(drop_target, drop_target_ptr, false);
707 // Update vtbl pointer
708 offset = drop_target_ptr.ToInt64();
709 offset += 2 * Marshal.SizeOf(typeof(IntPtr));
710 Marshal.WriteIntPtr(drop_target_ptr, new IntPtr(offset));
712 return drop_target_ptr;
715 internal static void ReleaseUnmanaged(IntPtr drop_target_ptr) {
716 Marshal.FreeHGlobal(drop_target_ptr);
719 internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
721 if (IID_IUnknown.Equals(riid) || IID_IDropTarget.Equals(riid)) {
722 Marshal.WriteIntPtr(ppvObject, @this);
727 catch (Exception e) {
728 Console.WriteLine("Got exception {0}", e.Message);
731 Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
732 return E_NOINTERFACE;
735 internal static uint AddRef(IntPtr @this) {
736 // We only use this for DnD, try and fake it
740 internal static uint Release(IntPtr @this) {
741 // We only use this for DnD, try and fake it
745 internal static uint DragEnter(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
748 window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
750 DragDropEventArgs.x = pt_x.ToInt32();
751 DragDropEventArgs.y = pt_y.ToInt32();
752 DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
753 DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
754 DragDropEventArgs.keystate = (int)grfkeyState;
756 Control.FromHandle(window).DndEnter(DragDropEventArgs);
758 Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
763 internal static uint DragOver(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
766 window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
768 DragDropEventArgs.x = pt_x.ToInt32();
769 DragDropEventArgs.y = pt_y.ToInt32();
770 DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
771 DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
772 DragDropEventArgs.keystate = (int)grfkeyState;
774 Control.FromHandle(window).DndOver(DragDropEventArgs);
776 Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
781 internal static uint DragLeave(IntPtr @this) {
784 window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
786 Control.FromHandle(window).DndLeave(EventArgs.Empty);
791 internal static uint Drop(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect)
795 window = Marshal.ReadIntPtr (@this, Marshal.SizeOf (typeof (IntPtr)));
797 DragDropEventArgs.x = pt_x.ToInt32 ();
798 DragDropEventArgs.y = pt_y.ToInt32 ();
799 DragDropEventArgs.allowed_effect = (DragDropEffects) Marshal.ReadIntPtr (pdwEffect).ToInt32();
800 DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
801 DragDropEventArgs.keystate = (int) grfkeyState;
803 Control control = Control.FromHandle (window);
804 if (control == null) {
805 control.DndDrop (DragDropEventArgs);
809 Marshal.WriteInt32 (pdwEffect, (int) DragDropEventArgs.Effect);
815 internal static bool HandleWMDropFiles(ref MSG msg) {
822 count = Win32DragQueryFile(hDrop, -1, IntPtr.Zero, 0);
824 dropfiles = new string[count];
826 sb = new StringBuilder(256);
827 for (int i = 0; i < count; i++) {
828 Win32DragQueryFile(hDrop, i, sb, sb.Capacity);
829 dropfiles[i] = sb.ToString();
832 DragDropEventArgs.Data.SetData(DataFormats.FileDrop, dropfiles);
834 Control.FromHandle(msg.hwnd).DndDrop(DragDropEventArgs);
839 private static bool AddFormatAndMedium(ClipboardFormats cfFormat, object data) {
847 case ClipboardFormats.CF_TEXT: {
848 hmem = Marshal.StringToHGlobalAnsi((string)data);
852 case ClipboardFormats.CF_UNICODETEXT: {
853 hmem = Marshal.StringToHGlobalUni((string)data);
857 case ClipboardFormats.CF_HDROP: {
860 long hmem_string_ptr;
861 IntPtr string_buffer;
862 int string_buffer_size;
864 sb = new StringBuilder();
866 // Make sure object is enumerable; otherwise
867 if ((data is string) || !(data is IEnumerable)) {
868 sb.Append(data.ToString());
872 e = ((IEnumerable)data).GetEnumerator();
873 while (e.MoveNext()) {
874 sb.Append(e.Current.ToString());
880 string_buffer = Marshal.StringToHGlobalUni(sb.ToString());
881 string_buffer_size = (int)XplatUIWin32.Win32GlobalSize(string_buffer);
883 // Write DROPFILES structure
884 hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, 0x14 + string_buffer_size);
885 hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem);
886 Marshal.WriteInt32(hmem_ptr, 0x14); // pFiles
887 Marshal.WriteInt32(hmem_ptr, 1 * Marshal.SizeOf(typeof(uint)), 0); // point.x
888 Marshal.WriteInt32(hmem_ptr, 2 * Marshal.SizeOf(typeof(uint)), 0); // point.y
889 Marshal.WriteInt32(hmem_ptr, 3 * Marshal.SizeOf(typeof(uint)), 0); // fNc
890 Marshal.WriteInt32(hmem_ptr, 4 * Marshal.SizeOf(typeof(uint)), 1); // fWide
892 hmem_string_ptr = (long)hmem_ptr;
893 hmem_string_ptr += 0x14;
895 XplatUIWin32.Win32CopyMemory(new IntPtr(hmem_string_ptr), string_buffer, string_buffer_size);
896 Marshal.FreeHGlobal(string_buffer);
897 XplatUIWin32.Win32GlobalUnlock(hmem_ptr);
902 case ClipboardFormats.CF_DIB: {
903 b = XplatUIWin32.ImageToDIB((Image)data);
905 hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, b.Length);
906 hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem);
907 Marshal.Copy(b, 0, hmem_ptr, b.Length);
908 XplatUIWin32.Win32GlobalUnlock(hmem);
918 if (hmem != IntPtr.Zero) {
919 medium = new STGMEDIUM();
920 medium.tymed = TYMED.TYMED_HGLOBAL;
921 medium.hHandle = hmem;
922 medium.pUnkForRelease = IntPtr.Zero;
923 DragMediums.Add(medium);
925 format = new FORMATETC();
926 format.ptd = IntPtr.Zero;
927 format.dwAspect = DVASPECT.DVASPECT_CONTENT;
929 format.tymed = TYMED.TYMED_HGLOBAL;
930 format.cfFormat = cfFormat;
931 DragFormats.Add(format);
939 private static int FindFormat(FORMATETC pformatetc) {
940 for (int i = 0; i < DragFormats.Count; i++) {
941 if ((((FORMATETC)DragFormats[i]).cfFormat == pformatetc.cfFormat) &&
942 (((FORMATETC)DragFormats[i]).dwAspect == pformatetc.dwAspect) &&
943 ((((FORMATETC)DragFormats[i]).tymed & pformatetc.tymed)) != 0) {
950 private static void BuildFormats(object data) {
955 // Build our formats based on object data
956 if (data is String) {
957 AddFormatAndMedium(ClipboardFormats.CF_TEXT, data);
958 AddFormatAndMedium(ClipboardFormats.CF_UNICODETEXT, data);
959 AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
960 } else if (data is Bitmap) {
961 AddFormatAndMedium(ClipboardFormats.CF_DIB, data);
962 } else if (data is ICollection) {
963 // FIXME - test with .Net and found how this is handled
964 AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
965 } else if (data is ISerializable) {
966 // FIXME - test with .Net and found how this is handled
970 internal static DragDropEffects StartDrag(IntPtr Window, object data, DragDropEffects allowed) {
977 data_object = ComIDataObject.GetUnmanaged();
978 drop_source = ComIDropSource.GetUnmanaged(Window);
980 result = (IntPtr)DragDropEffects.None;
982 Win32DoDragDrop(data_object, drop_source, (IntPtr)allowed, ref result);
985 ComIDataObject.ReleaseUnmanaged(data_object);
986 ComIDropSource.ReleaseUnmanaged(drop_source);
988 DragFormatArray = null;
991 return (DragDropEffects)result.ToInt32();
994 internal static bool UnregisterDropTarget(IntPtr Window) {
995 Win32RevokeDragDrop(Window);
999 internal static bool RegisterDropTarget(IntPtr Window) {
1004 hwnd = Hwnd.ObjectFromWindow(Window);
1009 drop_target = ComIDropTarget.GetUnmanaged(Window);
1010 hwnd.marshal_free_list.Add(drop_target);
1011 result = Win32RegisterDragDrop(Window, drop_target);
1013 if (result != S_OK) {
1020 static MethodInfo CreateFuncPtrInterface(AssemblyBuilder assembly, string MethodName, Type ret_type, int param_count) {
1023 Type[] il_param_types;
1026 mb = assembly.DefineDynamicModule("XplatUIWin32.FuncInterface" + MethodName);
1027 tb = mb.DefineType ("XplatUIWin32.FuncInterface" + MethodName, TypeAttributes.Public);
1029 param_types = new Type[param_count];
1030 il_param_types = new Type[param_count + 1];
1032 il_param_types[param_count] = typeof(IntPtr);
1033 for (int i = 0; i < param_count; i++) {
1034 param_types[i] = typeof(IntPtr);
1035 il_param_types[i] = typeof(IntPtr);
1038 MethodBuilder method = tb.DefineMethod (
1039 MethodName, MethodAttributes.Static | MethodAttributes.Public,
1040 ret_type, il_param_types);
1042 ILGenerator ig = method.GetILGenerator ();
1043 if (param_count > 5) ig.Emit (OpCodes.Ldarg_S, 6);
1044 if (param_count > 4) ig.Emit (OpCodes.Ldarg_S, 5);
1045 if (param_count > 3) ig.Emit (OpCodes.Ldarg_S, 4);
1046 if (param_count > 2) ig.Emit (OpCodes.Ldarg_3);
1047 if (param_count > 1) ig.Emit (OpCodes.Ldarg_2);
1048 if (param_count > 0) ig.Emit (OpCodes.Ldarg_1);
1049 ig.Emit (OpCodes.Ldarg_0);
1050 ig.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, ret_type, param_types);
1051 ig.Emit (OpCodes.Ret);
1053 Type t = tb.CreateType ();
1054 MethodInfo m = t.GetMethod (MethodName);
1059 [DllImport ("ole32.dll", EntryPoint="RegisterDragDrop", CallingConvention=CallingConvention.StdCall)]
1060 private extern static uint Win32RegisterDragDrop(IntPtr Window, IntPtr pDropTarget);
1062 [DllImport ("ole32.dll", EntryPoint="RevokeDragDrop", CallingConvention=CallingConvention.StdCall)]
1063 private extern static int Win32RevokeDragDrop(IntPtr Window);
1065 [DllImport ("ole32.dll", EntryPoint="DoDragDrop", CallingConvention=CallingConvention.StdCall)]
1066 private extern static uint Win32DoDragDrop(IntPtr pDataObject, IntPtr pDropSource, IntPtr dwOKEffect, ref IntPtr pdwEffect);
1068 //[DllImport ("shell32.dll", EntryPoint="DragAcceptFiles", CallingConvention=CallingConvention.StdCall)]
1069 //private extern static int Win32DragAcceptFiles(IntPtr Window, bool fAccept);
1071 [DllImport ("ole32.dll", EntryPoint="OleInitialize", CallingConvention=CallingConvention.StdCall)]
1072 private extern static int Win32OleInitialize(IntPtr pvReserved);
1074 [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
1075 private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, IntPtr lpszFile, int cch);
1077 [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
1078 private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
1080 [DllImport ("shell32.dll", EntryPoint="SHCreateStdEnumFmtEtc", CallingConvention=CallingConvention.StdCall)]
1081 private extern static uint Win32SHCreateStdEnumFmtEtc(uint cfmt, FORMATETC[] afmt, ref IntPtr ppenumFormatEtc);