0

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.

Steven Carlson
  • 925
  • 1
  • 10
  • 25
M.M
  • 138,810
  • 21
  • 208
  • 365
  • haven't used c++builder in a long time, but I usually relied on a timer for this. – sp2danny Apr 13 '15 at 01:31
  • @sp2danny yeah that was my original solution, but timers work via windows messages so I think it is equivalent to the custom windows message idea – M.M Apr 13 '15 at 01:34

1 Answers1

1

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Your first para sounds like you're describing simulating asynchronous sockets by using a blocking socket plus a thread.. whereas the Indy intro documentation talks at length about how blocking sockets are good and async sockets are a hack. – M.M Apr 13 '15 at 22:11
  • My understanding of `TIdAntifreeze` is that it is basically the same as `MsgWaitForMultipleObject` anyway, is that correct? This application's main purpose is to monitor this socket, it doesn't really do anything else except wait for data to come in and display things on the main form based on that data. So at this stage I will stick with the main thread block/antifreeze but if the application grows in scope then I'll move the socket to another thread as you suggest. – M.M Apr 13 '15 at 22:13
  • @MattMcNabb: I am describing asynchronous behavior *in relation to the main UI thread*, not in relation to the *socket I/O itself*. Performing synchronous socket I/O in a thread and then interact with the UI thread asynchronously. That does not differ from what the Intro documentation says. – Remy Lebeau Apr 13 '15 at 22:22
  • 1
    @MattMcNabb: `TIdAntiFreeze` is not really analogous to `MsgWaitForMultipleObjects()`. `TIdAntiFreeze` provides a hook so Indy code running in the main thread can directly call `Application.ProcessMessage()` before/after socket calls, such as in reading/writing loops. But `ProcessMessages()` is being called even if no messages are pending. For `MsgWaitForMultipleObjects()`, the socket code would run in a different thread, and the waiting thread's message queue would be monitored while waiting on the socket thread, so `ProcessMessages()` can be called only when messages are actually pending. – Remy Lebeau Apr 13 '15 at 22:32