简体   繁体   English

使用Delphi 2007从虚拟文件夹加载文件

[英]Load File From Virtual Folder Using Delphi 2007

I am trying to load the contents of a file from one of the Windows virtual folders (for example, a camera or iPhone picture folder). 我试图从其中一个Windows虚拟文件夹(例如,相机或iPhone图片文件夹)加载文件的内容。 Below is some sample code that I am using to play around with this: 下面是我正在使用的一些示例代码:

procedure TfrmForm.ButtonClick(Sender: TObject);
Var
  Dialog: TAttachDialog;
  Enum: IEnumShellItems;
  Name: LPWSTR;
  Item: IShellItem;
  Strm: IStream;
  OStrm: TOLEStream;
  FStrm: TFileStream;
  Result: HRESULT;
  Buf: Array[0..99] Of Char;
  Read: LongInt;
begin
  Result := CoInitializeEx(Nil, COINIT_APARTMENTTHREADED Or
                                COINIT_DISABLE_OLE1DDE);
  If Succeeded(Result) Then
  Begin
    Dialog := TAttachDialog.Create(Self);
    Try
      Dialog.Options := [fdoAllowMultiSelect, fdoPathMustExist,
                         fdoFileMustExist];
      Dialog.Title := 'Select Attachments';

      If Dialog.Execute(Self.Handle) Then
      Begin
        If FAILED(Dialog.ShellItems.EnumItems(Enum)) Then
          Raise Exception.Create('Could not get the list of files selected.');

        While Enum.Next(1, Item, Nil) = S_OK Do
        Begin
          If (Item.GetDisplayName(SIGDN_NORMALDISPLAY, Name) = S_OK) Then
          Begin
            mResults.Lines.Add(Name);
            CoTaskMemFree(Name);
          End;

          If Item.BindToHandler(Nil, BHID_Stream, IID_IStream, Strm) = S_OK Then
          Begin
            OStrm := TOLEStream.Create(Strm);
            FStrm := TFileStream.Create('C:\Temp\Test.jpg', fmCreate);
            FStrm.CopyFrom(OStrm, OStrm.Size);
            FreeAndNil(OStrm);
            FreeAndNil(FStrm);
            Strm := Nil;
          End;

          Item := Nil;
        End;
      End;
    Finally
      FreeAndNil(Dialog);
    End;
    CoUninitialize;
  End;
end;

TAttachDialog is just a descendant of TCustomFileOpenDialog that exposes the ShellItems property. TAttachDialog只是TCustomFileOpenDialog的后代,它暴露了ShellItems属性。 In my actual application, I need a TStream object returned. 在我的实际应用程序中,我需要返回一个TStream对象。 So, in this example, I am using a TFileStream top copy the source file as proof of concept that I have successfully accessed the file using a Delphi stream. 所以,在这个例子中,我使用TFileStream顶部复制源文件作为概念证明,我已经使用Delphi流成功访问了该文件。 Everything works Ok until I try the FStrm.CopyFrom at which point I get a "Not Implemented" error. 一切正常,直到我尝试FStrm.CopyFrom,此时我收到“未实现”错误。 What am I doing wrong with this or is there a better way entirely to do what I want? 我做错了什么,或者有更好的办法完全做我想做的事情?

The only time TStream itself raises a "not implemented" error is if neither the 32bit or 64bit version of Seek() are overridden in a descendant class (or one of them erroneously called the inherited method). 唯一一次TStream本身引发“未实现”错误的是,如果Seek()的32位或64位版本都没有在后代类中被覆盖(或者其中一个错误地称为inherited方法)。 If that were true, an EStreamError exception is raised saying "ClassName.Seek not implemented". 如果这是真的,则会引发一个EStreamError异常,说“ClassName.Seek未实现”。

TOLEStream does override the 32bit version of Seek() to call IStream.Seek() . TOLEStream会覆盖32位版本的Seek()来调用IStream.Seek() However, it does not override the TStream.GetSize() property getter. 但是,它不会覆盖TStream.GetSize()属性getter。 So when you are reading the OStrm.Size value before calling CopyFrom() , it calls the default TStream.GetSize() method, which uses Seek() to determine the stream size - Seek() to get the current position, then Seek() again to the end of the stream, saving the result, then Seek() again to go back to the previous position. 因此,当您在调用CopyFrom()之前读取OStrm.Size值时,它会调用默认的TStream.GetSize()方法,该方法使用Seek()来确定流大小 - Seek()以获取当前位置,然后Seek()再次到流的末尾,保存结果,然后再次Seek()返回到前一个位置。

