Laden...

ShellProvider - Delete, Move, Copy, Rename

Erstellt von inflames2k vor 12 Jahren Letzter Beitrag vor 12 Jahren 4.791 Views
inflames2k Themenstarter:in
2.298 Beiträge seit 2010
vor 12 Jahren
ShellProvider - Delete, Move, Copy, Rename

Beschreibung:

Mit der Klasse können Dateien / Ordner mittels Shell-Operationen gelöscht, verschoben und kopiert werden. Dabei werden die Windows-Standard-Dialoge für die jeweilige Operation angezeigt.

Umgesetzt habe ich die Klasse nachdem ich die Frage in Windows Dialog zum Löschen von Ordnern aus eigenen Programm heraus benutzen gelesen habe und die Grundlegende Idee nicht schlecht fand.


 [color][SIZE][B]Hinweis![/B][/SIZE][/COLOR]

Die Klasse funktioniert womöglich nicht unter Windows 7. Ich habe sie damals nur auf Windows XP getestet. Auf meinem privaten Notebook (Windows 7) funktionieren die Methoden zumindest nicht. 

[SIZE]Getestet am 16.04.2012[/SIZE]


public class ShellProvider
	{
		#region imports

		[DllImport("shell32.dll")]
		static extern int SHFileOperation([In] ref SHFILEOPSTRUCT lpFileOp);

		#endregion

		#region nested

		private enum FO_Func : uint
		{
			FO_MOVE = 0x0001,
			FO_COPY = 0x0002,
			FO_DELETE = 0x0003,
			FO_RENAME = 0x0004,
		}

		private struct SHFILEOPSTRUCT
		{
			public IntPtr hwnd;
			public Int32 wFunc;
                        [MarshalAs(UnmanagedType.LPWStr)]
			public string pFROM;
                        [MarshalAs(UnmanagedType.LPWStr)]
			public string pTo;
			public FILEOP_FLAGS_ENUM fFlags;
			public bool fAnyOperationsAborted;
			public Int32 hNameMappings;
			public string lpszProgressTitle;
		}

		private enum FILEOP_FLAGS_ENUM : ushort
		{
			FOF_MULTIDESTFILES = 0x0001,
			FOF_CONFIRMMOUSE = 0x0002,
			FOF_SILENT = 0x0004,  // don't create progress/report
			FOF_RENAMEONCOLLISION = 0x0008,
			FOF_NOCONFIRMATION = 0x0010,  // Don't prompt the user.
			FOF_WANTMAPPINGHANDLE = 0x0020,  // Fill in SHFILEOPSTRUCT.hNameMappings
			// Must be freed using SHFreeNameMappings
			FOF_ALLOWUNDO = 0x0040,
			FOF_FILESONLY = 0x0080,  // on *.*, do only files
			FOF_SIMPLEPROGRESS = 0x0100,  // means don't show names of files
			FOF_NOCONFIRMMKDIR = 0x0200,  // don't confirm making any needed dirs
			FOF_NOERRORUI = 0x0400,  // don't put up error UI
			FOF_NOCOPYSECURITYATTRIBS = 0x0800,  // dont copy NT file Security Attributes
			FOF_NORECURSION = 0x1000,  // don't recurse into directories.
			FOF_NO_CONNECTED_ELEMENTS = 0x2000,  // don't operate on connected elements.
			FOF_WANTNUKEWARNING = 0x4000,  // during delete operation, warn if nuking instead of recycling (partially overrides FOF_NOCONFIRMATION)
			FOF_NORECURSEREPARSE = 0x8000,  // treat reparse points as objects, not containers
		}

		#endregion

		#region Fields
		#endregion

		#region Properties
		#endregion

		#region Construction / Destruction
		#endregion

		#region Methods

		/// <summary>
        /// Method to delete a file or folder by shell
        /// </summary>
        /// <param name="sPath">path to the file / folder</param>
        public void Delete(string sPath, bool bMoveToBin, bool bWithDialog)
        {
            this.RunFileOperation(sPath, string.Empty, FO_Func.FO_DELETE, (bMoveToBin ? FILEOP_FLAGS_ENUM.FOF_ALLOWUNDO : 0) | (!bWithDialog ? FILEOP_FLAGS_ENUM.FOF_NOCONFIRMATION: 0));
        }

        /// <summary>
        /// Method to move a file
        /// </summary>
        /// <param name="sSource">the source path</param>
        /// <param name="sDestination">the destination path</param>
        public void Move(string sSource, string sDestination, bool bWithDialog)
        {
            this.RunFileOperation(sSource, sDestination, FO_Func.FO_MOVE, !bWithDialog ? FILEOP_FLAGS_ENUM.FOF_NOCONFIRMATION : 0);
        }

        /// <summary>
        /// Method to copy a file
        /// </summary>
        /// <param name="sSource">the source of the file</param>
        /// <param name="sDestination">the files destination</param>
        public void Copy(string sSource, string sDestination, bool bWithDialog)
        {
            this.RunFileOperation(sSource, sDestination, FO_Func.FO_COPY, !bWithDialog ? FILEOP_FLAGS_ENUM.FOF_NOCONFIRMATION : 0);
        }

        /// <summary>
        /// Method to rename a file or folder
        /// </summary>
        public void Rename(string sSource, string sDestination, bool bWithDialog)
        {
            this.RunFileOperation(sSource, sDestination, FO_Func.FO_RENAME, !bWithDialog ? FILEOP_FLAGS_ENUM.FOF_NOCONFIRMATION : 0);
        }

        /// <summary>
        /// Method to run the file operation
        /// </summary>
        /// <param name="sSource">the source file</param>
        /// <param name="sDestination">the destination file</param>
        /// <param name="func">the func</param>
        /// <param name="flags">the flags</param>
        /// <returns>result code</returns>
        private int RunFileOperation(string sSource, string sDestination, FO_Func func, FILEOP_FLAGS_ENUM flags)
        {
            SHFILEOPSTRUCT structure = new SHFILEOPSTRUCT();
            structure.hwnd = IntPtr.Zero;
            structure.wFunc = (int)func;
            structure.pFROM = sSource;
            structure.pTo = sDestination;
            structure.fFlags = flags;

            return SHFileOperation(ref structure);
        }

		#endregion
	}  

