/// <summary> /// This is overridden to handle drop operations correctly in a help file builder project /// </summary> /// <inheritdoc /> public override int Drop(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { DropDataType dropDataType = DropDataType.None; if (pDataObject == null) { return(VSConstants.E_INVALIDARG); } pdwEffect = (uint)DropEffect.None; // If the source is within the project, let the base class handle it if (this.SourceDraggedOrCutOrCopied) { return(base.Drop(pDataObject, grfKeyState, itemid, ref pdwEffect)); } // Get the node that is being dragged over and ask it which node should handle this call HierarchyNode targetNode = NodeFromItemId(itemid); if (targetNode == null) { return(VSConstants.S_FALSE); } targetNode = targetNode.GetDragTargetHandlerNode(); dropDataType = this.HandleSelectionDataObject(pDataObject, targetNode); // Since we can get a mix of files that may not necessarily be moved into the project (i.e. // documentation sources and references), we'll always act as if they were copied. pdwEffect = (uint)DropEffect.Copy; return((dropDataType != DropDataType.Shell) ? VSConstants.E_FAIL : VSConstants.S_OK); }
/// <summary> /// After a drop or paste, will use the dwEffects /// to determine whether we need to clean up the source nodes or not. If /// justCleanup is set, it only does the cleanup work. /// </summary> internal void CleanupSelectionDataObject(bool dropped, bool cut, bool moved, bool justCleanup) { if (this.ItemsDraggedOrCutOrCopied == null || this.ItemsDraggedOrCutOrCopied.Count == 0) { return; } try { IVsUIHierarchyWindow w = UIHierarchyUtilities.GetUIHierarchyWindow(this.site, HierarchyNode.SolutionExplorer); foreach (HierarchyNode node in this.ItemsDraggedOrCutOrCopied) { if ((moved && (cut || dropped) && !justCleanup)) { // do not close it if the doc is dirty or we do not own it bool isDirty, isOpen, isOpenedByUs; uint docCookie; IVsPersistDocData ppIVsPersistDocData; DocumentManager manager = node.GetDocumentManager(); if (manager != null) { manager.GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out ppIVsPersistDocData); if (isDirty || (isOpen && !isOpenedByUs)) { continue; } // close it if opened if (isOpen) { manager.Close(__FRAMECLOSE.FRAMECLOSE_NoSave); } } node.Remove(true); } else if (w != null) { ErrorHandler.ThrowOnFailure(w.ExpandItem((IVsUIHierarchy)this, node.ID, EXPANDFLAGS.EXPF_UnCutHighlightItem)); } } } finally { // Now delete the memory allocated by the packaging of datasources. // If we just did a cut, or we are told to cleanup, then we need to free the data object. Otherwise, we leave it // alone so that you can continue to paste the data in new locations. if (moved || cut || justCleanup) { this.ItemsDraggedOrCutOrCopied.Clear(); this.CleanAndFlushClipboard(); } this.dataObject = null; this.dropDataType = DropDataType.None; } }
/// <summary> /// Handle the Paste operation to a targetNode /// </summary> protected internal override int PasteFromClipboard(HierarchyNode targetNode) { int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; //Get the clipboardhelper service and use it after processing dataobject IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper)); if (clipboardHelper == null) { return(VSConstants.E_FAIL); } try { //Get dataobject from clipboard IOleDataObject dataObject = null; ErrorHandler.ThrowOnFailure(UnsafeNativeMethods.OleGetClipboard(out dataObject)); if (dataObject == null) { return(VSConstants.E_UNEXPECTED); } DropEffect dropEffect = DropEffect.None; DropDataType dropDataType = DropDataType.None; try { dropDataType = this.ProcessSelectionDataObject(dataObject, targetNode.GetDragTargetHandlerNode()); dropEffect = this.QueryDropEffect(dropDataType, 0); } catch (ExternalException e) { Trace.WriteLine("Exception : " + e.Message); // If it is a drop from windows and we get any kind of error ignore it. This // prevents bogus messages from the shell from being displayed if (dropDataType != DropDataType.Shell) { throw e; } } finally { // Inform VS (UiHierarchyWindow) of the paste returnValue = clipboardHelper.Paste(dataObject, (uint)dropEffect); } } catch (COMException e) { Trace.WriteLine("Exception : " + e.Message); returnValue = e.ErrorCode; } return(returnValue); }
/// <summary> /// Called when one or more items are dropped into the target hierarchy or hierarchy window when the mouse button is released. /// </summary> /// <param name="pDataObject">Reference to the IDataObject interface on the item being dragged. This data object contains the data being transferred in the drag-and-drop operation. /// If the drop occurs, then this data object (item) is incorporated into the target hierarchy or hierarchy window.</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See <seealso cref="IVsHierarchyDropDataTarget"/></param> /// <param name="itemid">Item identifier of the drop data target over which the item is being dragged</param> /// <param name="pdwEffect">Visual effects associated with the drag-and drop-operation, such as a cursor, bitmap, and so on. /// The value of dwEffects passed to the source object via the OnDropNotify method is the value of pdwEffects returned by the Drop method</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public override int Drop(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { if (pDataObject == null) { return(VSConstants.E_INVALIDARG); } pdwEffect = (uint)DropEffect.None; // Get the node that is being dragged over and ask it which node should handle this call HierarchyNode targetNode = NodeFromItemId(itemid); if (targetNode != null) { targetNode = targetNode.GetDragTargetHandlerNode(); } else { // There is no target node. The drop can not be completed. return(VSConstants.S_FALSE); } int returnValue; try { DropDataType dropDataType = DropDataType.None; dropDataType = ProcessSelectionDataObject(pDataObject, targetNode); pdwEffect = (uint)this.QueryDropEffect(dropDataType, grfKeyState); // If it is a drop from windows and we get any kind of error we return S_FALSE and dropeffect none. This // prevents bogus messages from the shell from being displayed returnValue = (dropDataType != DropDataType.Shell) ? VSConstants.E_FAIL : VSConstants.S_OK; } catch (System.IO.FileNotFoundException e) { Trace.WriteLine("Exception : " + e.Message); if (!Utilities.IsInAutomationFunction(this.Site)) { string message = e.Message; string title = string.Empty; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton); } returnValue = VSConstants.E_FAIL; } return(returnValue); }
/// <summary> /// Process dataobject from Drag/Drop/Cut/Copy/Paste operation /// </summary> /// <remarks>The targetNode is set if the method is called from a drop operation, otherwise it is null</remarks> /// internal DropDataType ProcessSelectionDataObject(IOleDataObject dataObject, HierarchyNode targetNode) { DropDataType dropDataType = DropDataType.None; bool isWindowsFormat = false; // Try to get it as a directory based project. List <string> filesDropped = DragDropHelper.GetDroppedFiles(DragDropHelper.CF_VSSTGPROJECTITEMS, dataObject, out dropDataType); if (filesDropped.Count == 0) { filesDropped = DragDropHelper.GetDroppedFiles(DragDropHelper.CF_VSREFPROJECTITEMS, dataObject, out dropDataType); } if (filesDropped.Count == 0) { filesDropped = DragDropHelper.GetDroppedFiles(NativeMethods.CF_HDROP, dataObject, out dropDataType); isWindowsFormat = (filesDropped.Count > 0); } if (dropDataType != DropDataType.None && filesDropped.Count > 0) { string[] filesDroppedAsArray = filesDropped.ToArray(); string sourceProjectPath = DragDropHelper.GetSourceProjectPath(dataObject); HierarchyNode node = (targetNode == null) ? this : targetNode; // For directory based projects the content of the clipboard is a double-NULL terminated list of Projref strings. if (isWindowsFormat) { // This is the code path when source is windows explorer VSADDRESULT[] vsaddresults = new VSADDRESULT[1]; vsaddresults[0] = VSADDRESULT.ADDRESULT_Failure; int addResult = AddItem(node.ID, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, (uint)filesDropped.Count, filesDropped.ToArray(), IntPtr.Zero, vsaddresults); if (addResult != VSConstants.S_OK && addResult != VSConstants.S_FALSE && addResult != (int)OleConstants.OLECMDERR_E_CANCELED && vsaddresults[0] != VSADDRESULT.ADDRESULT_Success) { ErrorHandler.ThrowOnFailure(addResult); } return(dropDataType); } else { if (AddFilesFromProjectReferences(node, filesDroppedAsArray)) { return(dropDataType); } } } // If we reached this point then the drop data must be set to None. // Otherwise the OnPaste will be called with a valid DropData and that would actually delete the item. return(DropDataType.None); }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemid">Item identifier for the item currently being dragged</param> /// <param name="pdwEffect">On entry, a pointer to the current DropEffect. On return, must contain the new valid DropEffect</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragEnter(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { pdwEffect = (uint)DropEffect.None; this.dropDataType = QueryDropDataType(pDataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)this.QueryDropEffect(this.dropDataType, grfKeyState); } return VSConstants.S_OK; }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemid">Item identifier for the item currently being dragged</param> /// <param name="pdwEffect">On entry, a pointer to the current DropEffect. On return, must contain the new valid DropEffect</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public int DragEnter(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { pdwEffect = (uint)DropEffect.None; var item = NodeFromItemId(itemid); if (item.GetDragTargetHandlerNode().CanAddFiles) { _dropType = QueryDropDataType(pDataObject); if (_dropType != DropDataType.None) { pdwEffect = (uint)QueryDropEffect(grfKeyState); } } return VSConstants.S_OK; }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemid">Item identifier for the item currently being dragged</param> /// <param name="pdwEffect">On entry, a pointer to the current DropEffect. On return, must contain the new valid DropEffect</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragEnter(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { pdwEffect = (uint)DropEffect.None; if (this.SourceDraggedOrCutOrCopied) { return(VSConstants.S_OK); } this.dropDataType = QueryDropDataType(pDataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)this.QueryDropEffect(this.dropDataType, grfKeyState); } return(VSConstants.S_OK); }
public override int DragOver(uint grfKeyState, uint itemid, ref uint pdwEffect) { if (this.dataObject == null) { this.dataObject = PackageSelectionDataObject(false); } this.dropDataType = QueryDropDataType(this.dataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)QueryDropEffect(dropDataType, grfKeyState); } //We should also analyze if the node being dragged over can accept the drop if (!CanTargetNodeAcceptDrop(itemid)) { pdwEffect = (uint)DropEffect.None; } return(VSConstants.S_OK); }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemid">Item identifier for the item currently bbeing dragged</param> /// <param name="pdwEffect">On entry, a pointer to the current DropEffect. On return, must contain the /// new valid DropEffect</param> /// <returns>S_OK if the method succeeds</returns> public override int DragEnter(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { pdwEffect = (uint)DropEffect.None; if (this.SourceDraggedOrCutOrCopied) { return VSConstants.S_OK; } else { this.dataObject = (IOleDataObject)pDataObject; } this.dropDataType = QueryDropDataType(pDataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)QueryDropEffect(this.dropDataType, grfKeyState); } return VSConstants.S_OK; }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="pDataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemid">Item identifier for the item currently being dragged</param> /// <param name="pdwEffect">On entry, a pointer to the current DropEffect. On return, must contain the new valid DropEffect</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragEnter(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { pdwEffect = (uint)DropEffect.None; // changed from MPFProj: // http://mpfproj10.codeplex.com/WorkItem/View.aspx?WorkItemId=8145 /* if(this.SourceDraggedOrCutOrCopied) { return VSConstants.S_OK; }*/ this.dropDataType = QueryDropDataType(pDataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)this.QueryDropEffect(this.dropDataType, grfKeyState); } return VSConstants.S_OK; }
/// <summary> /// Returns the drop effect. /// </summary> /// <remarks> /// // A directory based project should perform as follow: /// NO MODIFIER /// - COPY if not from current hierarchy, /// - MOVE if from current hierarchy /// SHIFT DRAG - MOVE /// CTRL DRAG - COPY /// CTRL-SHIFT DRAG - NO DROP (used for reference based projects only) /// </remarks> internal DropEffect QueryDropEffect(DropDataType dropDataType, uint grfKeyState) { //Validate the dropdatatype if ((dropDataType != DropDataType.Shell) && (dropDataType != DropDataType.VsRef) && (dropDataType != DropDataType.VsStg)) { return(DropEffect.None); } // CTRL-SHIFT if ((grfKeyState & NativeMethods.MK_CONTROL) != 0 && (grfKeyState & NativeMethods.MK_SHIFT) != 0) { // Because we are not referenced base, we don't support link return(DropEffect.None); } // CTRL if ((grfKeyState & NativeMethods.MK_CONTROL) != 0) { return(DropEffect.Copy); } // SHIFT if ((grfKeyState & NativeMethods.MK_SHIFT) != 0) { return(DropEffect.Move); } // no modifier if (this.SourceDraggedOrCutOrCopied) { return(DropEffect.Move); } else { return(DropEffect.Copy); } }
/// <summary> /// Returns the drop effect. /// </summary> /// <remarks> /// // A directory based project should perform as follow: /// NO MODIFIER /// - COPY if not from current hierarchy, /// - MOVE if from current hierarchy /// SHIFT DRAG - MOVE /// CTRL DRAG - COPY /// CTRL-SHIFT DRAG - NO DROP (used for reference based projects only) /// </remarks> internal DropEffect QueryDropEffect(DropDataType dropDataType, uint grfKeyState) { //Validate the dropdatatype if ((dropDataType != DropDataType.Shell) && (dropDataType != DropDataType.VsRef) && (dropDataType != DropDataType.VsStg)) { return DropEffect.None; } // CTRL-SHIFT if ((grfKeyState & NativeMethods.MK_CONTROL) != 0 && (grfKeyState & NativeMethods.MK_SHIFT) != 0) { // Because we are not referenced base, we don't support link return DropEffect.None; } // CTRL if ((grfKeyState & NativeMethods.MK_CONTROL) != 0) return DropEffect.Copy; // SHIFT if ((grfKeyState & NativeMethods.MK_SHIFT) != 0) return DropEffect.Move; // no modifier if (this.SourceDraggedOrCutOrCopied) { return DropEffect.Move; } else { return DropEffect.Copy; } }
public static bool AttemptVsFormat(HierarchyNode activeNode, ushort cfFormat, Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, uint grfKeyState, out DropDataType pddt) { pddt = DropDataType.None; FORMATETC fmtetc = new FORMATETC(); fmtetc.cfFormat = cfFormat; fmtetc.ptd = IntPtr.Zero; fmtetc.dwAspect = (uint)DVASPECT.DVASPECT_CONTENT; fmtetc.lindex = -1; fmtetc.tymed = (uint)TYMED.TYMED_HGLOBAL; bool hasData = false; try { QueryGetData(pDataObject, ref fmtetc); hasData = true; } catch (Exception) { } if (hasData) { try { STGMEDIUM stgmedium = GetData(pDataObject, ref fmtetc); if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { IntPtr hDropInfo = stgmedium.unionmember; if (hDropInfo != IntPtr.Zero) { pddt = DropDataType.VsRef; try { activeNode.AddFiles(UtilGetFilesFromPROJITEMDrop(hDropInfo)); Marshal.FreeHGlobal(hDropInfo); } catch (Exception e) { Marshal.FreeHGlobal(hDropInfo); throw e; } return true; } } } catch (Exception e) { Console.WriteLine("Exception:" + e.Message); } } return false; }
/// <summary> /// Called when one or more items are dragged out of the hierarchy or hierarchy window, or when the drag-and-drop operation is cancelled or completed. /// </summary> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragLeave() { this.dropDataType = DropDataType.None; return(VSConstants.S_OK); }
DropEffect QueryDropEffect(DropDataType ddt, uint grfKeyState){ // We are reference-based project so we should perform as follow: // for shell and physical items: // NO MODIFIER - LINK // SHIFT DRAG - NO DROP // CTRL DRAG - NO DROP // CTRL-SHIFT DRAG - LINK // for reference/link items // NO MODIFIER - MOVE // SHIFT DRAG - MOVE // CTRL DRAG - COPY // CTRL-SHIFT DRAG - LINK if ((ddt != DropDataType.Shell) && (ddt != DropDataType.VsRef) && (ddt != DropDataType.VsStg)) return DropEffect.None; switch (ddt){ case DropDataType.Shell: goto case DropDataType.VsStg; case DropDataType.VsStg: // CTRL-SHIFT if ((grfKeyState & MK_CONTROL) != 0 && (grfKeyState & MK_SHIFT) != 0){ return DropEffect.Link; } // CTRL if ((grfKeyState & MK_CONTROL) != 0) return DropEffect.None; // SHIFT if ((grfKeyState & MK_SHIFT) != 0) return DropEffect.None; // no modifier return DropEffect.Link; case DropDataType.VsRef: // CTRL-SHIFT if ((grfKeyState & MK_CONTROL) != 0 && (grfKeyState & MK_SHIFT) != 0){ return DropEffect.Link; } // CTRL if ((grfKeyState & MK_CONTROL) != 0){ return DropEffect.Copy; } // SHIFT if ((grfKeyState & MK_SHIFT) != 0){ return DropEffect.Move; } // no modifier return DropEffect.Move; } return DropEffect.None; }
public virtual void DragLeave() { CCITracing.TraceCall(); _ddt = DropDataType.None; }
/// <summary> /// After a drop or paste, will use the dwEffects /// to determine whether we need to clean up the source nodes or not. If /// justCleanup is set, it only does the cleanup work. /// </summary> internal void CleanupSelectionDataObject(bool dropped, bool cut, bool moved, bool justCleanup) { if (this.ItemsDraggedOrCutOrCopied == null || this.ItemsDraggedOrCutOrCopied.Count == 0) { return; } // If the source and destination are within the same project, the // number of items dropped and selected should be equal. Debug.Assert(!this.SourceDraggedOrCutOrCopied || (dropItems == null || dropItems.Count == 0 || (dropItems.Count > 0 && dropItems.Count == this.ItemsDraggedOrCutOrCopied.Count)), "Number of drop items didn't match number of items selected."); try { int index = -1; IVsUIHierarchyWindow w = UIHierarchyUtilities.GetUIHierarchyWindow(this.site, HierarchyNode.SolutionExplorer); foreach (HierarchyNode node in this.ItemsDraggedOrCutOrCopied) { index++; bool shouldRemove = ((moved && dropped) || cut) && !justCleanup; // get matching drop item // there might not be any drop items if an error occured early on if (dropItems != null && dropItems.Count > 0) { DragDropItem dropItem = dropItems[index]; if (dropItem.userCancelled) shouldRemove = false; } if (shouldRemove) { // do not close it if the doc is dirty or we do not own it bool isDirty, isOpen, isOpenedByUs; uint docCookie; IVsPersistDocData ppIVsPersistDocData; DocumentManager manager = node.GetDocumentManager(); if (manager != null) { manager.GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out ppIVsPersistDocData); if (isDirty || (isOpen && !isOpenedByUs)) { continue; } // close it if opened if (isOpen) { manager.Close(__FRAMECLOSE.FRAMECLOSE_NoSave); } } node.Remove(true); } else if (w != null) { w.ExpandItem((IVsUIHierarchy)this, node.ID, EXPANDFLAGS.EXPF_UnCutHighlightItem); } } } finally { try { // Now delete the memory allocated by the packaging of datasources. // If we just did a cut, or we are told to cleanup, then we need to free the data object. Otherwise, we leave it // alone so that you can continue to paste the data in new locations. if (moved || cut || justCleanup) { this.ItemsDraggedOrCutOrCopied.Clear(); this.CleanAndFlushClipboard(); } } finally { this.dropItems.Clear(); this.dropDataType = DropDataType.None; } } }
/// <summary> /// Retrives data from a VS format. /// </summary> public static List <string> GetDroppedFiles(ushort format, Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject, out DropDataType ddt) { ddt = DropDataType.None; List <string> droppedFiles = new List <string>(); // try HDROP FORMATETC fmtetc = CreateFormatEtc(format); if (QueryGetData(dataObject, ref fmtetc) == VSConstants.S_OK) { STGMEDIUM stgmedium = DragDropHelper.GetData(dataObject, ref fmtetc); if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { // We are releasing the cloned hglobal here. IntPtr dropInfoHandle = stgmedium.unionmember; if (dropInfoHandle != IntPtr.Zero) { ddt = DropDataType.Shell; try { uint numFiles = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, 0xFFFFFFFF, null, 0); // We are a directory based project thus a projref string is placed on the clipboard. // We assign the maximum length of a projref string. // The format of a projref is : <Proj Guid>|<project rel path>|<file path> uint lenght = (uint)Guid.Empty.ToString().Length + 2 * NativeMethods.MAX_PATH + 2; char[] moniker = new char[lenght + 1]; for (uint fileIndex = 0; fileIndex < numFiles; fileIndex++) { uint queryFileLength = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, fileIndex, moniker, lenght); string filename = new String(moniker, 0, (int)queryFileLength); droppedFiles.Add(filename); } } finally { Marshal.FreeHGlobal(dropInfoHandle); } } } } return(droppedFiles); }
public override int DragOver(uint grfKeyState, uint itemid, ref uint pdwEffect) { if (this.dataObject == null) { this.dataObject = PackageSelectionDataObject(false); } this.dropDataType = QueryDropDataType(this.dataObject); if (this.dropDataType != DropDataType.None) { pdwEffect = (uint)QueryDropEffect(dropDataType, grfKeyState); } //We should also analyze if the node being dragged over can accept the drop if (!CanTargetNodeAcceptDrop(itemid)) pdwEffect = (uint)DropEffect.None; return VSConstants.S_OK; }
/// <summary> /// Handle the Paste operation to a targetNode. Do not call directly /// outside of PasteFromClipboard. /// </summary> private int PasteFromClipboardCore(HierarchyNode targetNode) { int returnValue = (int)OleConstants.OLECMDERR_E_NOTSUPPORTED; //Get the clipboardhelper service and use it after processing dataobject IVsUIHierWinClipboardHelper clipboardHelper = (IVsUIHierWinClipboardHelper)GetService(typeof(SVsUIHierWinClipboardHelper)); if (clipboardHelper == null) { return VSConstants.E_FAIL; } try { //Get dataobject from clipboard IOleDataObject dataObject = null; ErrorHandler.ThrowOnFailure(UnsafeNativeMethods.OleGetClipboard(out dataObject)); if (dataObject == null) { return VSConstants.E_UNEXPECTED; } DropEffect dropEffect = DropEffect.None; DropDataType dropDataType = DropDataType.None; try { this.SourceDraggedOrCutOrCopied = this.dataWasCut; dropDataType = this.ProcessSelectionDataObject(dataObject, targetNode.GetDragTargetHandlerNode(), 0); dropEffect = this.QueryDropEffect(dropDataType, 0); } catch (ExternalException e) { Trace.WriteLine("Exception : " + e.Message); // If it is a drop from windows and we get any kind of error ignore it. This // prevents bogus messages from the shell from being displayed if (dropDataType != DropDataType.Shell) { throw e; } } finally { // Inform VS (UiHierarchyWindow) of the paste returnValue = clipboardHelper.Paste(dataObject, (uint)dropEffect); } } catch (COMException e) { Trace.WriteLine("Exception : " + e.Message); returnValue = e.ErrorCode; } return returnValue; }
/// <summary> /// Called when one or more items are dragged out of the hierarchy or hierarchy window, or when the drag-and-drop operation is cancelled or completed. /// </summary> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public int DragLeave() { _dropType = DropDataType.None; return VSConstants.S_OK; }
/// <include file='doc\Hierarchy.uex' path='docs/doc[@for="HierarchyNode.DragLeave"]/*' /> public virtual int DragLeave(){ _ddt = DropDataType.None; return 0; }
/// <include file='doc\Hierarchy.uex' path='docs/doc[@for="HierarchyNode.DragEnter"]/*' /> public virtual int DragEnter(Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect){ pdwEffect = (uint)DropEffect.None; if (dragSource) return 0; _ddt = QueryDropDataType(pDataObject); if (_ddt != DropDataType.None){ pdwEffect = (uint)QueryDropEffect(_ddt, grfKeyState); } return 0; }
/// <summary> /// After a drop or paste, will use the dwEffects /// to determine whether we need to clean up the source nodes or not. If /// justCleanup is set, it only does the cleanup work. /// </summary> public void CleanupSelectionDataObject(bool dropped, bool cut, bool moved, bool justCleanup) { if (this.ItemsDraggedOrCutOrCopied == null || this.ItemsDraggedOrCutOrCopied.Count == 0) { return; } try { IVsUIHierarchyWindow w = UIHierarchyUtilities.GetUIHierarchyWindow(this.site, HierarchyNode.SolutionExplorer); foreach (HierarchyNode node in this.ItemsDraggedOrCutOrCopied) { if ((moved && (cut || dropped) && !justCleanup)) { // do not close it if the doc is dirty or we do not own it bool isDirty, isOpen, isOpenedByUs; uint docCookie; IVsPersistDocData ppIVsPersistDocData; DocumentManager manager = node.GetDocumentManager(); if (manager != null) { manager.GetDocInfo(out isOpen, out isDirty, out isOpenedByUs, out docCookie, out ppIVsPersistDocData); if (isDirty || (isOpen && !isOpenedByUs)) { continue; } // close it if opened if (isOpen) { manager.Close(__FRAMECLOSE.FRAMECLOSE_NoSave); } } node.Remove(true); } else if (w != null) { ErrorHandler.ThrowOnFailure(w.ExpandItem((IVsUIHierarchy)this, node.ID, EXPANDFLAGS.EXPF_UnCutHighlightItem)); } } } finally { try { // Now delete the memory allocated by the packaging of datasources. // If we just did a cut, or we are told to cleanup, then we need to free the data object. Otherwise, we leave it // alone so that you can continue to paste the data in new locations. if (moved || cut || justCleanup) { this.ItemsDraggedOrCutOrCopied.Clear(); this.CleanAndFlushClipboard(); } } finally { this.dropDataType = DropDataType.None; } } }
public static bool AttemptVsFormat(HierarchyNode activeNode, ushort cfFormat, Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, uint grfKeyState, out DropDataType pddt) { pddt = DropDataType.None; FORMATETC fmtetc = new FORMATETC(); fmtetc.cfFormat = cfFormat; fmtetc.ptd = IntPtr.Zero; fmtetc.dwAspect = (uint)DVASPECT.DVASPECT_CONTENT; fmtetc.lindex = -1; fmtetc.tymed = (uint)TYMED.TYMED_HGLOBAL; bool hasData = false; try { QueryGetData(pDataObject, ref fmtetc); hasData = true; } catch { } if (hasData) { try { STGMEDIUM stgmedium = GetData(pDataObject, ref fmtetc); if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { IntPtr hDropInfo = stgmedium.unionmember; if (hDropInfo != IntPtr.Zero) { pddt = DropDataType.VsRef; try { activeNode.AddFiles(UtilGetFilesFromPROJITEMDrop(hDropInfo)); } finally { Marshal.FreeHGlobal(hDropInfo); } return(true); } } } catch (Exception e) { Trace.WriteLine("Exception:" + e.Message); } catch { Trace.WriteLine("Exception"); } } return(false); }
/// <summary> /// Returns the drop effect. /// </summary> /// <remarks> /// // A directory based project should perform as follow: /// NO MODIFIER /// - COPY if not from current hierarchy, /// - MOVE if from current hierarchy /// SHIFT DRAG - MOVE /// CTRL DRAG - COPY /// CTRL-SHIFT DRAG - NO DROP (used for reference based projects only) /// </remarks> internal DropEffect QueryDropEffect(DropDataType dropDataType, uint grfKeyState) { //Validate the dropdatatype if ((dropDataType != DropDataType.Shell) && (dropDataType != DropDataType.VsRef) && (dropDataType != DropDataType.VsStg)) { return DropEffect.None; } // CTRL-SHIFT if ((grfKeyState & NativeMethods.MK_CONTROL) != 0 && (grfKeyState & NativeMethods.MK_SHIFT) != 0) { // Because we are not referenced base, we don't support link return DropEffect.None; } // CTRL if ((grfKeyState & NativeMethods.MK_CONTROL) != 0) return DropEffect.Copy; // SHIFT if ((grfKeyState & NativeMethods.MK_SHIFT) != 0) return DropEffect.Move; // If the source project is this project, default to move items, // otherwise copy items. if (this.SourceDraggedOrCutOrCopied) return DropEffect.Move; else return DropEffect.Copy; }
/// <summary> /// Called as soon as the mouse drags an item over a new hierarchy or hierarchy window /// </summary> /// <param name="dataObject">reference to interface IDataObject of the item being dragged</param> /// <param name="keyState">Current state of the keyboard and the mouse modifier keys. See docs for a list of possible values</param> /// <param name="itemId">Item identifier for the item currently being dragged</param> /// <param name="effect">On entry, a pointer to the current DropEffect. On return, must contain the new valid DropEffect</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragEnter(IOleDataObject dataObject, uint keyState, uint itemId, ref DropEffects effect) { effect = DropEffects.None; if(this.SourceDraggedOrCutOrCopied) { return VSConstants.S_OK; } this._dropDataType = QueryDropDataType(dataObject); if(this._dropDataType != DropDataType.None) { effect = this.QueryDropEffect(this._dropDataType, keyState); } return VSConstants.S_OK; }
/// <summary> /// Called when one or more items are dropped into the target hierarchy or hierarchy window when the mouse button is released. /// </summary> /// <param name="pDataObject">Reference to the IDataObject interface on the item being dragged. This data object contains the data being transferred in the drag-and-drop operation. /// If the drop occurs, then this data object (item) is incorporated into the target hierarchy or hierarchy window.</param> /// <param name="grfKeyState">Current state of the keyboard and the mouse modifier keys. See <seealso cref="IVsHierarchyDropDataTarget"/></param> /// <param name="itemid">Item identifier of the drop data target over which the item is being dragged</param> /// <param name="pdwEffect">Visual effects associated with the drag-and drop-operation, such as a cursor, bitmap, and so on. /// The value of dwEffects passed to the source object via the OnDropNotify method is the value of pdwEffects returned by the Drop method</param> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code. </returns> public override int Drop(IOleDataObject pDataObject, uint grfKeyState, uint itemid, ref uint pdwEffect) { if (pDataObject == null) { return VSConstants.E_INVALIDARG; } pdwEffect = (uint)DropEffect.None; // Get the node that is being dragged over and ask it which node should handle this call HierarchyNode targetNode = NodeFromItemId(itemid); if (targetNode != null) { targetNode = targetNode.GetDragTargetHandlerNode(); } else { // There is no target node. The drop can not be completed. return VSConstants.S_FALSE; } int returnValue; try { this.isInPasteOrDrop = true; DropDataType dropDataType = DropDataType.None; dropDataType = ProcessSelectionDataObject(pDataObject, targetNode, grfKeyState); pdwEffect = (uint)this.QueryDropEffect(dropDataType, grfKeyState); // If it is a drop from windows and we get any kind of error we return S_FALSE and dropeffect none. This // prevents bogus messages from the shell from being displayed returnValue = (dropDataType != DropDataType.Shell) ? VSConstants.E_FAIL : VSConstants.S_OK; } catch (System.IO.FileNotFoundException e) { Trace.WriteLine("Exception : " + e.Message); if (!Utilities.IsInAutomationFunction(this.Site)) { string message = e.Message; string title = string.Empty; OLEMSGICON icon = OLEMSGICON.OLEMSGICON_CRITICAL; OLEMSGBUTTON buttons = OLEMSGBUTTON.OLEMSGBUTTON_OK; OLEMSGDEFBUTTON defaultButton = OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST; VsShellUtilities.ShowMessageBox(this.Site, title, message, icon, buttons, defaultButton); } returnValue = VSConstants.E_FAIL; } finally { this.isInPasteOrDrop = false; this.dropAsCopy = false; } return returnValue; }
/// <include file='doc\Hierarchy.uex' path='docs/doc[@for="HierarchyNode.DragLeave"]/*' /> public virtual int DragLeave() { _ddt = DropDataType.None; return NativeMethods.S_OK; }
/// <summary> /// Called when one or more items are dragged out of the hierarchy or hierarchy window, or when the drag-and-drop operation is cancelled or completed. /// </summary> /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns an error code.</returns> public override int DragLeave() { this.dropDataType = DropDataType.None; return VSConstants.S_OK; }
// ================= Drag/Drop/Cut/Copy/Paste ======================== // Ported from HeirUtil7\PrjHeir.cpp void ProcessSelectionDataObject(Microsoft.VisualStudio.OLE.Interop.IDataObject pDataObject, uint grfKeyState, out DropDataType pddt){ pddt = DropDataType.None; // try HDROP FORMATETC fmtetc = DragDropHelper.CreateFormatEtc(CF_HDROP); bool hasData = false; try{ DragDropHelper.QueryGetData(pDataObject, ref fmtetc); hasData = true; } catch (Exception){ } if (hasData){ try{ STGMEDIUM stgmedium = DragDropHelper.GetData(pDataObject, ref fmtetc); if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL){ IntPtr hDropInfo = stgmedium.unionmember; if (hDropInfo != IntPtr.Zero){ pddt = DropDataType.Shell; try{ uint numFiles = DragQueryFile(hDropInfo, 0xFFFFFFFF, null, 0); char[] szMoniker = new char[MAX_PATH + 1]; IVsProject vsProj = (IVsProject)this.projectMgr; for (uint iFile = 0; iFile < numFiles; iFile++){ uint len = DragQueryFile(hDropInfo, iFile, szMoniker, MAX_PATH); string filename = new String(szMoniker, 0, (int)len); // Is full path returned if (File.Exists(filename)){ VSADDRESULT[] vsaddresult = new VSADDRESULT[1]; vsaddresult[0] = VSADDRESULT.ADDRESULT_Failure; string[] files = new String[1]{ filename }; // TODO: support dropping into subfolders... vsProj.AddItem(this.projectMgr.hierarchyId, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, 1, files, IntPtr.Zero, vsaddresult); } } Marshal.FreeHGlobal(hDropInfo); } catch (Exception e){ Marshal.FreeHGlobal(hDropInfo); throw e; } } } return; } catch (Exception){ hasData = false; } } if (DragDropHelper.AttemptVsFormat(this, DragDropHelper.CF_VSREFPROJECTITEMS, pDataObject, grfKeyState, out pddt)) return; if (DragDropHelper.AttemptVsFormat(this, DragDropHelper.CF_VSSTGPROJECTITEMS, pDataObject, grfKeyState, out pddt)) return; }
/// <summary> /// Retrieves data from a VS format. /// </summary> public static List<string> GetDroppedFiles(ushort format, Microsoft.VisualStudio.OLE.Interop.IDataObject dataObject, out DropDataType ddt) { ddt = DropDataType.None; List<string> droppedFiles = new List<string>(); // try HDROP FORMATETC fmtetc = CreateFormatEtc(format); if (QueryGetData(dataObject, ref fmtetc) == VSConstants.S_OK) { STGMEDIUM stgmedium = DragDropHelper.GetData(dataObject, ref fmtetc); if (stgmedium.tymed == (uint)TYMED.TYMED_HGLOBAL) { // We are releasing the cloned hglobal here. IntPtr dropInfoHandle = stgmedium.unionmember; if (dropInfoHandle != IntPtr.Zero) { ddt = DropDataType.Shell; try { uint numFiles = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, 0xFFFFFFFF, null, 0); // We are a directory based project thus a projref string is placed on the clipboard. // We assign the maximum length of a projref string. // The format of a projref is : <Proj Guid>|<project rel path>|<file path> uint lenght = (uint)Guid.Empty.ToString().Length + 2 * NativeMethods.MAX_PATH + 2; char[] moniker = new char[lenght + 1]; for (uint fileIndex = 0; fileIndex < numFiles; fileIndex++) { uint queryFileLength = UnsafeNativeMethods.DragQueryFile(dropInfoHandle, fileIndex, moniker, lenght); string filename = new String(moniker, 0, (int)queryFileLength); droppedFiles.Add(filename); } } finally { Marshal.FreeHGlobal(dropInfoHandle); } } } } return droppedFiles; }
/// <summary> /// Process data object from Drag/Drop/Cut/Copy/Paste operation /// </summary> /// <remarks>The targetNode is set if the method is called from a drop operation, otherwise it /// is null</remarks> private DropDataType HandleSelectionDataObject(IOleDataObject dataObject, HierarchyNode targetNode) { DropDataType dropDataType = DropDataType.None; bool isWindowsFormat = false; if (targetNode == null) { targetNode = this; } // Try to get it as a directory based project List <string> filesDropped = DragDropHelper.GetDroppedFiles(DragDropHelper.CF_VSSTGPROJECTITEMS, dataObject, out dropDataType); if (filesDropped.Count == 0) { filesDropped = DragDropHelper.GetDroppedFiles(DragDropHelper.CF_VSREFPROJECTITEMS, dataObject, out dropDataType); } if (filesDropped.Count == 0) { filesDropped = DragDropHelper.GetDroppedFiles(NativeMethods.CF_HDROP, dataObject, out dropDataType); isWindowsFormat = (filesDropped.Count > 0); } // Handle documentation sources and references first. These will be removed from the list before // passing on what's left to add as standard project files. if (isWindowsFormat && filesDropped.Count != 0) { List <string> docSources = filesDropped.Where(f => { string ext = Path.GetExtension(f); return(ext.Equals(".sln", StringComparison.OrdinalIgnoreCase) || ext.EndsWith("proj", StringComparison.OrdinalIgnoreCase)); }).ToList(), refSources = filesDropped.Where(f => { string ext = Path.GetExtension(f); return(ext.Equals(".dll", StringComparison.OrdinalIgnoreCase) || ext.Equals(".exe", StringComparison.OrdinalIgnoreCase) || ext.Equals(".winmd", StringComparison.OrdinalIgnoreCase)); }).ToList(), xmlDocSources = filesDropped.Where(f => { string file = Path.GetFileNameWithoutExtension(f), ext = Path.GetExtension(f); // We only want XML files with a base name that matches an assembly in the list return(ext.Equals(".xml", StringComparison.OrdinalIgnoreCase) && refSources.Any(r => Path.GetFileNameWithoutExtension(r).Equals(file, StringComparison.OrdinalIgnoreCase))); }).ToList(), allDocSources = docSources.Concat(refSources).Concat(xmlDocSources).ToList(); var docSourcesNode = targetNode as DocumentationSourcesContainerNode; // If dropped on the Documentation Sources node, add all documentation sources if (docSourcesNode != null) { foreach (string f in allDocSources) { if (!f.EndsWith(".sln", StringComparison.OrdinalIgnoreCase)) { docSourcesNode.AddDocumentationSource(f); } else { foreach (string project in SandcastleBuilder.Utils.MSBuild.SelectProjectsDlg.SelectSolutionOrProjects(f)) { docSourcesNode.AddDocumentationSource(project); } } } } else { var refsNode = targetNode as SandcastleBuilderReferenceContainerNode; // If dropped on the references node, add all reference files if (refsNode != null) { foreach (string f in refSources) { var node = refsNode.AddReferenceFromSelectorData(new VSCOMPONENTSELECTORDATA { type = VSCOMPONENTTYPE.VSCOMPONENTTYPE_File, bstrFile = f }, null); // Clear the Name and AseemblyName metadata and set the HintPath metadata so that it // treats it correctly when the project is reloaded if (node != null) { string hintPath = f; if (Path.IsPathRooted(hintPath)) { hintPath = PackageUtilities.GetPathDistance(this.ProjectMgr.BaseURI.Uri, new Uri(hintPath)); } node.ItemNode.SetMetadata(ProjectFileConstants.Name, null); node.ItemNode.SetMetadata(ProjectFileConstants.AssemblyName, null); node.ItemNode.SetMetadata(ProjectFileConstants.HintPath, hintPath); } } } } // Remove the documentation source and reference files from the list filesDropped = filesDropped.Except(allDocSources).ToList(); } // Handle all other file types if (dropDataType != DropDataType.None && filesDropped.Count > 0) { string[] filesDroppedAsArray = filesDropped.ToArray(); // For directory based projects the content of the clipboard is a double-NULL terminated list of // Projref strings. if (isWindowsFormat) { // This is the code path when source is Windows Explorer VSADDRESULT[] vsaddresults = new VSADDRESULT[1]; vsaddresults[0] = VSADDRESULT.ADDRESULT_Failure; int addResult = this.AddItem(targetNode.ID, VSADDITEMOPERATION.VSADDITEMOP_OPENFILE, null, (uint)filesDropped.Count, filesDroppedAsArray, IntPtr.Zero, vsaddresults); if (addResult != VSConstants.S_OK && addResult != VSConstants.S_FALSE && addResult != (int)OleConstants.OLECMDERR_E_CANCELED && vsaddresults[0] != VSADDRESULT.ADDRESULT_Success) { ErrorHandler.ThrowOnFailure(addResult); } return(dropDataType); } else if (AddFilesFromProjectReferences(targetNode, filesDroppedAsArray)) { return(dropDataType); } } // If we reached this point then the drop data must be set to None. Otherwise the OnPaste will be // called with a valid DropData and that would actually delete the item. return(DropDataType.None); }