Your code and text suggest you have several misunderstandings about how message handlers work. First, you ask about accessing private message handlers. You don't need access to private message handlers from parent classes. You can override the handler of any message, regardless of whether the parent class handles that message. Just write your message handler. It will automatically override the parent's handler, even if the parent's handler was private. (In fact, that's why we often declare message handlers private in the first place — descendants can always override them, and since there's no reason to call one directly, there's no reason to make it public.)
It looks like you're trying to get the base class's message-handling behavior by calling DefaultHandler
. That will work sometimes, but only by accident. DefaultHandler
goes to the base class's message handler. If there are other classes in between the base class and your descendant, a call to DefaultHandler
will skip their handlers. Instead of that function, use the inherited
directive, just like you would when overriding ordinary methods.
When you want your object to behave as if a message had been sent to it, you don't always have to send it a message with SendMessage
. Instead, you can call the object's Perfrom
method. All the same message-dispatch operations will occur, but you can skip the Windows message queue.
If you have two methods that should perform many similar tasks, you have a few options:
- Copy and paste the code so both functions look similar.
- Put all the code in one function, and then call it from the second function.
- Put all the code in a new, third function, and then call it from both functions.
The first option isn't usually a good idea. The second option can be good if the first function is guaranteed to always be a subset of the second function. If it needs to do something that the second function won't always want, though, then it's not appropriate to call it from the second function. The third option is what Robert's answer suggests.
The second option might be what you need, if my crystal ball is working properly. I think you wish for your wm_SysCommand handler to do some hit testing, so you want to call the wm_NCHitTest
message handler. That's easy.
procedure TForm1.WMSysCommand;
var
Hit: DWord;
begin
Hit := Perform(wm_NCHitTest, ...);
if (Msg.CmdType = SC_MAXIMIZE) or (Hit = htCaption) then // if command is Maximize or reciever message of Caption Bar click
begin
if CheckWin32Version(6, 0) then
Constraints.MaxHeight := 507
else
Constraints.MaxHeight := 499;
Constraints.MaxWidth := 0;
end
else if (Msg.CmdType = SC_MINIMIZE) or (Hit = htCaption) then // if command is Minimize
begin
if (EnsureRange(Width, 252, 510) >= (510 / 2)) then
PreviewOpn.Caption := '<'
else
PreviewOpn.Caption := '>';
end;
inherited;
end;
Notice a few changes I made to your code. First, I use Perform
to invoke the object's wm_NCHitTest handler, and I store the result in a variable. I use that variable in the next conditions to check where the mouse was clicked. Second, I removed the or
tests from your conditionals. You were combining the named constants with their numeric equivalents, which is pointless and confusing. Third, I replaced the DefaultHandler
call with one to inherited
.
Beware, though: The wm_SysCommand message is sent for keyboard messages as well as mouse messages. There won't always be a valid hit test. You're probably going about this sys-command handler all wrong, but it's hard to tell what you're really after.