Save Workspace MFC C++ MDI - c++

I have a MFC MDI application. The app can have 2 or more dialogs open. I want to implement the "Save Workspace" feature so that the user, when opening the workspace next time, opens the dialogs that were opened when he saved and closed the workspace. How to do this?

The functionality is built into the CMDIFrameWndEx implementation. SaveMDIState stores the current setup, while LoadMDIState restores it. The documentation also explains, how to persist the position and size of the frame window itself, in case that's something you want, too.

Generally this is accomplished by storing the current state of the application into some sort of persistent store. Depending on your architecture this could be a local configuration file (xml, json, etc) stored under the Windows User's profile directory (you could also use the Windows Registry), a remote store such as a database could be used or perhaps such state could be stored into cloud storage. Just depends on how the application currently handles configuration and how universal you want to make the state storage.
You will want to implement some sort or running history of UI state. Storing the currently open windows and their locations when they are loaded, closed and moved. Inject a history tracker into each MDI child that is created. This could be a singleton type in the MDI parent. It should have facility to look up a window by its handle and should store the relevant information in a structure that makes sense for serialization. In each of the afore mentioned events add calls to the tracker with the appropriate changes. The tracker should persist along whatever rules you determine are appropriate.
The load process then requires that the MDI parent interrogate the tracker after it has initialized with what ever stored state existed. Using the stored information (window type and location (and data?)) the MDI parent then opens up the appropriate children at the appropriate locations.

Related

SHGetFileInfo performance issues

Here is an excerpt from the Windows documentation about the SHGetFileInfo() function:
You should call this function from a background thread. Failure to do so could cause the UI to stop responding.
Does this apply to extracting the folder icons as well?
One of our applications resembles Windows Explorer, and we pursue two antagonistic goals: to support as many Windows Explorer's features as possible, and to be as fast as possible. Having the latter in mind, I assigned to each folder the default icon (obtained with the help of the SHGFI_USEFILEATTRIBUTES flag). But after some time it turned out, that a few of our customers use custom folder icons.
So, should I create new threads to calculate the icon for each folder, or is there a way to quickly extract a folder icon in the main thread, given the fact that the number of custom folder icons is negligible?
For example, a way to retrieve only cached icons could be a solution, I think. There is a function IShellItemImageFactory::GetImage(), which allows to obtain only cached icons, but it unfortunately returns HBITMAP instead of HICON.
It seems that I found an appropriate solution.
First of all, I prepare and store a pair containing the default folder icon and its index in the system image list. Then, when the request for a folder icon arrives, I immediately return the default icon, and launch a thread from the Windows thread pool.
In the launched thread I calculate the actual folder icon and its index with the help of the SHGetFileInfo API. If the index is the same as index of the default icon, I destroy the icon. Only if the obtained index differs from the default icon index, I post notification to the control in the main thread.
In this way the control is notified only about folders that really have custom icons, and the main thread is not overburdened with redundant notifications.

MFC Saving Custom Header Column Widths

So I'm just learning MFC to see if I want to start using it over normal Win32 programming. I have a SDI MFC application setup. I have a view with members that create a CTreeCtrl and CHeaderCtrl. I have a CDwordArray setup as m_ColWidths that is currently in my View class, but using MFC, should this be in the document class instead since I'll want to save and restore it to keep the users widths when program exits? I guess even though it's only part of the view it's still data and use GetDocument() to reference them?
TIA!!
Application state should not be stored in the document. The purpose of the CDocument(-derived) class is:
A document represents the unit of data that the user typically opens with the File Open command and saves with the File Save command.
CDocument supports standard operations such as creating a document, loading it, and saving it. The framework manipulates documents using the interface defined by CDocument.
The designated entity to store application state (e.g. size and visibility of UI elements) is the CWinAppEx(-derived) implementation:
CWinAppEx handles the application state, saves the state to the registry, loads the state from the registry, [...].

What is a good MFC C++ GUI architecture for multiple similar window arrangements

