How to find default directory from a CFileDialog

I am trying to extract the initial directory so that the user can start from the folder that they chose last time. I use a CFileDialog to open the file and in Win98 it typically starts in "My Documents". If the user navigates somewhere else, then this folder is remembered for the duration of the session. I want to remember this so that I can set it at the start of the next session. I thought that in the WM_CLOSE of the CMainFrame class I could put the following:

    CFileDialog fd(TRUE);

    CString sFinalDir = fd.m_ofn.lpstrInitialDir;
    theApp.WriteProfileString(SETTINGS_KEY,               INITIALDIR_KEY, sFinalDir);

I could then do the following in the InitInstance of my app:

   // find initial directory, if any
    m_sInitialDir = GetProfileString(SETTINGS_KEY, INITIALDIR_KEY);

and stuff this into the m_ofn struct so that subsequent File Opens would start at the previous folder.

Unfortunately the m_ofn contains a null for the lpstrInitialDir when I do the WM_CLOSE. How can I get at the internal folder that CFileDialog is holding so that I can start there next time. Once I have this how can I ensure that this folder is the place to start next time. I was going to create a CFileDialog and then set the m_ofn.lpstrInitialDir member to the last directory that I can recover from the registry.

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

  Try saving the initial directory immediately after the user closes the dialog box.  When the OK button is pressed, it seem like your waiting to long to get the data and it is no longer valid.

My 2 cents...
Here is the basic technique:

When your program starts, use a command like:

  m_sOpenFileDir= theApp.GetProfileString("Prefs", "OpenFileDir", "c:\\My Documents");

