18
votes

I have a component that was developed by my company, and would like to remove one of the published properties that is no longer needed and clashes with the way the component works now.

Is there a way to remove the property and not cause property not found errors at runtime or design time when forms that use the component are loaded? i.e. Is there a way to make Delphi silently drop a component property?

3

3 Answers

19
votes

Depending on the property, the easiest would be to leave the property, but mark it as deprecated and just have the Read/Write bits point to a field that's never used.

Alternatively, you can override DefineProperties and call Filer.DefineProperty('PropertyName', ReadProc); where PropertyName is the property you've removed, and ReadProc is a function that calls various TReader Read* functions. This has the advantage that the properties aren't in your interface anymore.

For example, say you've removed this property:

property Center: TPoint read FPoint write SetPoint;

Here's what you would add to your component:

TMyComponent = class...
private
  procedure SkipReadPoint(Reader: TReader);
protected
  procedure DefineProperties(Filer: TFiler); override;
end;

procedure TMyComponent.DefineProperties(Filer: TFiler);
begin
  inherited;
  Filer.DefineProperty('Center', SkipReadPoint, nil, False);
end;

procedure TMyComponent.SkipReadPoint(Reader: TReader);
begin
  Reader.ReadListBegin;
  Reader.ReadInteger;
  Reader.ReadInteger;
  Reader.ReadListEnd;
end;

Skipping a simple type like Boolean or Integer is easier, since you can just call ReadBoolean or ReadInteger without bothering with the ReadList functions.

In our case we had a lot of similar properties across a bunch of classes (for CLX compatibility) so we had global "dummy" functions like this:

procedure DummyReadBool(Self: Pointer; Reader: TReader);
begin
  Reader.ReadBoolean;
end;
const
  SkipReadBool: TMethod = (Code: @DummyReadBool; Data: nil);

and then the DefineProperty call looks like this:

Filer.DefineProperty('PropName', TReaderProc(SkipReadBool), nil, False);

That way each class doesn't have to have duplicate Skip* functions.

20
votes

Yes. Just remove the property, then override DefineProperties and process it there. That will satisfy the streaming system by loading the value which you can just throw away. Be sure to do nothing when writing the stream.

6
votes

You can't "silently" remove it, if it's stored in the .DFM or referenced in code.

If it wasn't referenced in code, and it's stored in text .DFM files, the JVCL has a utility called DFM Cleaner that will go through the .DFMs and remove the properties for you. Then you can open the forms and recompile your applications safely. It's part of the JVCL and is placed in the $(JVCL)\DevTools folder during install.