I am considering a rewrite of an MFC Dialog application I wrote over a decade ago. I originally chose a Dialog application type because in general the user clicks control inputs and the application provides real-time data from hardware via USB and displays the data in edit boxes. The app also writes information to a file. Since the user never does any file editing I didn't see a need for SDI or MDI application type.
I've now learned that the SDI application type along with CFormView provides some interesting advantages such as scrolling, window resizing:
http://forums.codeguru.com/showthread.php?267664-MFC-Dialog-How-to-enhance-a-dialog-based-application-with-Menu-Toolbar
The reason for my rewrite is that my application is un-maintainable and doesn't scale well. Originally I created a CDialog for each type of "screen" that I show but lots of code is common among the various screens. In fact over time I started reusing CDialog classes and with the use of state variables simply hid, renamed, or repositioned many of the controls to make the screen look appropriate in the context of the application.
I tried deriving the CDialog classes from a common base class but I didn't achieve great code reuse this way. I also found that I had common resources that I was constantly passing around to the various windows which just added unnecessary overhead.
As the application evolved it also became difficult to keep track of the state of the application (for processing USB hardware data input, user input, button enabling etc). Using a hierarchical statechart as the basis for my application might clean this up.
Should I consider putting a superset of ALL the necessary controls on ONE CFormView and simply hiding, renaming, and repositioning controls from the very beginning and using a statechart to manage this?
All the examples I see put the code directly in the input control handlers but maybe I should use the handlers to change state and then let the state machine do the decision-making to reduce this spaghetti code.
So my primary questions are:
1. Would SDI would buy me anything for writing and reading files (such as reporting and logging) if the user does not perform editing?
2. Does CFormView make sense?
3. Does it make sense to put all controls on one CFormView instead of multiple classes and Dialog resources?
4. Have you tried using a state machine in MFC such as Boost Statechart or Miro Samek's Quantum Leaps?
http://www.boost.org/doc/libs/1_58_0/libs/statechart/doc/index.html
http://www.state-machine.com/products/index.html

How to save layout settings of MFC application?

I understand there are functions that can easily write windows registry, however I found out that in new MFC project created with wizard, some information (like split bar position, visibility of controls) gets stored automatically (or at least I found no CWinApp::Write* calls in the project). Since I have also older projects that don't have this behaviour I need to figure out how to make this without help of project wizard. Would anyone please know how does this work?
The MFC control state saving magic happens in the 'New' MFC Feature Pack, specifically in the SaveState methods, for example CMFCToolBar::SaveState.
To take advantage of this you'll therefore need to upgrade your Toolbars and Menus to use the newer controls and upgrade your application to inherit from CWinAppEx. I recommend that you use a New MFC Wizard based app as a guide on how to upgrade your old MFC app.
Most of the information is saved in CPane::SaveState(), thus if you want state of some component saved, you need to use classes derived from CPane. (for more info here is the class hierarchy).
The process of saving window states is initiated through CFrameImpl::OnClosingMainFrame(). This function in turn calls CWinAppEx::SaveState() which saves some application settings and then ALL instances of CMFCToolBar (they add themselves to global list of CMFCToolBars in call to OnCreate). In a similar way all dockable panes are saved but the list belongs to your main frame. Then positioin and size of your main frame is saved.
CViews and CFrameWnds are somewhat less favored, for what I found and tried out, the only information saved was visibility.
I used that loooong time ago. If I correctly reminds it, you should save the informations you want in a overridden CWinApp::ExitInstance() before calling base class method, and you load them in CWinApp::InitInstance. Be sure to allow for default values, because at first run, there will be nothing to load, and do not forget to call (or copy) base class.

In MFC program, how to pass data between different dialog?

In web development, when we want to pass something between different pages, we might use the Session to save the data. But in MFC, what can we use to store these things?
Thanks!
Typical MFC Applications will have a Document-View-Frame architecture. Data is stored in the Document object, and accessed globally. You can access it anywhere via AfxGetMainWnd().
AfxGetApp() will also get you a pointer to your main application, which is another good spot to store data if you're not using a Document View architecture. If there is a lot of data, you can construct a class to hold the data, then add an instance as a member variable to the CWinApp in your project.
Another option, which I don't recommend but I have seen, is to have the dialogs themselves as member variables in the CWinApp, and then each dialog can reference the other. Basically, the user clicks 'ok', but then the dialog disappears, but is not deleted. This means all the data they entered is still accessable via the dialog variable.
There are a ton of ways to share data between dialogs. You may need to be more specific about your needs.
Store it in a global variable.
Store it in thread local storage (TLS).
Have one Dialog send a window message via SendMessage() or PostMessage().
Things get more complicated from there.