One client experiences strange behavior with our software when working with Office documents through OLE. The code crashes when an instance of some derived TOleContainer class tries to activate an OLE object by calling DoVerb(ovInPlaceActivate) .
There are various error messages, including:
- (0x80030002)% 1 not found.
- (0x80030005) Access denied.
- (0x800706BE) A call to the remote procedure failed.
See my code:
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;
What should the code do? The THKSOleContainer class SaveToStream , but instead of saving some internal OLE stream that only the OLE container can open, it stores the contents of the container in a temporary file and reads it back to TFileStream . The result should be the source document as a stream. TfrmOleOffice is the form on which the THKSOleContainer instance is THKSOleContainer .
What cases work correctly and what not? First of all, everything works fine on my computer. I do not know any other client experiencing this problem. But on client computers, it crashes when the document has been edited, and SaveToStream is called when the form is validated. If a document has been downloaded but not activated, it does not crash. In fact, SaveToStream is also called SaveToStream , but it succeeds.
I use Microsoft Excel 2010 - home and business, while the client has Microsoft Excel 2010 - Professional Plus installed. My system and its system is Windows 7 x64.
Any ideas on what might be wrong?
"Reference"
GSerg: They have an antivirus, but you donβt?
- We checked this by temporarily disabling the antivirus, but with no effect. We even restarted the computer (and ensured that the antivirus was still disabled).