Using MFC, posting variable to thread along with message - c++

I am using CWinThread. And I have made the main GUI send to the thread an array in LPARAM. Example, this code WORKS:
//On GUI
char *headData = "L1";
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)head);
On the thread:
void CMyThread::OnSendhead( WPARAM, LPARAM lParam){
char *head = (char*)lParam;
if (strcmp(head,"L1")==0){
//This line is reached.
}
return;
}
But when I make a little change here:
char *head = "L1"
unsigned char byteHead[3];
memcpy(byteHead, head, 3);
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)byteHead);
On the thread:
void CMyThread::OnSendhead( WPARAM, LPARAM lParam){
unsigned char* byteHead = (unsigned char*)lParam;
char head[3];
memcpy(head, byteHead,3);
head[3] = '\0';
if (strcmp(head,"L1")==0){
//This line is nerver reached.
}
return;
}
The line inside if is not reach. I have moved the code on thread to GUI for testing (without casting to LPARAM), and everthing works. So I guess I can't cast between lParam and unsigned char*? Why, and how can I do this? Thank you guys

PostMessage doesn't process the message immediately, but leaves it for the message loop to pick up later. If the data pointed to by lparam has been destroyed in the meantime, it's going to fail.
In your first example, you're passing a string literal. String literals tend to stay valid for the full lifetime of the program, so this is OK.
In the second example, you're using a local variable that presumably gets destroyed soon after you do the PostMessage.
To make this work, use SendMessage instead; it gets processed immediately. Or use a variable that is guaranteed to be valid until the message is processed.

With PostMessage or PostThreadMessage you should always use heap allocated memory to send data, as small as bool and in the message handler function you delete it. You can wrap a message in some struct, for example:
struct MyMsg
{
int msgCode; // specific to you, and you know underlying datatype
char buffer[1024]; // or have a `vector` or dynamic-array you'd manage
};
Sender:
MyMsg* msg = new MyMsg;
msg->msgCode = 0x1; // It's a string
strcpy_s(msg->buffer, "abc");
PostThreadMessage(threadID,SEND_HEAD, 0, (LPARAM)msg);
Receiver:
void CMyThread::OnSendhead( WPARAM, LPARAM lParam)
{
MyMsg* msg= (MyMsg*)lParam;
// use msg
delete msg;
}

Related

How does one move a std::unique_ptr between windows without risking a memory leak?

