[英]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_NOTIMPL
, TOLEStream.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=0
到CopyFrom()
,它将读取源流的Position
和Size
属性,从而导致相同的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.