使用VirtualFileDataObject IStream的拖放大的虚拟文件 [英] Drag and Drop large virtual files with IStream using VirtualFileDataObject

查看:207
本文介绍了使用VirtualFileDataObject IStream的拖放大的虚拟文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我成功地使用的 VirtualFileDataObject迟延的博客代码,但我想避免流整个文件到内存中。

I am successfully using VirtualFileDataObject code from Delay's blog, but i want to avoid streaming the entire file into memory.

我发现对堆栈溢出的拖放从C#大型虚拟文件到Windows资源管理器的问题是由马修回答,通过改变SetData方法的签名。

I found this previously answered question on Stack Overflow Drag and Drop large virtual files from c# to Windows Explorer The question was answered by matthieu, by changing the signature of the SetData method.

下面是我的问题,改变SetData方法的签名之后,其他地方调用它仍然在寻找旧签名。

Here is my problem, after changing the signature of the SetData method, other places that call it are still looking for the old signature.

下面是原来的SetData;

Here is the original SetData;

   public void SetData(short dataFormat, int index, Action<Stream> streamData)
    {
        _dataObjects.Add(
            new DataObject
            {
                FORMATETC = new FORMATETC
                {
                    cfFormat = dataFormat,
                    ptd = IntPtr.Zero,
                    dwAspect = DVASPECT.DVASPECT_CONTENT,
                    lindex = index,
                    tymed = TYMED.TYMED_ISTREAM
                },
                GetData = () =>
                {
                    // Create IStream for data
                    var ptr = IntPtr.Zero;
                    var iStream = NativeMethods.CreateStreamOnHGlobal(IntPtr.Zero, true);
                    if (streamData != null)
                    {
                        // Wrap in a .NET-friendly Stream and call provided code to fill it
                        using (var stream = new IStreamWrapper(iStream))
                        {
                            streamData(stream);
                        }
                    }
                    // Return an IntPtr for the IStream
                    ptr = Marshal.GetComInterfaceForObject(iStream, typeof(IStream));
                    Marshal.ReleaseComObject(iStream);
                    return new Tuple<IntPtr, int>(ptr, NativeMethods.S_OK);
                },
            });
    }



马修建议改变它;

matthieu suggested to change it to;

public void SetData(short dataFormat, int index, Stream stream)
{
  ...
  var iStream = new StreamWrapper(stream);
  ...
  // Ensure the following line is commented out:
  //Marshal.ReleaseComObject(iStream);
  return new Tuple<IntPtr, int>(ptr, NativeMethods.S_OK);
 ...
}

在我进行这些更改下面的调用将不行; (这就是我需要帮助)
我如何解决这个呼叫;

After I make these changes the following call will not work; ( and this is where i need help) How do i fix this call;

            foreach (var fileDescriptor in fileDescriptors)
        {
            **SetData(FILECONTENTS, index, fileDescriptor.StreamContents);**
            index++;
        }



基本上改变行动streamData要流流引起我的问​​题。我不知道如何称呼它为更改后。

Basically changing "Action streamData" To "Stream stream" is causing my problems. I am not sure on how to call it after the changes are made.

所有这些代码来自延迟VirtualFileDataObject。我不知道我是否应该在这里或不发布它。但是,如果你按照它上面的链接将带您到博客,以便您可以查看它。

All this code comes from Delays VirtualFileDataObject. I don't know if i should post it on here or not. But if you follow the link above it will take you to the blog so you can view it.

我是如此接近,只是不知道这最后一步了,感谢您抽出宝贵看看

I am so close, just can't figure this last step out, thanks for taking a look

推荐答案

我有完全相同的问题。这里是我做过什么来解决这个问题(这就像你说的并没有在对方的回答得到了充分的阐述)

I've had exactly the same problem. Here is what I did to fix this issue (which as you say has not been fully addressed in the other answer)

1)修改的FileDescriptor 此的 StreamContents 属性:

public Action<Stream> StreamContents { get; set; }



这样:

to this:

public Func<Stream> StreamContents { get; set; }



的(而不是通过一个的客户端可以写,我们将期待一个我们可以,而这正是浏览器是如何工作的以及它预计)读

