首页 > 解决方案 > 使用 Win32 API 的文件拖放在文件资源管理器等某些应用程序上不起作用

问题描述

我在 .NET Core 应用程序上使用 Win32 API 实现了文件拖放。问题是,它适用于某些应用程序,而不适用于其他一些应用程序。

为什么会这样?

我实现 IDataObject 的“DataObject”FORMATETCEnumFormatEtc(). 其中我只返回一个 FORMATETC。

new FORMATETC()
{
    cfFormat = CF_HDROP,
    ptd = IntPtr.Zero,
    dwAspect = DVASPECT.DVASPECT_ICON,
    lindex = -1,
    tymed = TYMED.TYMED_HGLOBAL
}

On QueryGetData(),如果格式的 tymed 是TYMED_HGLOBAL,则返回 S_OK 表示我正在拖动文件。否则返回 DV_E_TYMED 意味着我没有那种类型的数据。

GetData()or GetDataHere(), if format.cfFormat == CF_HDROPand format.tymed == TYMED.TYMED_HGLOBAL, 我这样填写medium

medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_HGLOBAL;
medium.unionmember = mem;
medium.pUnkForRelease = IntPtr.Zero;

, 这样mem分配的内存在哪里DROPFILES

IntPtr CreateDropFiles(string[] strFiles)
{
    var buffer = new MemoryStream();
    var df = new DROPFILES();
    IntPtr ipGlobal = IntPtr.Zero;
    int bufferLength;

    foreach(var file in strFiles)
    {
        var b = Encoding.Unicode.GetBytes(file);
        buffer.Write(b, 0, b.Length);
        buffer.WriteByte(0);
        buffer.WriteByte(0);
    }
    buffer.WriteByte(0);
    bufferLength = (int)buffer.Length;

    // Allocate and get pointer to global memory
    int intTotalLen = Marshal.SizeOf(df) + bufferLength;
    ipGlobal = Marshal.AllocHGlobal(intTotalLen);

    df.pFiles = Marshal.SizeOf(df);
    df.fWide = true;

    Marshal.StructureToPtr(df, ipGlobal, true);
    var ipNew = new IntPtr(ipGlobal.ToInt64() + Marshal.SizeOf(df));
    Marshal.Copy(buffer.ToArray(), 0, ipNew, bufferLength);

    return ipGlobal;
}

相比之下,使用 WinForm 的方法将文件拖放到文件资源管理器或 VS Code 就可以了,如下所示。

var data = new System.Windows.Forms.DataObject(
    System.Windows.Forms.DataFormats.FileDrop,
    new string[] { file1, file2 });
dummy.DoDragDrop(data, System.Windows.Forms.DragDropEffects.Copy);

标签: c#winapi.net-corepinvokeole

解决方案


推荐阅读