I am calling a library function which also need a callback function as its only argument. It is time consuming function and the callback is called frequently to pass messages to the client (my application) to display. The problem is I want to copy the message and pass it onto the main thread for display but because it is callback function, I see no other way but to use globals to do that and that's what I am trying to avoid/make better.
The callback is static member function of my CTestDlg which alrady has m_hWnd member where I want to post the messages. However for the sake of callback I have yet defined another static g_hWnd member so my callback can access it and post message to it. This part doesn't look very nice to me but my callback routine is collecting messages wonderfully.
My callback function is the following
void CTestDlg::OnNotify (int code, const char * msg)
{
char * message = NULL; // to copy the message
message = new char[ strlen( msg) + 1 ]();
strcpy_s( message, strlen(msg) +1, msg );
PostMessageA( g_hWnd, ID_NOTIFY_MSG, code, (LPARAM) message );
}
I am running the library call in a separate thread and because it is callback to that function, it also runs in the same thread. Is there a better way to change hand in this callback function and pass the message to main thread or a particularly window to display?
If your callback is a static method, it has no access to instance data, so you must store your state data (the main window handle, in your case) in a static or global variable.
You can move the handle from a global variable to a static CTestDlg::s_hWnd variable.
Related
So I have been trying to implement the concept of multithreading to an MFC application I am making. I used the method suggested here. It works fine but I am having an issue with using data given by the user while the thread is working.
I'll explain.
I am making a simple GUI to send and receive data over a serial port. So the data in IDC_SEND is user-input, and is then sent through the serial port. I am using the WINAPI definition of GetDlgItemText, but since the controlling function for AfxBeginThread is defined as a static function I cannot do this. So I tried ::GetDlgItemText, but that calls the CWnd definition which takes one or three or four(?) arguments.
So ::GetDlgItemText(IDC_SEND, CString text) doesn't work. This problem continues for SetDlgItemText too.
I have tried getting the data outside my controlling function, but since it is defined to return a UINT type, I cannot get the received data out.
The relevant code
void CCommTest2Dlg::OnButton()
{
THREADSTRUCT *_param = new THREADSTRUCT;
_param->_this = this;
AfxBeginThread (StartThread, _param);
}
UINT CCommTest2Dlg::StartThread(LPVOID param)
{
THREADSTRUCT* ts = (THREADSTRUCT*)param;
AfxMessageBox ("Thread is started!");
//Opened Serial Port
//Writing data from Editbox
CString text;
::GetDlgItemText(IDC_SEND,text);//********ERROR HERE!!
serial.Write(text);
//At Receiver port data is wriiten into CString a.
CString a;
::SetDlgItemText( IDC_RECV, a);//Apparently this calls the SetDlgItemText from the CWnd class, and not the Windows API that takes more than one argument.
AfxMessageBox ((LPCTSTR)a);//This works, but I need the data in the EditBox.
//Closing Ports
delete ts; //Edit 1
return 1;}
A few definitions:
static UINT StartThread (LPVOID param);
//structure for passing to the controlling function
typedef struct THREADSTRUCT
{
CCommTest2Dlg* _this;
} THREADSTRUCT;
UINT StartThread(void);
Any thoughts?
PS: Also Edit 1 at the end was added by me as I read that this implementation could result in memory leaks. Does it look like the addition might have fixed that?
I try to write a Multithreading WIN32 Application in C++, but due to i get difficulties.
One of the Window Procedure creates a Thread, which manages the output of this window. If this Window Procedure receives a message (from the other Window Procedures), it should transmit it to their Thread. At the beginning i worked with the _beginthread(...) function, what doesn't work.
Then i tried it with the CreateThread(...) function, and it worked? What did i do wrong?
(My English isn't so good, i hope you understand my problem)
Code with CreateThread(...):
DWORD thHalloHandle; // global
HWND hwndHallo; // Hwnd of WndProc4
...
LRESULT APIENTRY WndProc4 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static PARAMS params ;
switch (message)
{
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
CreateThread(NULL, 0, thHallo, ¶ms, 0, &thHalloHandle);
return 0 ;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...
}
Code with _beginthread(...):
...
case WM_CREATE: {
params.hwnd = hwnd ;
params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
thHalloHandle = (DWORD)_beginthread (thHallo, 0, ¶ms) ;
return 0;
}
...
case WM_SPACE: {
PostThreadMessage(thHalloHandle, WM_SPACE, 0, 0);
return 0;
}
...
thHallo for CreateThread:
DWORD WINAPI thHallo(void *pvoid)
{
static TCHAR *szMessage[] = { TEXT(...), ...};
// Some Declaration
pparams = (PPARAMS) pvoid;
while(!pparams->bKill)
{
MsgReturn = GetMessage(&msg, NULL, 0, 0);
hdc = GetDC(pparams->hwnd);
if(MsgReturn)
{
switch(msg.message)
{
// case....
}
}
}
return 0;
}
thHallo for _beginthread(...):
void thHallo(void *pvoid)
{
...
// The Same like for CreateThread
...
_endthread();
}
The _beginthread/ex() function is proving to be radically difficult to eliminate. It was necessary back in the previous century, VS6 was the last Visual Studio version that required it. It was a band-aid to allow the CRT to allocate thread-local state for internal CRT variables. Like the ones used for strtok() and gmtime(), CRT functions that maintain internal state. That state must be stored separately for each thread so that the use of, say, strtok() in one thread doesn't screw up the use of strtok() in another thread. It must be stored in thread-local state. _beginthread/ex() ensures that this state is allocated and cleaned-up again.
That has been worked on, necessarily so when Windows 2000 introduced the thread-pool. There is no possible way to get that internal CRT state initialized when your code gets called by a thread-pool thread. Quite an effort btw, the hardest problem they had to solve was to ensure that the thread-local state is automatically getting cleaned-up again when the thread stops running. Many a program has died on that going wrong, Apple's QuickTime is a particularly nasty source of these crashes.
So forget that _beginthread() ever existed, using CreateThread() is fine.
There's a serious problem with your use of PostThreadMessage(). You are used the wrong argument in your _beginthread() code which is why it didn't work. But there are bigger problems with it. The message that is posted can only ever be retrieved in your message loop. Which works fine, until it is no longer your message loop that is dispatching messages. That happens in many cases in a GUI app. Simple examples are using MessageBox(), DialogBox() or the user resizing the window. Modal code that works by Windows itself pumping the message loop.
A big problem is the message loop in that code knows beans about the messages you posted. They just fall in the bit-bucket and disappear without trace. The DispatchMessage() call inside that modal loop fails, the message you posted has a NULL window handle.
You must fix this by using PostMessage() instead. Which requires a window handle. You can use any window handle, the handle of your main window is a decent choice. Better yet, you can create a dedicated window, one that just isn't visible, with its own WndProc() that just handles these inter-thread messages. A very common choice. DispatchMessage() can now no longer fail, solves your bug as well.
Your call to CreateThread puts the thread ID into thHalloHandle. The call to _beginthread puts the thread handle into thHalloHandle.
Now, the thread ID is not the same as the thread handle. When you call PostThreadMessage you do need to supply a thread ID. You only do that for the CreateThread variant which I believe explains the problem.
Your code lacks error checking. Had you checked for errors on the call to PostThreadMessage you would have found that PostThreadMessage returned FALSE. Had you then gone on to call GetLastError that would have returned ERROR_INVALID_THREAD_ID. I do urge you to include proper error checking.
In order to address this you must first be more clear on the difference between thread ID and thread handle. You should give thHalloHandle a different name: thHalloThreadId perhaps. If you wish to use _beginthread you will have to call GetThreadId, passing the thread handle, to obtain the thread ID. Alternatively, use _beginthreadex which yields the thread ID, or indeed CreateThread.
Your problem is that you need a TID (Thread Identifier) to use PostThreadMessage.
_beginthread doesn't return a TID, it return a Thread Handle.
Solution is to use the GetThreadId function.
HANDLE hThread = (HANDLE)_beginthread (thHallo, 0, ¶ms) ;
thHalloHandle = GetThreadId( hThread );
Better Code (see the documentation here)
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, thHallo, ¶ms, 0, &thHalloHandle ) ;
I'm trying to create a worker thread in a class called ClientManager, but I can't get access to AfxGetMainWnd() from the new CWinThread, i.e:
UINT ClientManager::WorkerThreadProc( LPVOID param ){
ClientManager *pThis = reinterpret_cast<ClientManager*>(param);
return pThis -> DoThreadJob();
}
UINT ClientManager::DoThreadJob(){
createClientSession("1");
return 0;
}
void ClientManager::createThread(){
m_clientManagerThread = AfxBeginThread(WorkerThreadProc,this,0,0,0,NULL);
}
void ClientManager::createClientSession(CString clientID){
if (AfxGetMainWnd()->GetSafeHwnd()== NULL){
_cprintf("NULL");
}
}
Output: NULL
AfxGetMainWnd()->GetSafeHwnd() works in the main thread.
Thanks!
AfxGetApp()->GetMainWnd() works in threads.
No need to store the window handle in a member of ClientManager.
The documentation says:
If AfxGetMainWnd is called from the application's primary thread, it returns the application's main window according to the above rules. If the function is called from a secondary thread in the application, the function returns the main window associated with the thread that made the call.
So you need to make the call from the main thread. Do this just before you call AfxBeginThread and store the resulting window handle in a member of ClientManager. Then your thread can gain access to the window handle via its ClientManager reference.
I have an Observer class and a Subscriber class.
For testing purposes, the observer creates a thread that generates fake messages and calls CServerCommandObserver::NotifySubscribers(), which looks like this:
void CServerCommandObserver::NotifySubscribers(const Command cmd, void const * const pData)
{
// Executed in worker thread //
for (Subscribers::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
{
const CServerCommandSubscriber * pSubscriber = *it;
const HWND hWnd = pSubscriber->GetWindowHandle();
if (!IsWindow(hWnd)) { ASSERT(FALSE); continue; }
SendMessage(hWnd, WM_SERVERCOMMAND, cmd, reinterpret_cast<LPARAM>(pData));
}
}
The subscriber is a CDialog derived class, that also inherits from CServerCommandSubscriber.
In the derived class, I added a message map entry, that routes server commands to the subscriber class handler.
// Derived dialog class .cpp
ON_REGISTERED_MESSAGE(CServerCommandObserver::WM_SERVERCOMMAND, HandleServerCommand)
// Subscriber base class .cpp
void CServerCommandSubscriber::HandleServerCommand(const WPARAM wParam, const LPARAM lParam)
{
const Command cmd = static_cast<Command>(wParam);
switch (cmd)
{
case something:
OnSomething(SomethingData(lParam)); // Virtual method call
break;
case // ...
};
}
The problem is, that I see strange crashes in the HandleServerCommand() method:
It looks something like this:
Debug Error!
Program: c:\myprogram.exe
Module:
File: i386\chkesp.c
Line: 42
The value of ESP was not properly
saved across a function call. This is
usually the result of calling a
function declared with one calling
convention with a function pointer
declared with a different calling
convention.
I checked the function pointer that AfxBeginThread() wants to have:
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID); // AFXWIN.H
static UINT AFX_CDECL MessageGeneratorThread(LPVOID pParam); // My thread function
To me, this looks compatible, isn't it?
I don't know, what else I have to look for. Any ideas?
I made another strange observation, that might be related:
In the NotifySubscribersmethod, I call IsWindow() to check if the window to which the handle points, exists. Apparently it does. But calling CWnd::FromHandlePermanent() returns a NULL pointer.
From afxmsg_.h:
// for Registered Windows messages
#define ON_REGISTERED_MESSAGE(nMessageVariable, memberFxn) \
{ 0xC000, 0, 0, 0, (UINT_PTR)(UINT*)(&nMessageVariable), \
/*implied 'AfxSig_lwl'*/ \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > \
(memberFxn)) },
So the signature is LRESULT ClassName::FunctionName(WPARAM, LPARAM), while yours is void ClassName::FunctionName(const WPARAM, const LPARAM). This should not compile, at least under VS2008 it doesn't.
What is your HandleServerCommand declaration in the CServerCommandSubscriber class (in the header file)?
To me, this looks compatible, isn't
it?
Syntactically it looks that way.
I don't know, what else I have to look
for. Any ideas?
Yes: I've had the same problem when compiling a plugin library with debug settings and used in a Release-compiled application.
Basically, the problem looks like a stack corruption.
Since you're running NotifySubscribers in a separate thread, consider using PostMessage (or PostThreadMessage) instead of SendMessage.
This may not be the actual cause of the crash, but the change should be made anyway (as you're switching threading contexts by using SendMessage with no guarding of the data whatsoever.
I eventually decided to do it without window messages and am now posting my workaround here. Maybe it will help someone else.
Instead of letting the observer post window messages to its subscribers, I let the observer put data into synchronized subscriber buffers. The dialog class subscriber uses a timer to periodically check its buffers and call the apropriate handlers if those aren't empty.
There are some disadvantages:
It's more coding effort because for each data type, a buffer member needs to be added to the subscriber.
It's also more space consuming, as the data exists for each subscriber and not just once during the SendMessage() call.
One also has to do the synchronization manually instead of relying on the observer thread being suspended while the messages are handled.
A - IMO - huge advantage is that it has better type-safety. One doesn't have to cast some lParam values into pointers depending on wParam's value. Because of this, I think this workaround is very acceptable if not even superior to my original approach.
Inside my app, I want to send a message to a dialog from a different thread.
I want to pass an std::exception derived class reference to the dialog.
Something like this:
try {
//do stuff
}
catch (MyException& the_exception) {
PostMessage(MyhWnd, CWM_SOME_ERROR, 0, 0); //send the_exception or the_exception.error_string() here
}
I want to receive the message in my dialog and show the error that is in the_exception.error_string()
LPARAM CMyDlg::SomeError(WPARAM, LPARAM)
{
show_error( ?????
return 0;
}
passing the std::string the_exception.error_string() using PostMessage would also be ok, I guess.
You can't pass the address of the string in PostMessage, since the string is probably thread-local on the stack. By the time the other thread picks it up, it could have been destroyed.
Instead, you should create a new string or exception object via new and pass its address to the other thread (via the WPARAM or LPARAM parameter in PostMessage.) The other thread then owns the object and is responsible for destroying it.
Here is some sample code that shows how this could be done:
try
{
// do stuff
}
catch (const MyException& the_exception)
{
PostMessage(myhWnd, CWM_SOME_ERROR, 0, new std::string(the_exception.error_string));
}
LPARAM CMyDlg::SomeError(WPARAM, LPARAM lParam)
{
// Wrap in a unique_ptr so it is automatically destroyed.
std::unique_ptr<std::string> msg = reinterpret_cast<std::string*>(lParam);
// Do stuff with message
return 0;
}
As long as you are within a process simply passing a void* pointer and some care on object lifetime are enough.
If is SendMessage you can pass it in LPARAM as a void* cast, and the client uncast it back to your string type. Because SendMessage is synchronous, you are safe:
If the specified window was created by
the calling thread, the window
procedure is called immediately as a
subroutine. If the specified window
was created by a different thread, the
system switches to that thread and
calls the appropriate window
procedure. Messages sent between
threads are processed only when the
receiving thread executes message
retrieval code. The sending thread is
blocked until the receiving thread
processes the message
If you want to use PostMessage then you'll have to do an explicit hand off because the call is asynchronous: make a copy of the string on the heap and by calling the PostMessage you have passed the delete responsability to the calee (the dialog).
If you go out of process (MyhWnd belongs to a different process) then is a whole different story and you'll have to marshal your message into something like a global atom.
As long as you know that your window (or instance of CMyDlg) will still be around after posting the message you could simply store the error string in a member variable and read from this in your message handler.