Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
ShellProvider - Delete, Move, Copy, Rename
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2354

Themenstarter:

ShellProvider - Delete, Move, Copy, Rename

beantworten | zitieren | melden

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
Dieser Beitrag wurde 5 mal editiert, zum letzten Mal von inflames2k am .
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
winSharp93
myCSharp.de - Experte

Avatar #avatar-2918.png


Dabei seit:
Beiträge: 6155
Herkunft: Stuttgart

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2354

Themenstarter:

beantworten | zitieren | melden

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 | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers
Cat
myCSharp.de - Member

Avatar #avatar-3070.jpg


Dabei seit:
Beiträge: 790

beantworten | zitieren | melden

Außerdem ist Delete noch falsch implementiert bei bMoveToBin = true und bWithDialog = false (dafür gibt es den |= Operator :P).
private Nachricht | Beiträge des Benutzers
1mannlan
myCSharp.de - Member



Dabei seit:
Beiträge: 88
Herkunft: Deutschland, Bayreuth

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
inflames2k
myCSharp.de - Experte

Avatar #AARsmmPEUMee0tQa2JoB.png


Dabei seit:
Beiträge: 2354

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von inflames2k am .
Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager | Spielkartenbibliothek
private Nachricht | Beiträge des Benutzers