You are catching the FORM'S paint event, not the BUTTON'S paint event. Every window receives its own painting messages (WM_PAINT, WM_DRAWITEM, etc).
Your code can be simplified a little. If you use the button's WindowProc property, you won't need to call GetWindowLongPtr() directly (and even then, SetWindowSubclass() would have been a better choice). Also, since your DrawColoredTxt() function is completely erasing the button and drawing it yourself, there is no point in calling the default paint handler at all.
Try this:
...
procedure DrawColoredTxt(aBtn: TButton; aCaption: string);
private
FOriginalButtonProc: TWndMethod;
procedure ButtonWndProc(var Message: TMessage);
...
procedure TForm1.DrawColoredTxt(aBtn: TButton; aCaption: string);
begin
...
end;
procedure TForm1.ButtonWndProc(var Message: TMessage);
var
PS: TPaintStruct;
begin
case Message.Msg of
WM_PAINT: begin
BeginPaint(Button2.Handle, PS);
try
FOriginalButtonProc(Message);
DrawColoredTxt(Button2, 'Admin');
finally
EndPaint(Button2.Handle, PS);
end;
end;
// Forward all other messages to original handler
else
FOriginalButtonProc(Message);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FOriginalButtonProc := Button2.WindowProc;
Button2.WindowProc := ButtonWndProc;
Button2.Repaint;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
if Assigned(FOriginalButtonProc) then
begin
Button2.WindowProc := FOriginalButtonProc;
FOriginalButtonProc := nil;
end;
Button2.Caption := 'Admin';
Button2.Repaint;
end;
But, that being said, since you are drawing the entire button anyway, you may as well just use the BS_OWNERDRAW style and handle the WM_DRAWITEM message, as explained earlier in this discussion thread.