从 TOleContainer 中提取文档数据时,`DoVerb(ovInplaceActivate)` 崩溃并显示各种错误消息
`DoVerb(ovInplaceActivate)` crashes with various error messages when a document's data is extracted from TOleContainer
一位客户在使用我们的软件通过 OLE 处理 Office 文档时遇到了一些奇怪的行为。当某些派生 TOleContainer
class 的实例试图通过 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;
代码应该做什么? Class THKSOleContainer
重新实现 SaveToStream
但不是保存一些内部 OLE 流,只有OLE 容器可以正常打开,它将容器的内容保存到某个临时文件中并将其读回 TFileStream
。结果应该是作为流的本机文档。
TfrmOleOffice
是显示 THKSOleContainer
实例的表单。
什么情况运行正常,什么不正常?首先,在我的电脑上,一切运行都很好。我不知道有任何其他客户也遇到过这个问题。
但是在该客户的计算机上,当编辑文档并在表单确认时调用 SaveToStream
时,它会崩溃。如果文档已加载但未激活,它不会 而不会 崩溃。实际上,SaveToStream
也被调用了,但它成功了。
我使用 Microsoft Excel 2010 - Home and Business,而客户使用 Microsoft Excel 2010 - Professional Plus 已安装。我的系统和他的系统都是Windows 7 x64.
有什么可能出错的想法吗?
"FAQ"
GSerg:
They have an antivirus and you don't?
- 我们通过暂时停用防病毒软件进行了检查,但没有效果。我们甚至重新启动了计算机(并确保杀毒软件仍处于停用状态)。
似乎是,在函数 TfrmOleOffice.SaveToStream
中调用 FOleContainer.Close
导致了保存问题。在我提供 此调用被注释掉.
的版本后,客户在保存时不再出现错误
我们还检测到 另一个麻烦制造者:Excel COM 加载项用于 Microsoft Dynamics NAV。停用后,加载时不再发生错误,也没有。 Excel 有时在 OleCreateFromFile
通话时会呆在那里。我们现在将尝试更改其加载行为,以便仅在需要时加载它。可能这也导致了一些保存方面的问题。
一位客户在使用我们的软件通过 OLE 处理 Office 文档时遇到了一些奇怪的行为。当某些派生 TOleContainer
class 的实例试图通过 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;
代码应该做什么? Class THKSOleContainer
重新实现 SaveToStream
但不是保存一些内部 OLE 流,只有OLE 容器可以正常打开,它将容器的内容保存到某个临时文件中并将其读回 TFileStream
。结果应该是作为流的本机文档。
TfrmOleOffice
是显示 THKSOleContainer
实例的表单。
什么情况运行正常,什么不正常?首先,在我的电脑上,一切运行都很好。我不知道有任何其他客户也遇到过这个问题。
但是在该客户的计算机上,当编辑文档并在表单确认时调用 SaveToStream
时,它会崩溃。如果文档已加载但未激活,它不会 而不会 崩溃。实际上,SaveToStream
也被调用了,但它成功了。
我使用 Microsoft Excel 2010 - Home and Business,而客户使用 Microsoft Excel 2010 - Professional Plus 已安装。我的系统和他的系统都是Windows 7 x64.
有什么可能出错的想法吗?
"FAQ"
GSerg: They have an antivirus and you don't?
- 我们通过暂时停用防病毒软件进行了检查,但没有效果。我们甚至重新启动了计算机(并确保杀毒软件仍处于停用状态)。
似乎是,在函数 TfrmOleOffice.SaveToStream
中调用 FOleContainer.Close
导致了保存问题。在我提供 此调用被注释掉.
我们还检测到 另一个麻烦制造者:Excel COM 加载项用于 Microsoft Dynamics NAV。停用后,加载时不再发生错误,也没有。 Excel 有时在 OleCreateFromFile
通话时会呆在那里。我们现在将尝试更改其加载行为,以便仅在需要时加载它。可能这也导致了一些保存方面的问题。