Now, at some point, you will bring up the CFileDialog, as follows:

  CFileDialog dlg( TRUE );
  dlg.m_ofn.lpstrInitialDir=(LPCSTR) m_sOpenFileDir;
  int nRet= dlg.DoModal();
  if (nRet== IDOK) {
    // learn the dir by getting the first part of the filepath...
    m_sOpenFileDir= dlg.GetPathName();
    m_sOpenFileDir= m_sOpenFileDir.Left( dlg.m_ofn.nFileOffset); // leave only the d:\dir\dir

    // save that dir for next time...
    theApp.WriteProfileString("Prefs", "OpenFileDir", m_sOpenFileDir );

    // now take the desired action (read the file, etc...)
The result is:
* The very first time your program runs, m_sOpenFileDir will get set to C:\My Documents (a standard default).

* Whenever the user OKs the OpenFile dlg, you will assume that that is his preferred directory, so you save it to the registry.

* Thereafter, each time you use the Open File Dialog, it will remember the last place the user selected .. within the current run AND in future runs.

-- Dan
emitchellAuthor Commented:
I had originally thought of saving the directory that the user has chosen but that would require me to put the above code in all the places that the CFileDialog is invoked. Presumably, inside the CFileDialog there is knowledge of what the last folder was since if FileOPen is used twice in a row, the second CFileDialog starts off in the folder where the first one finished.

Isn't there a way to extract from the CFileDialog where it would first open if it were invoked. In this case I just have get hold of this in the WM_CLOSE of the CMainFrame and save it once.
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Actually, it is a bit more complicated.  See the info on lpszInitialDir at this link (or in the MDSN documentation on the OPENFILENAME structure):

It seems that the system keeps a most-recently-used directory for each program -- probably in the registry somewhere. That will take effect in certain cases where you dont specify the initial dir and don't provide a filename.

>>Isn't there a way to extract from the CFileDialog where it would first open..

Nothing is documented, and simply instatiating a CFileDialog will certainly fail.  You would need to call DoModal(), which defeats the purpose.

>>that would require me to put the above code in all the places that the CFileDialog is invoked.

Most programs use this in only one or two places.  How hard is that?  

However, you can try this:  Never pass in a filename and leave lpszInitialDir pointing to "\0" -- that way the system will handle things in the default manor which you prefer.

-- Dan
See following link for example project:
emitchellAuthor Commented:
I should have explained what I was trying do better. I want to save the folder from which the user does a File/Open or File/Save As... When the user starts up next time they should be looking in the last folder, wherever it happens to be. In general our users will only use one folder! I would think that this would be a fairly standard thing to do. Our users don't want to always start in "My Documents" since that is where the unsophisticated user will always store stuff. This causes untold clutter.

When I look closer, it is the DocManager that executes OnFileOpen(...) which then passes an empty string on to DocManager::DoPromptFileName(...). If I can replace this DocManager::OnFileOpen() I could call the DoPromptFileName(...) with the last folder opened for the file name. Unfortunately, I can't get at the CFileDialog inside the DoPromptFileName to do my own saving of the file. Nor do I think that I can override any of DocManager's functions.

From Dan's comments, I think that I have to give up on getting at the last folder that is internal to the Windows function ::GetOpenFileName(&m_ofn). As he says, this is probably tucked away in some undocumented place.

One plan up for discussion would be to override the CWinApp::OnFileOpen() so that I can suggest a folder name. This is just a one liner:

void CWinApp::OnFileOpen()
     ASSERT(m_pDocManager != NULL);
Place within my override the following (comes from CDocManager::OnFileOpen():

    // prompt the user (with all document templates)
    CString newName;
    if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
        return; // open cancelled

    // if returns NULL, the user has already been alerted

and replace the CString newName; with the getting of the first file from the MRU list as in:

CSring newName = GetProfileString(_T("Recent File List"),

Does anyone have a better idea? Any time there is a File/Open or a File/Save the file is placed on the MRU list so my picking up this file would get me to the right place if everything works as expected.
Hi Axter,
Did you read the question?

Hi emitchell,
From TN022

ID_FILE_OPEN:   Opens an existing document.
Note   You must connect this to your CWinApp-derived class's message map to enable this functionality.

CWinApp::OnFileOpen has a very simple implementation of calling CWinApp::DoPromptFileName followed by CWinApp::OpenDocumentFile with the file or path name of the file to open. The CWinApp implementation routine DoPromptFileName brings up the standard FileOpen dialog and fills it with the file extensions obtained from the current document templates.

One common customization of ID_FILE_OPEN is to customize the FileOpen dialog or add additional file filters. The recommended way to customize this is to replace the default implementation with your own FileOpen dialog, and call CWinApp::OpenDocumentFile with the document's file or path name. There is no need to call the base class.

Therefore, you should simply porovide a handler for ID_FILE_OPEN, and in it, call CFileDialog and if the return is IDOK, call OpenDocumentFile()

-- Dan

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial

ur question seems similar lie the action we used to perform in winzip which stores the last extracted output folder..

y not create a key in the registry..the key  will hold the latest folder where a open or save information is performed..create a key in win registry...write into it the folder path..and b4 the user performs an open operation..or when the user clicks open icon or whatsoever read from the key and then let the folder where the operation ws perfomed be displayed
emitchellAuthor Commented:
Dan's suggestion worked like a charm. I was trying to find a virtual function that I could add to when all I needed to do was to handle ID_FILE_OPEN in my main app. For the record I did the following. First pick up File1 from the MRU list in the InitInstance and save it into a member string variable:

    // find initial directory, if any and put it into
    // the string held within this class. it will only
    // be used once for the first open and then will
    // be erased
    m_sInitialDir = GetProfileString(RECENTFILELIST_KEY
     , _T("File1"));

Then handle the ID_FILE_OPEN with the following function:

    // use the initial dir the first time we prompt for a file
    // name. after a successful open, the file name will be
    // changed to be the empty string and the default dir
    // will be supplied by the CFileDialog internal memory
    if(!DoPromptFileName(m_sInitialDir, AFX_IDS_OPENFILE,
        // open cancelled
    // if returns NULL, the user has already been alerted

    // now erase the initial dir since we only want to use it once

The user must open something so we start off in the folder that corresponds to File1 of the MRU. After that, Windows keeps track of which folders we have navigated to so we can use an empty string within the same session.

emitchellAuthor Commented:
Thanks Dan. You solved the problem. It was harder than I had originally thought!

emitchellAuthor Commented:
Thanks Dan. You solved the problem. It was harder than I had originally thought!

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.