gpt4 book ai didi

delphi - XE2 中的 COM 是否损坏?我该如何解决它?

转载 作者:行者123 更新时间:2023-12-03 14:32:37 25 4
gpt4 key购买 nike

更新:XE2 Update 2 修复了下述错误。

下面的程序是从实际程序中截取的,在 XE2 中失败并出现异常。这是 2010 年的回归。我没有 XE 来测试,但我希望该程序在 XE 上运行良好(感谢 Primož 确认代码在 XE 上运行良好)。

program COMbug;

{$APPTYPE CONSOLE}

uses
SysUtils, Variants, Windows, Excel2000;

var
Excel: TExcelApplication;
Book: ExcelWorkbook;
Sheet: ExcelWorksheet;
UsedRange: ExcelRange;
Row, Col: Integer;
v: Variant;

begin
Excel := TExcelApplication.Create(nil);
try
Excel.Visible[LOCALE_USER_DEFAULT] := True;
Book := Excel.Workbooks.Add(EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorkbook;
Sheet := Book.Worksheets.Add(EmptyParam, EmptyParam, 1, EmptyParam, LOCALE_USER_DEFAULT) as ExcelWorksheet;

Sheet.Cells.Item[1,1].Value := 1.0;
Sheet.Cells.Item[2,2].Value := 1.0;
UsedRange := Sheet.UsedRange[LOCALE_USER_DEFAULT] as ExcelRange;
for Row := 1 to UsedRange.Rows.Count do begin
for Col := 1 to UsedRange.Columns.Count do begin
v := UsedRange.Item[Row, Col].Value;
end;
end;
finally
Excel.Free;
end;
end.

在 XE2 32 位中,错误是:

Project COMbug.exe raised exception class $C000001D with message 'system exception (code 0xc000001d) at 0x00dd6f3e'.

第二次执行UsedRange.Columns时发生错误。

在 XE2 64 位中,错误是:

Project COMbug.exe raised exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'

同样,我认为错误发生在第二次执行 UsedRange.Columns 时,但 64 位调试器以一种有点奇怪的方式逐步执行代码,所以我不能 100% 确定那个。

我已提交QC report对于这个问题。

在我看来,Delphi COM/自动化/接口(interface)堆栈中的某些东西似乎完全被破坏了。这对我采用 XE2 来说是一个十足的亮点。

有没有人有过这个问题的经验?有人对我如何尝试解决该问题有任何提示和建议吗?调试这里真正发生的事情超出了我的专业领域。

最佳答案

解决方法

rowCnt := UsedRange.Rows.Count;
colCnt := UsedRange.Columns.Count;
for Row := 1 to rowCnt do begin
for Col := 1 to colCnt do begin
v := UsedRange.Item[Row, Col].Value;
end;
end;

这也有效(并且可以帮助您在更复杂的用例中找到解决方法):

function ColCount(const range: ExcelRange): integer;
begin
Result := range.Columns.Count;
end;

for Row := 1 to UsedRange.Rows.Count do begin
for Col := 1 to ColCount(UsedRange) do begin
v := UsedRange.Item[Row, Col].Value;
end;
end;

分析

在DispCallByID中的System.Win.ComObj中执行_Release时崩溃

varDispatch, varUnknown:
begin
if PPointer(Result)^ <> nil then
IDispatch(Result)._Release;
PPointer(Result)^ := Res.VDispatch;
end;

尽管 Delphi XE(XE 使用汇编程序版本)中相同过程的 PUREPASCAL 版本不同...

varDispatch, varUnknown:
begin
if PPointer(Result)^ <> nil then
IDispatch(Result.VDispatch)._Release;
PPointer(Result)^ := Res.VDispatch;
end;

...两种情况下的汇编代码是相同的(编辑:不正确,请参阅最后的注释):

@ResDispatch:
@ResUnknown:
MOV EAX,[EBX]
TEST EAX,EAX
JE @@2
PUSH EAX
MOV EAX,[EAX]
CALL [EAX].Pointer[8]
@@2: MOV EAX,[ESP+8]
MOV [EBX],EAX
JMP @ResDone

有趣的是,这会崩溃......

for Row := 1 to UsedRange.Rows.Count do begin
for Col := 1 to UsedRange.Columns.Count do begin
end;
end;

...但事实并非如此。

row := UsedRange.Rows.Count;
col := UsedRange.Columns.Count;
col := UsedRange.Columns.Count;

其原因是使用了隐藏的局部变量。在第一个示例中,代码编译为...

00564511 6874465600       push $00564674
00564516 6884465600 push $00564684
0056451B A12CF35600 mov eax,[$0056f32c]
00564520 50 push eax
00564521 8D8508FFFFFF lea eax,[ebp-$000000f8]
00564527 50 push eax
00564528 E8933EEAFF call DispCallByIDProc

...这被调用了两次。

在第二个示例中,使用了堆栈上的两个不同的临时位置(ebp - ???? 偏移量):

00564466 6874465600       push $00564674
0056446B 6884465600 push $00564684
00564470 A12CF35600 mov eax,[$0056f32c]
00564475 50 push eax
00564476 8D8514FFFFFF lea eax,[ebp-$000000ec]
0056447C 50 push eax
0056447D E83E3FEAFF call DispCallByIDProc
...
0056449B 6874465600 push $00564674
005644A0 6884465600 push $00564684
005644A5 A12CF35600 mov eax,[$0056f32c]
005644AA 50 push eax
005644AB 8D8510FFFFFF lea eax,[ebp-$000000f0]
005644B1 50 push eax
005644B2 E8093FEAFF call DispCallByIDProc

当清除存储在这个临时位置的内部接口(interface)时,就会发生该错误,这种情况仅在第二次执行“for”情况时发生,因为该接口(interface)中已经存储了一些内容 - 当“for”执行时,它被放在那里”第一次被叫到。在第二个示例中,使用了两个位置,因此该内部接口(interface)始终初始化为 0,并且根本不调用 Release。

真正的错误是这个内部接口(interface)包含垃圾,当调用 Release 时,会发生糟糕的事情。

经过更多挖掘,我注意到释放旧接口(interface)的汇编代码并不相同 - XE2 版本缺少一条“mov eax, [eax]”指令。爱荷华,

IDispatch(Result)._Release;

这是一个错误,但确实应该是

IDispatch(Result.VDispatch)._Release;

令人讨厌的 RTL 错误。

关于delphi - XE2 中的 COM 是否损坏?我该如何解决它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7886116/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com