Access the Winform control that started a thread - c++

I've got a WinForm project which uses a PageControl and PageTabs. Say there are two PageTabs, each with their own UserControl object. If one UserControl starts a Thread() which is meant to loop endlessly and access a TextBox on the UserControl that started it, how does that thread's process access the correct UserControl.
More specifically:
The GUI.h has two PageTabs, each with their own UserControl object.
The first tab has a ReceiveButton which starts a thread. That thread does a lot of work on a loop and updates the TextBox.
The second tab is essentially the same, but has it's own ReceiveButton and TextBox. This button also starts a thread and is supposed to update this TextBox.
I'm having a tough time figuring out how to make each thread access/update it's own respective TextBox.
Here's sort of the chain of code my UserControl follows:
//MyUserControl.h
void ContinueNormally(void);
System::Void buttonReceive_Click(System::Object^ sender, System::EventArgs^ e)
{
this->myThread = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &MyUserControl::ContinueNormally));
this->myThread->Start();
}
//GUI.h
#include "MyUserControl.h"
void BufferRecieveLoop()
{
while (true)
{
//receive from multicast
incoming.Process(buffer, bytes_read, endian); //this is the method in the other .h file
}
}
void MyUserControl::ContinueNormally()
{
//setup
BufferRecieveLoop();
//cleanup
}
//EntityStateProcessorPdu.h
#include "MyUserControl.h"
void EntityStatePduProcessor::Process(const DIS::Pdu& packet)
{
//do stuff
///Below are attempts at accessing the correct textbox, all in vain :(
//GUI_Example_Receive::Globals::gui->SetConsoleTextBoxText(sysStr);
//GUI_Example_Receive::Globals::gui->Controls->Find("myUserControl", true)[0]->Controls->Find("")
//GUI_Example_Receive::MyUserControl::SetTextBoxConsoleText(sysStr);
}
I should also note that this works just fine with one UserControl, or one PageTab. I'm Invoking correctly to get the UI thread to do the updating.

In Win32 (and pretty much any OS GUI that I know of) only allows one "thread" to access the GUI. This is normally known as the "GUI Thread".
The "GUI Thread" is the thread that runs the Win32 message pump.
Normally what you do is post your own "custom" messages that will be run in the GUI thread and you update your GUI controls from there.
I don't know the C++ GUI library you are using but it will most likely provide some sort of utility for post messages or code to be run on the GUI thread.

In Windows Forms every controls has a method Invoke, that it does what you search:
calls a delegate in the same thread that creates the control.

Related

Qt DLL in MFC app - How to make QDialog *really* modal?

At the moment I am developing a Windows DLL with Qt 5.9.2 (MSVC 2015 compiler), which should be loaded by an existing, commercial MFC application. Upon request of this application a modal instance of QDialog should be displayed.
Since QApplication::exec() would block the entire application, I "simulate" the event loop using the following code:
void Core::createQApplicationInstance()
{
// Check, if there's already a 'QApplication' instance running (unlikely)
if (!QApplication::instance())
{
int argc = 1;
// Create a new 'QApplication' instance
m_app = new QApplication(argc, nullptr);
// Create a 'QTimer' instance to call 'processEvents' periodically:
// We can't run 'm_app->exec()' because it would block everything,
// so we'll use this 'hacky-whacky' method here
m_timer = new QTimer;
// Connect the timer's timeout to the app's 'processEvents' via a lambda
QObject::connect(
m_timer,
&QTimer::timeout,
[&]()
{
m_app->processEvents();
}
);
// Start the timer with the fixed 'message' interval
m_timer->start(kMsgInterval);
}
}
If my DLL should now display a modal dialog, it works (partially) with the following code:
{...}
case eUserIGeneral:
{
qDebug() << "<< eUserIGeneral";
QDialog w;
w.setModal(true);
w.exec();
// --> Code here is executed AFTER the dialog has been closed
}
break;
//-------------------------------------------------------------------
{...}
The code after w.exec() will actually be executed AFTER the dialog was closed (as intended). However, the main application still remains responsive and is not affected by the modality of my dialog, which Is not as I expected it to behave.
How can I make sure that inputs in the main application are locked when calling a modal DLL dialog?
Although I don't have a real answer to your question, there too much stuff wrong with your code to be properly explained in a comment. Therefore I am writing this as an answer.
QApplication::exec(): I strongly recommend revising the decision against it. If you want the window to be modal, why would it be wrong to "block the entire application" until it is closed? Note that you will not block the Qt part of the application, only the one that calls exec.
QTimer: A timer can only run inside an event loop. So the m_app->processEvents() either never executes, or you already have an event loop running. Either way, there is no use for the timer.
w.setModal(): If what this does is not correct for you, check out setWindowModality().
w.exec(): Ignores the value of setModal(). Read the documentation of setModal() and exec() to find out more.
w.exec(): Executes an event loop. If this somewhat does what you want, QApplication::exec() should work too. Just make sure to exit the main event loop when done.
w.exec(): Is not executed after the dialog was closed. It is executes while the dialog is shown. It blocks until the dialog is closed. So you will start executing it, show the dialog, close the dialog, and then return from it. Read the documentation of exec() to find out more.

