Link to home
Start Free TrialLog in
Avatar of RonMexico
RonMexico

asked on

MFC: How to pass ASCII data from DLL thread to main code

Hi, experts.

I have inherited an old-school MFC Windows CE program, and am having to make some modifications to it.  As part of this I have to pass additional data between disparate parts.  What we have is a Main program that calls into a DLL.  The DLL starts a background process that acts as a TCP server.  When that TCP server received data I need to push it all the way back up to the Main program.

After some research it seems the WINAPI PostMessage function (see FIGURE 1) is the way to go.  When Main launches the DLL it passes in its own HWND.  After the spawned TCP server process receives the data it calls PostMessage with (1) this saved HWND (2) a message ID, (3) wParam is the length of the received data, and (4) the lParam is a pointer to the received data itself.    Pseudocode for both the DLL thread caller, and the main code callee, are shown below in FIGURES 2 and 3.

What I'm seeing is that the function IS called in  my RemoteControlTCPMsg function, and the length is correct, BUT my string data is not correct -- weird, corrupted data.  The way I'm packaging the string data is mixed and matched from a few examples, but apparently something was lost in translation.

Could someone please provide a line or two of code that would properly preserve a char buffer when passed via PostMessage from a DLL thread to a main app such as mine?  

Thanks VERY much, I'm sort of at my wits end here.  Any thoughts/insight are appreciated.


*******************
*** FIGURE 1: PostMessage doc from MSDN

BOOL WINAPI PostMessage(
  _In_opt_  HWND hWnd,
  _In_      UINT Msg,
  _In_      WPARAM wParam,
  _In_      LPARAM lParam
);
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms644944%28v=vs.85%29.aspx)


*******************
*** FIGURE 2: Pseudocode for the calling code in the DLL background thread:

#define RC_COMMAND_BUFFER_SIZE = 256;
char m_Cmd[RC_COMMAND_BUFFER_SIZE];
int m_CmdLen = 0;

(when event occurs, m_Cmd and and m_CmdLen are populated and this is called:)

PostMessage(m_hWnd, MSG_ID, m_CmdLen,(LPARAM)(new CString(m_Cmd, m_CmdLen)));

*******************
*** FIGURE 3: Code for the receiving code in the main code:

int CWAMPropertySheet::RemoteControlTCPMsg(WPARAM wParam, LPARAM lParam)
{

int length = = (int)wParam;
CString * rx_string = (CString*) lParam;

// handler code for the received text data and length

}
Avatar of Janusz Czopowik
Janusz Czopowik
Flag of United States of America image

If I understood your explanation properly, you are trying to pass data between processes: one main and the other spawned by the dll.
You will not succeed using post/send message, since memory in two processes is mapped differently.
Even if you manage using windows handle, you are passing the pointer to a memory in the second process.
The pointer main process receives, is pointing to some memory of your main process, not to a memory location in the secondary process.
Use WM_COPYDATA or see this: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of RonMexico
RonMexico

ASKER

@JohnCz:  Thanks.  I believe WM_COPYDATA goes through the windows "message pump", correct?  Like mouse clicks?  Seems very roundabout and asynchronous, and doesn't seem appropriate for what is essentially fast-streaming, serial data, (TCP data); do you disagree?  

Certainly this can't be an exotic thing -- I swear I've come across a way to package/unpackage string data for DLLs, and also a way to go across threads.  There must be a way for both?
@jkr: thanks!  We'll try that and post back...
>>Certainly this can't be an exotic thing

It for sure isn't. BTW, why not passing the buffer to the thread directly and just send a notification when the data has arrived?
Interesting question... I'm actually working with someone who made that decision.  I will challenge him on it.  :)
Well, the 'pro' clearly is that you don't have to create a buffer in the thread and take care of disposing that properly later on. 'Con': The buffer is off-limits until you receive the notification message.
.... um, having said that, I should add that you wouldn't have to rely on a message, e.g. an event handle would work as well ;o)
@RonMexico,

I think you are confusing two things.

I believe WM_COPYDATA goes through the windows "message pump", correct?  Like mouse clicks?  Seems very roundabout and asynchronous, and doesn't seem appropriate for what is essentially fast-streaming, serial data, (TCP data); do you disagree?

Windows does not have any message pump. This term was introduced by MFC where message pump is a part that handles idle processing.
Windows use message loop that is called from MFC CWinApp Run function.
This message loop dispatches messages as usual returning only when message received belongs to the idle group.
After message pump handles idle, it enters the message loop again until another idle message is received.
I do not quite understand your question about WM_COPYDATA message.
Depending how do deliver message to a window, message is placed in a window’s message queue (PostMessage) or system calls window’s procedure directly (SendMessage).

Certainly this can't be an exotic thing -- I swear I've come across a way to package/unpackage string data for DLLs, and also a way to go across threads.  There must be a way for both?
Another confusing thing: you mention communication between different threads; this is OK to send data between different threads.
But in your case (again if I understood your question correctly) you are dealing with exchanging data between two different processed and this requires different approach in comparison to data exchange between threads.
jkr, that worked!  Thanks so much.