Win32DnD.cs :  » 2.6.4-mono-.net-core » System.Windows.Forms » System » Windows » Forms » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Windows.Forms 
System.Windows.Forms » System » Windows » Forms » Win32DnD.cs
// 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)
//  Srikanth Madikeri  (csri_1986@yahoo.com) - Win32 Drop files.
// 

// 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 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");

    static 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)
      {
          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 control = Control.FromHandle (window);
        if (control != null) {
          control.DndDrop (DragDropEventArgs);
          return S_FALSE;
        }
 
        Marshal.WriteInt32 (pdwEffect, (int) DragDropEventArgs.Effect);

        return S_OK;
      }
    }

    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: {
          b = XplatUIWin32.StringToAnsi ((string)data);
          hmem = XplatUIWin32.CopyToMoveableMemory (b);
          break;
        }

        case ClipboardFormats.CF_UNICODETEXT: {
          b = XplatUIWin32.StringToUnicode ((string)data);
          hmem = XplatUIWin32.CopyToMoveableMemory (b);
          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.CopyToMoveableMemory (b);
          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);
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.