Solved

How to find default directory from a CFileDialog

Posted on 2001-07-23
12
1,470 Views
Last Modified: 2013-11-20
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.

0
Comment
Question by:emitchell
  • 5
  • 3
  • 2
  • +2
12 Comments
 
LVL 3

Expert Comment

by:cypherljk
ID: 6310750
Howdy,
  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...
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 6310893
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
0
 

Author Comment

by:emitchell
ID: 6312407
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.
0
 
LVL 49

Expert Comment

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

http://msdn.microsoft.com/library/en-us/winui/hh/winui/commdlg3_1hma.asp

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
0
 
LVL 30

Expert Comment

by:Axter
ID: 6314353
See following link for example project:

http://codeguru.earthweb.com/files/getFolder.html
0
 
LVL 30

Expert Comment

by:Axter
ID: 6314473
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:emitchell
ID: 6314528
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);
     m_pDocManager->OnFileOpen();
}
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,
        OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
        return; // open cancelled

    AfxGetApp()->OpenDocumentFile(newName);
    // 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"),
    _T("File1"));

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.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 200 total points
ID: 6314665
Hi Axter,
Did you read the question?

Hi emitchell,
From TN022 http://msdn.microsoft.com/library/en-us/vcmfc98/html/_mfcnotes_tn022.asp

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
0
 
LVL 2

Expert Comment

by:MaheshSundararaman
ID: 6315853
mitch

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
0
 

Author Comment

by:emitchell
ID: 6317529
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:

void
CRaceApp::OnFileOpen()
{
    // 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,
            OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL)) {
        // open cancelled
        return;
    }
    AfxGetApp()->OpenDocumentFile(m_sInitialDir);
    // if returns NULL, the user has already been alerted

    // now erase the initial dir since we only want to use it once
    m_sInitialDir.Empty();
}

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.

0
 

Author Comment

by:emitchell
ID: 6317540
Thanks Dan. You solved the problem. It was harder than I had originally thought!

Ed
0
 

Author Comment

by:emitchell
ID: 6321610
Thanks Dan. You solved the problem. It was harder than I had originally thought!

Ed
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Host to IP 7 73
Detect CR LF to each line 12 137
maven archtype selection in eclipse 1 51
fizzArray2 challenge 1 61
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

747 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

11 Experts available now in Live!

Get 1:1 Help Now