#if UNITY_EDITOR
using System;
using System.Runtime.InteropServices;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Windows 平台高级路径工具
/// </summary>
public class WindowsAdvancedPathTools
{
const int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint OPEN_EXISTING = 3;
const uint GENERIC_READ = 0x80000000;
const int FSCTL_GET_REPARSE_POINT = 0x000900A8;
const uint IO_REPARSE_TAG_SYMLINK = 0xA000000C; // 软连接
const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003; // 挂载点
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[StructLayout(LayoutKind.Sequential)]
struct REPARSE_DATA_BUFFER
{
public uint ReparseTag;
public ushort ReparseDataLength;
public ushort Reserved;
public ushort SubstituteNameOffset;
public ushort SubstituteNameLength;
public ushort PrintNameOffset;
public ushort PrintNameLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_REPARSE_DATA_BUFFER_SIZE)]
public byte[] PathBuffer;
}
public static string GetReparsePointTarget(string reparsePointPath)
{
IntPtr hFile = CreateFile(reparsePointPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
if (hFile == IntPtr.Zero || hFile == new IntPtr(-1))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
try
{
IntPtr outBuffer = Marshal.AllocHGlobal(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
try
{
uint bytesReturned;
bool result = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, outBuffer, (uint)MAXIMUM_REPARSE_DATA_BUFFER_SIZE, out bytesReturned, IntPtr.Zero);
if (!result)
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
var reparseDataBuffer = Marshal.PtrToStructure<REPARSE_DATA_BUFFER>(outBuffer);
if (reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_SYMLINK || reparseDataBuffer.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
{
string targetPath = System.Text.Encoding.Unicode.GetString(reparseDataBuffer.PathBuffer, reparseDataBuffer.SubstituteNameOffset, reparseDataBuffer.SubstituteNameLength);
return targetPath;
}
else
{
throw new InvalidOperationException("指定的文件不是软连接或挂载点");
}
}
finally
{
Marshal.FreeHGlobal(outBuffer);
}
}
finally
{
CloseHandle(hFile);
}
}
}
}
#endif // UNITY_EDITOR
工作中有时会碰到在不同项目中创建软连接的情况,所以就会有获取到软连接真实地址的需要,这里提供一个类,可以做到这一点。
但是一定要传入软连接的节点目录,就是被创建为软连接的那个文件夹才行,软连接内部的文件夹是无法被获取到真实地址的。
4369

被折叠的 条评论
为什么被折叠?



