You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForms粘贴WhatsApp长路径文件失败求助

解决WhatsApp长路径文件粘贴到WinForms应用的问题

核心问题在于Clipboard.GetFileDropList()依赖的CF_HDROP剪贴板格式本身存在260字符的路径长度限制,而Windows资源管理器能正常粘贴是因为它读取的是剪贴板中的OLE格式数据(CFSTR_FILEDESCRIPTORW和CFSTR_FILECONTENTS),绕过了旧格式的限制。以下是具体解决思路和实现:

解决步骤

1. 直接读取剪贴板的OLE文件格式

跳过CF_HDROP,直接访问剪贴板中用于传输文件的OLE私有格式:

  • CFSTR_FILEDESCRIPTORW:存储文件的元数据(包括完整长路径)
  • CFSTR_FILECONTENTS:存储文件的实际内容

2. 通过P/Invoke调用Windows API实现读取

由于.NET的Clipboard类未直接封装这些格式的访问,需要用P/Invoke调用底层Windows API:

定义必要的结构体和API

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public static class ClipboardLongPathHelper
{
    private const uint CFSTR_FILEDESCRIPTORW = 0x0000002F;
    private const uint CFSTR_FILECONTENTS = 0x00000030;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct FILEDESCRIPTORW
    {
        public uint dwFlags;
        public Guid clsid;
        public System.Drawing.Size sizel;
        public System.Drawing.Point pointl;
        public uint dwFileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct FILEGROUPDESCRIPTORW
    {
        public uint cItems;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public FILEDESCRIPTORW[] fgd;
    }

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr GetClipboardData(uint uFormat);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool OpenClipboard(IntPtr hWndNewOwner);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool CloseClipboard();

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GlobalLock(IntPtr hMem);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GlobalUnlock(IntPtr hMem);

    public static string[] GetLongPathFileDropList()
    {
        if (!OpenClipboard(IntPtr.Zero))
            return Array.Empty<string>();

        try
        {
            IntPtr hFgd = GetClipboardData(CFSTR_FILEDESCRIPTORW);
            if (hFgd == IntPtr.Zero)
                return Array.Empty<string>();

            IntPtr pFgd = GlobalLock(hFgd);
            if (pFgd == IntPtr.Zero)
                return Array.Empty<string>();

            try
            {
                FILEGROUPDESCRIPTORW fgd = Marshal.PtrToStructure<FILEGROUPDESCRIPTORW>(pFgd);
                string[] files = new string[fgd.cItems];

                // 遍历每个文件描述符,计算结构体偏移
                for (int i = 0; i < fgd.cItems; i++)
                {
                    IntPtr pItem = IntPtr.Add(pFgd, Marshal.SizeOf<uint>() + i * Marshal.SizeOf<FILEDESCRIPTORW>());
                    FILEDESCRIPTORW item = Marshal.PtrToStructure<FILEDESCRIPTORW>(pItem);
                    files[i] = item.cFileName;
                }

                return files;
            }
            finally
            {
                GlobalUnlock(hFgd);
            }
        }
        finally
        {
            CloseClipboard();
        }
    }
}

在WinForms中使用该工具类

在你的窗体粘贴事件中,替换Clipboard.GetFileDropList()为自定义方法:

private void Form1_Paste(object sender, EventArgs e)
{
    string[] files = ClipboardLongPathHelper.GetLongPathFileDropList();
    if (files.Length > 0)
    {
        // 处理完整路径的文件,例如复制到目标目录
        foreach (string filePath in files)
        {
            // 直接使用完整长路径即可,无需额外转义
            Console.WriteLine("完整文件路径:" + filePath);
        }
    }
}

3. 补充说明

  • 之前的长路径配置无效的原因:Clipboard.GetFileDropList()依赖的CF_HDROP是Windows旧文件传输机制,即使应用启用了长路径支持,该API内部仍会截断路径到260字符,必须直接读取OLE格式才能获取完整路径。
  • 如果需要获取文件实际内容(而非仅路径),可以进一步读取CFSTR_FILECONTENTS格式的数据,通过StgOpenStorage等API提取文件内容。

内容的提问来源于stack exchange,提问作者Marioj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:45:19