帮助在C#中使用PInvoke CreateDirectory()

时间:2010-08-26 15:28:57

标签: c# pinvoke

我在VS2010中使用C#for WinForms应用程序,我需要创建一个目录,其中路径对于.NET方法而言太大(我相信248字符串限制),并且跨越了谷歌的建议以使用Unicode Win32 CreateDirectory()。我最初尝试使用Unicode调用它并传递参数,但在几次尝试失败之后,我已经减少了代码并使用了完全正确的代码:

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

我仍然遇到同样的错误:

发现了System.AccessViolationException   Message =尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

不可否认,我对调用Win32函数一无所知,我真的只是拉动我在网上找到并尝试学习的内容。谁能告诉我我做错了什么?删除问题的非必要代码,我有:

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);
        }
    }
}

更新:使用Hans的建议,我确实让它在本地工作。但是,当我尝试使用UNC地址创建目录时,例如传入:

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

我现在得到:

发现了System.ComponentModel.Win32Exception   Message =文件名,目录名或卷标语法不正确

我已经确认\\ mydomain.com \ foo \ bar \确实存在。

解决方案:

使用Hans代码和一个小修改来检查它是否是UNC路径(参考:http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx,在“最大路径长度限制”下):

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

1 个答案:

答案 0 :(得分:5)

您没有使用Unicode版本,需要[DllImport]声明中的CharSet = CharSet.Unicode。此外,创建具有长名称的目录与安全属性无关。您必须在名称前添加@"\\?\"。因此:

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