QTest asynchronous signal interception

I am investigating QTest for GUI testing. It appears that there is no mechanism in QTest to asynchronously test a signal callback. Am I misunderstanding how to use QTest, or misunderstanding the intended functionality provided by QTest?
For example, I am attempting to test a signal which launches a modal QMessageBox popup in response to clicking a QPushButton. I want to test events and state between the clicking of the button and clicking 'OK' on the QMessageBox. I have tried using QSignalSpy.wait(), QTestEventList.simulate(), QTest::mouseClick(), QTest::mouseEvent(), and QTRY_VERIFY(), all of which, when called from the testing code, do not return until after clicking 'OK' on the QMessageBox popup. Therefore, to test anything before all event handlers return, I would have to do something like install an event filter on the object under test, and write my own asynchronous testing code.
This is all the same code we would have to write if we weren't using a test library and we can do all of this without using QTest. For example, we can manually get a handle to the object under test, connect signals for testing, invoke an event to trigger the event handler or invoke the signal manually, and also write the installed test handlers that interact with the test environment before returning execution to the point at which the event was launched. What does QTest gain us here?
(Also posted on Qt forums)
Working with synchronous events using qtestlib is a bit tricky. If you look into the sources of qtestlib, you can find that event simulation are pretty straightforward. So, qtestlib doesn't provide any methods to handle synchronous events. Anyway, it's possible to handle Qt modal windows which are spawned by your app.
Main note to this question is that GUI objects can't be accessed from others threads except GUI thread. And moreover GUI could be created only in thread where QApplication was created. So some tricks like spawning a new thread to press OK button in QMessageBox will be unsuccessful with error like this object can not be accessed from other thread somewhere in QWidget sources.
To avoid this case async event could be triggered with Qt slots mechanism. First of all you should define a Helper object with some slot, for example
class Helper {
Helper() {}
public slots:
doSmth();
}
Further you should create an instance of this object in the testcase
void BlahblahTest::testCase1() {
Helper h;
...
And before you invoke some synchronous event with, for example, QTest::mouseClick, set a delayed action with
QTimer::singleShot(delay, &h, SLOT(doSmth));
Depends on your needs the implementation of doSmth could be like that
void Helper::doSmth() {
QList<QWidget *> tlw = qApp()->topLevelWidgets();
foreach (QWidget *w, tlw) {
if (...) { // w is a messagebox
Qt::keyClick(w, Qt::Key_Enter);
}
}
}

Displaying window from ui-thread sometimes blocks the main ui-thread

I am not an MFC expert, and definately not a multithread expert but still, I want to understand this strange behavior. At some places when I create an MFC ui thread in my application it is started and can display a messagebox no problem, with the main ui thread blocked. However sometimes if I create the thread, then the thread execution stops until the main ui thread non-blocked again.
Of course the situation is made up. The main ui thread's blocking, symbolizes some kind of synchronisation, while the ui thread's messagebox symbolizes some more complex ui dialog.
This is more of a theoretical question. I am primary interested in the reason why this could happen? Here is an example :
class MessageBoxThread : public CWinThread
{
DECLARE_DYNCREATE( MessageBoxThread );
public:
virtual BOOL InitInstance()
{
CWinThread::InitInstance();
AfxMessageBox(_T("Some text"));
return TRUE;
}
};
IMPLEMENT_DYNCREATE( MessageBoxThread , CWinThread );
void testing()
{
MessageBoxThread* pMessageBoxThread = new MessageBoxThread ();
pMessageBoxThread->CreateThread();
Sleep(10000);
AfxMessageBox(_T("It Worked!"));
}
So in terms of the example, if I put 'testing' function into CWinApp::InitInstance it is working as expected (showing 'Some text' first then after 10 sec showing 'It Worked!'). However if I put it into a random place deep inside my application, it might happen that the two messageboxes appear at the same time after the 10 sec sleep. What could cause such behavior?
I am not an MFC fan, but knowing Win32 I can see what is happening. By putting it "deep" you probably mean calling the testing() function in some window message processing code - a code that runs on the main UI thread and processes pumped messages. So you are putting your UI thread to sleep which in this case is similar to what a message box or a modal dialog would do. So, your message pump (implemented in CWinApp I think) is blocked by this Sleep() waiting you to complete processing the message in response to which your code is executed (does not matter what message).
Okay, I finally found the answer. When someone creates a ui thread, that person must initialize the m_pMainWnd member which contains the ui threads base window. If you fail to do so, the framework will use the application provided main window, which is the one in the main ui thread. Since that one is blocked because of the Sleep() method, the other ui thread will only respond when the main thread is not blocked.

Can I have multiple GUI threads in MFC?

I have a large MFC based application that includes some potentially very slow tasks in the main thread. This can give the appearance that the application has hung when it is actually working its way through a long task. From a usability point of view, I'd like to be giving the user some more feedback on progress, and have an option to abort the task in a clean manner. While hiving the long tasks off into separate threads would be a better long term solution, I'm thinking a pragmatic short term solution is create a new GUI thread encapsulated in its own object complete with dialog including progress bar and cancel button, used in a similar manner to a CWait object. The main thread monitors the cancel status via an IsCancelled method, and finishes via a throw when required.
Is this a reasonable approach, and if so is there some MFC code out there already that I can use, or should I roll my own? First sketch looks like this
class CProgressThread : public CWinThread
{
public:
CProgressThread(int ProgressMax);
~CProgressThread()
void SetProgress(int Progress);
BOOL IsCancelled();
private:
CProgressDialog *theDialog;
}
void MySlowTask()
{
CProgressThread PT(MaxProgress);
try
{
{
{ // deep in the depths of my slow task
PT.SetProgress(Progress);
if (PT.IsCancelled())
throw new CUserHasHadEnough;
}
}
}
catch (CUserHasHadEnough *pUserHasHadEnough)
{
// Clean-up
}
}
As a rule, I tend to have one GUI thread and many worker threads, but this approach could possibly save me a bunch of refactoring and testing. Any serious potential pitfalls?
Short answer, Yes, you can have multiple GUI thread in MFC. But you can't access the GUI component directly other than the created thread. The reason is because the Win32 under the MFC stores the GUI handler per thread based. It means the handler in one thread isn't visible to another thread. If you jump to the CWinThread class source code, you can find a handler map attribute there.
Windows (MFC) doesn't has hard difference between the worker thread & GUI thread. Any thread can be changed to GUI thread once they create the message queue, which is created after the first call related to the message, such as GetMessage().
In your above code, if the progress bar is created in one thread and MySlowWork() is called in another thread. You can only use the CProgressThread attributes without touch the Win32 GUI related functions, such as close, setText, SetProgress... since they all need the GUI handler. If you do call those function, the error will be can't find the specified window since that handler isn't in the thread handler mapping.
If you do need change the GUI, you need send the message to that progress bar owner thread. Let that thread handles the message by itself (message handler) through the PostThreadMessage, refer to MSDN for detail.

Callback implementation using Windows message loop

I have C++ library (Win32 Console) where I have implemented an asynchronous function using a timer. The asynchronous method returns device information.
I have created a separate thread, "Timer Thread", to create a hidden window and then I call SetTimer() and then the implemented message loop.
When the timer expires, it enables a callback.
When I use the library in a console application, it is working fine.
In an MFC application I am doing a post message to update the user interface when the callback triggers. The post message is not working.
If I remove the message loop in the library, it is working fine in the MFC application.
I came to conclusion that:
I guess the problem is due to two message loops, one MFC (main thread) and the TimerThread message loop. So when the callback is called and the subsequent PostMessage results in the TimerThread message loop and not reported in the MFC (main thread) message loop.
If I remove the TimerThread message loop then it works fine in the MFC application, but it fails to work in the console application.
How do I overcome this problem?
class IDeviceEnumerationCallback
{
public:
virtual void onDeviceDiscovered(DeviceInfo* pDeviceInfo,unsigned short nNoOfDevice) = 0;
};
class IDeviceDiscovery
{
public:
virtual int InitialiseDiscovery(IDeviceEnumerationCallback*) = 0;
virtual void UnInitialiseDiscovery() = 0;
virtual int EnumerateDevice() = 0;
};
class CDeviceDiscovery:IDeviceDiscovery
{
//Implementation
}
In the MFC/console application I am implementing IDeviceEnumerationCallback to get a callback.
I am using Bonjour API to enumerate the device and all the methods in Bonjour API are callbacks.
I am wating for some time interval to enumerate a device using Bonjour API and then say after 400 ms I am calling a callback to return the result. In the MFC application when the callback is called, I am doing a PostMessage() to update the user interface.
Earlier I tried without Windows message pump. I had a SetTimer function, and it is working with the MFC application, but for the console application, the callback never gets called, so I implemented a message pump here. Now it is not working for MFC application.
First, there's no reason to do what you did: creating a separate threads, then creating a window in it, set the window timer, run the message loop, respond to the WM_TIMER message and invoke the callback.
If you create "your own" thread - you don't actually need all this. You could just implement a simple loop with either Sleep (or WaitForXXXX if you want an abort option), and invoke your callback.
Usually one creates a hidden window with a timer to avoid creating an additional thread. That is, within a thread that operates GUI (and hence - runs the message loop) you create a window, and it will be served by the message loop. Actually this is would you could do in your MFC app.
However, as you said, you want a generic code for both MFC and console apps.
In MFC application I am doing post message to update UI when the
callback triggers.the post message is Not wokring.
What exactly do you mean by "diung post message"? The message should be posted either to a specific window, or to the thread. In the first case it's dispatched to the window procedure, and in the second case the message loop implementation is responsible for handling the message.
If you post your message to a specific window - how do you get its handle (HWND)? Is it your app's main window (AfxGetMainWnd)? What does your thread start working, after the MFC has created the main window, or earlier?
I ask all those question because you seem to be a newbie (no offences), and those are typical mistakes.
The problem is that you should not be creating a hidden window and using SetTimer instead you should be using the MFC worker thread functionality for background work.
//You create a thread like so.
// you need a CMyObject only if you need to pass any information
//to the thread function.
CMyObject *pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
//This function will be run in separate thread
UINT MyThreadProc( LPVOID pParam )
{
//The parameter that was passed to this function
CMyObject* pObject = (CMyObject*)pParam;
while( 1 )
{
//add your code to do stuff.
Sleep(5000); //or whatever your SetTimer interval was
}
return 0; // thread completed successfully
}