CS/SymbolicLink.cs
using System;
using System.Runtime.InteropServices; using System.ComponentModel; using System.Text; using Microsoft.Win32.SafeHandles; namespace Valentia.CS { public class SymbolicLink { private const int FileShareRead = 1; private const int FileShareWrite = 2; private const int CreationDispositionOpenExisting = 3; private const int FileFlagBackupSemantics = 0x02000000; internal static class Win32 { [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, SymLinkFlag dwFlags); [DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int GetFinalPathNameByHandle(IntPtr handle, [In, Out] StringBuilder path, int bufLen, int flags); [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode, SetLastError = true)] public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr SecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); internal enum SymLinkFlag { File = 0, Directory = 1 } } public static void CreateSymLink(string name, string target, bool isDirectory = false) { if (!Win32.CreateSymbolicLink(name, target, isDirectory ? Win32.SymLinkFlag.Directory : Win32.SymLinkFlag.File)) { throw new Win32Exception(); } } public static string GetSymbolicLinkTarget(System.IO.DirectoryInfo symlink) { var directoryHandle = Win32.CreateFile(symlink.FullName, 0, 2, IntPtr.Zero, CreationDispositionOpenExisting, FileFlagBackupSemantics, IntPtr.Zero); if (directoryHandle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); var path = new StringBuilder(512); var size = Win32.GetFinalPathNameByHandle(directoryHandle.DangerousGetHandle(), path, path.Capacity, 0); if (size < 0) throw new Win32Exception(Marshal.GetLastWin32Error()); // The remarks section of GetFinalPathNameByHandle mentions the return being prefixed with "\\?\" // More information about "\\?\" here -> http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx if (path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\') { return path.ToString().Substring(4); } return path.ToString(); } } } |