I am trying to get the window handles to a Delphi application from an external application. I can see that there are a few windows created (TApplication, TFrmMain and a few others), and I know that TApplication is the "controller", but never visible. However, can I read what the value for the real window is? I know that it is TFrmMain (for this specific application), but is it possible to actually figure this out somehow? Is the information stored in the window properties,or somewhere else? Thanks!
No, there is no documented way to discover which of the windows represents Application.MainForm from outside the application. In newer versions of Delphi, the main form's window handle isn't necessarily Application.MainForm.Handle anyway; applications can handle the OnGetMainFormHandle event to return whatever they want — that's used for choosing the parent window for modal dialogs.
You can guess by looking for windows with "main" in their class names, but even if you find one, there's no guarantee that there's only one instance of it. Applications can have multiple top-level windows, in which case it doesn't make much sense to designate any one of them as the "main" one.
The class name of any Delphi form is also the registered window classname of the underlying "Windows window". So you should be able to use the FindWindow() Windows API call to get the window handle of TFrmMain a little something like:
hWnd := FindWindow('TFrmMain', NIL);
If there are (potentially) multiple instances of a given form class name then you may be able to distinguish between them by using the 2nd parameter (Window Name, i.e. "caption" or title). If that still isn't enough then you may need to get a little bit more sophisticated and look at using the EnumWindows() function and checking the properties of the windows to find the one of interest.
To test the classname of an arbirary window handle (e.g. in your callback function that you use with EnumWindows()), use GetClassName(), e.g:
function GetWindowClassName(const aHWND: HWND): String;
var
buf: array[0..255] of Char; // Tip: Use a more appropriately sized array
begin
GetClassName(SomeHWND, #buf, Length(buf));
result := buf;
end;
...
if SameText(GetWindowClassName(hwnd), 'TFrmMain') then
...
etc
Without specific details of your particular implementation challenge it's difficult to say which is most likely to work best for you, but hopefully that should be enough pointers to get you heading down the right track.
I usually use WinDowse to help me get started, but then you have to use the API functions as described by Deltics.
Related
I wrote a set of components that link to each other via published interface properties. They are registered and installed in a design package.
Using published interface properties is not that common in Delphi, and thus, unsurprisingly, doesn't seem to work that well.
It works fine when components reside on the same form, however interface property links between components on different forms cause issues.
Unlike object links to components on another form, interface links don't seem to be recognized by IDE. What I mean is best described by an example, when you have 2 forms open in IDE, and have links between components on them, then trying to switch to form view as text (Alt+F12) would cause IDE to correctly complain that:
Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.
But if the property is an interface then this does not happen, what happens instead is that the link is severed (and that's the best case scenario when you use Notification mechanism to clear references, otherwise you're left with an invalid pointer)
Another problem, likely as a consequence of the same bug is that when you open a project in IDE, the order in which forms will be reopened is undefined, so IDE can try to open a form that contains components that have interface links to components on another form, but that other form is not recreated yet. So this effectively results in either AV or severed links.
Back in 90s while I used Datasets and Datasources I remember similar issues with links between forms disappearing, so this is somewhat similar.
As a temp workaround I added duplicate published properties, for each Interface property I added another that is declared as TComponent. This makes Delphi aware there is a link between forms, but is an ugly workaround to say the least.
So I wonder if there is something I can do to fix this issue ? It's an IDE bug and likely not fixable directly, but perhaps I can override something or otherwise hook in to streaming mechanism to more effectively workaround this bug.
I haven't ever gone so deep into streaming mechanism, but I suspect the Fixup mechanism is supposed to deal with this. There is a csFixups TComponentState so I hope a workaround is possible.
Edit: Using D2007.
Update:
New updated reproducible example uploaded to http://www.filedropper.com/fixupbugproject2
Added property ComponentReference: TComponent so that it's easy to compare and trace interface vs component streaming.
I narrowed the problem down to assembler level which is a bit out of my depth.
In procedure GlobalFixupReferences in classes unit it calls:
(GetOrdProp(FInstance, FPropInfo) <> 0)
which eventually executes:
function TInterfacedComponent.GetInterfaceReference: IInterface;
begin
// uncomment the code bellow to avoid exception
{ if (csLoading in ComponentState) and (FInterfaceReference = nil) then
// leave result unassigned to avoid exception
else
}
result := FInterfaceReference; // <----- Exception happens here
end;
As you can see from the comment, the only way I found to avoid the exception is to leave the result unassigned, but that breaks the functionality since comparison above in GlobalFixupReferences fails due to GetOrdProp <> 0, which severes the link.
tracing deeper the more exact location of exception is in
procedure _IntfCopy(var Dest: IInterface; const Source: IInterface); in system unit
This line in particular raises an read of address 0x80000000
{ Now we're into the less common cases. }
##NilSource:
MOV ECX, [EAX] // get current value
So, why MOV fails and what's wrong with ECX or EAX I have no idea.
To summarize, the problem happens only with published interface properties that have a getter method, and the property points to component on another form/module (and that form/module is not recreated yet). In such case restoring form DFM causes an AV.
I'm pretty sure the bug is in the ASM code in GetOrdProp, but it's beyond my ability to fix, so the
easiest workaround is to use a Field instead of a getter method and read it directly in the property. This is, fortunately good enough for my case currently.
Alternatively, you can declare the property as TComponent instead of interface, then write a TComponentProperty descendant, override ComponentMayBeSetTo to filter component that don't support the required interface. And of course register it using RegisterPropertyEditor
I'm working with DirectShow in firemonkey, and i have a problem with outputting Video.
iVideoWindow.Put_Owner(Panel1.Handle);
I need handle of TPanel, to display video at it. But FMX controls have no handle. I know, that Firemonkey is not based on traditional windows and FMX do not provide this, but how to solve this problem? I have no idea, please, help me.
If you want to get a window handle as an HWND (Win32 API) type, you can now call this function:
WindowHandleToPlatform(form1.Handle).wnd
Put this in your uses clause:
uses
FMX.Platform.Win;
Note that just calling WindowHandleToPlatform(form1.Handle) will not work, you have to access its .Wnd property to obtain the Win32 handle.
Since this makes an application less portable, it is also a good idea to put {$IFDEF MSWINDOWS} around the code whenever doing this, and if you ever port to MacOS, you'll have to write separate code for that platform. Or, put this code into a separate unit that deals only with MSWindows-related stuff, and IFDEF that unit into your uses.
FmxHandleToHWND is marked deprecated now.
WindowHandleToPlatform will convert given FireMonkey handle to its platform dependent window handle (in your case a Windows handle).
Use Timage control, then you can assign your output to Image1.Bitmap.Handle. Its the only component that provides window Handle under FMX
To get handle of a panel, try this :
uses
FMX.Platform.Win;
var
Handle : HWND;
begin
Handle := TWinWindowHandle (Panel1).Wnd;
end;
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 has a piece of code where I override TStringGrid's inplace editor and the hint window. For this, I created my own string grid based on TStringGrid and use a TEdit for inplace editor and a TPanel for tool tips. In TMyStringGrid.Create constructor I initialize them like this:
Constructor TMyStringGrid.Create();
Begin
inherited Create(AOwner);
MyEditor:= TEdit.Create(Self);
MyEditor.Parent := Self;
End;
In this case the owner (the main form) is freeing the controls. I used this for years and it worked.
The thing is that other people argue that the programmer should use NIL instead the Self when instantiation the child controls and later to manually free them in the Destroy destructor. It seems that the second alternative has gigantic advantage over the first one, especially when you dynamically create lots of child controls (not my case). Other problem with my code, they say, is that the child controls may be freed after an Application.ProcessMessages call while the application may still want to use them.
So, I should let my code unchanged or should I manually create and free the child controls?
There is a any Borland example of compound controls?
Delphi 7, Win XP
Reference: http://delphi.about.com/od/kbcurt/ss/dynamiccreateno.htm
Yes you can use your code without changing it.
There is a any Borland example of compound controls?
Best example is to check the implementation of TLabeledEdit.
It was creating the label in constructor
if Assigned(FEditLabel) then exit;
FEditLabel := TBoundLabel.Create(Self);
FEditLabel.FreeNotification(Self);
FEditLabel.FocusControl := Self;
There's no good reason to pass nil instead of Self in this situation. That AOwner parameter is there specifically for that reason. Take advantage of it.
There's a reason to pass nil when creating a control and manually destroy it, but for a completely different situation: if you're creating a control (typically a form) inside a function. This is a pretty common pattern, for example:
MyDialog := TMyDialog.Create(nil);
try
result := MyDialog.ShowModal;
finally
MyDialog.Free;
end;
There, you want to free it immediately instead of waiting around until the current form gets destroyed, which could be much later. But when it comes to sub-components, you usually want them to be destroyed at the same time as the parent component, not later, so pass Self to AOwner and let the VCL take care of it for you.
Considering that constructor, the grid instance is owned by Aowner (which is tipically a TForm or a TFrame). The inplace editor is owned and parented by the grid instance. I don't see how ProcessMessages would cause destruction of the child objects, since they will be destroyed in the destroying loop of TMyStringGrid. That's nothing I can see of wrong on that implementation - and I use that same design for the components I create. Ownership is there on VCL to easy our lifes when managing objects' lifetime. And is not the case where nil is recomended as owner, which is shown in Mason' answer.
In the pattern shown by Mason , the reason for the NIL is that, without a owner, the object destruction will not enter in a Notification loop. If you create a lot of components which destruction you handle manually, you want to make sure the owner is NIL, otherwise a lot of code get executed (without need) in each component construction/destruction.
Many moons ago, there was an excelent white paper on the web archive of (now defunct) eagle-software.com
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.