MFC: how to differentiate "Save" vs "Save As"? - visual-studio

In my previous question (MFC: how to change default file name for CFileDialog?), I overload DoSave function to supply a file name suggestion. Within this function is there way to differentiate "Save" vs "Save As"? Because I should only pop out dialog window if it is "Save As".
BOOL CMyDoc::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
{
if (IsSaveAS() || m_saved_file_name.IsEmpty())
{
CString file_name = some_suggested_file_name;
CFileDialog file_dialog(false, ..., file_name, ...);
if (file_dialog.DoModal() == IDOK)
{
m_saved_file_name = file_dialog.GetPathName();
}
}
OnSaveDocument(m_saved_file_name);
return TRUE;
}

The dialog should be popped when lpszPathName == NULL || *lpszPathName == '\0'.
This covers the case where DoSave is called from OnFileSaveAs:
void CDocument::OnFileSaveAs()
{
if(!DoSave(NULL))
TRACE(traceAppMsg, 0, "Warning: File save-as failed.\n");
}
And also the case where the associated file is read-only and cannot be written to.
BOOL CDocument::DoFileSave()
{
DWORD dwAttrib = GetFileAttributes(m_strPathName);
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
{
// we do not have read-write access or the file does not (now) exist
if (!DoSave(NULL))
{
TRACE(traceAppMsg, 0, "Warning: File save with new name failed.\n");
return FALSE;
}
}
else
{
if (!DoSave(m_strPathName))
{
TRACE(traceAppMsg, 0, "Warning: File save failed.\n");
return FALSE;
}
}
return TRUE;
}
It also matches the logic of the builtin DoSave.
BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace)
// Save the document data to a file
// lpszPathName = path name where to save document file
// if lpszPathName is NULL then the user will be prompted (SaveAs)
// note: lpszPathName can be different than 'm_strPathName'
// if 'bReplace' is TRUE will change file name if successful (SaveAs)
// if 'bReplace' is FALSE will not change path name (SaveCopyAs)
{
CString newName = lpszPathName;
if (newName.IsEmpty())
{
// ...
if (!AfxGetApp()->DoPromptFileName(newName,
// ...

Related

ON_CONTROL_RANGE C++ error invalid type conversion

I am programming the windows base application using MFC. when I was trying to use ON_CONTROL_RANGE function there is an error message popped up.
Visual Studio was used to build the app.
error
E0171 invalid type conversion
why is this error comes up,
give me a hint
Code
#define IDC_USR_MANUAL_TUNING_CH1_CHECK 1134
#define IDC_USR_MANUAL_TUNING_CH7_CHECK 1140
ON_CONTROL_RANGE(BN_CLICKED, IDC_USR_MANUAL_TUNING_CH1_CHECK, IDC_USR_MANUAL_TUNING_CH8_CHECK, OnUsrManualTuningChCheck)
void CMainteManualTuningDialog::OnUsrManualTuningChCheck(int nId)
{
if (FALSE == m_bInitFlag) // Initialization flag TRUE: Initialized / FALSE: Uninitialized
{
return;
}
UpdateData(TRUE);
int nChCnt = nId - IDC_USR_MANUAL_TUNING_CH1_CHECK;
if ((CH1 > nChCnt) || (CH8 < nChCnt))
{
return;
}
// unused
if (FALSE == m_bUseCheck[nChCnt])
{
if (nChCnt == m_rbutCh)
{
MessageBox("While selecting a channel, it cannot be invalidated.");
m_bUseCheck[nChCnt] = TRUE; // invalid
}
else
{
m_butUseCheck[nChCnt].SetWindowText(MSG_IGNORE); // Ignore
m_butChSel[nChCnt].EnableWindow(FALSE); // invalid
g_eTuningStat[nChCnt] = E_TUNING_STAT_NONE; // unused
m_strStatCh[nChCnt] = MSG_NONE; // unused
if (FALSE == m_clp->ZeroSetSend(nChCnt, m_pcTuningData))
{
((CMicroDetectorView*)m_hpView)->PostMessage(WM_USR_ALARM, eAPP_T);
}
}
}
// use
else
{
m_butUseCheck[nChCnt].SetWindowText(MSG_USE); // Use
m_butChSel[nChCnt].EnableWindow(TRUE); // Effectiveness
// Unadjusted the adjustment status
SetStatStill(nChCnt);
}
UpdateData(FALSE);
}
when we use the ON_CONTROL_RANGE(wNotifyCode, id, idLast, memberFxn)
memberFxn Fn has to use UINT variables

I want to copy, paste and cut content in my CEdit from my Clipboard

This is the event handlers i implemented to the copy, paste and Cut buttons in my MFCRibbonBar:
in the MyRibbonView.cpp:
void CMyRibbonView::OnEditCopy()
{
CWnd *wnd = GetFocus();
if (wnd == pEdit)
pEdit->Copy();
if (!OpenClipboard())
{
AfxMessageBox(_T("Cannot open the Clipboard"));
return;
}
if (!EmptyClipboard())
{
AfxMessageBox(_T("Cannot empty the Clipboard"));
return;
}
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64);
strcpy_s((char*)hGlob, 64, "Current selection\r\n");
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
CString msg;
msg.Format(_T("Unable to set Clipboard data, error: %d"), GetLastError());
AfxMessageBox(msg);
CloseClipboard();
GlobalFree(hGlob);
return;
}
CloseClipboard();
}
void CMyRibbonView::OnEditPaste()
{
if (OpenClipboard())
{
HANDLE hClipboardData = GetClipboardData(CF_TEXT);
char *pchData = (char*)GlobalLock(hClipboardData);
CString strFromClipboard;
strFromClipboard = pchData;
pEdit->SetWindowText(strFromClipboard);
GlobalUnlock(hClipboardData);
CloseClipboard();
}
}
void CMyRibbonView::OnEditCut()
{
OnEditCopy();
pEdit->SetWindowText(L" ");
}
There is no errors, it's just not working. I tested it by adding the messages to check if it's actually the data or not but they're not popping up.
You need to GlobalLock your hGlob memory before copying your character string into it (this operation converts it into a usable pointer for your process - see here), and then call GlobalUnlock after you've done that (so that the clipboard can access hGlob):
HGLOBAL hGlob = GlobalAlloc(GMEM_FIXED, 64); // Maybe also need GMEM_MOVEABLE here instead?
char* cCopy = (char*)GlobalLock(hGlob);
strcpy_s(cGlob, 64, "Current selection\r\n");
GlobalUnlock(hGlob);
if (::SetClipboardData(CF_TEXT, hGlob) == NULL)
{
//...
And you'll need a similar arrangement for the paste operation.

CFileDialog shows different contents according to Windows versions

I tried to show only the drives shared with Remote Desktop in a file selection dialog. Below is what I want to show:
(Image) Windows 10 - Only the shared drives are shown.
But the list of the drives and folders in the left pane are different according to the Windows OS version. The links to the screenshots are in a reply comment.
How can we show the same list of the drives and folders in the multiple Windows versions?
This is the implementation:
CFileDialog my_file_dialog(TRUE);
CComPtr<IFileDialogCustomize> file_dialog = my_file_dialog.GetIFileDialogCustomize();
CComPtr<IFileDialog2> dialog2;
if (FAILED(file_dialog->QueryInterface(&dialog2))) {
::AfxMessageBox(_T("Failed to query the interface of IFileDialog2."));
return;
}
CComPtr<IShellItemFilter> shell_item_filter =
new CVisibleShellItemFilter(REMOTE_APP_VISIBLE_PATHS);
if (FAILED(dialog2->SetFilter(shell_item_filter))) {
::AfxMessageBox(_T("Failed to set the shell item filter to the file dialog."));
return;
}
CComPtr<IShellItem> shell_item;
if (FAILED(::SHCreateItemInKnownFolder(FOLDERID_ComputerFolder, 0, nullptr, IID_PPV_ARGS(&shell_item)))) {
::AfxMessageBox(_T("Failed to create a shell item for the computer folder."));
return;
}
if (FAILED(dialog2->SetDefaultFolder(shell_item))) {
::AfxMessageBox(_T("Failed to set the default folder to the computer folder."));
return;
}
CComPtr<IShellItem> shell_item_desktop;
if (FAILED(::SHCreateItemInKnownFolder(FOLDERID_Desktop, 0, nullptr, IID_PPV_ARGS(&shell_item_desktop)))) {
::AfxMessageBox(_T("Failed to create a shell item for the desktop."));
return;
}
if (FAILED(dialog2->SetNavigationRoot(shell_item_desktop))) {
::AfxMessageBox(_T("Failed to set the navigation root to the computer folder."));
return;
}
CComPtr<IShellItem> currently_selected_folder;
if (FAILED(dialog2->GetFolder(&currently_selected_folder))) {
::AfxMessageBox(_T("Failed to set the navigation root to the computer folder."));
return;
}
if (!IsVisible(ToPathPartsList(REMOTE_APP_VISIBLE_PATHS), currently_selected_folder)) {
if (FAILED(dialog2->SetFolder(shell_item))) {
::AfxMessageBox(_T("Failed to set the folder to the computer folder."));
return;
}
}
if (my_file_dialog.DoModal() == IDOK) {
m_message.SetWindowTextW(my_file_dialog.GetPathName());
}
else {
m_message.SetWindowTextW(_T(""));
}
What I did were:
Construct an instance of CFiledialog.
Retrieved an instance of IFileDialogCustomize by CFiledialog::GetIFileDialogCustomize().
Retrieved an instance of IFileDialog2 from the isntance of IFileDialogCustomize.
Set an instance of IShellItemFilter to the file dialog by IFileDialog::SetFilter().
Set the default folder to the PC (My Computer) folder by IFileDialog::SetDefaultFolder().
Set the navigation root to the PC (My Computer) folder by IFileDialog::SetNavigationRoot().
Set the folder to the PC (My Computer) folder by IFileDialog::SetFolder() if the current folder is not a shared drive or its descendant folders.
Show the file dialog.
I did 2. to retrieve an instance of IFileDialog2 from the instance of IFileDialogCustomize. This is because I want to support both "Open" and "Save" file dialog by the same routine.
The point is 4.. I will show the implementation of IShellItemFilter later.
I did 5. because a folder other than a shared drive or its descendant folders is shown if the default folder is not than a shared drive or its descendant folders.
I did 6. because I don't want to show the minimum contents in the file dialog, and I don't want to show the desktop folder.
I did 7. because a folder other than a shared drive or its descendant folders is shown if the current folder is not than a shared drive or its descendant folders.
The implementation of IShellItemFilter was:
// If the desktop_absolute_parsing is "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", it shows the
// virtual folder that represents My Computer (PC).
// http://www.atmarkit.co.jp/ait/articles/1004/09/news094.html
static const std::wstring MY_COMPUTER_PATH = L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}";
// If the desktop_absolute_parsing starts with \\tsclient\, it shows a drive shared with
// Remote Desktop (or RemoteApp) or its child folder.
// https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/74673059-17b0-4a80-80ac-66b5dc419b56?forum=vcgeneralja
static const std::wstring REMOTE_APP_SHARED_FOLDER_PATH_PREFIX = L"\\\\tsclient\\";
static const std::vector<std::wstring> REMOTE_APP_VISIBLE_PATHS = {
// Add My Compter to the paths so that users can navigate from the My Compter in the folder
// view.
MY_COMPUTER_PATH,
REMOTE_APP_SHARED_FOLDER_PATH_PREFIX,
};
// Converts a give string to lower cases.
// str String
// return Lower case string.
std::wstring ToLower(std::wstring str) {
std::transform(str.begin(), str.end(), str.begin(),
[](auto ch) { return std::tolower(ch, std::locale()); });
return str;
}
// Split a givn path to the parts. Users need to split a path into the path parts, and pass to
// the function below for the processing speed.
// ex) "c:\\windows\\system32" -> {"c:", "\\", "windows", "system32"}
// file_path Path to be splitted.
// return Path parts.
std::vector<std::wstring> SplitPath(const std::wstring& file_path) {
using std::experimental::filesystem::v1::path;
path p(file_path);
return std::vector<std::wstring>(p.begin(), p.end());
}
// Checks if a path is equal to or an ancestor of another path.
// ancestor_path_parts Given path parts.
// descendant_path_parts Other path parts.
// returns true if ancestor_path_parts is equal to or an ancestor of descendant_path_parts.
// false, otherwise.
bool IsPathSelfOrAncestor(const std::vector<std::wstring>& ancestor_path_parts,
const std::vector<std::wstring>& descendant_path_parts) {
// Do not compare the path strings directly. Because "C:\Windows\System32" matches
// "C:\Windows\System", for example.
return std::search(descendant_path_parts.begin(), descendant_path_parts.end(),
ancestor_path_parts.begin(), ancestor_path_parts.end()) ==
descendant_path_parts.begin();
}
// Checks if two given paths are in a direct line. i.e. A path is equal to, ancestor of, or
// decendant of another path.
// path_parts1 Given path parts.
// path_parts2 Other path parts.
// return true if the given two paths are in a direct line. false, otherwise.
bool IsInDirectLine(const std::vector<std::wstring>& path_parts1, const std::vector<std::wstring>& path_parts2) {
return IsPathSelfOrAncestor(path_parts1, path_parts2) ||
IsPathSelfOrAncestor(path_parts2, path_parts1);
}
// Gets the display name from a given shell item.
// sigdnName SIGDN name.
// shell_item Shell item.
// name Display name.
// return S_OK if this method succeeds. false, otherwise.
HRESULT GetDisplayName(IShellItem* shell_item, SIGDN sigdnName, std::wstring& name) {
LPWSTR raw_name = nullptr;
HRESULT result;
if (FAILED(result = shell_item->GetDisplayName(sigdnName, &raw_name))) {
return result;
}
name = raw_name;
::CoTaskMemFree(raw_name);
raw_name = nullptr;
return S_OK;
}
// Checks if a given shell item is visible in a file/folder view.
// visible_path_parts_list List of the visble paths parts.
// shell_item Shell item to be checked.
// return true if the given shell item is visible. false, otherwise.
bool IsVisible(const std::vector<std::vector<std::wstring> >& visible_path_parts_list, IShellItem* shell_item) {
std::wstring desktop_absolute_parsing;
if (FAILED(GetDisplayName(shell_item, SIGDN_DESKTOPABSOLUTEPARSING,
desktop_absolute_parsing))) {
::AfxMessageBox(_T("Failed to get the diplay name of a shell item."));
return false;
}
auto path_parts = SplitPath(ToLower(desktop_absolute_parsing));
for (const auto& visible_path_parts : visible_path_parts_list) {
// Check if shell_item and visible_path are in the direct line. i.e. shell_item and
// visible_path are same, shell_item is an ancestor of visible_path, or shell_item is
// an descendant of visible_path.
// Let users to navigate in the case that shell_item is an ancestor of visible_path.
// Otherwise, users can not navigate to the visible_path through the folder view in
// the file selection dialog.
if (IsInDirectLine(path_parts, visible_path_parts)) {
return true;
}
}
return false;
}
// Converts the list of paths into the list of the path parts.
std::vector<std::vector<std::wstring> > ToPathPartsList(
const std::vector<std::wstring>& paths) {
std::vector<std::vector<std::wstring> > path_parts_list;
for (const auto& path : paths) {
path_parts_list.push_back(SplitPath(ToLower(path)));
}
return path_parts_list;
}
// CVisibleShellItemFilter show only the visible shell items which are listed in the given list
// of paths.
class CVisibleShellItemFilter : public IShellItemFilter {
public:
CVisibleShellItemFilter(const std::vector<std::wstring>& visible_paths) :
m_visible_path_parts_list(ToPathPartsList(visible_paths)) { }
HRESULT QueryInterface(REFIID riid, void** ppvObject) override {
if (ppvObject == nullptr) {
return E_POINTER;
}
if (riid == IID_IUnknown || riid == IID_IShellItemFilter) {
*ppvObject = static_cast<void*>(this);
AddRef();
return NO_ERROR;
}
else {
*ppvObject = nullptr;
return E_NOINTERFACE;
}
}
ULONG AddRef() override {
return ++m_reference_count;
}
ULONG Release() override {
ULONG reference_count = --m_reference_count;
if (reference_count == 0) {
delete this;
}
return reference_count;
}
HRESULT IncludeItem(IShellItem *psi) override {
return IsVisible(m_visible_path_parts_list, psi) ? S_OK : S_FALSE;
}
HRESULT GetEnumFlagsForItem(IShellItem *psi, SHCONTF *pgrfFlags) override {
*pgrfFlags = static_cast<SHCONTF>(-1);
return S_OK;
}
private:
ULONG m_reference_count = 0;
const std::vector<std::vector<std::wstring> > m_visible_path_parts_list;
};
CVisibleShellItemFilter::IncludeItem() returns S_OK if the desktop absolute parsing of a file is "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" or starts with "\tsclient\". "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" means PC (My Computer) folder, and "\tsclient\" is the file path prefix of the shared drives.
Thanks,
Updated (2017/09/07 11:54 JST)
"the content" -> "the list of the drives and folders"

how to host html control in my window using a buffer which contents a html file

I am developing a visual c++ applicatio(x64). what actually i am trying to do is that suppose we have a html file in window explorer(i mean file with file extension ".html"). when we single click on it we get its preview on preview pane(so we don't need to open this file we can see the file in preview pane on a single click to a file).
I have developed a similar type of application but in my case when i click on the "html file" i just get the code of that html file in preview pane(the code which you can see if you open that html file in notepad). which is not expected to happen but I want to have the preview of that "html file" not the code of that html file.
I think i need to host some browser control which will transform my html code in preview pane to the display of html file(If i am correct ???) How to do that ??
Here is my code for that-
IHTMLDocument2 * pDoc=NULL;
HRESULT hr2 = CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (LPVOID *) &pDoc);
if (pDoc)
{
IPersistStreamInit *pPersist = NULL;
pDoc->QueryInterface(IID_IPersistStreamInit,(LPVOID *) &pPersist);
if (pPersist)
{
IMarkupServices *pMS = NULL;
pPersist->InitNew();
pPersist->Release();
pDoc->QueryInterface(IID_IMarkupServices,(LPVOID *) &pMS);
if (pMS)
{
IMarkupContainer *pMC = NULL;
IMarkupPointer *pMkStart = NULL;
IMarkupPointer *pMkFinish = NULL;
pMS->CreateMarkupPointer(&pMkStart);
pMS->CreateMarkupPointer(&pMkFinish);
pMS->ParseString(HtmlFileContents,0,&pMC,pMkStart,pMkFinish);
//this HtmlFileContents is actually a buffer of olechar type which contains the code of html file (the code which you see when you open the html file in notepad)
if (pMC)
{
IHTMLDocument2 *pNewDoc = NULL;
pMC->QueryInterface(IID_IHTMLDocument,(LPVOID *) &pNewDoc);
if (pNewDoc)
{
IHTMLElement *pBody;
pNewDoc->get_body(&pBody);
if (pBody)
{
BSTR strText;
pBody->get_innerText(&strText);
hr = instance->CreatePreviewWindowForHtml(strText); // this function is responsible for displaying the html file in window. you can see its definition below after this code.
SysFreeString(strText);
pBody->Release();
}
pNewDoc->Release();
}
pMC->Release();
}
if (pMkStart)
pMkStart->Release();
if (pMkFinish)
pMkFinish->Release();
pMS->Release();
pMS->Release();
}
}
pDoc->Release();
}
return true;
and the function defintion of CreatePreviewWindowForHtml() is as below-
CreatePreviewWindowForHtml(PCWSTR pszRtfWide)
{
assert(m_hwndPreview3 == NULL);
HRESULT hr = E_FAIL;
if (m_hwndPreview3 == NULL)
{
HRESULT hr5 = HRESULT_FROM_WIN32(GetLastError());
}
if (m_hinstEditLibrary == NULL)
{
// MSFTEDIT_CLASS used below comes from this binary
m_hinstEditLibrary = LoadLibraryW(L"msftedit.dll");
}
if (m_hinstEditLibrary == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
// Create the preview window
HWND pr = m_hwndPreview3 = CreateWindowExW(0, MSFTEDIT_CLASS, NULL,
WS_CHILD | WS_VSCROLL | WS_VISIBLE | ES_MULTILINE | ES_READONLY, // Always create read-only
m_rcParent.left, m_rcParent.top, RECTWIDTH(m_rcParent), RECTHEIGHT(m_rcParent),
m_hwndPreview, NULL, NULL,NULL);
if (m_hwndPreview3 == NULL)
{
MessageBoxA(m_hwndPreview3,strerror(hr),"BTN WND2", MB_ICONINFORMATION);
}
else
{
int const cchRtf = 1 + wcslen(pszRtfWide);
PSTR pszRtf = (PSTR)CoTaskMemAlloc(cchRtf);
if (pszRtf)
{
WideCharToMultiByte(CP_ACP, 0, pszRtfWide, cchRtf, pszRtf, cchRtf, NULL, NULL);
SETTEXTEX st = { ST_DEFAULT, CP_ACP };
LRESULT hr4=SendMessage(m_hwndPreview3, EM_SETTEXTEX, (WPARAM) &st, (LPARAM) pszRtfWide);
if (SUCCEEDED(hr4))
{
hr = AdjustDialogPositionAndSize();
SendMessage(m_hwndPreview3, EM_SETTEXTEX, (WPARAM) &st, (LPARAM) pszRtfWide);
}
CoTaskMemFree(pszRtf);
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
return hr;
}
Any ideas why i have the html code in my window ?? What to do in the code in order to get the preview of html file in my window rather then html code ??
Please tell me if any doubts in understanding me ??
You have the html code in your window because you choose a richedit as the text renderer and your text did not start with "{\rtf".
If you want html display, you need an html renderer instead of a rich edit, something like MFC's CHtmlEditCtrl. If you don't want to use MFC you can write an ActiveX container to host the webbrowser control directly.

How could I choose one particular file to load with loadStrings

The title is explicit enough, I want to let the user choose the text file he want to open.
I do not know if there is an explorer or an input field already implemented on processing.
Any help would be great.
Use selectInput. From the Processing reference:
Opens a platform-specific file chooser dialog to select a file for input. After the selection is made, the selected File will be passed to the 'callback' function. If the dialog is closed or canceled, null will be sent to the function, so that the program is not waiting for additional input. The callback is necessary because of how threading works.
I've modified the example sketch they provide in the reference to include loading the file with the loadStrings method.
String[] txtFile;
void setup() {
selectInput("Select a file to process:", "fileSelected");
}
void fileSelected(File selection) {
if (selection == null) {
println("Window was closed or the user hit cancel.");
} else {
String filepath = selection.getAbsolutePath();
println("User selected " + filepath);
// load file here
txtFile = loadStrings(filepath);
}
}
There is no Implemented method, but you could could make a buffer and monitor key presses like so:
String[] File;
String keybuffer = "";
Char TriggerKey = Something;
void setup(){
//do whatever here
}
void draw(){
//Optional, to show the current buffer
background(255);
text(keybuffer,100,100);
}
void keyPressed(){
if(keyCode >= 'a' && keyCode <= 'z'){
keybuffer = keybuffer + key;
}
if(key == TriggerKey){
File = loadStrings(keybuffer + ".txt");
}
}
when triggerkey is pressed, it loads the file

Resources