(instead of passing a Stream the client can write, we'll expect a Stream we can read from, which is exactly how Explorer works and what it expects)

2)从这个修改的SetData 方法重载:

2) Modify the SetData method overload from this:

public void SetData(short dataFormat, int index, Action<Stream> streamData)

这样:

public void SetData(short dataFormat, int index, Func<Stream> streamData)

3)变更的SetData 代码的的GetData 拉姆达这样:

3) change SetData code's GetData lambda to this:

GetData = () =>
{
    ManagedIStream istream = null;
    if (streamData != null)
    {
        Stream stream = streamData();
        if (stream != null)
        {
            istream = new ManagedIStream(stream);
        }
    }

    IntPtr ptr = istream != null ? Marshal.GetComInterfaceForObject(istream, typeof(IStream)) : IntPtr.Zero;
    return new Tuple<IntPtr, int>(ptr, NativeMethods.S_OK);
},



4)添加此 ManagedIStream 类的代码(也可以删除 IStreamWrapper 类完全)

4) add this ManagedIStream class to the code (you can also delete the IStreamWrapper class completely)

private class ManagedIStream : IStream
{
    private Stream _stream;

    public ManagedIStream(Stream stream)
    {
        _stream = stream;
    }

    public void Clone(out IStream ppstm)
    {
        throw new NotImplementedException();
    }

    public void Commit(int grfCommitFlags)
    {
        throw new NotImplementedException();
    }

    public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
    {
        throw new NotImplementedException();
    }

    public void LockRegion(long libOffset, long cb, int dwLockType)
    {
        throw new NotImplementedException();
    }

    public void Read(byte[] pv, int cb, IntPtr pcbRead)
    {
        int read = _stream.Read(pv, 0, cb);
        if (pcbRead != IntPtr.Zero)
        {
            Marshal.WriteInt32(pcbRead, read);
        }
    }

    public void Revert()
    {
        throw new NotImplementedException();
    }

    public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
    {
        long newPos = _stream.Seek(dlibMove, (SeekOrigin)dwOrigin);
        if (plibNewPosition != IntPtr.Zero)
        {
            Marshal.WriteInt64(plibNewPosition, newPos);
        }
    }

    public void SetSize(long libNewSize)
    {
        _stream.SetLength(libNewSize);
    }

    public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
    {
        const int STGTY_STREAM = 2;
        pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
        pstatstg.type = STGTY_STREAM;
        pstatstg.cbSize = _stream.Length;
        pstatstg.grfMode = 0;

        if (_stream.CanRead && _stream.CanWrite)
        {
            const int STGM_READWRITE = 0x00000002;
            pstatstg.grfMode |= STGM_READWRITE;
            return;
        }

        if (_stream.CanRead)
        {
            const int STGM_READ = 0x00000000;
            pstatstg.grfMode |= STGM_READ;
            return;
        }

        if (_stream.CanWrite)
        {
            const int STGM_WRITE = 0x00000001;
            pstatstg.grfMode |= STGM_WRITE;
            return;
        }

        throw new IOException();
    }

    public void UnlockRegion(long libOffset, long cb, int dwLockType)
    {
        throw new NotImplementedException();
    }

    public void Write(byte[] pv, int cb, IntPtr pcbWritten)
    {
        _stream.Write(pv, 0, cb);
        if (pcbWritten != IntPtr.Zero)
        {
            Marshal.WriteInt32(pcbWritten, cb);
        }
    }
}

这就是它。现在,你可以使用这样的代码(使用相同的样品这里提供原文章:的http:// dlaa.me/blog/post/9913083 ):

That's it. Now you can use the code like this (using the same sample as in the original article available here: http://dlaa.me/blog/post/9913083):

new VirtualFileDataObject.FileDescriptor
{
    Name = "Alphabet.txt",
    Length = 26,
    ChangeTimeUtc = DateTime.Now.AddDays(-1),
    StreamContents = () =>
    {
        var contents = Enumerable.Range('a', 26).Select(i => (byte)i).ToArray();
        MemoryStream ms = new MemoryStream(contents); // don't dispose/using here, it would be too early
        return ms;
    }
};

这篇关于使用VirtualFileDataObject IStream的拖放大的虚拟文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