Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/Win32DnD.cs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/Win32DnD.cs1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Win32DnD.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Win32DnD.cs
new file mode 100644
index 00000000000..b85f172e254
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Win32DnD.cs
@@ -0,0 +1,1097 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok (pbartok@novell.com)
+//
+//
+
+// NOT COMPLETE
+
+using System;
+using System.Collections;
+using System.Drawing;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace System.Windows.Forms {
+ internal class Win32DnD {
+ #region Local Variables
+ private const uint DATADIR_GET = 1;
+ private const uint S_OK = 0x00000000;
+ private const uint S_FALSE = 0x00000001;
+ private const uint DRAGDROP_S_DROP = 0x00040100;
+ private const uint DRAGDROP_S_CANCEL = 0x00040101;
+ private const uint DRAGDROP_S_USEDEFAULTCURSORS = 0x00040102;
+ private const uint E_NOTIMPL = unchecked((uint)0x80004001);
+ private const uint E_NOINTERFACE = unchecked((uint)0x80004002);
+ private const uint E_FAIL = unchecked((uint)0x80004005);
+ private const uint OLE_E_ADVISENOTSUPPORTED = unchecked((uint)0x80040003);
+ private const uint DV_E_FORMATETC = unchecked((uint)0x80040064);
+
+ // To call function pointers
+ private static MethodInfo GetDataMethod;
+ private static object[] GetDataArgs;
+
+ // IDataObject Delegates
+ private static QueryInterfaceDelegate DOQueryInterface;
+ private static AddRefDelegate DOAddRef;
+ private static ReleaseDelegate DORelease;
+ private static GetDataDelegate GetData;
+ private static GetDataHereDelegate GetDataHere;
+ private static QueryGetDataDelegate QueryGetData;
+ private static GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
+ private static SetDataDelegate SetData;
+ private static EnumFormatEtcDelegate EnumFormatEtc;
+ private static DAdviseDelegate DAdvise;
+ private static DUnadviseDelegate DUnadvise;
+ private static EnumDAdviseDelegate EnumDAdvise;
+
+ // IDropSource Delegates
+ private static QueryInterfaceDelegate DSQueryInterface;
+ private static AddRefDelegate DSAddRef;
+ private static ReleaseDelegate DSRelease;
+ private static QueryContinueDragDelegate QueryContinueDrag;
+ private static GiveFeedbackDelegate GiveFeedback;
+
+ // IDropTarget Delegates
+ private static QueryInterfaceDelegate DTQueryInterface;
+ private static AddRefDelegate DTAddRef;
+ private static ReleaseDelegate DTRelease;
+ private static DragEnterDelegate DragEnter;
+ private static DragOverDelegate DragOver;
+ private static DragLeaveDelegate DragLeave;
+ private static DropDelegate Drop;
+
+ private static DragEventArgs DragDropEventArgs;
+ private static GiveFeedbackEventArgs DragFeedbackEventArgs;
+ private static QueryContinueDragEventArgs DragContinueEventArgs;
+ private static ArrayList DragFormats;
+ private static FORMATETC[] DragFormatArray;
+ private static ArrayList DragMediums;
+ #endregion // Local Variables
+
+ #region Delegate Definitions
+ // IUnknown
+ internal delegate uint QueryInterfaceDelegate(IntPtr @this, ref Guid riid, IntPtr ppvObject);
+ internal delegate uint AddRefDelegate(IntPtr @this);
+ internal delegate uint ReleaseDelegate(IntPtr @this);
+
+ // IDataObject
+ internal delegate uint GetDataDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pmedium);
+ internal delegate uint GetDataHereDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium);
+ internal delegate uint QueryGetDataDelegate(IntPtr @this, ref FORMATETC pformatetc);
+ internal delegate uint GetCanonicalFormatEtcDelegate(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut);
+ internal delegate uint SetDataDelegate(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release);
+ internal delegate uint EnumFormatEtcDelegate(IntPtr @this, uint direction, IntPtr ppenumFormatEtc);
+ internal delegate uint DAdviseDelegate(IntPtr @this, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection);
+ internal delegate uint DUnadviseDelegate(IntPtr @this, uint pdwConnection);
+ internal delegate uint EnumDAdviseDelegate(IntPtr @this, IntPtr ppenumAdvise);
+
+ // IDropSource
+ internal delegate uint QueryContinueDragDelegate(IntPtr @this, bool fEscapePressed, uint grfkeyState);
+ internal delegate uint GiveFeedbackDelegate(IntPtr @this, uint pdwEffect);
+
+ // IDropTarget
+ internal delegate uint DragEnterDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ internal delegate uint DragOverDelegate(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ internal delegate uint DragLeaveDelegate(IntPtr @this);
+ internal delegate uint DropDelegate(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect);
+ #endregion // Delegate Definitions
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct FORMATETC {
+ [MarshalAs(UnmanagedType.U2)]
+ internal ClipboardFormats cfFormat;
+ internal IntPtr ptd;
+ internal DVASPECT dwAspect;
+ internal int lindex;
+ internal TYMED tymed;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct STGMEDIUM {
+ internal TYMED tymed;
+ internal IntPtr hHandle;
+ internal IntPtr pUnkForRelease;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
+ internal struct DROPFILES {
+ internal uint pFiles;
+ internal uint pt_x;
+ internal uint pt_y;
+ internal bool fNC;
+ internal bool fWide;
+ internal string pText;
+ }
+
+ internal enum DVASPECT {
+ DVASPECT_CONTENT = 1,
+ DVASPECT_THUMBNAIL = 2,
+ DVASPECT_ICON = 4,
+ DVASPECT_DOCPRINT = 8
+ }
+
+ internal enum TYMED {
+ TYMED_HGLOBAL = 1,
+ TYMED_FILE = 2,
+ TYMED_ISTREAM = 4,
+ TYMED_ISTORAGE = 8,
+ TYMED_GDI = 16,
+ TYMED_MFPICT = 32,
+ TYMED_ENHMF = 64,
+ TYMED_NULL = 0
+ }
+
+ private static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDataObject = new Guid("0000010e-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDropSource = new Guid("00000121-0000-0000-C000-000000000046");
+ private static readonly Guid IID_IDropTarget = new Guid("00000122-0000-0000-C000-000000000046");
+
+ internal Win32DnD() {
+ // Required for all other OLE functions to work
+ Win32OleInitialize(IntPtr.Zero);
+
+ // We reuse those
+ DragDropEventArgs = new DragEventArgs(new DataObject(DataFormats.FileDrop, new string[0]), 0, 0, 0, DragDropEffects.None, DragDropEffects.None);
+ DragFeedbackEventArgs = new GiveFeedbackEventArgs(DragDropEffects.None, true);
+ DragContinueEventArgs = new QueryContinueDragEventArgs(0, false, DragAction.Continue);
+ DragFormats = new ArrayList();
+ DragFormatArray = new FORMATETC[0];
+ DragMediums = new ArrayList();
+
+ // Set up delegates
+ // IDataObject
+ DOQueryInterface = new QueryInterfaceDelegate(ComIDataObject.QueryInterface);
+ DOAddRef = new AddRefDelegate(ComIDataObject.AddRef);
+ DORelease = new ReleaseDelegate(ComIDataObject.Release);
+ GetData = new GetDataDelegate(ComIDataObject.GetData);
+ GetDataHere = new GetDataHereDelegate(ComIDataObject.GetDataHere);
+ QueryGetData = new QueryGetDataDelegate(ComIDataObject.QueryGetData);
+ GetCanonicalFormatEtc = new GetCanonicalFormatEtcDelegate(ComIDataObject.GetCanonicalFormatEtc);
+ SetData = new SetDataDelegate(ComIDataObject.SetData);
+ EnumFormatEtc = new EnumFormatEtcDelegate(ComIDataObject.EnumFormatEtc);
+ DAdvise = new DAdviseDelegate(ComIDataObject.DAdvise);
+ DUnadvise = new DUnadviseDelegate(ComIDataObject.DUnadvise);
+ EnumDAdvise = new EnumDAdviseDelegate(ComIDataObject.EnumDAdvise);
+
+ // IDropSource
+ DSQueryInterface = new QueryInterfaceDelegate(ComIDropSource.QueryInterface);
+ DSAddRef = new AddRefDelegate(ComIDropSource.AddRef);
+ DSRelease = new ReleaseDelegate(ComIDropSource.Release);
+ QueryContinueDrag = new QueryContinueDragDelegate(ComIDropSource.QueryContinueDrag);
+ GiveFeedback = new GiveFeedbackDelegate(ComIDropSource.GiveFeedback);
+
+ // IDropTarget
+ DTQueryInterface = new QueryInterfaceDelegate(ComIDropTarget.QueryInterface);
+ DTAddRef = new AddRefDelegate(ComIDropTarget.AddRef);
+ DTRelease = new ReleaseDelegate(ComIDropTarget.Release);
+ DragEnter = new DragEnterDelegate(ComIDropTarget.DragEnter);
+ DragOver = new DragOverDelegate(ComIDropTarget.DragOver);
+ DragLeave = new DragLeaveDelegate(ComIDropTarget.DragLeave);
+ Drop = new DropDelegate(ComIDropTarget.Drop);
+ }
+
+ internal class ComIDataObject {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DataObjectStruct {
+ internal IntPtr vtbl;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+ internal GetDataDelegate GetData;
+ internal GetDataHereDelegate GetDataHere;
+ internal QueryGetDataDelegate QueryGetData;
+ internal GetCanonicalFormatEtcDelegate GetCanonicalFormatEtc;
+ internal SetDataDelegate SetData;
+ internal EnumFormatEtcDelegate EnumFormatEtc;
+ internal DAdviseDelegate DAdvise;
+ internal DUnadviseDelegate DUnadvise;
+ internal EnumDAdviseDelegate EnumDAdvise;
+ }
+
+ internal static IntPtr GetUnmanaged() {
+ DataObjectStruct data_object;
+ IntPtr data_object_ptr;
+ long offset;
+
+ data_object = new DataObjectStruct();
+
+ data_object.QueryInterface = Win32DnD.DOQueryInterface;
+ data_object.AddRef = Win32DnD.DOAddRef;
+ data_object.Release = Win32DnD.DORelease;
+ data_object.GetData = Win32DnD.GetData;
+ data_object.GetDataHere = Win32DnD.GetDataHere;
+ data_object.QueryGetData = Win32DnD.QueryGetData;
+ data_object.GetCanonicalFormatEtc = Win32DnD.GetCanonicalFormatEtc;
+ data_object.SetData = Win32DnD.SetData;
+ data_object.EnumFormatEtc = Win32DnD.EnumFormatEtc;
+ data_object.DAdvise = Win32DnD.DAdvise;
+ data_object.DUnadvise = Win32DnD.DUnadvise;
+ data_object.EnumDAdvise = Win32DnD.EnumDAdvise;
+
+ data_object_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DataObjectStruct)));
+ Marshal.StructureToPtr(data_object, data_object_ptr, false);
+
+ // Update vtbl pointer
+ offset = data_object_ptr.ToInt64();
+ offset += Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(data_object_ptr, new IntPtr(offset));
+
+ return data_object_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr data_object_ptr) {
+ Marshal.FreeHGlobal(data_object_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDataObject.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static STGMEDIUM medium = new STGMEDIUM();
+ internal static uint GetData(IntPtr this_, ref FORMATETC pformatetcIn, IntPtr pmedium) {
+ int index;
+
+ index = FindFormat(pformatetcIn);
+ if (index != -1) {
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+ medium.hHandle = XplatUIWin32.DupGlobalMem(((STGMEDIUM)DragMediums[index]).hHandle);
+ medium.pUnkForRelease = IntPtr.Zero;
+ try {
+ Marshal.StructureToPtr(medium, pmedium, false);
+ }
+ catch (Exception e) {
+ Console.WriteLine("Error: {0}", e.Message);
+ }
+ return S_OK;
+ }
+
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint GetDataHere(IntPtr @this, ref FORMATETC pformatetc, ref STGMEDIUM pmedium) {
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint QueryGetData(IntPtr @this, ref FORMATETC pformatetc) {
+ if (FindFormat(pformatetc) != -1) {
+ return S_OK;
+ }
+ return DV_E_FORMATETC;
+ }
+
+ internal static uint GetCanonicalFormatEtc(IntPtr @this, ref FORMATETC pformatetcIn, IntPtr pformatetcOut) {
+ Marshal.WriteIntPtr(pformatetcOut, Marshal.SizeOf(typeof(IntPtr)), IntPtr.Zero);
+ return E_NOTIMPL;
+ }
+
+ internal static uint SetData(IntPtr this_, ref FORMATETC pformatetc, ref STGMEDIUM pmedium, bool release) {
+ return E_NOTIMPL;
+ }
+
+ internal static uint EnumFormatEtc(IntPtr this_, uint direction, IntPtr ppenumFormatEtc) {
+ if (direction == DATADIR_GET) {
+ IntPtr ppenum_ptr;
+
+ ppenum_ptr = IntPtr.Zero;
+ DragFormatArray = new FORMATETC[DragFormats.Count];
+
+ for (int i = 0; i < DragFormats.Count; i++) {
+ DragFormatArray[i] = (FORMATETC)DragFormats[i];
+ }
+ Win32SHCreateStdEnumFmtEtc((uint)DragFormatArray.Length, DragFormatArray, ref ppenum_ptr);
+ Marshal.WriteIntPtr(ppenumFormatEtc, ppenum_ptr);
+ return S_OK;
+ }
+ return E_NOTIMPL;
+ }
+
+ internal static uint DAdvise(IntPtr this_, ref FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal static uint DUnadvise(IntPtr this_, uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal static uint EnumDAdvise(IntPtr this_, IntPtr ppenumAdvise) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+ }
+
+ internal class ComIDataObjectUnmanaged {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDataObjectUnmanaged {
+ internal IntPtr QueryInterface;
+ internal IntPtr AddRef;
+ internal IntPtr Release;
+ internal IntPtr GetData;
+ internal IntPtr GetDataHere;
+ internal IntPtr QueryGetData;
+ internal IntPtr GetCanonicalFormatEtc;
+ internal IntPtr SetData;
+ internal IntPtr EnumFormatEtc;
+ internal IntPtr DAdvise;
+ internal IntPtr DUnadvise;
+ internal IntPtr EnumDAdvise;
+ }
+
+ private static bool Initialized;
+ private static MethodInfo GetDataMethod;
+ private static MethodInfo GetDataHereMethod;
+ private static MethodInfo QueryGetDataMethod;
+ private static MethodInfo GetCanonicalFormatEtcMethod;
+ private static MethodInfo SetDataMethod;
+ private static MethodInfo EnumFormatEtcMethod;
+ private static MethodInfo DAdviseMethod;
+ private static MethodInfo DUnadviseMethod;
+ private static MethodInfo EnumDAdviseMethod;
+ private static object[] MethodArguments;
+
+ private IDataObjectUnmanaged vtbl;
+ private IntPtr @this;
+
+ internal ComIDataObjectUnmanaged(IntPtr data_object_ptr) {
+ if (!Initialized) {
+ Initialize();
+ }
+
+ vtbl = new IDataObjectUnmanaged();
+ @this = data_object_ptr;
+ try {
+ vtbl = (IDataObjectUnmanaged)Marshal.PtrToStructure(Marshal.ReadIntPtr(data_object_ptr), typeof(IDataObjectUnmanaged));
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Exception {0}", e.Message);
+ }
+ }
+
+ private static void Initialize() {
+ AssemblyName assembly;
+ AssemblyBuilder assembly_builder;
+
+ if (Initialized) {
+ return;
+ }
+
+ assembly = new AssemblyName();
+ assembly.Name = "XplatUIWin32.FuncPtrInterface";
+ assembly_builder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
+
+ MethodArguments = new object[6];
+ GetDataMethod = CreateFuncPtrInterface(assembly_builder, "GetData", typeof(uint), 3);
+ GetDataHereMethod = CreateFuncPtrInterface(assembly_builder, "GetDataHere", typeof(uint), 3);
+ QueryGetDataMethod = CreateFuncPtrInterface(assembly_builder, "QueryGetData", typeof(uint), 2);
+ GetCanonicalFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "GetCanonicalFormatEtc", typeof(uint), 3);
+ SetDataMethod = CreateFuncPtrInterface(assembly_builder, "SetData", typeof(uint), 4);
+ EnumFormatEtcMethod = CreateFuncPtrInterface(assembly_builder, "EnumFormatEtc", typeof(uint), 3);
+ DAdviseMethod = CreateFuncPtrInterface(assembly_builder, "DAdvise", typeof(uint), 5);
+ DUnadviseMethod = CreateFuncPtrInterface(assembly_builder, "DUnadvise", typeof(uint), 2);
+ EnumDAdviseMethod = CreateFuncPtrInterface(assembly_builder, "EnumDAdvise", typeof(uint), 2);
+
+ Initialized = true;
+ }
+
+ internal uint QueryInterface(Guid riid, IntPtr ppvObject) {
+ uint ret;
+ IntPtr riid_ptr;
+
+ riid_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
+ Marshal.StructureToPtr(riid, riid_ptr, false);
+
+ MethodArguments[0] = vtbl.QueryInterface;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = riid_ptr;
+ MethodArguments[3] = ppvObject;
+
+ try {
+ ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(riid_ptr);
+
+ return ret;
+ }
+
+ internal uint AddRef() {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal uint Release() {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal uint GetData(FORMATETC pformatetcIn, ref STGMEDIUM pmedium) {
+ uint ret;
+ IntPtr pformatetcIn_ptr;
+ IntPtr pmedium_ptr;
+
+ pformatetcIn_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
+ Marshal.StructureToPtr(pformatetcIn, pformatetcIn_ptr, false);
+
+ pmedium_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STGMEDIUM)));
+
+ MethodArguments[0] = vtbl.GetData;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = pformatetcIn_ptr;
+ MethodArguments[3] = pmedium_ptr;
+
+ try {
+ ret = (uint)GetDataMethod.Invoke(null, MethodArguments);
+ Marshal.PtrToStructure(pmedium_ptr, pmedium);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(pformatetcIn_ptr);
+ Marshal.FreeHGlobal(pmedium_ptr);
+
+ return ret;
+ }
+
+ internal uint GetDataHere(FORMATETC pformatetc, ref STGMEDIUM pmedium) {
+ return E_NOTIMPL;
+ }
+
+ internal uint QueryGetData(FORMATETC pformatetc) {
+ uint ret;
+ IntPtr pformatetc_ptr;
+
+ pformatetc_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(FORMATETC)));
+ Marshal.StructureToPtr(pformatetc, pformatetc_ptr, false);
+
+ MethodArguments[0] = vtbl.GetData;
+ MethodArguments[1] = this.@this;
+ MethodArguments[2] = pformatetc_ptr;
+
+ try {
+ ret = (uint)QueryGetDataMethod.Invoke(null, MethodArguments);
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Caught exception {0}", e.Message);
+ ret = E_FAIL;
+ }
+
+ Marshal.FreeHGlobal(pformatetc_ptr);
+
+ return ret;
+ }
+
+ internal uint GetCanonicalFormatEtc(FORMATETC pformatetcIn, ref FORMATETC pformatetcOut) {
+ return E_NOTIMPL;
+ }
+
+ internal uint SetData(FORMATETC pformatetc, STGMEDIUM pmedium, bool release) {
+ return E_NOTIMPL;
+ }
+
+ internal uint EnumFormatEtc(uint direction, IntPtr ppenumFormatEtc) {
+ return E_NOTIMPL;
+ }
+
+ internal uint DAdvise(FORMATETC pformatetc, uint advf, IntPtr pAdvSink, ref uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal uint DUnadvise(uint pdwConnection) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ internal uint EnumDAdvise(IntPtr ppenumAdvise) {
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+ }
+
+
+ internal class ComIDropSource {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDropSource {
+ internal IntPtr vtbl;
+ internal IntPtr Window;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+ internal QueryContinueDragDelegate QueryContinueDrag;
+ internal GiveFeedbackDelegate GiveFeedback;
+ }
+
+ internal static IntPtr GetUnmanaged(IntPtr Window) {
+ IDropSource drop_source;
+ IntPtr drop_source_ptr;
+ long offset;
+
+ drop_source = new IDropSource();
+ drop_source.QueryInterface = Win32DnD.DSQueryInterface;
+ drop_source.AddRef = Win32DnD.DSAddRef;
+ drop_source.Release = Win32DnD.DSRelease;
+ drop_source.QueryContinueDrag = Win32DnD.QueryContinueDrag;
+ drop_source.GiveFeedback = Win32DnD.GiveFeedback;
+ drop_source.Window = Window;
+
+ drop_source_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_source));
+ Marshal.StructureToPtr(drop_source, drop_source_ptr, false);
+
+ // Update vtbl pointer
+ offset = drop_source_ptr.ToInt64();
+ offset += 2 * Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(drop_source_ptr, new IntPtr(offset));
+
+ return drop_source_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr drop_source_ptr) {
+ Marshal.FreeHGlobal(drop_source_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDropSource.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static uint QueryContinueDrag(IntPtr @this, bool fEscapePressed, uint grfkeyState) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ // LAMESPEC? - according to MSDN, when the any mousebutton is *pressed* it defaults to Drop.
+ // According to COM customary behaviour it's the other way round; which is what we do here
+ if (fEscapePressed) {
+ DragContinueEventArgs.drag_action = DragAction.Cancel;
+ } else if ((grfkeyState & (1+2+16)) == 0) { // Left, middle and right mouse button not pressed
+ DragContinueEventArgs.drag_action = DragAction.Drop;
+ } else {
+ DragContinueEventArgs.drag_action = DragAction.Continue;
+ }
+
+ DragContinueEventArgs.escape_pressed = fEscapePressed;
+ DragContinueEventArgs.key_state = (int)grfkeyState;
+
+ Control.FromHandle(window).DndContinueDrag(DragContinueEventArgs);
+
+ if (DragContinueEventArgs.drag_action == DragAction.Cancel) {
+ return DRAGDROP_S_CANCEL;
+ } else if (DragContinueEventArgs.drag_action == DragAction.Drop) {
+ return DRAGDROP_S_DROP;
+ }
+ return S_OK;
+ }
+
+ internal static uint GiveFeedback(IntPtr @this, uint pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragFeedbackEventArgs.effect = (DragDropEffects)pdwEffect;
+ DragFeedbackEventArgs.use_default_cursors = true;
+
+ Control.FromHandle(window).DndFeedback(DragFeedbackEventArgs);
+
+ if (DragFeedbackEventArgs.use_default_cursors) {
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+ }
+ return S_OK;
+ }
+ }
+
+ internal class ComIDropTarget {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IDropTarget {
+ internal IntPtr vtbl;
+ internal IntPtr Window;
+ internal QueryInterfaceDelegate QueryInterface;
+ internal AddRefDelegate AddRef;
+ internal ReleaseDelegate Release;
+
+ internal DragEnterDelegate DragEnter;
+ internal DragOverDelegate DragOver;
+ internal DragLeaveDelegate DragLeave;
+ internal DropDelegate Drop;
+ }
+
+ internal static IntPtr GetUnmanaged(IntPtr Window) {
+ IDropTarget drop_target;
+ IntPtr drop_target_ptr;
+ long offset;
+
+ drop_target = new IDropTarget();
+ drop_target.QueryInterface = Win32DnD.DTQueryInterface;
+ drop_target.AddRef = Win32DnD.DTAddRef;
+ drop_target.Release = Win32DnD.DTRelease;
+ drop_target.DragEnter = Win32DnD.DragEnter;
+ drop_target.DragOver = Win32DnD.DragOver;
+ drop_target.DragLeave = Win32DnD.DragLeave;
+ drop_target.Drop = Win32DnD.Drop;
+ drop_target.Window = Window;
+
+ drop_target_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(drop_target));
+ Marshal.StructureToPtr(drop_target, drop_target_ptr, false);
+
+ // Update vtbl pointer
+ offset = drop_target_ptr.ToInt64();
+ offset += 2 * Marshal.SizeOf(typeof(IntPtr));
+ Marshal.WriteIntPtr(drop_target_ptr, new IntPtr(offset));
+
+ return drop_target_ptr;
+ }
+
+ internal static void ReleaseUnmanaged(IntPtr drop_target_ptr) {
+ Marshal.FreeHGlobal(drop_target_ptr);
+ }
+
+ internal static uint QueryInterface(IntPtr @this, ref Guid riid, IntPtr ppvObject) {
+ try {
+ if (IID_IUnknown.Equals(riid) || IID_IDropTarget.Equals(riid)) {
+ Marshal.WriteIntPtr(ppvObject, @this);
+ return S_OK;
+ }
+ }
+
+ catch (Exception e) {
+ Console.WriteLine("Got exception {0}", e.Message);
+ }
+
+ Marshal.WriteIntPtr(ppvObject, IntPtr.Zero);
+ return E_NOINTERFACE;
+ }
+
+ internal static uint AddRef(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 1;
+ }
+
+ internal static uint Release(IntPtr @this) {
+ // We only use this for DnD, try and fake it
+ return 0;
+ }
+
+ internal static uint DragEnter(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragDropEventArgs.x = pt_x.ToInt32();
+ DragDropEventArgs.y = pt_y.ToInt32();
+ DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
+ DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
+ DragDropEventArgs.keystate = (int)grfkeyState;
+
+ Control.FromHandle(window).DndEnter(DragDropEventArgs);
+
+ Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
+
+ return S_OK;
+ }
+
+ internal static uint DragOver(IntPtr @this, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ DragDropEventArgs.x = pt_x.ToInt32();
+ DragDropEventArgs.y = pt_y.ToInt32();
+ DragDropEventArgs.allowed_effect = (DragDropEffects)Marshal.ReadIntPtr(pdwEffect).ToInt32();
+ DragDropEventArgs.current_effect = DragDropEventArgs.AllowedEffect;
+ DragDropEventArgs.keystate = (int)grfkeyState;
+
+ Control.FromHandle(window).DndOver(DragDropEventArgs);
+
+ Marshal.WriteInt32(pdwEffect, (int)DragDropEventArgs.Effect);
+
+ return S_OK;
+ }
+
+ internal static uint DragLeave(IntPtr @this) {
+ IntPtr window;
+
+ window = Marshal.ReadIntPtr(@this, Marshal.SizeOf(typeof(IntPtr)));
+
+ Control.FromHandle(window).DndLeave(EventArgs.Empty);
+
+ return S_OK;
+ }
+
+ internal static uint Drop(IntPtr @this, IntPtr pDataObj, uint grfkeyState, IntPtr pt_x, IntPtr pt_y, IntPtr pdwEffect) {
+ throw new Exception("Yeah baby, gimme a ride to WM_DROPFILES land");
+
+ #if InTheFuture
+ ComIDataObjectUnmanaged data_object;
+ FORMATETC format;
+ STGMEDIUM medium;
+ uint result;
+ IntPtr mem;
+
+
+ data_object = new ComIDataObjectUnmanaged(pDataObj);
+
+ format = new FORMATETC();
+ format.cfFormat = ClipboardFormats.CF_HDROP;
+ format.ptd = IntPtr.Zero;
+ format.dwAspect = DVASPECT.DVASPECT_CONTENT;
+ format.lindex = -1;
+ format.tymed = TYMED.TYMED_HGLOBAL;
+
+ medium = new STGMEDIUM();
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+
+ //mem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
+ //result = data_object.QueryInterface(IID_IDataObject, mem);
+ //Marshal.FreeHGlobal(mem);
+
+ //result = data_object.AddRef();
+
+ result = data_object.QueryGetData(format);
+
+ result = data_object.GetData(format, ref medium);
+
+ return E_NOTIMPL;
+ #endif
+ }
+ }
+
+ internal static bool HandleWMDropFiles(ref MSG msg) {
+ IntPtr hDrop;
+ int count;
+ StringBuilder sb;
+ string[] dropfiles;
+
+ hDrop = msg.wParam;
+ count = Win32DragQueryFile(hDrop, -1, IntPtr.Zero, 0);
+
+ dropfiles = new string[count];
+
+ sb = new StringBuilder(256);
+ for (int i = 0; i < count; i++) {
+ Win32DragQueryFile(hDrop, i, sb, sb.Capacity);
+ dropfiles[i] = sb.ToString();
+ }
+
+ DragDropEventArgs.Data.SetData(DataFormats.FileDrop, dropfiles);
+
+ Control.FromHandle(msg.hwnd).DndDrop(DragDropEventArgs);
+
+ return true;
+ }
+
+ private static bool AddFormatAndMedium(ClipboardFormats cfFormat, object data) {
+ STGMEDIUM medium;
+ FORMATETC format;
+ IntPtr hmem;
+ IntPtr hmem_ptr;
+ byte[] b;
+
+ switch(cfFormat) {
+ case ClipboardFormats.CF_TEXT: {
+ hmem = Marshal.StringToHGlobalAnsi((string)data);
+ break;
+ }
+
+ case ClipboardFormats.CF_UNICODETEXT: {
+ hmem = Marshal.StringToHGlobalUni((string)data);
+ break;
+ }
+
+ case ClipboardFormats.CF_HDROP: {
+ IEnumerator e;
+ StringBuilder sb;
+ long hmem_string_ptr;
+ IntPtr string_buffer;
+ int string_buffer_size;
+
+ sb = new StringBuilder();
+
+ // Make sure object is enumerable; otherwise
+ if ((data is string) || !(data is IEnumerable)) {
+ sb.Append(data.ToString());
+ sb.Append('\0');
+ sb.Append('\0');
+ } else {
+ e = ((IEnumerable)data).GetEnumerator();
+ while (e.MoveNext()) {
+ sb.Append(e.Current.ToString());
+ sb.Append('\0');
+ }
+ sb.Append('\0');
+ }
+
+ string_buffer = Marshal.StringToHGlobalUni(sb.ToString());
+ string_buffer_size = (int)XplatUIWin32.Win32GlobalSize(string_buffer);
+
+ // Write DROPFILES structure
+ hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, 0x14 + string_buffer_size);
+ hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem);
+ Marshal.WriteInt32(hmem_ptr, 0x14); // pFiles
+ Marshal.WriteInt32(hmem_ptr, 1 * Marshal.SizeOf(typeof(uint)), 0); // point.x
+ Marshal.WriteInt32(hmem_ptr, 2 * Marshal.SizeOf(typeof(uint)), 0); // point.y
+ Marshal.WriteInt32(hmem_ptr, 3 * Marshal.SizeOf(typeof(uint)), 0); // fNc
+ Marshal.WriteInt32(hmem_ptr, 4 * Marshal.SizeOf(typeof(uint)), 1); // fWide
+
+ hmem_string_ptr = (long)hmem_ptr;
+ hmem_string_ptr += 0x14;
+
+ XplatUIWin32.Win32CopyMemory(new IntPtr(hmem_string_ptr), string_buffer, string_buffer_size);
+ Marshal.FreeHGlobal(string_buffer);
+ XplatUIWin32.Win32GlobalUnlock(hmem_ptr);
+
+ break;
+ }
+
+ case ClipboardFormats.CF_DIB: {
+ b = XplatUIWin32.ImageToDIB((Image)data);
+
+ hmem = XplatUIWin32.Win32GlobalAlloc(XplatUIWin32.GAllocFlags.GMEM_MOVEABLE | XplatUIWin32.GAllocFlags.GMEM_DDESHARE, b.Length);
+ hmem_ptr = XplatUIWin32.Win32GlobalLock(hmem);
+ Marshal.Copy(b, 0, hmem_ptr, b.Length);
+ XplatUIWin32.Win32GlobalUnlock(hmem);
+ break;
+ }
+
+ default: {
+ hmem = IntPtr.Zero;
+ break;
+ }
+ }
+
+ if (hmem != IntPtr.Zero) {
+ medium = new STGMEDIUM();
+ medium.tymed = TYMED.TYMED_HGLOBAL;
+ medium.hHandle = hmem;
+ medium.pUnkForRelease = IntPtr.Zero;
+ DragMediums.Add(medium);
+
+ format = new FORMATETC();
+ format.ptd = IntPtr.Zero;
+ format.dwAspect = DVASPECT.DVASPECT_CONTENT;
+ format.lindex = -1;
+ format.tymed = TYMED.TYMED_HGLOBAL;
+ format.cfFormat = cfFormat;
+ DragFormats.Add(format);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static int FindFormat(FORMATETC pformatetc) {
+ for (int i = 0; i < DragFormats.Count; i++) {
+ if ((((FORMATETC)DragFormats[i]).cfFormat == pformatetc.cfFormat) &&
+ (((FORMATETC)DragFormats[i]).dwAspect == pformatetc.dwAspect) &&
+ ((((FORMATETC)DragFormats[i]).tymed & pformatetc.tymed)) != 0) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static void BuildFormats(object data) {
+
+ DragFormats.Clear();
+ DragMediums.Clear();
+
+ // Build our formats based on object data
+ if (data is String) {
+ AddFormatAndMedium(ClipboardFormats.CF_TEXT, data);
+ AddFormatAndMedium(ClipboardFormats.CF_UNICODETEXT, data);
+ AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
+ } else if (data is Bitmap) {
+ AddFormatAndMedium(ClipboardFormats.CF_DIB, data);
+ } else if (data is ICollection) {
+ // FIXME - test with .Net and found how this is handled
+ AddFormatAndMedium(ClipboardFormats.CF_HDROP, data);
+ } else if (data is ISerializable) {
+ // FIXME - test with .Net and found how this is handled
+ }
+ }
+
+ internal static DragDropEffects StartDrag(IntPtr Window, object data, DragDropEffects allowed) {
+ IntPtr result;
+ IntPtr data_object;
+ IntPtr drop_source;
+
+ BuildFormats(data);
+
+ data_object = ComIDataObject.GetUnmanaged();
+ drop_source = ComIDropSource.GetUnmanaged(Window);
+
+ result = (IntPtr)DragDropEffects.None;
+
+ Win32DoDragDrop(data_object, drop_source, (IntPtr)allowed, ref result);
+
+ // Cleanup again
+ ComIDataObject.ReleaseUnmanaged(data_object);
+ ComIDropSource.ReleaseUnmanaged(drop_source);
+ DragFormats.Clear();
+ DragFormatArray = null;
+ DragMediums.Clear();
+
+ return (DragDropEffects)result.ToInt32();
+ }
+
+ internal static bool UnregisterDropTarget(IntPtr Window) {
+ Win32RevokeDragDrop(Window);
+ return true;
+ }
+
+ internal static bool RegisterDropTarget(IntPtr Window) {
+ Hwnd hwnd;
+ IntPtr drop_target;
+ uint result;
+
+ hwnd = Hwnd.ObjectFromWindow(Window);
+ if (hwnd == null) {
+ return false;
+ }
+
+ drop_target = ComIDropTarget.GetUnmanaged(Window);
+ hwnd.marshal_free_list.Add(drop_target);
+ result = Win32RegisterDragDrop(Window, drop_target);
+
+ if (result != S_OK) {
+ return false;
+ }
+ return true;
+ }
+
+ // Thanks, Martin
+ static MethodInfo CreateFuncPtrInterface(AssemblyBuilder assembly, string MethodName, Type ret_type, int param_count) {
+ ModuleBuilder mb;
+ TypeBuilder tb;
+ Type[] il_param_types;
+ Type[] param_types;
+
+ mb = assembly.DefineDynamicModule("XplatUIWin32.FuncInterface" + MethodName);
+ tb = mb.DefineType ("XplatUIWin32.FuncInterface" + MethodName, TypeAttributes.Public);
+
+ param_types = new Type[param_count];
+ il_param_types = new Type[param_count + 1];
+
+ il_param_types[param_count] = typeof(IntPtr);
+ for (int i = 0; i < param_count; i++) {
+ param_types[i] = typeof(IntPtr);
+ il_param_types[i] = typeof(IntPtr);
+ }
+
+ MethodBuilder method = tb.DefineMethod (
+ MethodName, MethodAttributes.Static | MethodAttributes.Public,
+ ret_type, il_param_types);
+
+ ILGenerator ig = method.GetILGenerator ();
+ if (param_count > 5) ig.Emit (OpCodes.Ldarg_S, 6);
+ if (param_count > 4) ig.Emit (OpCodes.Ldarg_S, 5);
+ if (param_count > 3) ig.Emit (OpCodes.Ldarg_S, 4);
+ if (param_count > 2) ig.Emit (OpCodes.Ldarg_3);
+ if (param_count > 1) ig.Emit (OpCodes.Ldarg_2);
+ if (param_count > 0) ig.Emit (OpCodes.Ldarg_1);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.EmitCalli (OpCodes.Calli, CallingConvention.StdCall, ret_type, param_types);
+ ig.Emit (OpCodes.Ret);
+
+ Type t = tb.CreateType ();
+ MethodInfo m = t.GetMethod (MethodName);
+
+ return m;
+ }
+
+ [DllImport ("ole32.dll", EntryPoint="RegisterDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32RegisterDragDrop(IntPtr Window, IntPtr pDropTarget);
+
+ [DllImport ("ole32.dll", EntryPoint="RevokeDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32RevokeDragDrop(IntPtr Window);
+
+ [DllImport ("ole32.dll", EntryPoint="DoDragDrop", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32DoDragDrop(IntPtr pDataObject, IntPtr pDropSource, IntPtr dwOKEffect, ref IntPtr pdwEffect);
+
+ [DllImport ("shell32.dll", EntryPoint="DragAcceptFiles", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32DragAcceptFiles(IntPtr Window, bool fAccept);
+
+ [DllImport ("ole32.dll", EntryPoint="OleInitialize", CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32OleInitialize(IntPtr pvReserved);
+
+ [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, IntPtr lpszFile, int cch);
+
+ [DllImport ("shell32.dll", EntryPoint="DragQueryFileW", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.StdCall)]
+ private extern static int Win32DragQueryFile(IntPtr hDrop, int iFile, StringBuilder lpszFile, int cch);
+
+ [DllImport ("shell32.dll", EntryPoint="SHCreateStdEnumFmtEtc", CallingConvention=CallingConvention.StdCall)]
+ private extern static uint Win32SHCreateStdEnumFmtEtc(uint cfmt, FORMATETC[] afmt, ref IntPtr ppenumFormatEtc);
+ }
+}