Delphi and 'messages'.
Delphi is object-oriented and Delphi code tends to be event-driven, SO there
will always be messages flying around between a program and Windows, and
between components within an application, and so on and so forth. Sometimes
it may be appropriate to work with messages without recourse to Windows
functions, as Delphi itself is set up to help you deal with many of them.
Much of the time, however, it's quick and fairly simple to call a Windows
API function from within your Delphi code.
There's lots of documentation on this in Delphi online Help but here's a
few actual examples:
EXAMPLES.
*************************************************************************
Here we interrogate the Windows API to ascertain the total number of
characters in the previous lines of a RichEdit component -note that the
i variable is an integer value for the current line...
previousChars := SendMessage(REForm.RichEdit.Handle, EM_LINEINDEX, i, 0);
Note that SendMessage() is an API function, not a function built in to Delphi,
and if we use Delphi Help to tell us about SendMessage, the information we
get is actually from the Windows API Help system...
*************************************************************************
See also C:\MyDelphi\Scrolling for clever example of trapping Windows
messages
*************************************************************************
[interprocess, or INTER-APPLICATION messages...]
you could do is have a global variable that you fill in the calling
procedure and read in the message handler (the message would just be
saying, "Check the variable now.). That is not the best idea,
though, if for no other reason than it isn't very thread-safe.
Instead, you should pass all the information with the message, meanin you
should declare a record type that contains all the fields you need to
send. Allocate memory for the record (using New or AllocMem) and send the
pointer in the lParam value.
In the message handler, once it has finished with the data, free the
memory. Since you are using PostMessage, the pointer you send cannot be a
pointer to a local variable. PostMessage will return immediately to the
message poster and when that routine completes, the pointer will point to
memory that jus went out of scope, so you must allocate memory from the
heap.
type
PData = ^TData;
TData = record
Field1: Integer;
Field2: PChar;
Field3: Double;
end;
procedure TForm1.SendAMessage(Sender: TObject);
var
data: PData;
begin
new(data);
// populate data
data.Field1 := 28;
data.Field2 := nil;
data.Field3 := -4.5;
PostMessage(Handle, wm_CustomMessage, 0, lParam(data));
// Do not free data here.
end;
procedure TForm1.HandleAMessage(var Msg: TMessage);
var
data: PData;
begin
data := PData(Msg.lParam); // just a type-cast for easier use
// process your stuff here
dispose(data);
end;
Finally, check out the wm_CopyData message. It is designed moe for
interprocess communication (since pointers aren't valid across process
boundaries), but it should still work. It makes a copy of the data you
send so that you don't have to worry about persisting pointers.
--Rob
*************************************************************************
another 'handle messages' example:
[in a form's Uses clause:]
Messages
[procedure declaration]
procedure HandleMessages(var Msg: tMsg; var Handled: Boolean);
[in FormCreate]
Application.OnMessage := HandleMessages;
[body of procedure]
procedure TMainForm.HandleMessages(var Msg: tMsg; var Handled: Boolean);
//handy piece of code that could be used in other contexts. Here we subvert
//the default handling of arrow keys by, in effect, trapping Windows
//keypress messages. Navigation keys (tab, arrow keys, etc) are processed by
//Delphi OnKeyDown and OnKeyUp event handlers, so the code here allows us to
//step in and trap the messages for those keys before they reach the Delphi
//OnKeyDown and OnKeyUp event handlers...
//THIS PROC IS LIKELY TO BE OF ONLY TEMPORARY USEFULNESS-
//when the various parts of the application have been turned into COM objects
//then trying to subvert keypresses in this way may not be a good idea...
begin
if (Msg.message = WM_KeyDown) and
(Msg.wParam in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT]) then
begin
case Msg.wParam of
VK_LEFT: MoveLeftSBClick(Self);
VK_RIGHT: MoveRightSBClick(Self);
VK_UP: MoveUpSBClick(Self);
VK_DOWN: MoveDownSBClick(Self);
end;
Handled := True;
end;
end;