Ren*_*ann 5 delphi excel ole excel-2010
当通过OLE处理Office文档时,一位客户使用我们的软件会遇到一些奇怪的行为.当某个派生TOleContainer
类的实例尝试通过DoVerb(ovInPlaceActivate)
调用激活OLE对象时,代码崩溃.
有各种错误消息,包括:
看我的代码:
function TfrmOleOffice.SaveToStream: TStream;
var
LOleContainerState: TObjectState;
LModified: Boolean;
begin
Result := TMemoryStream.Create;
if IsEmpty and OleOfficeAvailable then exit;
if OleOfficeAvailable then
begin
LOleContainerStateBefore := FOleContainer.State;
LModified := FOleContainer.Modified; // 'FOleContainer.Modified' could be changed by 'FOleContainer.Close'
FOleContainer.Close;
FValue.Position := 0;
if LModified then // otherwise, take stored 'FValue' (see below)
FOleContainer.SaveToStream(FValue);
if LOleContainerStateBefore in [osUIActive] then
ActivateContainer; // reactivate the container
end;
Result.CopyFrom(FValue, 0);
end;
//---------------------------------------------------
procedure THKSOleContainer.SaveToStream(Stream: TStream);
var
TempLockBytes: ILockBytes;
TempStorage: IStorage;
DataHandle: HGlobal;
Buffer: Pointer;
Header: TStreamHeader;
R: TRect;
LFileName: String;
LFileStream: TFileStream;
begin
CheckObject;
if FModSinceSave then SaveObject;
// the following block might be obsolete
if FCopyOnSave then
begin
OleCheck(CreateILockBytesOnHGlobal(0, True, TempLockBytes));
OleCheck(StgCreateDocfileOnILockBytes(TempLockBytes, STGM_READWRITE
or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0, TempStorage));
OleCheck(FStorage.CopyTo(0, nil, nil, TempStorage));
OleCheck(TempStorage.Commit(STGC_DEFAULT));
OleCheck(GetHGlobalFromILockBytes(TempLockBytes, DataHandle));
end else
OleCheck(GetHGlobalFromILockBytes(FLockBytes, DataHandle));
// save the document as a temporary file and read it into a TFileStream
LFileName := IncludeTrailingPathDelimiter(GetMainTempFolder) + TPath.GetGUIDFileName + ExtractFileExt(FOriginalFileName); // get a unique temporary filename
SaveOleObject(LFileName);
try
LFileStream := TFileStream.Create(LFileName, fmOpenRead or fmShareDenyNone);
try
Stream.CopyFrom(LFileStream, 0);
finally
FreeAndNil(LFileStream);
end;
finally
SysUtils.DeleteFile(LFileName);
end;
FModified := False;
end;
procedure THKSOleContainer.SaveOleObject(AFileName: String = '');
var
LActivatedBefore: Boolean;
begin
LActivatedBefore := GetIsActivated;
DoVerb(ovInPlaceActivate, False); // <-- this call crashes with various error messages on several systems of a client
ForceDirectories(ExtractFilePath(AFileName));
OleObject.SaveAs(AFileName);
if not LActivatedBefore then
Close(OLECLOSE_NOSAVE, False);
end;
Run Code Online (Sandbox Code Playgroud)
应该做的代码是什么?类THKSOleContainer
重新实现,SaveToStream
但不是保存一些只有OLE容器可以正常打开的内部OLE流,而是将容器的内容保存到一些临时文件中并将其读回到TFileStream
.结果应该是作为流的本机文档.
TfrmOleOffice
是THKSOleContainer
显示实例的表单.
什么情况下运行正常,什么不运行?首先,在我的电脑上,一切运行正常.我不知道任何其他客户也没有遇到这个问题.但是在该客户的计算机上,当文档被编辑并SaveToStream
在表单确认时调用时,它会崩溃.如果该文件已加载,但没有被激活,它并没有崩溃.实际上,也SaveToStream
被称为,但它成功了.
我使用Microsoft Excel 2010 - 家庭和商业,而客户安装了Microsoft Excel 2010 - Professional Plus.我的系统和他的系统是Windows 7 x64.
关于什么可能出错的任何想法?
GSerg: 他们有防病毒而你没有?
FOleContainer.Close
似乎是,函数中的调用TfrmOleOffice.SaveToStream
导致了保存问题。在我提供了注释掉此调用的版本后,客户不再出现保存错误。
我们还发现了另一个麻烦制造者: Microsoft Dynamics NAV的 Excel COM 插件。停用后,加载时也不再出现错误。Excel 有时会在通话时冻结OleCreateFromFile
。我们现在将尝试更改其加载行为,以便仅在需要时才加载它。这可能也导致了一些储蓄问题。