How to find out the list of messages that a certain VCL component can accept ???/
For example if i want to scroll the Memo1 by sending message to it
I probably will write the following lines of code knowing that the memo can accept EM_LINESCROLL
SendMessage(Memo1->Handle,EM_LINESCROLL,-1,0);
//Memo1->Perform(EM_SCROLL,SB_LINEUP,0);
Memo1->Perform(EM_SCROLL,SB_LINEDOWN,0);
How to find to find out if certain VCL comps can accept or do not accept messages???
All components accept all messages, but if a component have no assigned message handler, it just does nothing
If you want to discover if VCL component have special handler to certain Windows message, you have to look into VCL sources, which are usually provided with C++Builder (except Starter Edition's of XE and XE2).
VCL Sources are located in %CBuilderDir%\Sources\VCL (looking at my CBuilder5/6)
Sources are written in delphi, but it won't be difficult to find all what we need.
First, You'll have to find defininition of your target class. You can search through whole VCL source dir for file with line looking like
TMemo = Class (for your example with TMemo)
Open file where you found your class, (usually it will be stdctrls.pas or controls.pas - most useful components are located there), go to the line with class definition and scroll a little down until you find a group of procedures, looking like
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
...and so on. These procedures are called in response to certain messages, which id's are provided after procedure definition.
If a class have procedure for certain message, then it provides some response to it.
Message handlers are inherited in delphi, so if you didn't find handler for your message, you can look into base classes and their message handlers. To discover full class hierarchy you can simply look into the help file, or look at class definition again TMemo = class (TCustomMemo) and take parent class name from braces.
Then you can repeat search for message handler for all parent classes untill you reach TObject :-)
By the way. Simpy searching through VCL source dir of my CBuilder5 for any presense of EM_LINESCROLL I've figured than no VCL component processes it.
If you only need to provide special interaction for certain message, not trying to figure if a component already have or not have message handlers your can simply override WindowProc method of your component. All descendants of TControl have this method.
This Method process all messages received by component, and you can add response to additional system or user messages here.
void __fastcall TMyForm::NewWndProc(Messages::TMessage &Message)
{
if (Message.Msg == EM_LINESCROLL)
// Do something special for this message
else OldWndProc(Message);
}
Only thing that you'll need to do is to preserve value of old WindowProc, to call it in NewWndProc after you do all your stuff.
Its better to define and assign NewWndProc and store old WindowProc for TMemo in the form which holds your component, so you won't need to mess with making new inherited component from TMemo. So, define TWndMethod OldWndProc in form and put following, for example, in form OnCreate() handler
TWndMethod OldWndProc = MyMemo->WindowProc;
MyMemo->WindowProc = NewWndProc;
Also your can prevent firing of predefined handlers, by not passing certain messages to OldWndProc. Be careful, if you prevent processing of sensible system messages (like WM_CREATE) you'll get errors.
TMemo is a thin wrapper around a standard Win32 API multiline EDIT control. You have to read the MSDN documentation to see which messages an EDIT control natively handles. TMemo does not process EM_LINESCROLL directly, but Windows does.
Related
IDR is a good tool for decompiling Delphi applications, but hHow do I know the ID number of Windows messages assigned to message handlers?
For example, from IDR decompiling, I see:
procedure sub_004D2398(var Msg: TMsg);dynamic;
The original source code is:
procedure Name_procedure(var Msg: TMsg); message 1028;
How do I know the message number 1028 while reverse-engineering the code in IDR?
A given procedure doesn't know whether it is a message handler or not, because that information is not stored in the procedure itself where a decompiler can easily access it (it in available in RTTI, though).
Every class has its own dispatch table that the compiler generates to hold pointers to all of the class's dynamic and message methods (and in the case of message, also their message IDs). So, when you declare a class procedure as a message handler, the compiler inserts an entry for that message ID in that class's dispatch table along with a pointer to the handler.
When a UI control receives a message, the message first goes to the control's WindowProc (which the app can subclass directly). If the message is not handled, it goes to the control's WndProc() method. If the message is still not handled, it goes to the TObject.Dispatch() method, which looks up the message ID in the control's dispatch table and calls the associated procedure if one is found. Otherwise, the message goes to the control's DefaultHandler() method.
So, unless IDR is smart enough to decompile a procedure, determine which class it belongs to, and find and decompile that class's dispatch table or RTTI to determine the message ID belonging to the procedure, then you will have to do this manually while you are analyzing the decompiled output. A class's VMT contains pointers to the class's dispatch table and RTTI (amongst other things).
Once you are able to determine the message ID that belongs to a given message handler, only then can you research and figure out what kind of message that ID might refer to, as described in Deltics' answer.
Normally to find the message declaration corresponding to a given message number you would just look in any header file (C/C++) or unit (Delphi) that declares message constants. From memory I think in (older?) Delphi versions this is in the Windows unit, or possibly Messages.
In the case of Delphi you will find a bunch of declarations similar to:
const
WM_LBUTTONDOWN = 513;
Or if in hex:
const
WM_LBUTTONDOWN = $0201;
Just find the declaration for the WM_ constant with a value of 1028 (or the hex equivalent, $0404).
However you almost certainly will not find one!
Private Messages
1028 is greater than 1024, and 1024 is the constant for the "special message": WM_USER. This is not intended to be used as a message directly but rather indicates the first message number that an application can use for its own, custom/private messages.
i.e. the message with value 1028 has no standard meaning across all Windows applications.
Rather it is the 4th "custom" or private message (or possibly 5th - some people start with WM_USER+1 as documented, others start with WM_USER) used by, and meaningful to, only that application.
In the absence of the original declared constant name for the message, whatever it means and is used for can only be determined by inspecting the code and identifying its use within that code.
I want to introduce some new methods into a custom control I am deriving from TCustomListBox.
What I want is a method that can be used when a item is added/inserted into the listbox, and a method for when an item is removed from the listbox.
What would be a good place to start with this? I know controls like TListView for example have an OnInsert event but I cannot see anything for listbox?
I wanted to introduce into my control for example:
OnInsert
OnRemove
Would I need to use some kind of API or Messages to detect when items are added/removed and then take it from there? Is there an easier way to do this or does it require some difficulty?
I tried looking at some of the VCL source but most of it is confusing for me.
Thanks in advance.
The API you need already exists.
If you inspect the source of a TCustomListBox you will see that the mechanism by which items are added, inserted or removed from a list is implemented using window messages. For example in TListBoxString.Add() as well as house-keeping code you will see that the string is eventually added by sending a message to the control:
Result := SendTextMessage(ListBox.Handle, LB_ADDSTRING, 0, S);
Delphi provides various mechanisms for providing handlers on control and window classes that respond to specific messages. Perhaps the most straightforward and appropriate, for adding a simple notification mechanism such as your require, is to implement a specific message handler method.
You provide a message handler procedure and declare which message it responds to. In your case, for example, you could add your own handling of the LB_ADDSTRING message:
TChattyList = class(TCustomListbox)
procedure LBAddString(var aMessage: TMessage); message LB_ADDSTRING;
end;
The parameters of the message (wParam and lParam) are packaged up inside the TMessage record passed as the by reference parameter to your handler). You will need to consult the Windows API documentation for the message in question to determine the use of these parameters.
You can do pretty much whatever you want in your message handler although you should always pay close attention to what a window is expected to do in response to documented messages, including any return values (set in the Result field of the TMessage parameter, which is why it is passed by reference, as var.
In this trivial example, the new handler calls inherited to ensure that the inherited implementation is allowed to respond by actually adding the new item string and then crudely pops up a message box to let us know that an item was added:
procedure TChattyList.LBAddString(var aMessage: TMessage);
begin
inherited;
ShowMessage('item added');
end;
In essence your event mechanism will do exactly the same, but instead of presenting a message box you would trigger your new event after allowing the inherited implementation to do it's work (and checking the result code set, to ensure that it was successful, according to the expected return values for the message in question):
procedure TChattyList.LBAddString(var aMessage: TMessage);
begin
inherited;
if (aMessage.Result = LB_ERR) or (aMessage.Result = LB_ERRSPACE) then
EXIT;
if Assigned(fOnInsert) then
fOnInsert(self);
end;
If the inherited handler failed to add an item then according to the documentation it should set the result to LB_ERR or LB_ERRSPACE, so we test for these values and exit if they are found. Otherwise we call the appropriate event handler, if one is assigned.
This assumes that for your purposes a simple TNotifyEvent is sufficient and that you do not discriminate between an item being inserted vs an item being added. You could of course have separate events or provide some indication in parameters to a specialised event type.
Which messages you choose to handle and expose as which sorts of events is then a question of exactly what your requirements are, but based on what you have stated in your question, at a minimum I think you will need message handlers for LB_ADDSTRING, LB_INSERTSTRING and LB_DELETESTRING.
You may need to handle additional messages and should consult the Windows API documentation for listbox controls for further information.
I'm trying to put together some components for using OpenGL in RAD Studio 2009. I want to have multiple Rendering Contexts.
My idea is to have something like a "main OpenGL component", called GLMaster. It's a TFrame descendant so it should provide me with a DC. Also there's a component for a GLMonitor, acting as camera.
I create an OpenGL RC in the overriden GLMaster.Loaded inside an "if not (csDesigning in ComponentState) then"-clause. The DC for this I do not keep, it's stated in the RAD Studio help that you shouldn't:
"TWinControl.Handle
Do not refer to the Handle property during component creation or streaming. The underlying window does not exist until the first time the Handle property is referenced. When this occurs, the HandleNeeded method is called automatically."
I handle this by function pointers in components using GLMaster pointing to GLMaster.GetCurrentDC (returns a HDC).
During destruction GLMonitor wants to clean up some render-to textures and other OpenGL resources. When retrieving the DC for a call to wglMakeActive the function pointer is followed and execution jumps to GLMaster.GetCurrentDC. Pointer(Self) tells me that it's the same GLMaster that we created the "master RC" in during the streaming of the components. The property [GLMaster.]Handle is now invalid! If I however free the GLMonitor in the app form's OnClose (using simply GLMonitor_1.Free;) the Handle inside GLMaster.GetCurrentDC is valid end everything works.
I managed to see that the handle used in GLMaster.Loaded is not the same (!?!?) as after the initialization is done and the app form is showed to the user. When I found this I googled my problem and added an overriden CreateParams to add CS_OWNDC to the GLMaster component. A breakpoint there tells me that it's being executed.
Why does the VCL/Delphi silently provides the newly created components with other Handles, and thereby indirectly other DCs, even if I provide the OWNDC flag? Is there someway to get an "ALL components are now loaded and their properties are read from the .dfm file and"-message so I can run GLMaster.InitEverything inside the component?
Right now I'm thinking the fastest way onward is to put this InitEverything in the main form's OnShow handler. And then a call to GLMatser.CleanAll in the main form's OnClose. But I don't want any code in the form, that's the reason I created the components in the first place!
P.S.
Not that I think it matters for this particular problem but I use OpenGL 3.2 Core Profile.
I'm answering the "Why does the VCL/Delphi silently provides the newly created components with other Handles".
Why an control's Window Handle might change at run-time
Your TFrame (an TWinControl descendant) is placed on an other TWinControl, let's say a TForm. The parent container provides property wrappers around many settings, allowing us to easily make changes; Some of those changes can't be implemented without re-creating the windhow handle. You can get a long list of properties that cause this to happen by doing a search for RecreateWnd in Forms.pas, Controls.pas etc.
Examples of properties that call RecreateWnd to implement a change at run-time:
TScollBox.BorderStyle
TForm.BorderIcons (for MDI childs)
When your TFrame's parent needs to change Window Handle, your TFrame is going to have to change Window Handle as well. Your Delphi Control, no matter the descendense, needs to be handle this, and other controls have it worst: Controls that are implemented as wrappers around Windows controls need to save state and reload state (TEdit, TComboBox, ...)
What I think is going on
While streaming (loading your form) some control does something that needs a Window Handle before loading finishes. It's very likely your own code! After everything finishes loading the Form might need to re-create it's Handle, and this in turn causes your Frame's handle to be changed.
What you might want to override
Given the way the VCL works, you need to be prepared for your Window Handle to change. You should do a search in Controls.pas for the words Handle, HDC. If your control is so intimately linked to it's Window Handle and HDC, it's in your best interest to read up on this stuff.
Take a look at those routintes. Maybe you can sopot a better place to hook:
CreateHandle
CreateWnd
DestroyHandle
DestroyWnd
GetDeviceContext
If the title is the question, then no, Delphi does not ignore CS_OWNDC when creating a frame. Just tested with the below procedure with a frame on a form. When the flag is not specified, the line is drawn on itself again and again, resulting with a line from (0,0) to (10,10). When the DC is owned, the line extends from (0,0) to (50,50), no need to tell but the retrieved DC is same at all times.
procedure TFrame2.WmPaint(var Msg: TWMPaint);
var
i: Integer;
DC: HDC;
Pt: TPoint;
begin
inherited;
for i := 1 to 5 do begin
DC := GetDC(Handle);
GetCurrentPositionEx(DC, #Pt);
LineTo(DC, Pt.X + 10, Pt.Y + 10);
ReleaseDC(Handle, DC);
end;
end;
if your question is this:
ALL components are now loaded and their properties are read from the .dfm file and
The answer is:
Yes, just override the Loaded method of your component. It is called when all the references are valid (after dfm reading is finished).
I have some code that does some setup of internal objects in the Loaded() function. However, some external objects are not completely created yet, but are AFTER the Loaded() function is complete. What function does Delphi call after it calls Loaded()?
Better yet what is the creation sequence of a component?
Basically I have a TCP Server and Client. Most people will place those two components into two separate applications, some will place them in the same application for local access.
My Client tries to fetch data from the server in OnLoaded(), but the server may not be up yet! I want to know if another function is called after all the OnLoaded()'s are called.
Loaded is called immediately after the dfm is streamed in, and shouldn't be used to access the server. Your best bet is probably to post a custom message to yourself in the constructor, and have a message handler procedure that responds to that message. Posting the message puts it into the end of the message queue, and therefore it won't get processed until all the other messages ahead of it has been handled. This should delay things long enough for your components to be fully constructed for use.
I've used breakpoints in some components and firmly established that AFTERCONSTRUCTION is called BEFORE LOADED not AFTER.
I've also done the same thing on a FORM and firmly established that AFTERCONSTRUCTION is called AFTER LOADED not BEFORE.
Bear in mind that AfterConstruction is a method in TObject, but Loaded is not. It follows that Loaded is generated by code that may not necessarily put it in a specific order relative to AfterConstruction, since Loaded is not actually part of the construction sequence of a TObject and AfterConstruction is.
Indeed, if you study the RTL source, you will see that Loaded is not even invoked by any self.method of a TComponent, but is in fact invoked by a stream reader that is reading the DFM, and that will most probably be happening under the control of an "owner" component. I strongly suggest therefore that its relationship relative to the execution of AfterConstruction is not really guaranteed. The fact that it appears in a particular order for a form is because the form is most likely the component to initiate stream reading. In other words, it smacks of a convenient accident that Loaded is before AfterConstruction in a form.
Further research shows that NON-FORM components that include the following code may never call the event handler.
procedure Txxx.AfterConstruction; override;
begin
inherited AfterConstruction;
if Assigned(FOnCreate) then FOnCreate(Self);
end;
The reason is that AfterConstruction, if invoked before properties are loaded, will find FOnCreate has not been assigned yet!
In such cases, you really HAVE to use the following:
procedure Loaded; override;
begin
inherited Loaded;
if assigned(OnLoaded) then OnLoaded(self);
end;
Like I said, this will produce different outcomes for a component owned by a form than it would for the form itself! The TForm component is usually the invoker of the DFM stream reader and it is the stream reader that calls Loaded for each component it reads from the form. This process starts (fortunately) BEFORE the form's AfterConstruction, but each component that is loaded by that reader gets its AfterConstruction method called BEFORE its loaded method.
QED.
The great irony is that the Delphi 6 help file says "The AfterConstruction method implemented in TObject does nothing. Override this method when creating a class that takes some action after the object is created. For example, TCustomForm overrides AfterConstruction to generate an OnCreate event."
What it omits to say is that if you try this on anything other than a TCustomForm (which does it already), it doesn't work! Because only a form (which has it already) will load its OnCreate property before calling AfterConstruction. Any other component won't, because the DFM reader invoked by the form calls AfterConstruction before Loaded! A clear case of Borland et. al. not understanding their own code, or at best, writing a help file entry that implies something is possible when in fact it is not.
Note, if your component is not on a form and is created at runtime (even if this is as an "owned" component), its "Loaded" method will NOT be called, because there was no stream reader involved.
Another point of interest is something that "Dr" Bob Swart wrote some time ago about AfterConstruction, namely that it represents the point where virtual methods can be invoked. Evidently this is only partly true: if a form's Loaded method is invoked BEFORE AfterConstruction, then you would not be able to invoke any virtual methods from Loaded if that were true. This is not the case (obviously) because Loaded is itself a virtual method! Evidently, Loaded for a form is called between the constructor and AfterConstruction by the stream reader. It begs the question: by what method is the stream reader actually invoked? My guess is either that it runs under control of the application (not the form) and that it deliberately invokes AfterConstruction differently for a form than for other components, OR that it is the last thing the form's constructor does after having created the VMT and hence the last thing that occurs before AfterConstruction is called in the form. Accordingly all the AfterConstruction-Loaded couplets of components owned by the form are called before the form's AfterConstruction is called. Tracing the calls also shows that mostly AfterConstruction is called for ALL of those components before ALL of their loaded methods are called. I didn't however test the case where there are hierarchical "parents" (such as panels with components on them), so there may be variations on this.
Normally you would override TObject.AfterConstruction for that purpose.
The order of execution is:
each Component.AfterConstruction in creation order
(Form or DataModule).Loaded
each Component.Loaded in creation order
(Form or DataModule).AfterConstruction
Trace:
Debug Output: button AfterConstruction Process Project2.exe (4876)
Debug Output: Form Loaded Process Project2.exe (4876)
Debug Output: button Loaded Process Project2.exe (4876)
Debug Output: Form AfterConstruction Process Project2.exe (4876)
I'm not sure what you mean with
the server may not be up yet
Anyway, if the client and the server are both on the same application form or datamodule, I see alternatives:
You may "force" the system to create the server before the client and up the server in the server's OnLoad and it will be up at the client OnLoad, because documentation says:
When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.
Inform the "client" whenever the server is UP to let it initialize (pull data from the server). You can use a direct method call, post a message or whatever you feel comfortable with.
Let the client stand up the server inside it's own OnLoad method.
Why not use the onCreate event of the main Form ?
After much searching, it looks like I have to assign RegisterComponentsProc and RegisterPropertyEditorProc, which I have done.
However, I thought that I could call my design time Register function, i.e. <myComponentUnit>.Register();.
When I do I get stack overflow, because, well ...
procedure myComponentUnit.Regiter;
begin
RegisterPropertyEditor(TypeInfo(Integer),
TMyComponent, 'myProperty', TMyProperty);
end;
procedure RegisterPropertyEditor(PropertyType: PTypeInfo;
ComponentClass: TClass; const PropertyName: string;
EditorClass: TPropertyEditorClass);
begin
if Assigned(RegisterPropertyEditorProc) then
RegisterPropertyEditorProc(PropertyType, ComponentClass, PropertyName,
EditorClass);
end;
So, I call .Register();
which calls RegisterPropertyEditor()
which call RegisterPropertyEditorProc()
which calls RegisterPropertyEditor() <=== aaargh!!
So, what should I have in the body of my RegisterPropertyEditorProc ?
After further searching, it looks like I want to call DesignEditors.RegisterPropertyEditor() directly, but it is not in the interface section ...
There is no point in trying to register a property editor at run-time, as it is not usable at run-time to begin with. It is only usable within the IDE during design-time.
Delphi does not include the source for the DesignEditors unit; its implementation is provided solely in the DesignIDE package. That package has access to IDE internals, such as the list of registered property editors. The IDE assigns values to the RegisterComponentsProc and RegisterPropertyEditorProc callback functions. As you noticed, RegisterPropertyEditor calls RegisterPropertyEditorProc. The IDE provides its own function to handle that event.
If you want to register a property editor at run time, then your program plays the role of the IDE. You need to provide implementations for those callback functions to register the property-editor classes with your own property-editing framework. You could probably just keep everything in a simple list. Then, when you want to know what kind of editor to display for a certain type of property, consult the list to find the best match.
You're correct that you should call your units' Register procedures. But that's how you initiate the registration process, not how you implement it. That part's up to you; Delphi doesn't provide any of this for you.