2 Stimmen

Hilfe mit PInvoke CreateDirectory () in C#

Ich bin mit C# für WinForms app in VS2010 und ich brauchte, um ein Verzeichnis zu erstellen, in dem der Pfad zu groß für die .NET-Methoden war (248 Zeichen Limit, ich glaube) und stieß auf Vorschläge von Google, um die Unicode Win32 CreateDirectory() zu verwenden. Ich hatte zunächst versucht, es mit Unicode und übergebenen Parametern aufzurufen, aber nach mehreren fehlgeschlagenen Versuchen habe ich den Code reduziert und verwende GENAU den Code hier gefunden:

http://www.pinvoke.net/default.aspx/Structures/SECURITY_ATTRIBUTES.html

Ich erhalte immer noch den gleichen Fehler:

System.AccessViolationException wurde abgefangen Message=Versucht, geschützten Speicher zu lesen oder zu schreiben. Dies ist oft ein Hinweis darauf, dass anderer Speicher beschädigt ist.

Zugegeben, ich weiß nichts über den Aufruf der Win32-Funktionen, ich bin wirklich nur ziehen, was ich online finden und versuchen zu lernen. Kann mir jemand sagen, was ich falsch mache? Ich habe für die Frage unwichtigen Code entfernt:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Text;

namespace RFCGenerator
{

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }

    public class RFC
    {

        [DllImport("kernel32.dll")]
        static extern bool CreateDirectory(string lpPathName, SECURITY_ATTRIBUTES lpSecurityAttributes);   

        protected void CopyDirectory(Uri Source, Uri Destination)
        {

            SECURITY_ATTRIBUTES lpSecurityAttributes = new SECURITY_ATTRIBUTES();
            DirectorySecurity security = new DirectorySecurity();
            lpSecurityAttributes.nLength = Marshal.SizeOf(lpSecurityAttributes);
            byte[] src = security.GetSecurityDescriptorBinaryForm();
            IntPtr dest = Marshal.AllocHGlobal(src.Length);
            Marshal.Copy(src, 0, dest, src.Length);
            lpSecurityAttributes.lpSecurityDescriptor = dest;
            string path = @"C:\Test";
            CreateDirectory(path, lpSecurityAttributes);
        }
    }
}

UPDATE: Mit Hilfe von Hans' Vorschlag habe ich dies lokal zum Laufen gebracht. Wenn ich jedoch versuche, ein Verzeichnis mit einer UNC-Adresse zu erstellen, z. B. durch Eingabe von:

 path = @"\\mydomain.com\foo\bar\newfolder"

Ich bekomme jetzt:

System.ComponentModel.Win32Exception wurde abgefangen Message=Die Syntax des Dateinamens, des Verzeichnisnamens oder der Datenträgerbezeichnung ist falsch

Ich habe überprüft, dass \\mydomain.com\foo\bar\ gibt es.

LÖSUNG:

Mit dem Code von Hans und einer kleinen Änderung, um zu prüfen, ob es sich um einen UNC-Pfad handelt (Referenz: http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx (siehe "Begrenzung der maximalen Trassenlänge"):

string UnicodePath = (path.StartsWith(@"\\")) ? @"\\?\UNC\" + (path.Remove(0, 2)) : @"\\?\" + path;
if (!CreateDirectory(UnicodePath, IntPtr.Zero))
    throw new System.ComponentModel.Win32Exception();

5voto

Hans Passant Punkte 894572

Sie verwenden nicht die Unicode-Version, die CharSet = CharSet.Unicode in der [DllImport]-Deklaration erfordert. Außerdem hat das Erstellen von Verzeichnissen mit langen Namen nichts mit dem Sicherheitsattribut zu tun. Sie müssen dem Namen das Präfix @"\\?\" . So:

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes); 
...
if (!CreateDirectory(@"\\?\" + path, IntPtr.Zero))
    throw new Win32Exception();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X