3

这是我从运行我们在 Delphi 2007 中构建的大型产品之一的客户那里获得的崩溃报告,我无法重现该报告,甚至没有通过调用堆栈直接涉及任何非 VCL 代码。

Delphi 2007中TMonitor的VCL源码很简单( Forms.pas)

TMonitor.GetBoundsRectGetMonitorInfo在初始化结构后调用 win32 API ,cbSize以便 Windows API 知道要返回的大小。

我一遍又一遍地看这段代码,我看不出这个关卡是如何崩溃的,除非 Self 指针无效,尽管我怀疑它实际上可能是THintWindow关卡故障,并且只有在TMonitor.GetBoundsRect这个故障变得可见崩溃,因为它以某种方式获得了指向无效TMonitor对象的指针并在其上调用了方法。

function TMonitor.GetBoundsRect: TRect;
var
  MonInfo: TMonitorInfo;
begin
  MonInfo.cbSize := SizeOf(MonInfo);
  GetMonitorInfo(FHandle, @MonInfo);  // <----- CRASH.
  Result := MonInfo.rcMonitor;
end;

通过 madExcept 的崩溃调用堆栈只能在客户端系统上重现:

main thread ($70):
004f5004 +010 myapp.exe Forms    6361  +2 TMonitor.GetBoundsRect
004f4fe2 +00a myapp.exe Forms    6352  +1 TMonitor.GetWidth
004e022f +06b myapp.exe Controls 9929  +7 THintWindow.ActivateHint
004e0457 +017 myapp.exe Controls 9970  +1 THintWindow.ActivateHintData
004f95fa +31a myapp.exe Forms    8923 +56 TApplication.ActivateHint
004f8fc1 +02d myapp.exe Forms    8728  +8 TApplication.HintTimerExpired
004f61e6 +022 myapp.exe Forms    7083  +3 HintTimerProc
7e4196c2 +00a USER32.dll                    DispatchMessageA
004f7f00 +0fc myapp.exe Forms    8105 +23 TApplication.ProcessMessage
004f7f3a +00a myapp.exe Forms    8124  +1 TApplication.HandleMessage
004f822f +0b3 myapp.exe Forms    8223 +20 TApplication.Run
0155cf77 +2f3 myapp.exe myapp    368  +41 initialization

上面整个调用栈中的所有代码都是VCL源代码,没有一个是我的。

除了禁用整个应用程序中的所有提示之外,我还能做些什么来进一步解决这个问题或解决它吗?

更新:注册和解除,以及异常地址:

exception class   : EAccessViolation
exception message : Access violation at address 004F5004 in module 'hirepnt.exe'. Read of address 00000004.

cpu registers:
eax = 00000000
ebx = 0012fccc
ecx = 7e42ac2c
edx = 0012fccc
esi = 07b694a8
edi = 0012fd14
eip = 004f5004
esp = 0012fc90
ebp = 0012fd1c

stack dump:
0012fc90  94 fc 12 00 28 00 00 00 - 2c ac 42 7e 70 b3 6f 02  ....(...,.B~p.o.
0012fca0  fc fc 12 00 01 00 00 00 - 70 b3 6f 02 cc 53 4f 00  ........p.o..SO.
0012fcb0  01 00 00 00 01 00 00 00 - 3c 56 4f 00 14 fd 12 00  ........<VO.....
0012fcc0  a8 94 b6 07 00 00 00 00 - e7 4f 4f 00 00 00 00 00  .........OO.....
0012fcd0  4b 64 4f 00 14 fd 12 00 - a8 94 b6 07 00 00 00 00  KdO.............
0012fce0  34 02 4e 00 4c fd 12 00 - c4 5c 40 00 1c fd 12 00  4.N.L....\@.....
0012fcf0  40 fd 12 00 97 fd 12 00 - 0c 23 4d 00 e0 01 00 00  @........#M.....
0012fd00  6d 01 00 00 e0 01 00 00 - 6d 01 00 00 41 02 00 00  m.......m...A...
0012fd10  80 01 00 00 34 fd 12 00 - 10 cc 6e 02 40 fd 12 00  ....4.....n.@...
0012fd20  5d 04 4e 00 d8 fd 12 00 - 0c 23 4d 00 f0 fd 12 00  ].N......#M.....
0012fd30  e0 01 00 00 6d 01 00 00 - 41 02 00 00 7c 01 00 00  ....m...A...|...
0012fd40  f4 fd 12 00 00 96 4f 00 - 00 00 00 00 0c fe 12 00  ......O.........
0012fd50  c4 5c 40 00 f4 fd 12 00 - 8c fe 12 00 c4 61 4f 00  .\@..........aO.
0012fd60  40 41 6f 02 00 00 00 00 - 00 00 00 00 28 05 00 00  @Ao.........(...
0012fd70  15 02 00 00 00 00 00 00 - 00 00 00 00 d9 04 00 00  ................
0012fd80  ac 01 00 00 84 00 00 e0 - 01 00 00 6d 01 00 00 41  ...........m...A
0012fd90  02 00 00 7c 01 00 00 01 - 4f 00 00 00 69 00 00 00  ...|....O...i...
0012fda0  51 00 00 00 6b 00 00 00 - e0 01 00 00 61 01 00 00  Q...k.......a...
0012fdb0  f0 84 22 06 0c 23 4d 00 - e0 01 00 00 6d 01 00 00  .."..#M.....m...
0012fdc0  56 05 00 00 18 00 00 ff - fe ff ff ff fe ff ff ff  V...............

disassembling:
[...]
004f4ff6        push    edi
004f4ff7        add     esp, -$28
004f4ffa        mov     ebx, edx
004f4ffc 6360   mov     dword ptr [esp], $28
004f5003 6361   push    esp
004f5004      > mov     eax, [eax+4]
004f5007        push    eax
004f5008        mov     eax, [$1644560]
004f500d        mov     eax, [eax]
004f500f        call    eax
004f5011 6362   mov     edi, ebx
[...]
4

1 回答 1

4

这很可能是 qc #53932(也是#25466 #57953),并且修补 Forms.pas 确实可以解决它。在我的情况下,使用 D7,它只能通过使用远程访问触发,问题/修复与 D2007 相同。

具体来说,补丁是改变TScreen.FindMonitor。这是 D7 更改,不确定是否需要对 D2007 进行任何编辑。

function TScreen.FindMonitor(Handle: HMONITOR): TMonitor;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to MonitorCount - 1 do
    if Monitors[I].Handle = Handle then
    begin
      Result := Monitors[I];
//      break;
      Exit;
    end;
  //if we get here, the Monitors array has changed, so we need to clear and reinitialize it
  for i := 0 to MonitorCount-1 do
    TMonitor(Monitors[i]).Free;
  fMonitors.Clear;
  EnumDisplayMonitors(0, nil, @EnumMonitorsProc, LongInt(FMonitors));
  for I := 0 to MonitorCount - 1 do
    if Monitors[I].Handle = Handle then
    begin
      Result := Monitors[I];
      Exit;
    end;
end;
于 2013-03-06T22:44:27.357 回答