Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`DoVerb(ovInplaceActivate)` crashes with various error messages when a document's data is extracted from TOleContainer

One customer experiences some strange behaviour with our software when working with Office documents via OLE. The code crashes when an instance of some derived TOleContainer class tries to activate the OLE object via DoVerb(ovInPlaceActivate) call.

There are various error messages, including:

  • (0x80030002) %1 could not be found.
  • (0x80030005) Access Denied.
  • (0x800706BE) The remote procedure call 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 is the code supposed to do? Class THKSOleContainer reimplements SaveToStream but instead of saving some internal OLE stream that only the OLE container can open properly it saves the container's content into some temporary file and reads it back into a TFileStream. Result should be the native document as a stream. TfrmOleOffice is a form on which the instance of THKSOleContainer is displayed.

What cases run properly, what do not? First of all, on my computer, everything runs fine. I don't know of any other customer experiencing this problem neither. But on that customer's computers it crashes when a document has been edited and SaveToStream is called on form's confirmation. If the document has been loaded but not activated, it does not crash. Actually, SaveToStream is called then, too, but it succeeds.

I use Microsoft Excel 2010 - Home and Business, whereas the customer has Microsoft Excel 2010 - Professional Plus installed. My system and his system are Windows 7 x64.

Any ideas on what could be wrong?


"FAQ"

GSerg: They have an antivirus and you don't?

  • We checked that by deactivating antivirus temporarely, but no effect. We even restarted the computer (and ensured that antivirus was still deactivated).
like image 596
René Hoffmann Avatar asked Oct 30 '22 21:10

René Hoffmann


1 Answers

Seems to be, that call of FOleContainer.Close in function TfrmOleOffice.SaveToStream caused the problems on saving. The customer got no errors on saving anymore after I provided a version in which this call was commented out.

We also detected another trouble-maker: an Excel COM-add-in for Microsoft Dynamics NAV. After it has been deactivated, there occured no more errors on loading, neither. Excel froze there on OleCreateFromFile call sometimes. We'll now try to change its load behaviour, so that it is only loaded if needed. It might be, that this caused some of the problems on saving, too.

like image 130
René Hoffmann Avatar answered Nov 15 '22 06:11

René Hoffmann