Get location of the control after hooking to Drawtext function - delphi

I have a VCL application that i'm testing but don't have the source code.
I need to validate what text was drawn to the labels on the screen but the labels are not a window so I create a hook to the drawtext function and i can get the text that was drawn to the screen.
But i cant validate where on the screen that text was drawn as the function gets hdc and a point where to draw the text in the context.
I need to figure where on the screen that hdc is located and make sure the the label is correct.
Is there a way to do it?
Managed unmanaged dose not matter to me.

You could build a DLL in Delphi and inject that DLL in the target process. As your are happily hooking Win32 APis, I suppose you will not have problems with that.
In that DLL, you could find (using Win32 APIs) the HWND which is the "parent" of the Label.
With that HWND, you can find the associated TWinControl. For that you must dive into the VCL source code.
For Delphi 4 (yes, I know, it's old) you have to build an Atom String, use GlobalFindAtom, and then GetProp. The result is a pointer to the TWinControl.
For Delphi7 (old, too) you have to use RegisterWindowMessage with a string made up off "ControlOfs" followed by the module handle and the thread ID. The LRESULT of a SendMessage is then a pointer to the TWinControl.
Sorry, I don't know for other Delphi versions, but all should be findable in the VCL sources.
Once you have the TWinControl pointer, you can enumerate the children as TComponent, and get their Name's (as they appear in the source code you don't have...), their ClassName's, and so on, you get the idea.

I think you would need to do something like this:
Call WindowFromDC to find out the window that hosts the label. As you know, a Delphi label is non-windowed and the control actually paints on its parent window. This may fail if the parent is double buffered. In that case you've no hope of getting the window handle from the device context since all you have is the device context of a bitmap.
Now that you have the window on which the label paints, you need to find out the location of the label on the window. The VCL calls SetWindowOrgEx to arrange that the device context has logical coordinates 0,0 at the top-left of the label. So you can call GetWindowOrgEx to find out the location of the label relative to the parent.
Now you know the location of the label relative to the parent, and the window handle of the parent, you can work out where the text is being drawn on screen with ClientToScreen.
Since device contexts only have meaning in the process that owns them, you'd need to inject into the target process to call this.

Related

Delphi, Firemonkey - How to draw on component canvas outside of paint

I am writing my first component for Firemonkey. It is very dynamic control and to keep refresh times minimal, when a property changes, I only want to modify the effected attributes rather than repaint the entire control.
The first issue I found was that unless you are in the Paint loop, you need to call Canvas.SetMatrix(AbsoluteMatrix) first otherwise canvas functions are referenced to the parents coordinates. I don't quite understand this.
The second issued is that when use this control on OSX, unless I call the inherited paint procedure (which I override) nothing changes on the canvas gets displayed. This works fine in Win32
Component is based off of TControl
You might not like this, but you're not supposed to paint outside of a paint event. So don't do it. Windows is a bit more forgiving if you break that rule, but you shouldn't do it on Windows either. For example, if your window is (partly) hidden, no updates are needed and the OS will skip the paint event. So instead of trying to work against the OS it is better to work with it. And usually there is a better alternative.
You can keep an internal "cache" bitmap and update that as needed. Then when the paint event comes, you can draw this entire bitmap. If possible, update this cached bitmap in the paint event if it needs changing.
If you want to temporarily highlight items, you can have a transparent window on top and paint on that window. Let the OS window manager do the heavy work for you.

Delphi - Activating the Hint from another control of Application

