1. <tfoot id='cbPrP'></tfoot>

    • <bdo id='cbPrP'></bdo><ul id='cbPrP'></ul>

    <small id='cbPrP'></small><noframes id='cbPrP'>

    <legend id='cbPrP'><style id='cbPrP'><dir id='cbPrP'><q id='cbPrP'></q></dir></style></legend>
      <i id='cbPrP'><tr id='cbPrP'><dt id='cbPrP'><q id='cbPrP'><span id='cbPrP'><b id='cbPrP'><form id='cbPrP'><ins id='cbPrP'></ins><ul id='cbPrP'></ul><sub id='cbPrP'></sub></form><legend id='cbPrP'></legend><bdo id='cbPrP'><pre id='cbPrP'><center id='cbPrP'></center></pre></bdo></b><th id='cbPrP'></th></span></q></dt></tr></i><div id='cbPrP'><tfoot id='cbPrP'></tfoot><dl id='cbPrP'><fieldset id='cbPrP'></fieldset></dl></div>

      将大型虚拟文件从 C# 拖放到 Windows 资源管理器

      时间:2023-08-25

        <tbody id='mkudC'></tbody>

          1. <legend id='mkudC'><style id='mkudC'><dir id='mkudC'><q id='mkudC'></q></dir></style></legend>

            <small id='mkudC'></small><noframes id='mkudC'>

            • <bdo id='mkudC'></bdo><ul id='mkudC'></ul>

                <i id='mkudC'><tr id='mkudC'><dt id='mkudC'><q id='mkudC'><span id='mkudC'><b id='mkudC'><form id='mkudC'><ins id='mkudC'></ins><ul id='mkudC'></ul><sub id='mkudC'></sub></form><legend id='mkudC'></legend><bdo id='mkudC'><pre id='mkudC'><center id='mkudC'></center></pre></bdo></b><th id='mkudC'></th></span></q></dt></tr></i><div id='mkudC'><tfoot id='mkudC'></tfoot><dl id='mkudC'><fieldset id='mkudC'></fieldset></dl></div>
                <tfoot id='mkudC'></tfoot>
                本文介绍了将大型虚拟文件从 C# 拖放到 Windows 资源管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

                问题描述

                我有一个 C# WPF 应用程序,其中一个部分用作 FTP 客户端,列出远程服务器上的文件并允许用户下载它们.我希望用户能够将文件从文件列表拖放到他们自己的机器上(即到 Windows 资源管理器外壳中).

                I have a C# WPF application with a section that serves as an FTP client, listing files on a remote server and allowing the user to download them. I want the user to be able to drag and drop files from the file listing onto their own machine (i.e. into a Windows Explorer shell).

                为此,我使用了 Delay 博客中的 VirtualFileDataObject 代码,使用 SetDataAction 重载.这适用于较小的文件.

                To accomplish this, I used the VirtualFileDataObject code from Delay's blog, using the Action<Stream> overload of SetData. This works great on smaller files.

                我的问题是:我正在处理的一些文件非常大(2+ GB),VirtualFileDataObject 类处理流的方式涉及将整个文件读入内存,这对于那些非常大的文件,最终可能会引发存储空间不足"错误.

                My problem is: some of the files I'm dealing with are very large (2+ GB), and the way the VirtualFileDataObject class handles the stream involves reading the entire thing into memory, which can end up throwing a "not enough storage" error for those very large files.

                VirtualFileDataObject 代码的相关部分如下.如何重写此代码以不要求整个流都在内存中?

                The relevant section of the VirtualFileDataObject code is below. How can I rewrite this code to not require the entire stream to be in memory?

                    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);
                                },
                            });
                    }
                

                尤其是GetData这一段是罪魁祸首:

                In particular, this section of GetData is the culprit:

                // Wrap in a .NET-friendly Stream and call provided code to fill it
                using (var stream = new IStreamWrapper(iStream)) {
                    streamData(stream);
                }
                

                streamData 是我提供的 Action ,它将实际文件数据写入流.我的代表只是打开一个文件并将字节读取到提供的流中.

                streamData is the Action<stream> I provide which writes the actual file data to the stream. My delegate is just opening a file and reading the bytes into the provided stream.

                有没有办法避免这最后一步,也许以某种方式直接传递文件流以供 Explorer shell 读取?我正在考虑将 iStream 替换为指向我拥有的 .NET 文件流的指针......但我对 COM 互操作的了解还不够,甚至不知道这样做的语法.任何提示/方向将不胜感激!

                Is there a way to avoid this last step, perhaps somehow passing the file stream directly to be read from by the Explorer shell? I'm thinking something like replacing iStream with a pointer to the .NET filestream I've got...but I don't know enough about COM interop to even know the syntax for doing that. Any tips/direction would be appreciated!

                推荐答案

                我遇到了同样的问题,不过很容易解决;)

                I got the same issue, easy to fix though ;)

                问题是我们正在创建一个新的内存流,而它并不需要,因为我们已经有了我们的.您可以在 c# 中创建一个实现 IStream 的 Stream 包装器:

                The problem is that we are creating a new memory stream whereas it is not needed since we already have ours. You can create in c# an Stream wrapper that implements IStream:

                    /// <summary>
                /// Simple class that exposes a read-only Stream as a IStream.
                /// </summary>
                private class StreamWrapper : IStream
                {
                
                   private Stream _stream;
                
                   public StreamWrapper(Stream stream)
                
                   {
                       _stream = stream;
                   }
                
                   public void Read(byte[] pv, int cb, System.IntPtr pcbRead)
                
                   {
                       Marshal.WriteInt32(pcbRead, _stream.Read(pv, 0, cb));
                   }
                
                   public void Seek(long dlibMove, int dwOrigin, System.IntPtr plibNewPosition)
                
                   {
                       Marshal.WriteInt32(plibNewPosition, (int)_stream.Seek(dlibMove, (SeekOrigin)dwOrigin));
                   }
                
                   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 Revert()
                
                   {
                       throw new NotImplementedException();
                   }
                
                   public void SetSize(long libNewSize)
                
                   {
                       throw new NotImplementedException();
                   }
                
                   public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
                
                   {
                       throw new NotImplementedException();
                   }
                
                   public void UnlockRegion(long libOffset, long cb, int dwLockType)
                
                   {
                       throw new NotImplementedException();
                   }
                
                   public void Write(byte[] pv, int cb, IntPtr pcbWritten)
                
                   {
                       throw new NotImplementedException();
                   }
                }
                

                然后在 VirtualFileDataObject 类中,更改 SetData 方法的签名,以便现在传递一个 Stream:

                And then in the VirtualFileDataObject class, change the signature of the SetData method so that you pass now a Stream:

                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);
                 ...
                }
                

                现在,不会创建新的内存流.

                Now, no new memory stream will be created.

                有关更多信息,请访问 http://blogs.msdn.com/b/delay/archive/2009/11/04/creating-something-from-nothing-asynchronously-developer-friendly-virtual-file-implementation-for-net-improved.aspx#10496772 并阅读我的评论

                For further info, go to http://blogs.msdn.com/b/delay/archive/2009/11/04/creating-something-from-nothing-asynchronously-developer-friendly-virtual-file-implementation-for-net-improved.aspx#10496772 and read my comments

                这篇关于将大型虚拟文件从 C# 拖放到 Windows 资源管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

                上一篇:WatiN FireEvent 未在 FireFox 中传递事件属性 下一篇:文件拖放在列表框上不起作用

                相关文章

                最新文章

                <legend id='falze'><style id='falze'><dir id='falze'><q id='falze'></q></dir></style></legend>
                <tfoot id='falze'></tfoot>
              • <i id='falze'><tr id='falze'><dt id='falze'><q id='falze'><span id='falze'><b id='falze'><form id='falze'><ins id='falze'></ins><ul id='falze'></ul><sub id='falze'></sub></form><legend id='falze'></legend><bdo id='falze'><pre id='falze'><center id='falze'></center></pre></bdo></b><th id='falze'></th></span></q></dt></tr></i><div id='falze'><tfoot id='falze'></tfoot><dl id='falze'><fieldset id='falze'></fieldset></dl></div>

                <small id='falze'></small><noframes id='falze'>

                • <bdo id='falze'></bdo><ul id='falze'></ul>