Overwrite OnFileOpen and OnFileSave function - registry is not updated? - c++

I have a little problem that I do not know how to solved:
I am writing a program that involves data serialization. I decided to override the OnFileOpen and OnFileSave function because I wanted to modify the File Dialog Box when open/save the file.
My problem is: after I load the file, the program title still remains 'Untitled' and the 'Recent File' list under the 'File' menu bar is not updated either.
I suppose I need to add some code to update the registry? But I struggle to find the solution of it...
Thank you all for the helps! Highly appreciated!
Here are my OnFileOpen and OnFileSave code:
void CXXXDoc::OnFileOpen()
{
// TODO: Add your command handler code here
TCHAR szFilters[]= _T("XXX Type Files (*.xxx)|*.xxx|All Files (*.*)|*.*||");
CFileDialog fileDlg(TRUE, _T("xxx"), _T("*.xxx"), OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, szFilters);
if(fileDlg.DoModal() == IDOK)
{
CFile oldFile;
ASSERT (oldFile != NULL);
oldFile.Open(fileDlg.GetPathName(), CFile::modeRead | CFile::shareExclusive);
FilePathName = fileDlg.GetPathName();
SetTitle(FilePathName);
CArchive loadArchive(&oldFile, CArchive::load | CArchive::bNoFlushOnDelete); // Create the archive to load data, the archive must be closed manually after the loading process
Serialize(loadArchive);
loadArchive.Close();
oldFile.Close();
UpdateAllViews(0);
}
}
void CXXXDoc::OnFileSave()
{
CFile newfile;
ASSERT (newfile != NULL);
newfile.Open(FilePathName, CFile::modeWrite);
CArchive saveArchive(&newfile, CArchive::store); // Create the archive to save data,
Serialize(saveArchive);
saveArchive.Close();
newfile.Close();
}

To keep the most recently used (MRU) list updated, you need to call CWinApp::AddToRecentFileList (MSDN here). So, for your OnFileOpen, you might do this:
AfxGetApp()->AddToRecentFileList(FilePathName);
As the remarks in MSDN say:
You should call the LoadStdProfileSettings member function to load the
current MRU file list before you use this member function.
The framework calls this member function when it opens a file or
executes the Save As command to save a file with a new name.

Related

CFileDialog with realtive path

