Solved

How to send structure  between windows.

Posted on 2014-03-26
17
418 Views
Last Modified: 2014-04-01
I have a C++ MFC app with multiple windows derived from CFormView. How can I send back and forth a structure between windows.
0
Comment
Question by:vakils
  • 6
  • 6
  • 2
17 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 39955699
'WM_COPYDATA' (http://msdn.microsoft.com/en-us/library/windows/desktop/ms649011%28v=vs.85%29.aspx) is whar you are looking for. Take a look at http://msdn.microsoft.com/en-us/library/windows/desktop/ms649009%28v=vs.85%29.aspx ("Using Data Copy") and http://www.codeproject.com/Articles/115/Inter-Process-Communication-using-WM-COPYDATA ("Inter-Process Communication using WM_COPYDATA"), with the latter article demonstrating that even between processes, all with full source code included.
Note that you could theorhetically pass a pointer to a struct via any message's 'lParam',but that can't take into account which scope the object's lifetime that this pointer refers to is limited.
0
 

Author Comment

by:vakils
ID: 39957768
I have, from caller window CCallerView:
CParentDocument* pDoc = (CParentDocument*) GetDocument(); //Parent of all Docs
CTargetView* pView = (CTargetView*) pDoc->CreateForm(IDD_TARGET_VIEW_FORM, title, TRUE); //Target Window
pView->ShowWindow(SW_HIDE);
structuretopass* p;
//initialize p;
//pass "this" pointer
pView->InitData(p, this);
pView->ShowWindow(SW_SHOW);
CreateForm will initialize window with OnInitialUpdate before I call InitData, is there a better way?
//call back from target window
CCallerView* pCallerView = this;
this->CallSomeCodeInCaller();

Open in new window

Will this work?
0
 
LVL 86

Expert Comment

by:jkr
ID: 39957994
If you can guarantee that the data's lfetime (in your case 'this') will exced the time needed for processing the message - sure, then you are on the safe side. But then, are there any other means to make that connection between the message recipient and the message source? If so, you might want to look at these first, otherwise, it's OK.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 39958221
vakils, new views to a document should be created via doc templates. you may look in the InitInstance function of your application class how you could create a new view by using a triple of frame window class, document class and view class.

jkr, my comment about using wparam or lparam for passing pointers was by accident and it was in no way intended to repeat any parts of your comment. actually I didn't read your comment to end because the question here requires mfc skills and basic windows solutions where pointers were casted are not recommendable, error-prone and the wrong advise. so indeed I apologize for having posted some words regarding messaging without knowing that a few words were part of your comment as well, especially as this was in no way the main part of my comment. if you wouldn't have removed my comment, anyone could see that your reproaches regarding it were overblown, even reasonless.

I see very well that you try to use your administration rights here in ee to gain some advantages in the competition against me. that makes me sad as your knowledge in windows and my knowledge of application and network programming at many platforms could be a good complement.

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 39958270
I do not believe for a minute that you posted "by accident";
it is true.

I told the user how to define a  new mfc windows message id and that they could use that id by using mfc message maps. then I added to this part of the comment (which was only about the fourth part of my whole comment, the rest explained why this is not a recommendable way) that when using the ID "a pointer to structure could be passed by means of WPARAM or LPARAM". contrary to my comment that was removed, jkr's comment is still to be seen. his wording at the end of his comment was

Note that you could theorhetically pass a pointer to a struct via any message's 'lParam'

you may judge whether such a part could be accidently be overseen or not. I am very thoroughly be reading other experts comment and rarely forget to use a an "to add to above comments" or "as told by jkr" when I was aware of this (what also easily could be verified when looking to some of my comments).

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 39959118
the following link contains a sample how you could add a second view to an already created document:

http://msdn.microsoft.com/en-us/library/vstudio/e59dtf8h(v=vs.110).aspx

generally the views should not have mutual pointers but should pass the information to their (parent) document object. the document then could call UpdateAllViews member function to pass the information to the (other) views. the views would get the information in their OnUpdate member function.

the document also could search its list of all views by functions GetFirstViewPosition and GetNextView member functions. the right view class could be checked by calling

pView->IsKindOf( RUNTIME_CLASS( CTargetView ) )

Open in new window

for all the view pointers returned by GetNextView. that way you selectively could pass information to your views from document. alternatively you could derive all your views from same baseclass, then cast the CView* to this baseclass and call virtual functions.

Sara
0
 

Author Comment

by:vakils
ID: 39960280
All Views and their respective Documents are Registered using:
pApp->RegisterDocTemplate(IDD_TARGET_FORM, IDI_FORM_UPDATABLE, 
RUNTIME_CLASS(CTargetDocument), NULL, RUNTIME_CLASS(TargetView));
called from InitInstance of App
The form windows derived from CFormView are stored in tree control 
making File explorer style application.
I found an interesting code in app for data exchange:
From caller View, invoke target window and send "this" pointer
CTargetView* pView = (CTargetView*)
			((CApp*)AfxGetApp())->CreateForm(IDD_TARGET_FORM, 
				"Form Title", NULL);
pView->ShowWindow(SW_HIDE);
pView->InitData(this, &somestructure); // send this pointer, 
and struct, see implementation below
pView->ShowWindow(SW_SHOW);

Target Window code stores "this":
void CTargetView::InitData(CWnd* pTargetWnd, SomeStructure* p)
{
    m_pTargetWnd = pTargetWnd;
    m_pStruct = p;
}
And sends message, backs to Caller
m_pTargetWnd->SendMessage(WM_USER_SOME_MESSAGE, 0, 0);
The caller has message handler:
ON_MESSAGE(WM_USER_SOME_MESSAGE, OnSomeFn)
1. What I don't understand is: 
Why SendMessage is used instead of this->OnSomeFn();
Now here's the problem
If I want to send a structure  repeatedly to and from TargetView, 
and this structure is dynamic(different every time), 
How can I do without opening multiple Target windows 
as above code would do.  (CreateForm)

Open in new window

0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 32

Expert Comment

by:sarabande
ID: 39961076
jkr, sorry? i hope you know what you are talking about. because i don't. you say you don't break rules but your reasonless attacks spoiled the current thread what is a violence.


m_pTargetWnd->SendMessage(WM_USER_SOME_MESSAGE, 0, 0);
The caller has message handler:
ON_MESSAGE(WM_USER_SOME_MESSAGE, OnSomeFn)
1. What I don't understand is:
Why SendMessage is used instead of this->OnSomeFn();

this->OnSomeFn() would be the wrong object. The target view was created by the caller view and the caller view calls pView->InitData(this, p) . so the 1st argument is the caller view. unfortunately the variable is named pTargetView which is a wrong name.

callbacks between windows often were done by message calls rather than by direct calls if the calls are more a notification between independent objects. but in your sample it not quite understandable why the pointer to the other view was stored in a member. that is critical cause if the view was closed the pointer is going to become invalid.

the correct way is to pass the information to the document which then could call all its views by direct calls or by notification (UpdateAllViews).

Sara
0
 

Author Comment

by:vakils
ID: 39962810
OK. I understand that caller window could be closed, thus "this" pointer becomes null and SendMessage is used instead. Why pTargetView (the caller window) is a wrong name?
If I want to send a structure via SendMessage, how would I code SendMessage? the lParam or wParam values?
0
 

Author Comment

by:vakils
ID: 39962875
Reading carefully your post, I understand what you are saying:
1. The code actually uses SendMessage to caller window, so if caller window is up, it will listen and process message
2. pTargetView should be pCallerView for clarity.
3. From Caller, I am invoking Target Window and passing data via InitData, are you saying to send this to Document class of Target Window? And then Document update Target Window by OnUpdate? Each doc has only one view in this app.
4. Now my problem is to open Target Window only once, but the current code would initiate multiple instances of Target View. How do I prevent that?
I think we are pretty close to resolution when item 4. is figured out.
0
 
LVL 32

Expert Comment

by:sarabande
ID: 39963824
if you have multiple documents the app would be the top of tree and pass information between documents.

so if you have information in caller view you would directly call your document and pass the information. The document would create an notification out-of the information (just another word) and pass it to the app. The app would decide whether it has to create a new document or if there is already a (target) document for the notification. in case a new document is needed the app could use a new doc template to create a new document with frame and view. after creation, the app would pass the notification to the new document. if the target document already exists the app can iterate all doc templates and for each doc template it can iterate the documents until the target document was found. the target document either would call UpdateAllViews and pass the notification to them. Or, if the target view doesn't yet exist it would call a function like the CreateForm to create the view. then it could pass the notification directly by a function like InitData. note, the view is not fully created to that time, it normally would not have processed the WM_INITDIALOG (or WM_INITIAL_UPDATE) message. therefore InitData should not use any message functions or initialize controls here but only store the information in a member. copies would better than storing pointers. if you need further actions you could call PostMessage to your own window with an user message. PostMessage calls will be put at end of message queue and so will be processed when all other initializations are done.

Sara
0
 

Author Comment

by:vakils
ID: 39967684
All Docs and their respective views are registered on initialization of application. As said before, the application is explorer style with tree control on left and view on right.
All views have a grid control which has data. All windows can be opened by clicking on tree control (uses CreateForm)
I need to share the data from grid of one view to grid of another view.
So the steps:
When user selects(right-clicks) on a line in grid of caller view, a context menu appears. On a selection, I call CreateForm to invoke target window. This does all the gyrations that you mentioned above. So sequence is:
1. Call CreateForm to invoke Target Window.
2. Send the data to target window via InitData. The target window stores the data.
3. When user retrieves data in grid of target window, the doc of target window fetches data and sends OnUpdate notification to target window, which populates the grid.
4. Then target window adds additional data to it's grid which was passed via InitData(if it is not null).
5. If target window accepts data it does a SendMessage to caller window and caller window marks data as accepted.
6. I have to do this for each line grid of caller window. Caller data manages memory for data( a pointer) passed (via new/delete operators)
Is this the right way or there's a better way. Please send me a cookbook approach like steps I mentioned above, and not "under the hood stuff".
0
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
ID: 39969727
do you show both caller and target view parallel or only one of them?  if the latter do you replace the caller view by the target view when the user does the selection via context menu or do you only 'prepare' the target view to show the right data when it is manually selected by the user?

generally, i would do the following:

- after user selection in context menu,  I would call model function to pass the information.
  (if the model has same data than the view you probably only have to pass row number and event).
- the model then retrieves the target model identifier and calls its parent (controller if any or machine) passing the information available so far.
- the parent would create a new target model if it does not exist already.
- it then calls the target model with the information available.
- if controllers exist, the controller would pass the information to the target controller (if it is a different one). the target controller then would create or retrieve the target model and call appropriate function to pass the information.
- the target model then updates its data with the information and creates a new view (if not already existing).
- then it invalidates the target view.
- if the target view should be shown immediately and replaces the caller view, you would inform the controller (or main window) that the current view should hide and the new view should show.
- next time when the target view was displayed, it recognizes that it was invalidated and retrieve all data from model.
- the model returns ok.
- the parent of the model returns ok
- the caller model updates it data and set the 'accepted' flag for the row.
- it returns ok to the caller view.
- the caller view updates the grid.

note in the above you also could call UpdateAllViews from models to "refresh" the display. generally the views should not hold data their self  (beside of the contents displayed in the grid) but get the data from their model. invalidation of a view could be made for the whole grid or for each row separately.

Sara
0
 

Author Closing Comment

by:vakils
ID: 39970472
It is like file explorer, you can click on any node and a corresponding window would open.
Then you retrieve data in the grid of the window. You can have multiple windows, each showing different data set based on criteria. You have option to see all opened window  on right side (tile, cascade or dock)
So caller window opens target window via context menu and brings it to focus. Both windows are open. If target is already open then a new instance is opened for this operation. The whole idea is to insert a row selected in caller's grid to be added to target's grid. If target accepts the row it informs caller and caller marks that row as accepted. The target gets it's data from one source while caller gets from another source, that's the reason of this whole operation. All data is stored in grids of windows and is retrieved by their documents and updated via OnUpdate.
I think I got what you are saying. Sorry, could not attach pics due to non-disclosure policy.
Thanks for your solution.
0

Featured Post

Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

Join & Write a Comment

Suggested Solutions

This article covers general Notes 8.5 troubleshooting information including recreating the Notes\Data folder.
Let’s list some of the technologies that enable smooth teleworking. 
Using Adobe Premiere Pro, the viewer will learn how to set up a sequence with proper settings, importing pictures, rendering, and exporting the finished product.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now