2016-12-07 4 views
1

Я работаю над огромным старым исходным кодом, где есть несколько видов спорта, где вызывается SetFocus, но не проверяется, является ли элемент управления видимым или включенным.Избегайте того, что SetFocus вызывает исключение

Из-за ограниченного времени и огромного количества исходного кода я решил, что хочу проигнорировать эти ошибки, поскольку фокус (в нашем случае) не является критичной функцией. Повышенное исключение приведет к полному сбою, а пропущенный Focus - это просто оптическая проблема.

Мой текущий план заключается в следующем:

1) создать блок с классом помощника, как это:

type 
    TWinControlEx = class helper for TWinControl 
    procedure SetFocusSafe; 
    end; 

procedure TWinControlEx.SetFocusSafe; 
begin 
    if CanFocus then SetFocus; 
end; 

2) Я включать устройство для каждого устройства, которое использует «.SetFocus» (Я буду использовать глобальный поиск кода)

3) Я заменить каждую .SetFocus с .SetFocusSafe

Существует проблема, хотя: Если это возможно, я хочу, чтобы избежать этого, коллег согла Точно также используйте .SetFocus или забудьте включить модуль classhelper.

Какие у меня были другие возможности?

Лучшим случаем было бы, если есть метод/взломать, чтобы сделать SetFocus невозможным исключение. (Без перекомпиляции VCL)

+3

Было бы гораздо проще исправить код правильно, чем вы предлагаете. –

+1

Согласился, что лучшим решением является только его исправить. Если вы вызываете 'SetFocus' на элемент управления, который не может быть сфокусирован, ваш код каким-то образом не синхронизируется с ожидаемым состоянием приложения. Это указывает на более широкие проблемы, когда вы выполняете код в неподходящем контексте. Если состояние приложения не то, что вы ожидаете, то это говорит о том, что раньше что-то пошло не так, что может каскадироваться еще больше проблем в будущем. –

ответ

4

Просто патч TWinControl.SetFocus метод:

unit SetFocusFix; 

interface 

implementation 

uses 
    Controls, 
    Forms, 
    SysUtils, 
    Windows; 

type 
    TWinControlHack = class(TWinControl) 
    public 
    procedure SetFocus; override; 
    end; 

procedure TWinControlHack.SetFocus; 
var 
    Parent: TCustomForm; 
begin 
    if not CanFocus then Exit; 

    Parent := GetParentForm(Self); 
    if Parent <> nil then 
    Parent.FocusControl(Self) 
    else if ParentWindow <> 0 then 
    Windows.SetFocus(Handle) 
    else 
    ValidParentForm(Self); 
end; 

procedure RedirectFunction(OrgProc, NewProc: Pointer); 
type 
    TJmpBuffer = packed record 
    Jmp: Byte; 
    Offset: Integer; 
    end; 
var 
    n: UINT_PTR; 
    JmpBuffer: TJmpBuffer; 
begin 
    JmpBuffer.Jmp := $E9; 
    JmpBuffer.Offset := PByte(NewProc) - (PByte(OrgProc) + 5); 
    if not WriteProcessMemory(GetCurrentProcess, OrgProc, @JmpBuffer, SizeOf(JmpBuffer), n) then 
    RaiseLastOSError; 
end; 

initialization 
    RedirectFunction(@TWinControl.SetFocus, @TWinControlHack.SetFocus); 

end. 
3

Альтернативно

TWinControlEx = class helper for TWinControl 
    procedure SetFocus; reintroduce; 
    end; 

с ...

procedure TWinControlEx.SetFocus; 
var 
    Parent: TCustomForm; 
begin 
    if not CanFocus then Exit; 
    Parent := GetParentForm(Self); 
    if Parent <> nil then 
    Parent.FocusControl(Self) 
    else if ParentWindow <> 0 then 
    Winapi.Windows.SetFocus(Handle) 
    else 
    ValidParentForm(Self); 
end; 

 Смежные вопросы

  • Нет связанных вопросов^_^