当从TOleContainer提取文档的数据时,DoVerb(ovInplaceActivate)崩溃,出现各种错误消息
一个客户在使用OLE处理Office文档时,会遇到与我们的软件有些奇怪的行为。 当一些派生的TOleContainer
类的实例尝试通过DoVerb(ovInPlaceActivate)
调用激活OLE对象时,代码崩溃。
有各种错误消息,包括:
- (0x80030002) %1找不到。
- (0x80030005) 访问被拒绝。
- (0x800706BE) 远程过程调用失败。
看我的代码:
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;
代码应该做什么? 类THKSOleContainer
重新实现SaveToStream
而不是保存一些内部的OLEstream,只有OLE容器可以正常打开它将容器的内容保存到一些临时文件中,并将其读回到TFileStream
。 结果应该是本地文档作为stream。 TfrmOleOffice
是显示THKSOleContainer
实例的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
调用上冻结。 现在我们将尝试更改其加载行为,以便只在需要时加载它。 这可能是,这也导致了一些节省的问题。