Schlagwörter: Löschen mit Standard-Dialog, Shelloperationen, Windows Shell, Shell Kopiervorgang, Shell Verschieben

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

5.742 Beiträge seit 2007
vor 12 Jahren

Als kleinen Verbesserungsvorschlag solltest du noch die Rückgabewerten der API-Funktionen auswerten und entsprechend Exceptions werfen.

Zudem solltest es auch möglich sein, das Marshalling der Strings mit Attributen zu lösen, statt manuell Nullbytes anzuhängen.

inflames2k Themenstarter:in
2.298 Beiträge seit 2010
vor 12 Jahren

Zu den Rückgabewerten:
Ich bin mir nicht sicher, ob das sinnvoll ist. Ich habe das ganze jetzt mehrfach getestet und immer wenn es fehlschlägt, wird durch das Betriebssystem bereits eine Fehlermeldung ausgegeben. Insofern gehe ich davon aus, dass eine weitere Verarbeitung des Result-Codes hier nicht notwendig ist.

Zum Marshalling statt manueller Nullbytes:
Das werd ich heut Abend noch hinzufügen.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

771 Beiträge seit 2009
vor 12 Jahren

Außerdem ist Delete noch falsch implementiert bei bMoveToBin = true und bWithDialog = false (dafür gibt es den |= Operator 😛).

1
88 Beiträge seit 2009
vor 12 Jahren

Es scheint auch, als würde moveToBin nicht richtig funktionieren, auf der Verschieben von Dateien in den Papierkorb wird auch darauf hingewiesen, das man mit diesem Flag aufpassen muss (Vollständiger Pfadname?!). Das ändern des Flags bringt zumindest beim angeben von Ordnern, die gelöscht werden sollen, keinen Unterschied.

inflames2k Themenstarter:in
2.298 Beiträge seit 2010
vor 12 Jahren

Ich habe die offensichtlichen Fehler korrigiert, und den Grundlegenden API Aufruf in eine eigene Methode gepackt.

Die Auswertung des Fehlercodes habe ich aus oben genannten Gründen erst einmal weg gelassen.

// EDIT: Die volle Flagliste ist nicht notwendig, lasse ich aber drin, falls jemand die Operationen mit anderen Flags ausführen lassen möchte.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |