When a function return we say the control is transferred back to the calling procedure. Likewise a loop that finishes transfers control back. So how does "control transfer" actually work in the computer, what is the mechanism for control transfer?
Related
I'm faced with the daunting task of having to intercept and handle the WM_GETOBJECT message whenever it is sent to any TWinControl on a Form.
every panel
every nested panel
every edit box
every combo box
every button
every toolbar
every datetime picker
every image
every listview
every treeivew
every win control
on every form
Obviously i'd prefer not to have to individually subclass every control:
it's difficult to do correctly (may people use SetWindowSubclass when they want to start subclassing, and RemoveWindowSubclass when they're done, and don't realize the crash they just introduced)
it's difficult to do correctly
it requires subclassing every control individually, likely through a child control iteration function (which has the common bug of failing if you apply it when the form handle is created and removing them when the form handle is destroyed)
Is there a way to be involved in the handling of every message sent directly to a child control using SendMessage
similar to how TApplicationEvents.OnMessage can intercept every posted message
similar to how KeyPreview allows a form to see every send Key message
If you don't want to subclass each individual control (which is certainly an option, and one that can be simplified using interposer classes, for instance), then you can instead use a thread-specific WH_CALLWNDPROC or WH_CALLWNDPROCRET hook via the Win32 API SetWindowsHookEx() function. The hooks will tell you which HWND is receiving each message, and you don't need to implement the hooks in a DLL when hooking a thread in the same process as the hooker.
If you need the TWinControl* pointer for a given HWND, you can use the VCL's FindControl() function in the Vcl.Controls unit.
I use Delphi XE5 and have to realize the possibility for the user to drag different files (docx, xlsx, pictures (jpeg, gif, ...), E-Mails, ... into a component. The component should show the filename or the header of the E-Mail.
Than i want to save this file into a Blob-field in the SQL-Server Database.
Can anyone tell me whats the best possibility if possible with a short example.
Can i realize this with the standard delphi components or is it necessary to install special components.
Your component needs to be derived from TWinControl (TCustomControl, etc) so it has its own HWND to drag things onto. Then:
if you just want to capture dragged filenames, your component can process the WM_DROPFILES window message. This is a legacy message, but it still works. However, it only works when dragging physical files from the file system onto your window. For more advanced scenarios (dragging virtual data, dragging data from other apps, etc), you need to...
a. implement the IDropTarget interface instead. Write an object that implements IDropTarget, or use a third-party implementation such as from Ander's Melander's Drag&Drop suite.
b. register that object for your component's HWND using RegisterDragDrop() after it has been created (the best place to do that in in your component's overridden CreateWnd() method), and unregister the object using RevokeDragDrop() when the HWND is being destroyed (such as in the overridden DestroyWnd() method).
c. when the user drags something onto your component's window, your IDropTarget.DragEnter() implementation will be called. Examine the provided IDataObject to see if it holds a data format + transport scheme that you support (there can be multiple combinations at one time). Each piece of data will be identified by a unique clipboard format identifier, and a TYMED value indicating how the data is transferred. Some clipboard formats are pre-defined (see Shell Clipboard Formats), and some can be registered dynamically at runtime (see RegisterClipboardformat()). If you find a combination that you support, return DROPEFFECT_COPY to accept the drag, otherwise return DROPEFFECT_NONE to reject the drag.
d. if the user drops something onto your component's window (if accepted by DragEnter()), your IDropTarget.Drop() implementation will be called. Extract the data from the provided IDataObject and use it as needed. When dropping physical files, you will receive their paths+names and/or their ITEMIDLIST identifiers, then you can open and read the files as needed. When dropping virtual data/files, you will get the actual data instead (which is usually transferred as a block of memory in an HGLOBAL that you can access using GlobalLock(), or as an IStream interface, but there are other possibilities available).
See MSDN for more details:
Transferring Shell Objects with Drag-and-Drop and the Clipboard
Shell Data Object
Handling Shell Data Transfer Scenarios
I have a bar-code scanner with USB interface, so it appears as an HID.
There are reasons why I must breakpoint on the first character.
That brings my Delphi IDE to the front, it stops on the breakpoint and the rest of the bar-code is injected into my code as if it had been typed front the keyboard (which, in a way it has, as the USB scanner is just another HID).
Is there any way to avoid this? Or to add an initial check as to the source of the input?
It annoys me so much that I am now looking for a scanner with an RS232 interface.
The problem is that HID "devices" send information back to the computer in packets known as "reports".
In the case of a mag-swipe, or bar-code scanner, the "report" contains the entire number.
Which is to say, you don't receive reports character-by-character, but the entire string at once. (In the case of a mag-swipe, you will receive all two, or three, tracks in the same report).
So your code doesn't break "on the first character", it breaks "on the entire report". The fact that the remaining characters are there you can think of as a bonus (if you don't want to look at them you don't have to). But you won't be receiving any more "reports" for subsequent characters.
i cannot imagine any reason why you wouldn't want to know the bar-code at once. But most mag-swipe and bar-code scanners can be configured to emulate a keyboard, rather than a generic HID device. In that case you will receive multiple WM_KEYDOWN messages.
I have noticed a strange piece of behaviour when using MessageDlg and attempting to close my application via the Taskbar close all/group command.
My application is as follows:
There is a hidden main form which doesn't do anything other than handle some Windows Messages and pass them onto the child windows (if necessary).
Each child window has its parent set to the desktop (in order to get it displaying on the Taskbar).
Each child has an OnClose event which pops up a MessageDlg to prompt the user whether they want to save their session (if any content has been modified in anyway)
The issue seems to be it will continually close any windows that haven't been modified, however, when it hits a window that has been, 1 of 2 things are happening intermittently:
Regardless if I select "Yes/No" the Close All process seems to stop after that particular window is closed.
The dialog is not displayed and mrCancel is the result. Again the close all process stops after this window is closed.
A change I made was to use the WinAPI MessageBox function in replace of MessageDlg and this did seem to resolve the issue. However, I would really like to know why MessageDlg is acting like this?
My initial thought was when the dialog is being launched in the middle of the Close All perhaps the OS is sending a WM_CLOSE message to the dialog as it is technically part of the group (this would explain the dialog not appearing and defaulting to mrCancel as this is the equivalent of pressing the X). However, that doesn't explain why after I dismiss the dialog the Close All process does not continue to close any other windows in the group!
Any thoughts/idea's on this?
Windows doesn't send WM_CLOSE messages to these windows, it posts WM_SYSCOMMAND with the SC_CLOSE request. This in turn leads to the sending of WM_CLOSE messages if the standard Windows message box is used. If the MessageDlg() function is used instead, only the first posted WM_SYSCOMMAND leads to a WM_CLOSE, the others do not. It's hard to say for sure, but maybe this has something to do with the DisableTaskWindows() and EnableTaskWindows() calls that the VCL uses to "fake" modal dialogs. If you replace the Windows function with Application.MessageBox(), a wrapper that does use DisableTaskWindows() and EnableTaskWindows(), then it doesn't work either (which IMO supports this reasoning).
I think I can explain why switching from MessageDlg to MessageBox made things different. MessageDlg in turn calls the MessageDlgPosHelp which creates a Delphi form to look like the Windows MessageBox, and this form is called shown with ShowModal. This locks the entire application until it is closed.
MessageBox, on the other hand, defaults to MB_APPLMODAL which means you have to close it before the window it is attached to can be used. If you have nothing specified in the uFlags parameter then this is the default. This only prevents you from getting back to the window specified in the hwnd parameter, so other windows in your application are still accessible.
The Application.ProcessMessages command is well known and I use it in long processes to ensure my program will not tie up the computer.
But I have one fairly quick set of processing, where I am buffering a view into a file. During the buffering procedure, a few system messages may get sent off (e.g. redraw or scrollbar move or other events). I want to prevent these from getting handled by ProcessMessages until my buffering is complete.
Is there any way to either:
Prevent Application.ProcessMessages until my procedure is complete, or
Trap all messages generated during my procedure, and not release them until the end of the procedure.
Allowing the ProcessMessages to continue even if it sends messages you don't want should not be classed as problematic. With a bit of code refactoring, you could move the buffering method into a separate thread and go from there.
If you are attempting to copy the "visual contents" of a control into a file,
look at the WM_PRINT(xxx) message which allows child controls to paint themselves into bitmaps
try the LockWindowUpdate Win32 API method call which will turn off all painting messages to that control
override the WndProc/DefaultWndProc method on your control class or even the parent class if you need to and simply return "true" for each message sent
override specific control methods (such as "scroll bar moved", "OnPaint", "OnPaintBackground" etc) on the control class or even the parent and simply do nothing if your buffering is in progress
Overriding the WndProc or DefaultWndProc and simply returning true for each message essentially "turns off" ProcessMessages but it's not safe to do it this way because the control might need to process one or more messages to function correctly.
Turning off ProcessMessages is not possible (without rewriting the VCL code for message processing) because of the fact that it's part of how the VCL form's message loop has been constructed.
Trap all messages generated during my procedure, and not release them
until the end of the procedure.
There is a dirty hack you can do (only if you can not come up with a better way):
You can watch (trap) any messages by using Win32 Hooks.
Specifically, use SetWindowsHookEx with WH_CALLWNDPROC as the idHook value.
You can then record them in a list/queue and resend them when you want.
I learned way back in Windows 2 that windows messages will happen at times you don't expect them. Any part of a library can cause your app's message processing to happen. Rather than hold back the tide, make your code robust against the situation. This may be as simple as usinga a BeginUpdate/EndUpdate pair, or more complex (using a temporary and doing the final update at the end).
At a pedantic level, the way you "prevent" Application.ProcessMessages is to not call any code that
shows a modal dialog
calls SendMessage
runs its own local message loop
calls Application.ProcessMessages (which is a local message loop)
If you write a loop that does nothing but numerical calculations and file I/O, your UI will be frozen until you exit the loop because no messages are being processed.
If you want your UI to be responsive during some long-running operation of unknown arbitrary code (third party library) but you don't want certain kinds of actions to occur in your app during that time, that's a different problem - that's about preventing reentrancy. You want to prevent some parts of your code from being used while a particular activity is in progress. For example, modal dialogs prevent you from interacting with the app windows underneath the dialog by disabling all the app's top level windows except the modal dialog itself.