Главная arrow Лаборатория arrow Вскрываем ReadOnly property  
06.02.2012
Главное меню
Главная
Лаборатория
Книги по дельфи
Инструменты
Статьи
Видео
Юмор
Ссылки
Поиск
База знаний Delphi
Общие вопросы
Windows, WinAPI
Графика, Звук
IDE Delphi
Консоль
Авторизация





Забыли пароль?
Вы не зарегистрированы. Регистрация
Каталог@Mail.ru - каталог ресурсов интернет
Вскрываем ReadOnly property Версия для печати
Рейтинг: / 5
ХудшаяЛучшая 
Написал Snowy   
10.02.2009
При работе со сторонними компонентами и библиотеками, иногда может возникнуть несогласие с автором. В частности рассмотрим такой момент, когда автор класса сторонней библиотеки создал property, которую нельзя изменить, но нам очень хочется.
Данный приём имеет ряд ограничений. Поэтому я не буду брать какой-то конкретный класс, а нарисую примитивный для примера.
Допустим, есть такой класс:
  TStrikeCatsControl = class(TControl)
  private
    FCorrectValue: Integer;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property CorrectValue: Integer read FCorrectValue;
  end;
 
...
 
constructor TStrikeCatsControl.Create(AOwner: TComponent);
begin
  inherited;
  FCorrectValue := Screen.DesktopWidth div 2;
end;
Вобщем какой-то сторонний компонент, у которого есть проперти CorrectValue. Автор контрола считает, что данное проперти не нуждается в записи, а должно вычисляться автоматом.
Мы же считаем, что оно должно быть другим. Например Screen.Width div 2;
Как быть? Изменить исходники компонента? Логично, но нехорошо. Да их может и не быть. Можно использовать нехитрый трюк.
Допустим, мы бросили на форму данный контрол и хотим поменять ридонли проперти. Делается это просто, используя RTTI:
  PInteger(Integer(StrikeCatsControl1) + (Integer(GetPropInfo(TStrikeCatsControl, 'CorrectValue').GetProc) and $00FFFFFF))^ := Screen.Width div 2;
Здесь StrikeCatsControl1 - имя нашего контрола, TStrikeCatsControl - имя класса.
Используя RTTI, мы просто лезем в память и меняем значение FCorrectValue. Теперь эта проперти будет возвращать определённое нами значение.
Теперь об ограничениях:
  • Класс должен быть наследником от TPersistent или любого его наследника
  • Property должно ссылаться на private переменную. Если ссылается на геттер функцию, то вписывать просто некуда - значение вычисляемое, а не хранится в памяти
  • Property должно быть published, чтобы использовать RTTI
Впрочем последнее не совсем ограничение. Допустим, класс имеет такой вид:
  TStrikeCatsControl = class(TControl)
  private
    FCorrectValue: Integer;
  public
    constructor Create(AOwner: TComponent); override;
    property CorrectValue: Integer read FCorrectValue;
  end;
Это нам не сильно помешает. Просто создаём наследника, в котором перемещаем эту property в published:
  TMyStrikeCatsControl = class(TStrikeCatsControl)
  published
    property CorrectValue;
  end;
Всё. Теперь мы имеем RTTI для этого property. Немного изменится строка присвоения:
  PInteger(Integer(StrikeCatsControl1) + (Integer(GetPropInfo(TMyStrikeCatsControl, 'CorrectValue').GetProc) and $00FFFFFF))^ := Screen.Width div 2;
Просто заменим имя класса - RTTI нужно брать из наследника, ибо в родителе его нет.
Вопросы оставляйте в комментариях, ибо чувствую, что изложил не очень доступно.
Добавлено
Первое ограничение можно обойти также, как и третье, если поставить перед объявлением класса-наследника директиву {$M+}
Добавить новыйПоиск
GunSmoker   2009-02-19 21:02:33
1.
http://hallvards.blogspot.com/2004/05/hack-1-write-access-to-read-only.html
;)

2.
PInteger(@(StrikeCatsControl1. CorrectValue))^ := Screen.Width div 2;
GunSmoker   2009-02-19 21:04:32
Странно, мой код попортился. Ещё раз:

PInteger( @ ( StrikeCatsControl1. CorrectValue ) ) ^ := Screen.Width div 2;
Artema   2009-06-01 03:30:57
хай программеры
Илья   2010-04-28 11:26:10
А если у тебя на форме будет два компонента со свойствами подкласса FCorrectValue, то при таком условии как мне кажется изменятся свойства у всех компонентов на форме на устанавливаемое, а если учесть что свойства эти только для чтения, то получается, что при попытке восстановить второе на исходное, испохабим первое и наоборот. :confused:
Анонимно   2011-10-23 18:16:45
TStrikeCatsControl = class(TControl)
private
function GetCorrectValue(): Integer;
public
constructor Create(AOwner: TComponent); override;
property CorrectValue: Integer read GetCorrectValue;
end;

а в этом случае тоже "хак" сработает? или нужно всё-таки сначала найти исходники и убедиться, что read ведет на переменную?
Sheriff   2011-10-31 09:32:06
ну, самый простой вариант проверить как в примере, т.е. как отразиться на всех компонентах и будет ясно :), т.к. имея исходник всегда всё проще ;-)
комментарии
Имя:
Заголовок:
UBB-Код:
[b] [i] [u] [url] [quote] [code] [img] 
 
 
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch:
:(:shock::X:side::):P:unsure::woohoo::huh::whistle:;):s
:!::?::idea::arrow:
 
Security Image
Пожалуйста, введите проверочный код, который Вы видите на картинке.
 
След. >