一位客户在使用我们的软件时,通过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
方法,但不是保存一些只有OLE容器可以正确打开的内部OLE流,而是将容器内容保存到某个临时文件中,并将其读回到TFileStream
中。结果应该是本机文档作为流。
哪些情况能正常运行,哪些情况不能?首先,在我的电脑上,一切都运行良好。我也不知道其他客户是否遇到过这个问题。
但在该客户的计算机上,在编辑文档并在表单确认时调用SaveToStream
时会崩溃。如果已加载但未激活文档,则不会崩溃。实际上,SaveToStream
也会被调用,但成功了。
我使用的是Microsoft Excel 2010 - Home and Business,而客户安装的是Microsoft Excel 2010 - Professional Plus。我的系统和他的系统都是Windows 7 x64。
有什么想法可能出了什么问题吗?
"常见问题解答"
GSerg: 他们有杀毒软件而你没有吗?
- 我们通过暂时停用杀毒软件来检查,但没有效果。我们甚至重新启动了计算机(并确保杀毒软件仍处于停用状态)。