Is there a way to do this at the frame level? (I mean, without declaring a TEdit's descendant)
WM_PASTE is sent directly to the TEdit window, the TFrame never sees it, so you must subclass the TEdit directly in order to intercept the message. You can either:
have the TFrame assign a handler to the TEdit's WindowProc property. This is a simple approach if you have only a few TEdits to subclass, but it gets more complicated the more TEdits you want to subclass:
type
TMyFrame = class(TFrame)
Edit1: TEdit;
...
procedure FrameCreate(Sender: TObject);
...
private
PrevWndProc: TWndMethod;
procedure EditWndProc(var Message: TMessage);
...
end;
procedure TMyFrame.FrameCreate(Sender: TObject);
begin
PrevWndProc := Edit1.WindowProc;
Edit1.WindowProc := EditWndProc;
...
end;
procedure TMyFrame.EditWndProc(var Message: TMessage);
begin
if Message.Msg = WM_PASTE then
begin
if SomeCondition then
Exit;
end;
PrevWndProc(Message);
end;
write and install a new component that is derived from TEdit, similar to the TMemo example you presented.
define an interposer class that is local to just the TFrame's unit, above the TFrame class declaration, which will intercept WM_PASTE for every TEdit on the Frame:
type
TEdit = class(Vcl.StdCtrls.TEdit)
procedure WMPaste(var Message: TMessage); message WM_PASTE;
end;
TMyFrame = class(TFrame)
Edit1: TEdit;
Edit2: TEdit;
...
end;
procedure TEdit.WMPaste(var Message: TMessage);
begin
if not SomeCondition then
inherited;
end;