I'm trying to activate Hint from control of different application created from delphi upon focus, I'm using hook to identify the focused control, and then use WM_MOUSEMOVE, which I think will activate the Hint of that control, the handle would be the Control itself and the lParam is the Left and Top of the Control. The Control activate the OnMouseMove Event, but the Hint never shows. but when I use SetCursorPos, Hint show, but I need to show the Hint with out the cursor move on that Control. Can you please help me with this? Thank you in advance... by the way I'm using Delphi XE4
Among the really asked question is how to show the hint of a control that resides on another application (i am afraid without hook that application can not be done), the title is "Delphi - Activating the Hint from another control of Application".
First is first: That can be done without knowing what language the other app was done, but it is very complex to put it here (and i am not an expert on such way of coding, also i hate apps that work that way).
Second: The main idea is to hook the other application, search on Google some code of that apps, that can show you a rectangular hole square of the object the mouse is passing over, that application while doing it is iconized (i do not remember the name of it).
Waht such app does: As you move the mouse over the screen it overlays a rectangular over the control that mouse is over, then if you press the key to print screen, that small region is the only thing that goes to clipboard; on of such apps i saw had an extra funcion, they can move such controls if you press cursors on keyboard, also can hide/enable/disable such control... more, it can also make controls that are invisible to be visible, etc... i saw it working on my computer, and hey, for fun it is pretty and to DeBug or get extra things on some apps is also great (make some menús to be visible and enabled and then can use such funtions).
Please, please, understand i am agaist piracy and also against using such apps to let code to be run... some apps need pay for letting some menus enabled, but they have the code there, no need to change EXE to have/use that menus; just using this kind of apps makes that limited apps to be unlimited (just enable or show hidden menus and voila).
Note: To unhide menus, mouse point is not needed to be over the app, can be anywhere and is not moved.
The idea i want to say is: Any app can move, alter any control on any other app (at least on Windows) that is running, so maybe there can be a way to show such hint.
In the past i had use such app (sorry i do not remember the name) for DeBug my own apps, so i do not need to recompile in such cases where something was wrongly hidden, also work with buttons, labels, texts, combos, memos, etc.
Now my small problem is: I just need exactly what title say, but i can not make it to work.
Must be:
Mouse position must be irrelevant (it also must be able to be outside the application)
Just when a button that has focus is pressed with keyboard (Space or Enter) or just after some code somewhere on my application, i want to show the Hint of a specific TEdit for a short period of time.
I did not get Hint to be shown; not unless mouse point is over such TEdit but i want/need mouse pointer to not be over it, neither it to jump to the TEdit.
Idea Conept for that Hint to be shown: After doing some code that changes something, show extra info associated.
Example:
A button with that loads a file using an open dialog, filename is put on a ReadOnly TEdit (so it let user copy the text, but not change it); i want extra info that i punt on .Hint of such TEdit to be shown inmediatly.
That hint use is for not overload window with a lot of fields (TLabels) for showing such file data.
Simple idea: such Hint shows TimeStamp and size of the selected file.
P.D.: Not much related (since i am trying with a normal plain text hint), but hints can also store a full HTML page and with 3rd party tools be shown as an HTMLhint, so they can show a lot info of that file (also its content, etc) in a web based format; as i say i first try with standard plain text hints.
In order to show hint programatically you need to call TApplications ActivateHint method to which you specify the position parameter.
http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Forms.TApplication.ActivateHint
Based on position parameter Application automatically finds which controll is at that position and shows its hint.
NOTE: Position parameter screen coordinates in pixels and not your controll coordinates. So you will have to use ClientToScreen method to change your coordinates apropriately.
You can see simple example of how to use this here: https://stackoverflow.com/a/15031208/3636228
Now if you need to do this from another application then you will have to add some comunication mechanizm to these two application so that one could send a proper message to tell the other to show the hint at specific position. But this does require you to be able to change both applications.
EDIT: This works with VCL applications but I'm not sure if it would work with FireMonkey applications.

How to make my Deskband's (Taskbar Toolbar) Form transparent

I'm working on a Windows Deskband in Delphi XE2 for Windows XP, Vista and 7 (Win32 and Win64)...
I've implemented all the necessary interfaces (ITrayDeskBand, IDeskBandInfo, IDeskBand2, IDeskBand) in my code, and that all works exactly as it should (there are no warnings on Vista/7 complaining about compatibility as others have experienced).
The problem I have is that my Deskband Form appears with a non-transparent band. Also, only certain Controls are displaying (in this case TBitBtn and TImage containing a PNG). I need it to display TEdit and TComboBox objects properly too, but they won't appear at all.
I've tried enabling GlassFrame and SheetOfGlass properties on my Form, but this doesn't help one bit.
Furthermore, the Form itself is exceeding the top boundary of the Taskbar, meaning you cannot (for example) resize the Taskbar if the cursor is in-line with the top of the Taskbar immediately above my Deskband.
I believe there is something Delphi's VCL TForm type is doing behind the scenes which renders the TForm type incompatible as a Deskband container... but this is just a suspicion.
Here's a screenshot illustrating the various problems:
As you can see (above), the Deskband's Form is pale (instead of Transparent), it overlaps the top of the Taskbar (preventing resizing and Autohide triggering when the Taskbar is "hidden")
Any ideas?
UPDATE 1
Okay, I have been playing around and noticed that a totally different behaviour is observed when creating a TToolBar control to be used for the Deskband, rather than a form:
Notice there are three TToolButton controls (with their text virtually invisible due to the Glass theme)? There should also be a TEdit and TComboBox between two separators, but these refuse to display at all.
Also notice the artefacting (the repetition of actual Taskbar Icons)?
I'm not sure if this is a step in the right direction or not, but it might help you (or others) to deduce a solution!
Okay... I've finally figured this out, and it is the most absurd thing I've ever come across.
I'm posting my findings here for the benefit of others (to save you going through the nuisance I've just been through).
To get all of the controls on your Deskband Form to display and function properly, simply set the Visible property of your Form (in the IDE designer) to True.
Ridiculous, I know, but it works and is easily repeatable.