I currently maintenance an old MFC application and have problems with opening file dialogs. The Program has multiple different parts were the user select files for loading, eg sound, video and other program specific formats.
Opening a dialog should always open in a "specific" folder, depending on the file ending. Giving an directory path that contains "..\" will accept and the Dialog opens with the "last selected file".
CString fileDirectory = myHelper.getPath();
// fileDirectory is now "C:\coding\svn\source\MyProgram\..\..\bin\..\data\..\Audio\"
CFileDialog FileDialog(true, _T("MP3;WAV"), _T(fileDirectory), OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, _T("All music files (*.WAV;*.MP3)));
if (FileDialog.DoModal() == IDOK)
{ ... }
I use different CDialog classes (about 15, eg for editing audiofiles, for videofiles) and they all have similar code for opening dialogs like above.
How can i support the relative paths for the CFileDialog?
The CFileDialog supports setting up initial/default folder. Here is the code snippet that demonstrates how to use it:
const TCHAR szFilter[] = _T("Parameter Files (*.npf)|*.npf|All Files (*.*)|*.*||");
CFileDialog dlg(TRUE, _T("npf"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, this);
CString sParametersDir(CUtility::GetParametersDir());
dlg.m_ofn.lpstrInitialDir = sParametersDir.GetBuffer(_MAX_PATH);
if(dlg.DoModal() == IDOK)
{
m_ParametersFileEdit.SetWindowText(dlg.GetPathName());
}
sParametersDir.ReleaseBuffer();
Also regarding your code. There is no need to use _T() macro for CString objects. The CString class does support UNICODE automatically. The _T() macro should only be used for string literals.
You can use CPath class to normalize file path.
CPath path(sPath);
path.AddBackslash();
path.Append(_T("Config"));
path.Canonicalize();

C++ MFC CFileDialog won't save

I created a MFC programm with a menu option to Save a file. When I click it it shows the CFileDialog and I can choose the location where I want to save my file. When I Click save in the Dialog, it closes the dialog, but after that it does nothing. AND it didn't save my file. What am I doing wrong?
Here is the code
CFileDialog *dlg = new CFileDialog(FALSE, L"dr", NULL, NULL,
L"Drawings (*.dr)|*.dr|"
L"All Files||");
bool result = dlg->DoModal();
if(result)
{
MessageBox(0, dlg->GetPathName(), L"Draw", 0);
}
The bool result, is purely there to check if there is no problem/error.
The file save dialog is called "file save dialog" because its caption says "Save File" and it allows you to only select a single file. That does not mean that it actually does any saving of files. It just returns to you the filename selected by the user. You are still responsible for writing the code which will save your file using this filename.
The CFileDialog does not save the file for you, it only provides you with a dialog for the user to determine where (and if!) the file should be saved. The return value of DoModal() should be compared to IDOK before proceeding to save. From the dialog's member functions you can get the path and filename the user selected. With that, you can create/open a file and save your data.

How can I add text to the file I create using IFileOperation?

I looked at the MSDN samples for IFileOperation, and they show how to create a file, but I don't want to create a blank file, I want to add some text in it. Here's what I have from the sample:
IFileOperation *pfo;
HRESULT hr = CreateAndInitializeFileOperation(IID_PPV_ARGS(&pfo));
if (SUCCEEDED(hr))
{
hr = pfo->NewItem(psiFolder, FILE_ATTRIBUTE_NORMAL, c_szFileName, NULL, NULL);
if (SUCCEEDED(hr))
{
hr = pfo->PerformOperations();
}
pfo->Release();
}
In the pfo->NewItem call, the fourth parameter is for the template, but I don't want to define a template.I want to create a .Url file with the content:
[InternetShortcut]
URL=www.google.com
I can't even seem to control the format of the file, let alone the content. Please help!
IFileOperation::NewItem lets you access the functionality of the 'ShellNew' menu (the menu you get if you right-click in a folder, and select New from the context menu). It's designed to let you make a folder or an empty file, or create a new file from a pre-existing template. It doesn't let you make a file containing arbitrary data.
Once you've created a new empty file you could open it using CreateFile() and write your data to it using WriteFile(). But note that CreateFile() could create the file for you as well - there's really no need to use IFileOperation simply to create an empty file (unless you need its support for UAC to create the file in a protected location, but in that case you'll have trouble writing to it afterwards).

Windows LoadMenu error: "The specified resource name cannot be found in the image file."

I'm writing a program that, among other things, needs to display a context menu on right-click. I'm trapping WM_NOTIFY, the identifier of the control being clicked on, and NM_RCLICK. That all works great.
The problem comes in when I'm processing that right-click:
case NM_RCLICK:
{
HMENU Popup = LoadMenu(0, MAKEINTRESOURCE(IDR_NED_MENU));
if ( !Popup ) {
DWORD err = GetLastError();
char* buf;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, err, 0, buf, 1<<19, 0);
_ERROR("LoadMenu(0, MAKEINTRESOURCE(IDR_NED_MENU)); Error '%s' thrown; no menu loaded.", buf);
delete [] buf;
}
Popup = GetSubMenu(Popup, 0);
CheckMenuItem(Popup, 1, MF_CHECKED|MF_BYPOSITION);
POINT Point;
GetCursorPos(&Point);
switch (TrackPopupMenu(Popup, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD, Point.x, Point.y, 0, GetActiveWindow(), NULL)) {
// ...
Primarily, LoadMenu(0, MAKEINTRESOURCE(IDR_NED_MENU)); is returning NULL, and I'm getting an error message that states that "The specified resource name cannot be found in the image file."
Now, IDR_NED_MENU is the ID of a menu I have in the .rc file, and I've included the corresponding .rc.h file in this .cpp file. The actual dialog window IDs contained in the same .rc file work perfectly. This code is further copied and pasted from another project where the LoadMenu call worked perfectly: I did recreate the IDR_NED_MENU from scratch, though, and the IDs are somewhat different (but they do match between the .rc file and the .cpp file that has the code snippet I've pasted here); originally I'd accidentally created the menu in a separate .rc file so I sought to rectify that here. I noticed that in Visual Studio's Resource View, the dialogs are contained in the Dialog folder, while this is contained in the Menu folder (sensible), but I'm not sure what, if any, difference that makes.
Why would I be getting this error? Why can't it find IDR_NED_MENU?
I'm using Visual Studio 2010, and this is not an MFC project. I'm not sure what, if any, other relevant details I should include; let me know in comments and I'll edit-update.
Thanks.
The first parameter to LoadMenu must be a handle to your executable image where the resource resides. The handle is the first HINSTANCE that you get in WinMain. Alternatively you can obtain it by a call to GetModuleHandle(0).

How can I set the default file type for a CFileDialog?

I am using CFileDialog for displaying the open file dialog. I have set the filter as follows:
static TCHAR BASED_CODE szFilter[] = _T("Chart Files (*.xlc)|*.xlc|")
_T("Worksheet Files (*.xls)|*.xls|Data Files (*.xlc;*.xls)|")
_T("*.xlc; *.xls|All Files (*.*)|*.*||");
I need to set the default file type to be "Worksheet Files" whenever I DoModal the dialog box. I am unable to figure out how to do it. MS Paint is doing, it selects the "All Picture files" when we open the open file dialog.
Please let me know how to do it.
You're looking for the SetDefExt function. This allows you to specify the default file extension for an open/save file dialog box. Remember that the string you specify should not contain a period (.).
Of course, you could also just specify this in the constructor. The second parameter is the default extension (lpszDefExt).
You should read and write
This code will do the job during the run time of your program. To be able to display the last used selection next time you run your program, you can store the value of LastIndex in the Registry.
// A dialog box with several filters for various media file types
static int LastIndex = -1; // Holds the last used filter. You can store it in the Registry to use it during next run.
const TCHAR szFilter[] = _T("Video Files (*.mpg, *.mov, *.mp4)|*.mpg;*.mov;*.mp4|Audio Files (*.wav, *.mp3, *.m4a, *.flac)|*.wav;*.mp3;*.m4a;*.flac|MXF Files (*.mxf)|*.mxf|All Files (*.*)|*.*||");
CFileDialog dlg(TRUE, _T("Select Media File"), NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, szFilter, this);
if(LastIndex != -1) dlg.m_ofn.nFilterIndex = LastIndex; // restore last used index
// from last time
if (dlg.DoModal() == IDOK)
{
LastIndex = dlg.m_ofn.nFilterIndex; // Store last used index for next time
CString sFilePath = dlg.GetPathName();
}