So, my guess would be that the IStream you have obtained likely does not support random seeking so its Seek() method is returning E_NOTIMPL , which TOLEStream.Seek() would detect and raise an EOleSysError exception saying "Not implemented". 所以,我的猜测是你获得的IStream可能不支持随机搜索,所以它的Seek()方法返回E_NOTIMPLTOLEStream.Seek()将检测并引发一个EOleSysError异常,说“未实现”。

Try calling IStream.Stat() to get the stream size (or derive a class from TOLEStream and override the GetSize() method to call Stat() ), and then pass the returned size to CopyFrom() if > 0 (if you pass Count=0 to CopyFrom() , it will read the source stream's Position and Size properties, thus causing the same Seek() error), eg: 尝试调用IStream.Stat()来获取流大小(或从TOLEStream派生一个类并覆盖GetSize()方法以调用Stat() ),然后将返回的大小传递给CopyFrom() if> 0(如果你通过Count=0CopyFrom() ,它将读取源流的PositionSize属性,从而导致相同的Seek()错误,例如:

var
  ...
  Stat: STATSTG;
begin
  ...
  if Item.BindToHandler(Nil, BHID_Stream, IID_IStream, Strm) = S_OK Then
  try
    OStrm := TOLEStream.Create(Strm);
    try
      FStrm := TFileStream.Create('C:\Temp\Test.jpg', fmCreate);
      try
        OleCheck(Strm.Stat(Stat, STATFLAG_NONAME));
        if Stat.cbSize.QuadPart > 0 then
          FStrm.CopyFrom(OStrm, Stat.cbSize.QuadPart);
      finally
        FreeAndNil(FStrm);
      end;
    finally
      FreeAndNil(OStrm);
    end;
  finally
    Strm := Nil;
  end;
  ...
end;

The alternative would be to simply avoid TStream.CopyFrom() and manually copy the bytes yourself, by allocating a local buffer and then calling OStrm.Read() in a loop, writing each read buffer to FStrm , until OStrm.Read() reports that there is no more bytes to read: 另一种方法是简单地避免使用TStream.CopyFrom()并自己手动复制字节,方法是分配一个本地缓冲区,然后在循环中调用OStrm.Read() ,将每个读缓冲区写入FStrm ,直到OStrm.Read()报告为止。没有更多的字节要读:

var
  ...
  Buf: array[0..1023] of Byte;
  NumRead: Integer;
begin
  ...
  if Item.BindToHandler(Nil, BHID_Stream, IID_IStream, Strm) = S_OK Then
  try
    OStrm := TOLEStream.Create(Strm);
    try
      FStrm := TFileStream.Create('C:\Temp\Test.jpg', fmCreate);
      try
        repeat
          NumRead := OStrm.Read(Buf[0], SizeOf(Buf));
          if NumRead <= 0 then Break;
          FStrm.WriteBuffer(Buf[0], NumRead);
        until False;
      finally
        FreeAndNil(FStrm);
      end;
    finally
      FreeAndNil(OStrm);
    end;
  finally
    Strm := Nil;
  end;
  ...
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 确定文件是否位于 Delphi 2007 中的 ItemIDList 中的虚拟位置 - Determine if a file is in a virtual location from ItemIDList in Delphi 2007 使用delphi确定进程虚拟大小 - Determining process virtual size using delphi 如何处理从 Delphi 6 和 WinXP 到 Delphi 2007 和 Vista/Win7 的表单大小问题 - How to deal with form size issues from Delphi 6 and WinXP to Delphi 2007 and Vista/Win7 如何使用Delphi从文件扩展名获取图标和描述? - How to get icon and description from file extension using Delphi? 如何从Delphi中的已知文件夹GUID获取文件夹路径 - How to get folder path from Known folder GUID in Delphi 如何使用Java将文件从Windows文件夹写入UNIX文件夹 - How to write a file into unix folder from windows folder using java 具有代码页参数和teamcity的Delphi 2007编译 - Delphi 2007 compilation with codepage parameter and teamcity 如何在Delphi中使用SID设置Windows文件夹的权限 - How to set a Windows folder's permissions using SID's in Delphi 如何在Windows通用文件对话框中显示API填充的虚拟文件夹 - How to display an API populated virtual folder in Windows Common File Dialogs Microsoft Office Communicator 2007:从XML文件导入联系人组 - Microsoft Office Communicator 2007: Importing Contact Group from XML file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM