Delphi IPreviewHandler卸载COM对象需要很长时间并冻结应用程序
我正在尝试使用IPreviewHandler界面在我的应用程序中的TPanel上显示类似windows 7的预览 当我通过调用卸载(这意味着要处理COM对象)然后将对象置零来销毁预览对象时,就会出现问题。应用程序将冻结(在析构函数之后),直到预览主机进程退出。这可能需要几分钟。使用adobe预览.pdfs时经常发生这种情况 我想知道是否有一种方法可以避免这种情况,或者有一种不同的方法来完成文件预览Delphi IPreviewHandler卸载COM对象需要很长时间并冻结应用程序,delphi,winapi,com,ipreviewhandler,Delphi,Winapi,Com,Ipreviewhandler,我正在尝试使用IPreviewHandler界面在我的应用程序中的TPanel上显示类似windows 7的预览 当我通过调用卸载(这意味着要处理COM对象)然后将对象置零来销毁预览对象时,就会出现问题。应用程序将冻结(在析构函数之后),直到预览主机进程退出。这可能需要几分钟。使用adobe预览.pdfs时经常发生这种情况 我想知道是否有一种方法可以避免这种情况,或者有一种不同的方法来完成文件预览 unit uHostPreview; interface uses Winapi.ShlO
unit uHostPreview;
interface
uses
Winapi.ShlObj, Winapi.Messages, Winapi.ShLwApi, Winapi.Windows,
System.Classes,
Vcl.Controls, Vcl.Dialogs;
type
THostPreviewHandler = class(TCustomControl)
private
m_fileStream : TFileStream;
m_previewGUIDStr : string;
m_name : string;
m_memStream : TMemoryStream;
m_previewUnloading : Boolean;
m_loadFromMemStream : Boolean;
m_hwnd : HWND;
m_previewHandler : IPreviewHandler;
m_msg : string;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
function CreateFileFromStream(const in_Stream : TMemoryStream) : string;
protected
procedure Paint; override;
public
procedure LoadPreviewHandler;
constructor Create(AOwner: TWinControl; in_FileName : String) overload; reintroduce;
constructor Create(AOwner: TWinControl; in_Stream : TMemoryStream;
in_name : string) overload; reintroduce;
destructor Destroy; override;
end;
implementation
uses
SysUtils, Graphics, ComObj, ActiveX,
Registry, PropSys, ObBase, System.IOUtils;
constructor THostPreviewHandler.Create(AOwner: TWinControl; in_fileName : String) overload;
begin
inherited Create(AOwner);
m_hwnd := AOwner.handle;
m_previewHandler := nil;
m_previewGUIDStr := '';
m_fileStream := nil;
m_name := in_fileName;
m_loadFromMemStream := False;
m_msg := 'No Preview Available.';
end;
constructor THostPreviewHandler.Create(AOwner: TWinControl; in_stream : TMemoryStream;
in_name : string) overload;
begin
inherited Create(AOwner);
m_hwnd := AOwner.handle;
m_previewHandler := nil;
m_previewGUIDStr := '';
m_fileStream := nil;
m_memStream := in_stream;
m_name := in_name;
m_loadFromMemStream := True;
m_msg := 'No Preview Available.';
end;
//As Soon as the destructor finishes the application freezes until Preview Host processes end!!!
destructor THostPreviewHandler.Destroy;
begin
if (m_previewHandler<>nil) then
begin
m_previewHandler.Unload;
m_previewHandler := nil;
end;
if m_fileStream<>nil then
FreeAndNil(m_fileStream);
m_memStream := nil;
inherited;
end;
procedure THostPreviewHandler.Paint;
var
lpRect: TRect;
begin
//Now Done in the load preview. Means previews don't stall when rapidly switching between different files.
{ if (m_previewGUIDStr<>'') and (m_previewHandler<>nil) and not m_previewLoaded then
begin
m_previewLoaded := true;
m_previewHandler.DoPreview;
m_previewHandler.SetFocus;
end
else }
if m_previewGUIDStr='' then
begin
lpRect:=Rect(0, 0, Self.Width, Self.Height);
Canvas.Brush.Style :=bsClear;
Canvas.Font.Color :=clWindowText;
DrawText(Canvas.Handle, PChar(m_msg) ,Length(m_msg), lpRect, DT_VCENTER or DT_CENTER or DT_SINGLELINE);
end;
end;
function GetPreviewHandlerCLSID(const AFileName: string): string;
const
SID_IPreviewHandler = '{8895B1C6-B41F-4C1C-A562-0D564250836F}';
var
Buffer : array [0..1024] of Char;
BufSize : DWord;
RegQueryRes : HResult;
fileExtension : string;
LRegistry : TRegistry;
LExt, LFileClass : string;
LPerceivedType, LKey : string;
begin
Result := '';
fileExtension := ExtractFileExt(AFileName);
// Searches the registry for the preview handler for the current file extension
BufSize := Length(Buffer);
RegQueryRes := AssocQueryString(
ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCSTR_SHELLEXTENSION,
PChar(fileExtension),
SID_IPreviewHandler,
Buffer,
@BufSize
);
If RegQueryRes = S_OK then
begin
Result := String(Buffer)
end
end;
procedure THostPreviewHandler.LoadPreviewHandler;
const
GUID_ISHELLITEM = '{43826d1e-e718-42ee-bc55-a1e261c37bfe}';
var
prc : TRect;
LPreviewGUID : TGUID;
LInitializeWithFile : IInitializeWithFile;
LInitializeWithStream : IInitializeWithStream;
LInitializeWithItem : IInitializeWithItem;
LIStream : IStream;
LShellItem : IShellItem;
fname : string;
begin
HandleNeeded;
m_previewGUIDStr:=GetPreviewHandlerCLSID(m_name);
//If no matching preview handler is found. Exit.
if m_previewGUIDStr='' then
begin
exit;
end;
if m_fileStream<>nil then
FreeAndNil(m_fileStream);
LPreviewGUID:= StringToGUID(m_previewGUIDStr);
//Create a COM object to do the preview handling
m_previewHandler := CreateComObject(LPreviewGUID) As IPreviewHandler;
if (m_previewHandler = nil) then
begin
exit;
end;
if m_previewHandler.QueryInterface(IInitializeWithStream, LInitializeWithStream) = S_OK then
begin
if m_loadFromMemStream then
begin
LIStream := TStreamAdapter.Create(m_memStream, soReference) as IStream;
end
else
begin
m_fileStream := TFileStream.Create(m_name, fmOpenRead or fmShareDenyNone);
LIStream := TStreamAdapter.Create(m_fileStream, soReference) as IStream;
end;
LInitializeWithStream.Initialize(LIStream, STGM_READ);
end
else if (m_previewHandler.QueryInterface(IInitializeWithFile, LInitializeWithFile) = S_OK) then
begin
if not m_loadFromMemStream then
begin
LInitializeWithFile.Initialize(StringToOleStr(m_name), STGM_READ);
end
else
begin
fname := CreateFileFromStream(m_memStream);
LInitializeWithFile.Initialize(StringToOleStr(fname), STGM_READ);
end;
end
else if ((m_previewHandler.QueryInterface(IInitializeWithItem, LInitializeWithItem) = S_OK) and (not m_loadFromMemStream)) then
begin
if not m_loadFromMemStream then
begin
SHCreateItemFromParsingName(PChar(m_name), nil, StringToGUID(GUID_ISHELLITEM), LShellItem);
LInitializeWithItem.Initialize(LShellItem, 0);
end
else
begin
fname := CreateFileFromStream(m_memStream);
SHCreateItemFromParsingName(PChar(fname), nil, StringToGUID(GUID_ISHELLITEM), LShellItem);
LInitializeWithItem.Initialize(LShellItem, 0);
end;
end
else
begin
m_msg := 'Preview Could Not be Intialized.';
end;
prc := ClientRect;
m_previewHandler.SetWindow(m_hwnd, prc);
m_previewHandler.DoPreview;
end;
function THostPreviewHandler.CreateFileFromStream(const in_Stream : TMemoryStream) : string;
var
tempPath : string;
begin
tempPath := TPath.GetTempPath;
tempPath := tempPath + m_name;
in_Stream.SaveToFile(tempPath);
result := tempPath;
end;
procedure THostPreviewHandler.WMSize(var Message: TWMSize);
var
prc : TRect;
begin
inherited;
if m_previewHandler<>nil then
begin
prc := ClientRect;
m_previewHandler.SetRect(prc);
end;
end;
end.
单元预览;
接口
使用
Winapi.ShlObj、Winapi.Messages、Winapi.ShLwApi、Winapi.Windows、,
系统,班级,,
Vcl.控件、Vcl.对话框;
类型
THostPreviewHandler=类(TCustomControl)
私有的
m_fileStream:TFileStream;
m_previewGUIDStr:字符串;
m_name:string;
m_memStream:tmemorestream;
m_previewUnloading:布尔值;
m_loadFromMemStream:布尔值;
m_hwnd:hwnd;
m_previewHandler:IPreviewHandler;
m_msg:string;
过程WMSize(var消息:TWMSize);消息WM_大小;
函数CreateFileFromStream(流中的常量:TMemoryStream):字符串;
受保护的
程序漆;推翻
公众的
程序加载预览处理程序;
构造函数创建(AOwner:TWinControl;in_文件名:String)重载;重新引入;
构造函数创建(AOwner:TWinControl;in_Stream:TMemoryStream;
in_name:string)重载;重新引入;
毁灭者毁灭;推翻
结束;
实施
使用
SysUtils、图形、ComObj、ActiveX、,
注册表、PropSys、ObBase、System.IOUtils;
构造函数THostPreviewHandler.Create(AOwner:TWinControl;in_fileName:String)重载;
开始
继承的创建(AOOwner);
m_hwnd:=AOwner.handle;
m_previewHandler:=nil;
m_previewGUIDStr:='';
m_fileStream:=nil;
m_name:=in_文件名;
m_loadFromMemStream:=False;
m_msg:=“没有可用的预览。”;
结束;
构造函数THostPreviewHandler.Create(AOwner:TWinControl;in_stream:TMemoryStream;
in_name:string)重载;
开始
继承的创建(AOOwner);
m_hwnd:=AOwner.handle;
m_previewHandler:=nil;
m_previewGUIDStr:='';
m_fileStream:=nil;
m_memStream:=在_stream中;
m_name:=in_name;
m_loadFromMemStream:=真;
m_msg:=“没有可用的预览。”;
结束;
//只要析构函数完成,应用程序就会冻结,直到预览主机进程结束!!!
毁灭者Thospreviewhandler.毁灭;
开始
如果(m_previewhandernil)那么
开始
m_previewHandler.Unload;
m_previewHandler:=nil;
结束;
如果m_fileStreamnil那么
FreeAndNil(m_fileStream);
m_memStream:=nil;
继承;
结束;
工艺流程图。油漆;
变量
lpRect:TRect;
开始
//现在在加载预览中完成。意味着在不同文件之间快速切换时预览不会暂停。
{如果(m_PreviewGuidestr“”)和(m_previewHandlernil)且未加载m_previewLoaded,则
开始
m_previewLoaded:=真;
m_previewHandler.DoPreview;
m_previewHandler.SetFocus;
结束
else}
如果m_previewGUIDStr='',则
开始
lpRect:=Rect(0,0,Self.Width,Self.Height);
Canvas.Brush.Style:=bsClear;
Canvas.Font.Color:=clWindowText;
DrawText(Canvas.Handle、PChar(m_msg)、Length(m_msg)、lpRect、DT_VCENTER或DT_CENTER或DT_单线);
结束;
结束;
函数GetPreviewHandlerCLSID(const AFileName:string):string;
常数
SID_IPreviewHandler=“{8895B1C6-B41F-4C1C-A562-0D564250836F}”;
变量
缓冲区:字符的数组[0..1024];
BufSize:DWord;
RegQueryRes:HResult;
fileExtension:string;
地方学:树木学;
LExt,LFileClass:string;
LPerceivedType,LKey:string;
开始
结果:='';
fileExtension:=ExtractFileExt(AFileName);
//在注册表中搜索当前文件扩展名的预览处理程序
BufSize:=长度(缓冲区);
RegQueryRes:=AssocQueryString(
ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCSTR_SHELLEXTENSION,
PChar(文件扩展),
SID_IPreviewHandler,
缓冲器
@丰满
);
如果RegQueryRes=S_OK,则
开始
结果:=字符串(缓冲区)
结束
结束;
程序THostPreviewHandler.LoadPreviewHandler;
常数
GUID_ISHELLITEM=“{43826d1e-e718-42ee-bc55-a1e261c37bfe}”;
变量
中华人民共和国:特雷特;
LPreviewGUID:TGUID;
LinitalizeWithFile:IInitializeWithFile;
顺流搽剂:i初始顺流;
使用以下项目进行搽剂:I初始使用Thitem;
列表流:IStream;
LShellItem:IShellItem;
fname:字符串;
开始
熟练掌握;
m_previewGUIDStr:=GetPreviewHandlerCLSID(m_名称);
//如果未找到匹配的预览处理程序。出口
如果m_previewGUIDStr='',则
开始
出口
结束;
如果m_fileStreamnil那么
FreeAndNil(m_fileStream);
LPreviewGUID:=StringToGUID(m_previewGUIDStr);
//创建COM对象以执行预览处理
m_previewHandler:=CreateComObject(LPreviewGUID)作为IPreviewHandler;
如果(m_previewHandler=nil),则
开始
出口
结束;
如果m_previewHandler.QueryInterface(IIInitializeWithStream,LinitalizeWithStream)=S_OK,则
开始
如果m_loadFromMemStream,则
开始
LIStream:=TStreamAdapter.Create(m_memStream,sorreference)作为IStream;
结束
其他的
开始
m_fileStream:=TFileStream.Create(m_name、fmOpenRead或fmsharedynone);
LIStream:=TStreamAdapter.Create(m_fileStream,sorreference)作为IStream;
结束;
初始化(LIStream,STGM_READ);
结束
否则,如果(m_previewHandler.QueryInterface(IInitializeWithFile,LInitializeWithFile)=S_OK),则
开始
如果不是m_loadFromMemStream,则
开始
初始化(StringToOleStr(m_名称),STGM_读取);
if m_attachPreview<>nil then
begin
FreeAndNil(m_attachPreview);
end;
memStream := TMemoryStream.Create;
memStream.LoadFromFile('C:\Test');
if loadFromStream then
begin
//Preview can be loaded from a stream or a file
m_attachPreview := THostPreviewHandler.Create(pnlPreview, TMemoryStream, name);
end
else
begin
m_attachPreview := THostPreviewHandler.Create(pnlPreview, filePath);
end;
m_attachPreview.Top := 0;
m_attachPreview.Left := 0;
m_attachPreview.Width := pnlPreview.ClientWidth;
m_attachPreview.Height := pnlPreview.ClientHeight;
m_attachPreview.Parent := pnlPreview;
m_attachPreview.Align := alClient;
m_attachPreview.LoadPreviewHandler;
LInitializeWithFile.Initialize(StringToOleStr(FFileName), STGM_READ)
os := StringToOleStr(FFileName);
LInitializeWithFile.Initialize(os, STGM_READ);
SysFreeString(os);