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.
Related
Using C++Builder XE5.
My main form has an Indy blocking socket which I would like to connect to and block on, as soon as the application has started up and the main form shown.
What is the correct way to do this?
In previous versions or C++Builder, OnCreate and AfterConstruction were both unreliable. Normally I put code like this in the main .cpp file, just before Application->Run(), however that is not appropriate here because I am going to block (and rely on the TIdAntifreeze for message processing).
One way I thought of is to define a custom windows message and post that to myself, but I'm wondering if there is a "proper" way.
My main form has an Indy blocking socket which I would like to connect to and block on, as soon as the application has started up and the main form shown.
Do you really need to do blocking I/O in the main UI thread? Blocking operations, such as Indy's socket I/O, should be done in a worker thread instead.
If the main thread needs to block on a socket operation while still processing UI messages, you can use a waitable event object via CreateEvent() with MsgWaitForMultipleObject() in a loop that calls Application->ProcessMessages() only when there are messages to process, breaking the loop when the event is signaled. This is not generally the best option though. An event-driven model, where the worker thread notifies the main thread of activity/results, would be a better choice. You really should never block the main UI thread for anything.
What is the correct way to do this?
I would suggest having the MainForm constructor create a worker thread, and then the thread can manage the socket operations and synchronize with the main UI when needed.
In previous versions or C++Builder, OnCreate and AfterConstruction were both unreliable.
AfterConstruction() is reliable, and always has been. It is only the OnCreate event that was unreliable, and should never be used in C++ in favor of the constructor instead.
Normally I put code like this in the main .cpp file, just before Application->Run(), however that is not appropriate here because I am going to block (and rely on the TIdAntifreeze for message processing).
You really should not rely on TIdAntiFreeze, a worker thread is a better choice.
One way I thought of is to define a custom windows message and post that to myself
That will work. I use that technique myself at times. Just be aware that it is an HWND-based solution, so you need to make sure the HWND you post to is not destroyed/recreated after you post the message and before it is retrieved from the message queue. If you use the MainForm's HWND, post the message in the OnShow event. A better option is to use AllocateHWnd() to create a dedicated HWND for your custom messages.
Let's say I have a form Foo.
How do I create an instance of that which runs in it's own thread and gets updated even though the main application thread might be busy doing something else? For instance handling blocking network communication or something like that.
I understand the fundamentals and that I need to create a new thread, create the form instance in that thread etc. But then I figure I need an update loop for that thread/window and I'm not at all sure how that should look.
You shouldn't create forms in threads any than your main application thread, because windows message queue is associated only with this main thread.
Think differently: To be sure, that your forms are always updated and responsive, create separate threads for busy work like handling blocking newtork communications and so on, not for forms. In such case, after creating new thread, main form continues to pump messages from it's queue, while function in different thread is doing dirty-work that you need. When the working thread finishes, it can inform main thread about results, using PostMessage() WinAPI function. You should just simply provide handlers for such custom messages in your forms, and they will communicate with working threads seamlessly.
Also, if your "busy work" isn't very complicated, you can even deal without additional threads, by running your work in the form thread, and just calling ProcessMessages() function from time to time, to keep the form updated.
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.
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.
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.