Delphi: How to use windowless controls?

i know that windowless controls are not magic. A windowless control can have input focus (e.g. Internet Explorer). Input focus is nothing more than drawing either:
a blinking cursor
a dotted line around the perimeter
a slight blue tinge on a button
and when the user begins mashing keys, reacting appropriately. You know the keystrokes are meant for that focused control, because that's the control has focus.
In the case of my (Windows®) window, i would have to know that my windowless child control (let's pretend it's a descendant of TGraphicControl) gets the keyboard events. So during my form's OnKeyDown, OnChar, OnKeyUp, i would need to pretend they are going to my windowless child control.
Which i can do, but it is a pain.
But then the user will probably want to use Tab navigation, and i'll have to somehow intercept Delphi's normal tab control order handling, and hook in myself to say that this thing is the next (and previous) in the tab order.
Which i can do, but it is a pain.
And then there's ActiveControl, which doesn't understand anything except TWinControl's. So if Delphi ever tries to figure out who has focus, it will go insane. So i'd have to have an alternate implementation of ActiveControl.
Which i can do, but it is a pain.
In other words: is this just too much work? i'm fighting eveything that Delphi is, all so i can have a few dozen windowless controls accessible through keyboard input? The Delphi designers never contemplated using interactive windowless controls, and if i try now to work it in, i'll just stuck in the hurtlocker?
Delphi gave me the chance of aiding me willingly, but i have elected the way of pain.
Some further explanation of windowless controls is needed.
Not every control you interact with has to be a windows control. It is quite possible to have focus on, and send keyboard input to, a control that is not a Windows window.
For example, nearly every control you see in an Internet Explorer browser window is a windowless control. In the following screenshot you can see an edit control, which you can type in, and a button which (in this screenshot) has focus:
You can see the dotted focus rectangle, and the button is bluish (which on Windows indicates that it has focus).
If i were to press Spacebar while the Google Search button has focus, it would press the button. The reason this works is because Microsoft wrote an entire widget library of controls. These controls look and feel (almost) exactly like the regular common controls - they are very nearly exact clones of the Windows common controls, right down to the themes being applied.
Mozilla Firefox and Google Chrome also use a widget library of controls. They don't use Microsoft's built-in windowed controls, but instead use a library of graphical, interactive, windowless widgets.
And if you have a suitable development environment, then the windowless widgets work just like "normal" windowed controls. GTK+ is a widget library, and Glade is an IDE that lets you layout controls in that widget library.
i don't know in what development environment Firefox, Chrome, or Blender were created in, but their widgets support windowless controls.
So now onto my question.
Unless i'm mistaken, it appears to me that although Delphi supports a base TControl, (which has width, height, and can paint itself), it cannot receive keyboard focus. It seems to me that Borland never designed Delphi's VCL as a generic widget library. The only evidence i have to support this is that a Form's ActiveControl is a TWinControl:
property ActiveControl: TWinControl;
That doesn't mean that Delphi could be, or must be, limited to windowed controls. The VCL widget library could be extended to support giving focus to windowless controls.
But perhaps Delphi already supports windowless controls, and i just don't realize it? Is there already an established mechanism in Delphi to support giving focus to TControl's? But i'm a reasonably smart guy, and i'm pretty sure Delphi's VCL cannot do what other widget libraries can do.
Which then leads to another question: how much work would be be to subclass forms and such to support it? Is there someone else out there, perhaps someone on TeamB, who's much smarter than i, who has already tried it, and come to the conclusion that it's impossible?
i'm asking now, up front, if trying to add windowless control support is damn near impossible (i.e. futile) - so that i don't spend weeks on it for nothing. i'm trying to draw on the knowledge of a community of Delphi developers.
i'm asking a question.
It's futile to build windowless controls and fit them into Delphi's VCL framework.
You bring up Internet Explorer as an example. But in that case, it's entirely in charge of everything that resides on it. It has its own internal notion of what the active control is, but think about what it looks like from the outside: It's just one giant control. When you ask the OS what has focus, the single browser control has it, no matter which of the browser's subcontrols appears to have focus.
When you press Tab, it looks to the OS as though the browser has simply consumed a tab character, just like edit controls do. Edit controls move the cursor over a few spaces and add tab characters to their internal buffers; browser controls move the cursor to another region of the display.
You're thinking of doing all this on a Delphi TForm. Delphi forms already have a framework for managing the active control and handling keystrokes, and you're going to have to fight it all. If you want windowless controls, go the Internet Explorer route and build your own container control to hold them so that you can remain in charge of everything that happens inside it.
Your container can be a VCL control, but the things you put on it probably can't — they'll still be expecting to use the VCL focus- and keyboard-handling rules. Notice how you can't put ordinary Windows controls in Internet Explorer, either. Anything you put there needs to go through specific ActiveX interfaces. Maybe you'll need interfaces, too, or maybe you can just make your own set of control classes that descend from some special ancestor class you design to work with your container. Don't start with TGraphicControl; it's too entrenched in the VCL to be usable as the basis for your offshoot control library.
It will be a lot of work, but then again, so was Internet Explorer.
Yes, it is futile.
And it's not Delphi's fault, you're just fighting Windows itself.
If you need a control that behaves like a windowed control, use a windowed one.
And you're right, trying to recreate the whole API stack of windowed controls from scratch is a pain.
Yup, you pretty much have it figured out. Using windowless controls means that you lose everything Windows can do to help you. Having more than a couple on a single actual window is pain.
Most of these programs were most likely not originally developed using RAD type tools so had no choice but to re-invent the wheel. One of the largest advantages of Delphi is the deep VCL and 3rd party component support to provide the look you desire.
One technique that I have used with great success to reduce the amount of window handles used in a complex (tax preparation) form based application was to draw the text on a canvas, and moved a single TCustomEdit decendant to the position the user was editing. It was trivial to capture the TAB/Up/Down keys and move the edit to the appropriate position. The challenge we discovered was in drawing a hot rectangle around the mouse hovered field. We ended up with a grid array of TObject, where the array element would be nil (no field), a TLIst (grid contains multiple fields) or a a class that contained our field descriptor. This reduced the amount of range checks we had to perform since it was more likely that the box only contained a single field, or at most 4 fields.
fpGUI Toolkit is an example of what you want. The latest fpGUI code in the source code repository is based on a multi-windowed design. That simple means every widget/component has a window handle, but Windows or Linux does nothing with that window, other that basic notification messages (mouseenter, mouseexit, etc). fpGUI still has full control over where each component goes, if they are focusable, how they look etc. Some widgets/components in fpGUI are non-windowed components too. eg: TfpgScrollbar, TfpgMainMenu, the button in a ComboBox etc.
If you want a true non-windowed version, mean there is only one top-level window that has a window handle, all other widgets/components inside that window doesn't actually exist to the OS (they have no window handles), then fpGUI can help too. The initial design of fpGUI Toolkit was based on such a design. Again, look in the source code repository for the v0.4 branch of code. I that design, fpGUI had to handle absolutely everything, creating mouseenter/mouseleave events, translate co-ordinate systems for container components, handle (fake) component focus states etc... Yes the initial design is a LOT of work, but then you have a very portable framework which can easily be applied to other OSes too.
And yes, fpGUI is fully implemented in the Object Pascal language using the Free Pascal compiler to give me cross-platform support. Currently fpGUI runs on Windows, Linux (32 & 64-bit), Windows Mobile and Embedded Linux (ARM) devices.
I have no idea of what your problem really is, here, but I think this little history may be relevant...
We have an application which fills out a dozen forms. The user may fill out additional forms, and also change values filled out by the application it self.
Now, in our first implementation, we used windowed components for every single input field, so that the fields could receive focus and input. That turned out to be a big problem, because all this windows took a lot of resources.
We now have windowless controls for every input field. That means that all we end up with, is a combined drawing of the form and its input fields. When the user clicks inside the drawing, or uses some keystrokes to move/set focus, we create a new windowed control for the clicked field. When the user moves to the next input field, we destroy the first window, and create a new one. This way we only have one windowed control which again gave us a nice speed improvement.
Again - I have no idea of what you really want to manage. TWinControl is a TWinControl for a reason, but there may be a solution to what you want, what ever that would be...
I think fgGUI may help you out.
Do check its Wiki first.
I think you can use this framework for your application in Delphi as it is written totally in Pascal. Actually it is based on FreePascal ;)
HTH

Why does CreateDIBSection() fail when the window is offscreen?

I'm building a Delphi component to embed an SDL rendering surface on a VCL form. It works just fine as long as the form is on-screen at the moment that the SDL surface is created. Otherwise, it's not able to create any rendering textures.
I traced into the SDL code and ended up with the following function call, which fails (returns NULL):
data->hbm = CreateDIBSection(renderdata->memory_hdc, bmi, DIB_RGB_COLORS, &data->pixels, NULL, 0);
The HDC is a valid handle to the drawing context owned by a control that has its own HWND window handle, that's been set up properly. But when the control is created offscreen, which commonly happens in Delphi, (all forms, with their controls, are created in a hidden state until it's time to display them,) the CreateDIBSection call will fail until the control is actually visible.
Also, if it's created onscreen, then hidden and re-shown (if it's on a tab sheet and I switch tabs, for example,) any textures I create get blanked during this process.
This is driving me nuts. Anyone know what's going on and how I can work around it?
The drawing context is only valid during Paint processing.

Resources