Is it safe to use the SHFileOperation in a worker thread? - delphi

I would like to have
one background thread which will copy the files through the SHFileOperation function, always only one SHFileOperation at the time (but I want it to be in the thread)
I need the UI output, so I need to use the FOF_SIMPLEPROGRESS flag and pass something to the Wnd member
I have two questions
is it safe to call the SHFileOperation with FOF_SIMPLEPROGRESS flag (for user interaction) from the thread other than main ?
if yes, what handle should I pass into the Wnd member ? I've tried the handle of the main form, but when e.g. the overwrite confirmation dialog pops up and you confirm it, the main form is sent to the background, what is really strange
Note:
I have a queue for these operations, so only one SHFileOperation is performed at the time (after it's finished, the thread continues to the other action, what might be the next SHFileOperation)
Thanks a lot

It's perfectly safe to call SHFileOperation from a thread other than the main thread.
I would pass 0 as the hwnd member. If you pass the handle of the main window then I expect that window will be disabled because SHFileOperation is a modal dialog. Since the file confirmation and progress dialogs are the top level UI for the background thread, you don't want any windows to be disabled when these modal dialogs show.

Related

Parent window freezes when child window freezes altough it's from another process

Disclaimer: I'm not familiar with the Win32 API, especially how windows work.
I'd like to make the window of some process a child window of another process. The two processes are also parent and child. But I don't think that matters. So far, everything works like a charm - Until I freeze the main thread of the child window.
Imagine a container.exe that 'hosts' notepad.exe and someApplication.exe
When I suspend the main thread of someApplication.exe for a few seconds, its window is frozen for that amount of time. That's perfectly understandable. But the window of container.exe will also hang for the same time. The child windows of other hosted processes (like notepad.exe) will continue to work fine.
I am using the SetParent command to make a regular non-child window a child of my container.exe:
SetParent(
childProcess.HWND,
myOwnHWND
);
After that, I'm using setWindowPos:
SetWindowPos(
childProcess.HWND,
HWND_TOP,
someXPos,
someYPos,
0,
0,
SWP_FRAMECHANGED or SWP_NOSIZE or SWP_SHOWWINDOW
)
As the MSDN article on SetParent suggests, I also clear the WS_POPUP style attribute and add a WS_CHILD attribute. Since that didn't help either, I also added a WS_EX_NOACTIVATE extended style attribute, both by using the SetWindowLongPtr command. Finally, I tried sending both windows a WM_UPDATEUISTATE and then a WM_CHANGEUISTATE message but that also didn't change a thing.
The thing that confuses me is that the window of the parent process continues to be drawn normally, until I touch it. Then it freezes completely until the child window unfreezes. I suspect something called an 'input queue'. The MSDN article about a WM_ACTIVATE message states:
Sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the top-level window being deactivated, then to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately.
Because of that, I had high hopes for the WS_EX_NOACTIVATE extended style attribute.
To sum it up: Is actually possible to host the window of another process and to not freeze your own window when the child window freezes?
You cannot expect to block the GUI thread of any process. In your scenario things are a little more complex because there are two GUI threads. One for each process.
However, by establishing a parent/child relationship between windows of these processes you are also introducing a requirement that both GUI threads are serviced in good time.
Windows that are in a parent/child relationship will send each other messages. And if those messages are synchronous, that is sent rather than posted, then blocking one GUI thread will lead to the other being blocked.
The golden rule of GUI programming remains in force: do not block a GUI thread. If you have a long running task, then move it onto a background thread.
Update
OK, as explained here when you relate windows from different threads you attach their message queues to each other. And so if you block one thread, you block all of the attached threads.
So, don't block a GUI thread.

Threading, com+ calls with SendMessage messaging

I have an app which creates a thread which communicate with the main UI via windows messages. It simply send the message to the main app thread and received the status.
That way I am displaying modal windows and do other things.
The problem is when I have to display a form which makes a call to a com+ server.
That way I get OLE error 8001010D: An outgoing call cannot be made since the application is dispatching an input synchronous call.
I think it happens because primary SendMessage is in use and com+ calls need windows messaging for its tasks.
Anyway, In delphi I cannot display the form from a thread, but how Could I workaround the problem ... ?
Thanks
EDIT:
MAIN(UI) 2. A THREAD
A. A Thread(2) sends message to a main thread (1)
B. Main thread(1) receives the msg and before letting it come back to a thread
it displays the window.
C. The modal window in main thread wants to make a com+ call, the above error occurs.
What thread the modal window is in? 2. Which thread the COM call goes from? 3. Which thread the COM object was instantiated in? 4. Is the background thread initialized with an STA? 5. Is the modal form being shown from a SendMessage handler? – Roman R. 2 mins ago
MAIN
MAIN
MAIN
CoInitializeEx(nil, COINIT_MULTITHREADED);
yes.
The problem cause comes from inability of COM to marshal an outgoing COM call while processing SendMessage request. The error which comes up is RPC_E_CANTCALLOUT_ININPUTSYNCCALL (0x8001010D), which you are referring to. I was under impression that this only applies to SendMessage calls which are a part of incoming interthread COM requests, however this might have been a false assumption.
Your typical workaround would be to replace your SendMessage with PostMessage followed by waiting for synchronization object, event or semaphore. This way your caller background thread does not hold messaging to synchronize the calls and waits autonomously, on the main thread the message being dispatched through regular message queue and eventually reaches the same handler.
As a bonus, you have an option to safely terminate the background thread. If currently it's being locked by SendMessage API waiting for modal dialog, the suggested change would let you signal the synchronization object from the main thread and let it keep running, e.g. if you want to safely terminate it.
An alternate solution might be to call InSendMessage function and if true - defer modal UI, e.g. by again posting a message to self to pop the form up in another message handler later.

need to add a progress bar for when a (blocking) DLL call is busy

my delphi 2009 app uses a DLL that performs some activities that may take several seconds. i'd like to show a progress bar. unfortunately the DLL call is a blocking call & has no callback function.
a way i've been considering is to add a TTimer to my app. when the timer event fires, i look at the time and use that to calculate the progress % and update the progress bar.
i did that, would i have problems with the fact that the VCL is not thread safe?
thank you!
I don't know much about Delphi but if it runs on windows , you might need to do this.
1) Because your user interface is not thread safe, you need to PostMessage into the user-interface thread to update the progress bar.
2) If your user-interface thread is the thread calling into the DLL, then you wont be pumping messages, so you cant update your user-interface. You could call MsgWaitForMultipleObjectsEx to continue pumping messages while waiting, but since the wait is within the DLL , you dont have a handle to wait for. Is it possible to move your call into the DLL to another thread ? Then you can wait on that thread handle. This way your progress bar will continue to operate.
I dont know much about Delphi, but my colleagues tell me it runs Win32 based function calls, so it operates very much like a windows program on windows.
Since the DLL is blocking, you need to call it from a secondary worker thread. If you call it in the main thread, your TTimer will be blocked and thus unable to update the UI.

Delphi Thread freeze

I coding a service application that have two threads.
First thread, show a form with label.
Second thread, query ADO.
First thread always freezing with Hourglass cursor and no label caption.
Please help.
If you're trying to show a form from within a thread that is not the main thread, then you will run into strange things like this. The most notable of which is that if the form and label are created in the non-main thread, then you don't have a message loop to process the messages. If the form was created in the main thread, but you're attempting to show it from the non-main thread, then it is likely a dead lock due to how Windows deals with messages and threads.
When a window handle is created it is tied to the thread on which it was created. This means that Windows will ensure that any messages sent to that handle are processed on that thread.
I would strongly suggest you read up on how window messages, message queues, and handles all interact and function in a multi-threaded environment. If not done correctly, you are assured of some very odd and possibly unpredictable behavior.
I would call your condition either a Race, a Deadlock, or some other kind of error like that. As Allen says, if the background thread makes ANY direct access to the VCL controls, without using TThread.Synchronize(myMethod) to invoke the myMethod that touches your VCL foreground, then this alone would cause your trouble.
Post more information, including a sample of your code please.

How to Prevent ProcessMessages in Delphi

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.

Resources