2015-09-02 7 views
9

Beim Umbenennen eines Ordners in C# System.IO.Directory.Move wird System.IO.IOException (Nachricht "Zugriff verweigert") ausgelöst, wenn dieser Ordner oder ein Unterordner derzeit von einem Explorer (Windows 7) geöffnet wird Fenster. Die Befehlszeile RENAME schlägt ebenfalls fehl. Mit einem zweiten Explorer gelingt Windows.So benennen Sie einen Ordner in C# um, der gerade von Windows Explorer geöffnet wird

Der Fehler bleibt auch nach dem Zusammenklappen des übergeordneten Ordners (oder seiner Eltern) bestehen. In der Tat muss das bestimmte Explorer-Fenster geschlossen werden. So scheint der Explorer einige Sperren zu erstellen, nur um die Ordnerstruktur anzuzeigen und sie nicht zu veröffentlichen, selbst wenn der tatsächliche Ordner nicht mehr angezeigt wird (was pure nonsens IMO ist).

Gibt es eine Möglichkeit, einen Ordner umzubenennen (in einem Programm, z. B. mit C#), das derzeit durch ein Explorer-Fenster angezeigt wird (oder sichtbar war, siehe oben)?

aktualisieren

einen Weg gefunden, wie sie durch meine eigene Antwort auf diese Frage beschrieben (siehe unten) SHFileOperation() verwenden. Diese Lösung ist jedoch nicht sehr machbar (siehe auch unten).

+0

Ich habe das getestet und es funktioniert, wahrscheinlich haben Sie auch eine Datei geöffnet oder nicht genügend Berechtigungen für diesen Ordner. Ich habe ein Verzeichnis 'D: \ a' erstellt und über den Explorer dorthin geblättert, als ich diesen Code' Directory.Move ("D: \\ a", "D: \\ b"); ', den Ordner ausgeführt habe Der Name wurde in der Explorer- und Adressleiste automatisch geändert. –

+0

@Wouter: Ich denke, du musst ein weiteres Level hinzufügen. Erstellen Sie 'D: \ a \ b', navigieren Sie zu" D: \ a \ b "über den Explorer und versuchen Sie dann,' a' (als 'x' oder was auch immer) umzubenennen. Es funktioniert hier nicht. Navigieren Sie nun zu 'a' oder zu' computer', so dass weder 'a' noch' b' in diesem Fenster angezeigt werden (nur die Laufwerke werden angezeigt). Es funktioniert immer noch nicht. BTW, keine Dateien geöffnet und keine Erlaubnis Problem sicher. – user2261015

+0

Teilweise, wenn der Explorer den Unterordner anzeigt, wird die 'IOException' ausgelöst, wenn der Explorer das Root-Laufwerk anzeigt, funktioniert es. Ich muss sagen, dass ich unter Windows 10 teste, was den kleinen Unterschied erklären könnte. –

Antwort

2

Also meine eigene Frage nach einigen weiteren reasearch Ich beantworte ..

Der Ordner kann mit SHFileOperation() umbenannt werden wie hier gezeigt: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776887%28v=vs.85%29.aspx (ob dies der ‚Magie‘ verwendet von Wouter erwähnt oder nicht. ;-)

Aber wenn es eine Windows/.Net API wie System.IO.Directory.Move gibt, muss WTF die Shell verwenden? Nicht über Leistung sprechen ...

Wie auch immer, mit SHFileOperation() ist ein Schmerz in der a .. mit C#, da Sie all diese p-invoke Zeug deklarieren müssen. Und in diesem speziellen Fall müssen Sie verschiedene Strukturen für 32- und 64-Bit-Fenster verwenden, da die Packung anders ist (siehe http://www.pinvoke.net/default.aspx/shell32.shfileoperation). Dies ist sehr umständlich, da ich normalerweise AnyCPU als Ziel angeben würde. An diesem Punkt müssen Sie entweder zur Laufzeit verzweigen (in der Tat sehr schlecht), abhängig davon, ob Sie ein 64- oder 32-Bit-Prozess sind oder Sie für zwei verschiedene Ziele unterschiedlich bauen, was eine ziemlich große Auswirkung ist, nur um den albernen Explorer zu umgehen.

Grüße

4

Ich habe API Monitor v2 by Rohitab verwendet, um Windows API-Aufrufe zu überwachen.

Wenn Sie den Verzeichnisnamen D:\test-D:\abc zu ändern, wurde dieser Aufruf protokolliert:

explorerframe.dll ITransferSource::RenameItem (0x0000000015165738, "abc", TSF_COPY_CREATION_TIME | TSF_COPY_LOCALIZED_NAME | TSF_COPY_WRITE_TIME | TSF_DELETE_RECYCLE_IF_POSSIBLE, 0x00000000150f77d0) 

weiter in den Ausgang des Monitors Graben zeigt einige einheimische Anrufe:

enter image description here

Wie Sie kann sehen, sie verwenden nicht MoveFile, stattdessen verwenden sie NtOpenFile mit FILE_OPEN_FOR_BACKUP_INTENT und andere, um das ursprüngliche Verzeichnis zu öffnen, dann cal l NtSetInformationFile mit dem neuen Verzeichnisnamen und der Flagge FileRenameInformation, die dokumentiert ist here.

Leider sind dies alle Kernelaufrufe.

Sie können einen Griff in ein Verzeichnis in C/C++ von User-Mode wie diese:

HANDLE h = ::CreateFileA("D:\\test", 
    DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 
    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
    OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS, 
    NULL); 

Aber dann müssen Sie noch einen alternativen Benutzer-Modus für den NtSetInformationFile -Aufruf.

Einige Optionen gehen (nach Komplexität geordnet):

  • Sehen Sie, wenn Sie die Shell-Schnittstelle ITransferSource::RenameItem oder finden eine ready-to-use Shell-Funktion
  • Dig weiter in den User-Mode-Lösung verwenden können und versuchen Sie, eine Alternative zu NtSetInformationFile
  • zu finden Schreiben Sie einen Treiber, der eine IOCTL enthält, die diese Kernel-Modus-Sachen ausführt, und rufen Sie DeviceIoControl von C# auf.

aktualisieren

scheint, wie die SHFileOperation Funktion alle oben hat, wie durch die OP gefunden.

Wird diese Antwort online verlassen, weil es anderen zeigen könnte, wie man ähnliche Probleme debuggt und wertvolle Hinweise erhält.

0

hatte ich das gleiche Problem. Sobald ich ein Explorer-Fenster geöffnet und einmal in den Ordner zum Umbenennen navigiert hatte, schlug die Directory.Move mit einem "Zugriff verweigert" (Windows 7 Professional 64bit, Anwendung als x86 kompiliert).

Interessanterweise gelingt es dem Befehl Microsoft.VisualBasic.FileIO.FileSystem.MoveDirectory(...), den Inhalt in ein neues Verzeichnis zu verschieben. Das alte Verzeichnis kann nur dann nicht gelöscht werden, wenn Sie sich in einem Unterordner des zu verschiebenden Verzeichnisses befinden. Dies kann behoben werden, indem die Ausnahme, die beim ersten Fehler ausgelöst wird, abgefangen und ein zweites Mal erneut versucht wird. Jetzt wird auch der Quellordner entfernt.

Verwandte Themen