private void tv1_HandleDestroyed(object sender, EventArgs e) { //Debug.WriteLine("in handle destroyed") if (this.AllowDrop) { int res; res = ShellDll.RevokeDragDrop(tv1.Handle); if (res != 0) { Debug.WriteLine("RevokeDragDrop returned " + res); } //Else // Debug.WriteLine("HandleDestroyed with allowdrop false") } }
public ExpTree() { //This call is required by the Windows Form Designer. InitializeComponent(); //Add any initialization after the InitializeComponent() call //setting the imagelist here allows many good things to happen, but // also one bad thing -- the "tooltip" like display of selectednode.text // is made invisible. This remains a problem to be solved. SystemImageListManager.SetTreeViewImageList(tv1, false); StartUpDirectoryChanged += new ExpTreeLib.ExpTree.StartUpDirectoryChangedEventHandler(OnStartUpDirectoryChanged); OnStartUpDirectoryChanged(m_StartUpDirectory); if (tv1.IsHandleCreated) { if (this.AllowDrop) { if (Application.OleRequired() == System.Threading.ApartmentState.STA) { DragDropHandler = new TVDragWrapper(tv1); DragDropHandler.ShDragEnter += new ExpTreeLib.TVDragWrapper.ShDragEnterEventHandler(DragWrapper_ShDragEnter); DragDropHandler.ShDragLeave += new ExpTreeLib.TVDragWrapper.ShDragLeaveEventHandler(DragWrapper_ShDragLeave); DragDropHandler.ShDragOver += new ExpTreeLib.TVDragWrapper.ShDragOverEventHandler(DragWrapper_ShDragOver); DragDropHandler.ShDragDrop += new ExpTreeLib.TVDragWrapper.ShDragDropEventHandler(DragWrapper_ShDragDrop); int res; res = ShellDll.RegisterDragDrop(tv1.Handle, DragDropHandler); if (!(res == 0) || (res == -2147221247)) { Marshal.ThrowExceptionForHR(res); throw (new Exception("Failed to Register DragDrop for " + this.Name)); } } else { throw (new ThreadStateException("ThreadMustBeSTA")); } } } }
///<Summary>Given an IDataObject from some non-net source, Build the /// m_DragList ArrayList. /// Also ensure that the IDataObject has "Shell IDList Array" formatted data /// If not, build it in m_StreamCIDA, if so, copy to m_StreamCIDA ///If dealing with all FileSystem Items, /// </Summary> private void ProcessCOMIDataObject(ShellDll.IDataObject IDO) { //Don't even look for an ArrayList. If there, we don't know how to access //Therefore, we need either a "FileDrop" or a "Shell IDList Array" to //extract the info for m_DragList and to ensure that the IDataObject //actually has a "Shell IDList Array" int HR; //general use response variable ShellDll.FORMATETC fmtEtc; ShellDll.STGMEDIUM stg; //ensure m_StreamCIDA is nothing - will test for this later m_StreamCIDA = null; //First check for "Shell IDList Array" -- preferred in this case (and most others) int cf = ShellDll.RegisterClipboardFormat("Shell IDList Array"); if (cf != 0) { fmtEtc.cfFormat = (ShellDll.CF)cf; fmtEtc.lindex = -1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; stg.hGlobal = IntPtr.Zero; stg.pUnkForRelease = IntPtr.Zero; stg.tymed = (int)ShellDll.TYMED.HGLOBAL; HR = IDO.GetData(ref fmtEtc, ref stg); if (HR == 0) { IntPtr cidaptr = Marshal.ReadIntPtr(stg.hGlobal); m_StreamCIDA = MakeStreamFromCIDA(cidaptr); MakeDragListFromCIDA(); ShellDll.ReleaseStgMedium(ref stg); //done with this } else { try { Marshal.ThrowExceptionForHR(HR); } catch (Exception) { } } } //Check for "FileDrop" (CF.HDROP) if we have to if (m_Draglist.Count < 1) //skip this if already have list { fmtEtc.cfFormat = ShellDll.CF.HDROP; fmtEtc.lindex = -1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; stg.hGlobal = IntPtr.Zero; stg.pUnkForRelease = IntPtr.Zero; stg.tymed = 0; HR = IDO.GetData(ref fmtEtc, ref stg); if (HR == 0) //we have an HDROP and stg.hGlobal points to the info { IntPtr pHdrop = Marshal.ReadIntPtr(stg.hGlobal); int nrItems = ShellDll.DragQueryFile(pHdrop, -1, null, 0); int i; for (i = 0; i <= nrItems - 1; i++) { int plen = ShellDll.DragQueryFile(pHdrop, i, null, 0); StringBuilder SB = new StringBuilder(plen + 1); int flen = ShellDll.DragQueryFile(pHdrop, i, SB, plen + 1); Debug.WriteLine("Fetched from HDROP: " + SB.ToString()); try //if GetCShitem returns Nothing(it's failure marker) then catch it { m_Draglist.Add(ExpTreeLib.CShItem.GetCShItem(SB.ToString())); } catch (Exception ex) // in this case, just skip it { Debug.WriteLine("Error: CMyDataObject.ProcessComIDataObject - Adding via HDROP" + "\r\n" + "\t" + ex.Message); } } ShellDll.ReleaseStgMedium(ref stg); //done with this stg //Else // Marshal.ThrowExceptionForHR(HR) } } //Have done what we can to get m_DragList -- exit on failure if (m_Draglist.Count < 1) //Can't do any more -- Quit { return; //leaving m_IsValid as False } //May not have Shell IDList Array in IDataObject. If not, give it one if (m_StreamCIDA == null) //IDO does not yet have "Shell IDList Array" Data { m_StreamCIDA = MakeShellIDArray(m_Draglist); if (m_StreamCIDA == null) { return; //failed to make it } //Now put the CIDA into the original IDataObject fmtEtc.cfFormat = (ShellDll.CF)cf; //registered at routine entry fmtEtc.lindex = -1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; //note the hGlobal item in stg is a pointer to a pointer->Data IntPtr m_hg = Marshal.AllocHGlobal(Convert.ToInt32(m_StreamCIDA.Length)); Marshal.Copy(m_StreamCIDA.ToArray(), 0, m_hg, (int)m_StreamCIDA.Length); IntPtr hg = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(hg, 0, m_hg); stg.tymed = (int)ShellDll.TYMED.HGLOBAL; stg.hGlobal = hg; stg.pUnkForRelease = IntPtr.Zero; HR = IDO.SetData(ref fmtEtc, ref stg, true); //callee responsible for releasing stg if (HR == 0) { m_IsValid = true; } else //failed -- we have to release stg -- and leave m_IsValid as False { ShellDll.ReleaseStgMedium(ref stg); return; //m_isvalid stays False } } m_IsValid = true; //already had a Shell IDList Array, so all is OK }
///<Summary>Given an IDataObject from some non-net source, Build the /// m_DragList ArrayList. /// Also ensure that the IDataObject has "Shell IDList Array" formatted data /// If not, build it in m_StreamCIDA, if so, copy to m_StreamCIDA ///If dealing with all FileSystem Items, /// </Summary> private void ProcessCOMIDataObject(ShellDll.IDataObject IDO) { //Don't even look for an ArrayList. If there, we don't know how to access //Therefore, we need either a "FileDrop" or a "Shell IDList Array" to //extract the info for m_DragList and to ensure that the IDataObject //actually has a "Shell IDList Array" int HR; //general use response variable ShellDll.FORMATETC fmtEtc; ShellDll.STGMEDIUM stg; //ensure m_StreamCIDA is nothing - will test for this later m_StreamCIDA = null; //First check for "Shell IDList Array" -- preferred in this case (and most others) int cf = ShellDll.RegisterClipboardFormat("Shell IDList Array"); if (cf != 0) { fmtEtc.cfFormat = (ShellDll.CF)cf; fmtEtc.lindex = - 1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; stg.hGlobal = IntPtr.Zero; stg.pUnkForRelease = IntPtr.Zero; stg.tymed = (int)ShellDll.TYMED.HGLOBAL; HR = IDO.GetData(ref fmtEtc, ref stg); if (HR == 0) { IntPtr cidaptr = Marshal.ReadIntPtr(stg.hGlobal); m_StreamCIDA = MakeStreamFromCIDA(cidaptr); MakeDragListFromCIDA(); ShellDll.ReleaseStgMedium(ref stg); //done with this } else { try { Marshal.ThrowExceptionForHR(HR); } catch (Exception) { } } } //Check for "FileDrop" (CF.HDROP) if we have to if (m_Draglist.Count < 1) //skip this if already have list { fmtEtc.cfFormat = ShellDll.CF.HDROP; fmtEtc.lindex = - 1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; stg.hGlobal = IntPtr.Zero; stg.pUnkForRelease = IntPtr.Zero; stg.tymed = 0; HR = IDO.GetData(ref fmtEtc, ref stg); if (HR == 0) //we have an HDROP and stg.hGlobal points to the info { IntPtr pHdrop = Marshal.ReadIntPtr(stg.hGlobal); int nrItems = ShellDll.DragQueryFile(pHdrop, -1, null, 0); int i; for (i = 0; i <= nrItems - 1; i++) { int plen = ShellDll.DragQueryFile(pHdrop, i, null, 0); StringBuilder SB = new StringBuilder(plen + 1); int flen = ShellDll.DragQueryFile(pHdrop, i, SB, plen + 1); Debug.WriteLine("Fetched from HDROP: " + SB.ToString()); try //if GetCShitem returns Nothing(it's failure marker) then catch it { m_Draglist.Add(ExpTreeLib.CShItem.GetCShItem(SB.ToString())); } catch (Exception ex) // in this case, just skip it { Debug.WriteLine("Error: CMyDataObject.ProcessComIDataObject - Adding via HDROP" + "\r\n" + "\t" + ex.Message); } } ShellDll.ReleaseStgMedium(ref stg); //done with this stg //Else // Marshal.ThrowExceptionForHR(HR) } } //Have done what we can to get m_DragList -- exit on failure if (m_Draglist.Count < 1) //Can't do any more -- Quit { return; //leaving m_IsValid as False } //May not have Shell IDList Array in IDataObject. If not, give it one if (m_StreamCIDA == null) //IDO does not yet have "Shell IDList Array" Data { m_StreamCIDA = MakeShellIDArray(m_Draglist); if (m_StreamCIDA == null) { return; //failed to make it } //Now put the CIDA into the original IDataObject fmtEtc.cfFormat = (ShellDll.CF)cf; //registered at routine entry fmtEtc.lindex = - 1; fmtEtc.dwAspect = ShellDll.DVASPECT.CONTENT; fmtEtc.ptd = IntPtr.Zero; fmtEtc.Tymd = ShellDll.TYMED.HGLOBAL; //note the hGlobal item in stg is a pointer to a pointer->Data IntPtr m_hg = Marshal.AllocHGlobal(Convert.ToInt32(m_StreamCIDA.Length)); Marshal.Copy(m_StreamCIDA.ToArray(), 0, m_hg, (int)m_StreamCIDA.Length); IntPtr hg = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(hg, 0, m_hg); stg.tymed = (int)ShellDll.TYMED.HGLOBAL; stg.hGlobal = hg; stg.pUnkForRelease = IntPtr.Zero; HR = IDO.SetData(ref fmtEtc, ref stg, true); //callee responsible for releasing stg if (HR == 0) { m_IsValid = true; } else //failed -- we have to release stg -- and leave m_IsValid as False { ShellDll.ReleaseStgMedium(ref stg); return; //m_isvalid stays False } } m_IsValid = true; //already had a Shell IDList Array, so all is OK }