Add Delphi visual controls and windows messages


Delphi visual controls and windows messages
According to the encapsulation paradigm every class must provide all the methods and properties to manipulate it. The user of the class should not need to write any additional code except event handlers. But it’s not always easy with windows visual controls because the system sends notification messages associated with a control to its parent window. The parent window control can handle messages by itself or dispatch them to the corresponding child controls. The second way is more preferable because all code can be encapsulated within the control’s scope.

Let’s take an example. The TMemo component, which is a wrapper of the ‘edit’ control provided by windows has limited capacity. If you work in windows 95/98 operating system conduct a simple experiment. Create a new project with a form containing a TMemo component. Compile and run the application. Now copy big ammount of text to the clipboard from some other application and paste it in your TMemo control. Repeat pasting until the TMemo control is not able to add more text. Add operation fails without any notification. Normally you would need to handle this situation displaying a message of deleting a part of text or in some other way. If you go to the Tmemo event list you will not find anything like OnFull or OnOutOfMemory.

Windows defines a group of notification messages for the edit control beginning with EN_. You can easily find them in windows API help by looking for en_ substring. The messages are sent as WM_COMMAND message, which has the following representation in Delphi

TWMCommand = record
Msg: Cardinal;
ItemID: Word;
NotifyCode: Word;
Ctl: HWND;
Result: Longint;
end;

Here NotifyCode contains the code of the notification message and Ctl is the window handle of the edit control for which this notification is sent.

The message of our interest is EN_ERRSPACE, which is sent when the control runs out of memory and cannot perform a requested operation.
As mentioned above, the system sends WM_MESSAGE to the parent window of the control. Parent window can be any descendant of TwinControl class like Tform or Tpanel. In our experiment the parent window of the Tmemo control is the form on which you dropped it. To handle the EN_ERRSPACE notification we could overwrite the WMCommand procedure of the form.

procedure TForm1.WMCommand(var Message: TWMCommand);
begin
if message.NotifyCode=EN_ERRSPACE then begin
//do something here
MessageBox(self.GetParentHandle,’ErrSpace’ ,’TMemo’,0);
End
else inherited;
end;

But this solution is not universal because we need to write similar code again for every new form. Another problem is that if the parent control of TMemo is not a Tform this will not work because the message will be dispatched not to form. Try to drop a TPanel component and place TMemo on it. Now TForm1.WMCommand doesn’t work because the message is sent to TPanel control.

Better solution is to dispatch the message to the TMemo control and handle it there. Fortunately Delhpi has already done it for us. Every descendant of TWincontrol class when receiving WM_COMMAND message dispatches it to the appropriate child control changing the message ID to Msg + CN_BASE. For example when the parent control receives WM_COMMAND message it finds the control to which this message has been sent and send CN_BASE + WM_COMMAND message to it. Therefore to receive WM_COMMAND messages the child control should have a message handler procedure for CN_COMMAND message which is defined as follows
CN_COMMAND = CN_BASE + WM_COMMAND;

Now we can create TmemoEx component, which is aware of EN_ERRSPACE notification.

type
TMemoEx = class(TMemo)
private
FOnErrSpace: TNotifyEvent;
{CN_COMMAND is sent instead of WM_COMMAND}
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
published
property OnErrSpace: TNotifyEvent read FOnErrSpace write FOnErrSpace;
end;

procedure TMemoEx.CNCommand(var Message: TWMCommand);
begin
if message.NotifyCode=EN_ERRSPACE then begin
{make a call to user’s event if assigned}
if assigned(FOnErrSpace) then FOnErrSpace(self);
end
else inherited;

end;


Conclusion
The article highlights some details of handling windows messages by Delphi visual controls. The example, provided in the article gives step by step explanation of how the WM_COMMAND message is dispatched through different controls of a Form.

Related Discussions
  • HOW CAN I DEACTIVE DIAL-UP CONECTION? (2001-01-28 13:54:30)
    A guy named Ruben recently gave me this answer when I asked nearly the same question......... ----------------------------------------------------...
  • EACCSESSVIOLATION... (2001-01-30 02:44:22)
    Assuming MyRegistry is varible declared as TRegistry try this... with MyRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; if...
  • SIMPLE EMAIL QUESTION (2001-01-30 09:40:08)
    Here is the MemoryStreamToWebBrowser example I promised: // This writes a MemoryStream to the WebBrowser document // without using any disk...
  • MORE EXPLAIN (RUN AN APPLICATION BEFORE ALL OTHERS) (2001-01-26 17:11:58)
    There are other ways... You can make a boot disk. Anyway, your install program will be a DOS program. BUT, if you put your program in RunServices,...
  • HELP FINDING AV IN THIS COMPONENT (2001-02-16 10:23:12)
    Yes, I realize that, but even when I remove it I still get the AV.
  • HOW TO RETRIVIE WINDOWS 2000 UPTIME (2001-01-29 07:27:37)
    Thanks a lot! david, that did the trick. //Peter
  • HOW CAN I CHECK WHAT PROGRAMS ARE RUNNING? (2001-01-27 16:18:58)
    Thanks Mr. Baseball Wow! Your response was so quick and your answer was so concise that I can't believe that my dilemma was not just a walk...
  • CREATING SHORTCUTS (2001-01-28 03:16:27)
    This is a sample from the MSDN, I tried to translate it into Delphi. I did not try to execute it but it should work. If it won't, tell me and I'll...
  • DELETING THE EXEFILE... (2001-01-28 06:05:04)
    function CreateTempFileName: string; var TempDir: array of Char; count, len: LongInt; dummy, sec: Word; start: string; begin...
  • DIAL UP CONNECTION FOLDER (2001-01-29 11:11:29)
    For people who will read the last answer, sorry, I made a mistake : I forgot a parameter... Add ", false" after the key name in Reg.OpenKey......
Latest News
Submit News Form Past News
Latest Forum Entries