I want to do this project in C++ and be done with it once and for all:
select a movie from a list in one window and display the movie's details in another window.
I'd already arrived at Remy Lebeau's solution here and found his post because I'd realized the same limitation he did: it exposes the raw pointer to memory leakage.
(Please excuse my coding style).
MoviesWindow::MovieSelected( const unsigned int uint__MovieKey )
{ ...
std::unique_ptr<MovieBean> uptr__MovieBean = std::make_unique...
...
uptr__MovieBean->SetMovieTitle( row["MovieTitle"] );
uptr__MovieBean->SetYearReleased( row["YearReleased"] );
...
SendMessage( hwnd__MovieWindow, UWM_SendMovieBean, 0, (LPARAM) uptr__MovieBean->get() );
...
}
Fortunately, I have an advantage with SendMessage(): it won't end (releasing the std::unique_ptr) until the message handler returns, and the message handler's job is to clone the MovieBean.
MovieWindow::HandleUwmSendMovieBean( const HWND hwnd__MovieWindow, const UINT uint__WindowMessage, const WPARAM wParam, const LPARAM lParam )
{ UPTR__MovieBean = std::move( (*((MovieBean*) lParam).Clone() );
...
}
It seems the right way to do it is leave ownership of the std::unique_ptr with MovieSelected() until the actual moment of transfer by sending a reference to the handler, and using std::move on the reference.
MoviesWindow::MovieSelected( const unsigned int uint__MovieKey )
{ ...
SendMessage( hwnd__MovieWindow, UWM_SendMovieBean, 0, (LPARAM) &uptr__MovieBean );
...
}
But I cannot figure out how to get the reference out of lParam and into std::move. This would seem to be the one, but nope.
MovieWindow::HandleUwmSendMovieBean( const HWND hwnd__MovieWindow, const UINT uint__WindowMessage, const WPARAM wParam, const LPARAM lParam )
{ UPTR__NewMovieBean = std::move( reinterpret_cast<std::unique_ptr<MovieBean>*>( lParam ) );
...
}
I've tried every combination I can think of and ensured that the address sent is the address received and supplied to std::move. All I get are constant compiler errors (including a now-much-hated one about std::remove_reference), and crashes. Any insight would be appreciated.
SendMessage and unique_ptr are definitely not made for each other. I can give lots of hints here, but the best thing to do is to not be smuggling smart pointers through HWND messages.
I don't know what a UWM_SendMovieBean, but I'm guessing that's a custom windows message you either based of off WM_USER or RegisterWindowsMessage. So what you are really doing sounds like you are trying to signal another code component with SendMessage instead of a formal contract between the backing classes of both windows. It's not the worst thing ever to do this, but with a class as specialized as unique_ptr, it gets much harder to pull off.
The cheap and easy thing to do would be to have both windows share the row data structure that you have. Then your send message simply sends the uint__MovieKey as the WPARAM or LPARAM of your custom message.
But if you were on my team, and we were building this app together, I'd give you the crash course in Model-View-Presenter (and other MVC designs) that make these types of feature designs more maintainable.
I got the answer in two more tries:
MovieWindow::HandleUwmSendMovieBean( const HWND hwnd__MovieWindow, const UINT uint__WindowMessage, const WPARAM wParam, const LPARAM lParam )
{ UPTR__NewMovieBean = std::move( *((std::unique_ptr<MovieBean>*) lParam) );
...
}
Basically, sending the address of the std::unique_ptr<MovieBean> meant I was sending a pointer, so I needed to std::move(...) what the pointer was pointing to. It works fine.
This still seems sound to me: I'm leaving the MovieBean protected by a smart pointer while it's "in flight". It's effectively just a pass-by-reference that doesn't violate C++ Core Rule 33: Take a unique_ptr<widget>& parameter to express that a function reseats the widget.
The substantial problem in this usage is that my message handler is also the signal to read the MovieBean's copious information into the various CommonControls of the MovieWindow. Message handlers are supposed to be quick. The better approach is what #selbie suggested: the formal contract between the backing classes.

How to cast a LRESULT to a custom struct type?

I use sendMessage and replyMessage to communicate between two apps in the same laptop. On the receiver side, when it receives the message comes from sender, it will reply with a message. So in the sender process, it will cast the MyStruct to LRESULT, send reply this to the sender app. I tried to cast it back in the receiver side, it also works.
PCOPYDATASTRUCT result;
MyStruct* data;
LRESULT a;
MyStruct* t;
MyStruct* reply = new MyStruct;
switch (uMessageType)
{
case WM_COPYDATA:
result = (PCOPYDATASTRUCT)addtionalData;
data = (MyStruct*)result->lpData;
reply->msgId = 10;
strcpy_s(reply->msgInfo, 100, "test reply");
a = reinterpret_cast<LRESULT>(reply);
t = reinterpret_cast<MyStruct*>(a);//when cast the LRESULT data to MyStruct back here, it succeed
ReplyMessage(reinterpret_cast<LRESULT>(reply));
break;
However, when I was trying to cast this LRESULT to MyStruct in the sender side, it fails:
LRESULT result = SendMessage(test, WM_COPYDATA, (WPARAM)(HWND)hwndC, (LPARAM)(LPVOID)&data);
MyStruct* reply = (MyStruct*)result;//the value of reply is unreadable
How could I convert the LRESULT to my custom struct in the sender side ?
I just tried to send interger or float by the way. It works. However, if I use custom struct MyStruct, it won't work. I guess it is because the size of LRESULT is shorter than MyStruct.How to solve this problem ? The size of LRESULT is 4, size of int is also 4.
typedef struct msg{
int msgId;
char msgInfo[100];
}MyStruct;
When you send WM_COPYDATA, the data itself is copied to the receiving process.
The receiver of WM_COPYDATA gets a pointer to this copy.
It's very unlikely that the addresses are the same on both ends, but each end has a valid pointer to its own copy of the data.
On the other hand, ReplyMessage does no such copying and only returns the (reinterpreted) address of the sender's data.
This is not a valid address on the receiving end.
If you want to pass data back and forth, you need to use SendMessage with WM_COPYDATA in both directions, possibly adding your own protocol on top.

Send Cstring using and get answer using Win Message

I need to send string using win message and get back answer. Does following method has memory management problems regarding CString?
Call:
CString params = "Hello";
SendMessage(hWnd,WM_AUT_MESSAGE, (WPARAM)&params,0);
Answer:
LRESULT CMainWindow::OnMessageAuthorise(WPARAM wParam, LPARAM lParam)
{
CString *pStr = (CString*)wParam;
*pStr="Bye";
return 0;
}
It looks OK. SendMessage blocks and does not return until OnMessageAuthorise returns, so even with a pointer to a stack variable there is no race condition. (Assuming, of course, that all of this happens within the same process.)

Array of function pointers for the Windows Messages Procedure

everybody
I wanna try something and I need a little help. What I want to do is to create some functions, store their pointer into an array, then calling them inside the Windows Messages Procedure. For example:
int create_functions[10];
int paint_functions[10];
int func1() {
// code
}
void func2(int arg1) {
// code
}
create_functions[0] = *func1; // add pointer of func1 to the first array
create_functions[1] = *func2; // add pointer of func2 to the second array
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_CREATE:
// execute create_functions[0] - How do I do it?
case WM_PAINT:
// execute paint_functions[0] - How do I do it?
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
I know somebody will ask: why just don't execute the func1/func2 directly. Because I will decide what functions to be executed at run-time. Thanks to everybody for your help!
EDITED:
What about call-back functions? I don't understand very well how to use them?
If the question is: How can I do function pointers, I suggest you look at articles on the topic such as http://www.newty.de/fpt/index.html
If this is not your question, can you please edit and add more details.
This
int create_functions[10];
int paint_functions[10];
should be
void (*create_functions[10])(void);
void (*create_functions[10])(int);
and
// execute create_functions[0] - How do I do it?
// execute paint_functions[0] - How do I do it?
should be
create_functions[0]();
paint_functions[0](some_integer_here);
Also
create_functions[0] = *func1; // add pointer of func1 to the first array
create_functions[1] = *func2; // add pointer of func2 to the second array
should be
create_functions[0] = func1; // add pointer of func1 to the first array
create_functions[1] = func2; // add pointer of func2 to the second array
or
create_functions[0] = &func1; // add pointer of func1 to the first array
create_functions[1] = &func2; // add pointer of func2 to the second array
according to your taste or mood.
You can pass the pointer to your array in wParam.

How to send a string via PostMessage?

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.