Имеет ли TMonitor.GetBoundsRect ошибку нарушения доступа в Delphi 2007, вызванную VNC?
Это отчет о сбое, который я получаю от клиентов, использующих один из наших крупных продуктов, созданных в Delphi 2007, который я не могу воспроизвести, и в котором даже нет не-VCL-кода, напрямую связанного через стек вызовов.
Исходный код VCL для TMonitor в Delphi 2007 очень прост (Forms.pas
)
TMonitor.GetBoundsRect
вызывает win32 API GetMonitorInfo
после инициализации структуры 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
[...]
2 ответа
Скорее всего, это 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;
Задачу довольно просто воспроизвести следующим образом:
- Создайте приложение с главной формой с панелью и установите подсказку для панели.
- Запустите приложение.
- Наведите указатель мыши на панель, чтобы увидеть подсказку.
- Переключитесь на другого пользователя на своем компьютере, не закрывая приложение.
- Вернитесь к исходному пользователю и наведите указатель мыши на панель.
- Вы получаете нарушение доступа:
Нарушение прав доступа по адресу 0048A74 в модуле «App.exe». Чтение адреса 00000004.
Мой обходной путь заключается в обработке сообщения WM_WTSSESSION_CHANGE.
procedure TITMainForm.WMWTSSESSION_CHANGE(
var msg : TMessage);
begin
// Destroy and recreate screen to trigger call to GetMonitors.
FORMS.screen.Free;
FORMS.screen := TScreen.Create(NIL);
end;