CFileDialog :: Browse folders - mfc

When I try to instantiate a CFileDialog object it shows both the folders and files. How do you create a CFileDialog that browses for folders alone?

It is very simple, really.
Use CFolderPickerDialog which is derived from the class CFileDialog!

You can't do it with CFileDialog.
Either you will use SHBrowseForFolder Function or a wrapper for it, like CFolderDialog - Selecting Folders.

Starting from Vista it's recommended to use IFileDialog with the FOS_PICKFOLDERS option (see msdn):
CFileDialog od(TRUE/*bOpenFileDialog*/, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT , NULL, NULL, 0,
TRUE/*bVistaStyle*/);
IFileOpenDialog * openDlgPtr = od.GetIFileOpenDialog();
if ( openDlgPtr != NULL )
{
openDlgPtr->SetOptions(FOS_PICKFOLDERS);
openDlgPtr->Release();
}
od.DoModal();

Like someone mentioned, use CFolderPickerDialog which works great. I would like to give you example how to use it especially when using the multi select flag:
CFolderPickerDialog folderPickerDialog(initialFolder, OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING, this,
sizeof(OPENFILENAME));
CString folderPath;
if (folderPickerDialog.DoModal() == IDOK)
{
POSITION pos = folderPickerDialog.GetStartPosition();
while (pos)
{
folderPath = folderPickerDialog.GetNextPathName(pos);
}
}

starting from windows vista,you can use the Common Item Dialog .
void CQiliRegrvDlg::OnBnClickedSelectDir()
{
HRESULT hr = S_OK;
// Create a new common open file dialog.
IFileOpenDialog *pfd = NULL;
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Set the dialog as a folder picker.
DWORD dwOptions;
hr = pfd->GetOptions(&dwOptions);
if (SUCCEEDED(hr))
{
hr = pfd->SetOptions(dwOptions | FOS_PICKFOLDERS);
}
// Set the title of the dialog.
if (SUCCEEDED(hr))
{
hr = pfd->SetTitle(L"Folder");
}
// Show the open file dialog.
if (SUCCEEDED(hr))
{
hr = pfd->Show(m_hWnd);
if (SUCCEEDED(hr))
{
// Get the selection from the user.
IShellItem *psiResult = NULL;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
PWSTR pszPath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
if (SUCCEEDED(hr))
{
m_appDir = pszPath;
SetDlgItemText(IDC_STATIC, m_appDir);
CoTaskMemFree(pszPath);
}
psiResult->Release();
}
}
}
pfd->Release();
}
}

Seems to me the answer you are asking for is inside the code of
CMFCPropertyGridFileProperty::OnClickButton(CPoint /*point*/)
of the
<Your Visual Studio installation folder>\VC\atlmfc\src\mfc\afxpropertygridctrl.cpp
file.
If you do not have access to the code, I will post the essential part of it:
CString strPath = m_varValue.bstrVal;
BOOL bUpdate = FALSE;
if (m_bIsFolder)
{
if (afxShellManager == NULL)
{
CWinAppEx* pApp = DYNAMIC_DOWNCAST(CWinAppEx, AfxGetApp());
if (pApp != NULL)
{
pApp->InitShellManager();
}
}
if (afxShellManager == NULL)
{
ASSERT(FALSE);
}
else
{
bUpdate = afxShellManager->BrowseForFolder(strPath, m_pWndList, strPath);
}
}
else
{
CFileDialog dlg(m_bOpenFileDialog, m_strDefExt, strPath, m_dwFileOpenFlags, m_strFilter, m_pWndList);
if (dlg.DoModal() == IDOK)
{
bUpdate = TRUE;
strPath = dlg.GetPathName();
}
}
As you see, Microsoft itself does not use the Cfiledialog class when wants to open a dialog for picking folders.
For using code like that, your application class MUST be derived from CWinAppEx, not CWinApp

Actually there is a way to do this - I found it in codeguru: "Selected files and folders in CFileDialog"
If you are willing to make your own implementation of CFileDialog such as:
class CMyFileDialog : public CFileDialog
You can add the following code and it should work (It is slightly different from the codeguru example):
// This code overrides the OnNotify message of the CFileDialog
// and catches the CDN_SELCHANGE, this way you can also do
// something with the selected folders.
BOOL CMyFileDialog::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
NMHDR* pNotificationParam = (NMHDR*)lParam;
// Check that we got to the selection change notification.
int code = pNotificationParam->code;
if (code == CDN_SELCHANGE)
{
CStringArray theSelection;
GetListControllSelectedItems(theSelection);
// Do as you want with theSelection.
}
return CFileDialog::OnNotify(wParam, lParam, pResult);
}
// The following Code is accessing the selection in the CFileDialog
// and filling a string array with the selected names
BOOL CMyFileDialog::GetListControllSelectedItems(CStringArray& selectedItemNames)
{
BOOL rc = FALSE;
// Get the list control of the file dialog.
CWnd* pParentWnd = GetParent();
CWnd* pListControlWnd = pParentWnd->GetDlgItem(lst2);
if (pListControlWnd) {
// Get the selection from the list control.
CListCtrl* pListCtrl = (CListCtrl*)(pListControlWnd->GetDlgItem(1));
UINT selectionCount = pListCtrl->GetSelectedCount();
// When there are items selected.
if (selectionCount) {
rc = TRUE;
selectedItemNames.RemoveAll();
POSITION itemPos = pListCtrl->GetFirstSelectedItemPosition();
while (itemPos != NULL)
{
int itemNum = pListCtrl->GetNextSelectedItem(itemPos);
CString currentItemName = pListCtrl->GetItemText(itemNum, 0);
selectedItemNames.Add(currentItemName);
}
}
}
return rc;
}
Note: In CFileDialog::OnFileNameChange of the Microsoft MFC documentation they actually do hint toward this solution, but without elaborating too much.
I had a problem in my very old, legacy code, where I have a customized file dialog that actually needs to save a folder!!!
After twenty two years of hardship and pain, my code is now complete...

Related

How can I change the style of a control (CListBox) initialized with DDX_Control, before DDX_Control is called

I'm modifying an existing project and a dialog has controls I am subclassing to theme differently in some cases (in other cases I will leave it entirely alone). By the time DDX_Control() is called during DoDataExchange(), the hwnd for the ListBox already has styles applied. Specifically, at this time even if I do SetWindowLongPtr(), the LBS_OWNERDRAWFIXED does not work. By "does not work," I mean that although the style is applied, owner draw messages are not received by the CListBox.
Conversely, if I avoid the DDX_Control() and simply do a create, the ListBox does receive the messages and can be ownerdrawn. But if I do this there are now two HWND, only one of which is returned by GetDlgItem(). I believe I can make this work if necessary, but I wondered if there is a secret to intercept the HWND creation of the controls in the dialog (actually a CPropertyPage).
Below is code that doesn't work, with more commented code that "works" but isn't the way I wanted it to work, if possible.
void CMyPropertySheet::DoDataExchange(CDataExchange* pDX)
{
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(IDC_LIST1, &hWndCtrl);
if (themed) {
DWORD style = GetWindowLongPtr(hWndCtrl, GWL_STYLE) | LBS_OWNERDRAWFIXED;
SetWindowLongPtr(hWndCtrl, GWL_STYLE, style);
DDX_Control(pDX, IDC_LIST1, m_listbox);
//RECT wr;
//::GetWindowRect(hWndCtrl, &wr);
//m_listbox.Create(style, wr, this, IDC_LIST1);
} else {
DDX_Control(pDX, IDC_LIST1, m_listbox);
}
I should probably add I tried subclassing the window, but it didn't help, and CMyPropertySheet::PreSubclassWindow wasn't soon enough, either.
Some creation flags like LBS_OWNERDRAWFIXED and LBS_SORT are cached and modifying them afterwards have no effect. You have to change the template, or just make a duplicate of the listbox. Copy the style of the old listbox, then hide that listbox, change its ID, and create a new listbox based on the old one. You then have to remove DDX_Control(pDX, IDC_LIST1, m_listbox)
The example below starts with a standard list which has its sort flag set. It duplicates the listbox and disables the sort option.
For simplicity this example avoids LBS_OWNERDRAWFIXED, it uses LBS_SORT instead.
class CMyPropertyPage : public CPropertyPage
{
public:
CListBox m_listbox;
int m_listbox_index;
CMyPropertyPage(int idd) : CPropertyPage(idd)
{
m_listbox_index = 1;
}
void DoDataExchange(CDataExchange* pDX)
{
//This function is automatically called before
//CPropertyPage::OnInitDialog is complete
//On the first call, IDC_LIST1 will point to the template listbox
if(m_listbox.m_hWnd)
{
//m_listbox is ready,
//IDC_LIST1 will refer to the new listbox
DDX_LBIndex(pDX, IDC_LIST1, m_listbox_index);
}
}
BOOL OnInitDialog()
{
CPropertyPage::OnInitDialog();
CListBox* old_listbox = (CListBox*)GetDlgItem(IDC_LIST1);
if(old_listbox)
{
DWORD style = ~LBS_SORT & GetWindowLongPtr(old_listbox->m_hWnd, GWL_STYLE);
CRect rc;
old_listbox->GetWindowRect(&rc);
ScreenToClient(&rc);
old_listbox->SetDlgCtrlID(0);//change the old ID to something unused
old_listbox->ShowWindow(SW_HIDE); //hide the old listbox
m_listbox.Create(style | WS_BORDER, rc, this, IDC_LIST1);
m_listbox.SetFont(GetFont());
}
ASSERT(m_listbox.GetDlgCtrlID() == IDC_LIST1);
m_listbox.AddString(L"2");
m_listbox.AddString(L"1");
m_listbox.AddString(L"0");
UpdateData(FALSE);
return TRUE;
}
};
class CMyWinApp : public CWinApp
{
BOOL InitInstance()
{
CWinApp::InitInstance();
CPropertySheet sh;
CMyPropertyPage page(IDD_PAGE1);
sh.AddPage(&page);
sh.DoModal();
return TRUE;
}
} myapp;
OK, I'm not sure I recommend this to anyone, but I did find a way to modify the template, finally. I had to use VirtualProtect to unlock the memory of the template.
for (int i = 0; i < m_pages.GetSize(); i++) {
CPropertyPage* pPage = GetPage(i);
PROPSHEETPAGE* tpsp = &pPage->m_psp;
const DLGTEMPLATE* pTemplate;
if (tpsp->dwFlags & PSP_DLGINDIRECT) {
pTemplate = tpsp->pResource;
} else {
HRSRC hResource = ::FindResource(tpsp->hInstance, tpsp->pszTemplate, RT_DIALOG);
if (hResource == NULL) return false;
HGLOBAL hTemplate = LoadResource(tpsp->hInstance, hResource);
if (hTemplate == NULL) return false;
pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate);
if (pTemplate == NULL) return false;
}
if (afxOccManager != NULL) {
DLGITEMTEMPLATE *pItem = _AfxFindFirstDlgItem(pTemplate);
DLGITEMTEMPLATE *pNextItem;
BOOL bDialogEx = IsDialogEx(pTemplate);
int iItem, iItems = DlgTemplateItemCount(pTemplate);
for (iItem = 0; iItem < iItems; iItem++) {
pNextItem = _AfxFindNextDlgItem(pItem, bDialogEx);
DWORD dwOldProtect, tp;
if (bDialogEx) {
_DialogSplitHelper::DLGITEMTEMPLATEEX *pItemEx = (_DialogSplitHelper::DLGITEMTEMPLATEEX *)pItem;
if (pItemEx->id == IDC_LIST1) {
if (VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), PAGE_READWRITE, &dwOldProtect)) {
pItemEx->style |= LBS_OWNERDRAWFIXED;
VirtualProtect(&pItemEx->style, sizeof(pItemEx->style), dwOldProtect, &tp);
}
}
} else {
if (pItem->id == IDC_LIST1) {
if (VirtualProtect(&pItem->style, sizeof(pItem->style), PAGE_READWRITE, &dwOldProtect)) {
pItem->style |= LBS_OWNERDRAWFIXED;
VirtualProtect(&pItem->style, sizeof(pItem->style), dwOldProtect, &tp);
}
}
}
pItem = pNextItem;
}
}
}
return true;

Print a PDF file with MFC

In my app (MFC, C++) I have a button that creates a PDF file in a path.
Now I want to create another button that will print the pdf starting from the path and choosing some option like orientation and number of copies... but I'm not able to do that...
I saw that CPrintDialog shows the default dialog of the printer but I'm not able to attach the PDF file using the path.
I saw also the
ShellExecute(NULL, L"print", L"C:\\Documents\\1.pdf", NULL, NULL, SW_SHOWNORMAL);
that works but in this way I cannot choose any parameter...
How I can use the CPrintDialog to print an existing PDF that is in a path?
You have to use ShellExecuteEx and verb printto to get more control over printing:
SHELLEXECUTEINFO ShellInfo;
ZeroMemory(&ShellInfo, sizeof(SHELLEXECUTEINFO));
ShellInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShellInfo.lpVerb = L"printto";
ShellInfo.lpFile = L"C:\\Documents\\1.pdf";
ShellInfo.lpParameters = szPrinter;
ShellInfo.nShow = SW_SHOWNORMAL;
ShellInfo.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS;
if(::ShellExecuteEx(&ShellInfo))
{
if((int)ShellInfo.hInstApp > 32)
{
if(ShellInfo.hProcess != NULL)
{
DWORD dwExitCode = STILL_ACTIVE;
while(dwExitCode == STILL_ACTIVE)
{
if(!::GetExitCodeProcess(ShellInfo.hProcess, &dwExitCode))
{
dwExitCode = 0;
}
}
::CloseHandle(ShellInfo.hProcess);
}
}
}
To get the printer name:
CPrintDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
CString sPrinterName = dlg.GetDeviceName();
}
I have solved with a workaround. Instead of use the ShellExecute, I draw all the thing that I want to print using a CDC object attached to the hDC of a CPrintDialog class. Rember to manage the size of the draw depending on printer DPI like here.
A snippet only to have an idea:
CPrintDialog printDialog(FALSE);
printDialog.GetDefaults();
printDialog.m_pd.Flags &= ~PD_RETURNDEFAULT;
DEVMODE* pDevMode = printDialog.GetDevMode();
pDevMode->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PRINTQUALITY ;
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
pDevMode->dmPaperSize = DMPAPER_A4;
::GlobalUnlock(printDialog.m_pd.hDevMode);
if (printDialog.DoModal() == IDOK)
{
CDC* pDC = new CDC;
pDC->Attach(printDialog.m_pd.hDC);
pDCPDF->StartDoc(_T(""));
pDCPDF->StartPage();
// ...
//draw what you want
// ...
pDCPDF->EndPage();
pDCPDF->EndDoc(); //this starts the printer
pDCPDF->DeleteDC();
}
Hope to reach soon the reputation of 15 to vote the answer of other questions.
Thanks to Andrew Komiagin answers.

Prompting a user with an input box? [C++]

My goal is to simply use a pop-up box to ask the user for an input. I've searched around quite a bit and pretty much all the results say that creating a messageBox is really easy:
MessageBox (NULL, "Hello World" , "Hello", MB_OKCANCEL);
But that creating a pop-up that takes input is more involved and there isn't a straight forward way to do it. All of the results I could find on Google were dated somewhere from 2001 to 2005. I guess I'm here asking if some more straight forward solution has come about in recent years.
Hopefully something nice and straight forward like in Java:
int number = JOptionPane.showInputDialog ("Enter an integer");
If that isn't the case, could I get a brief explanation of how to do it?
Edit: I couldn't get anything to work. :( I ended up writing the code to do the work in Java, and then wrote one line of C++ code to call the .jar file. :-/ Since the issue was time sensitive, it was better than nothing.
If you are using Visual C++ Express there are a number of free resource editors that can be used to create dialogs. ResEdit is one of the better ones I've found.
You need to create a dialog resource in a .RC file that you add to your project.
Then, It is a very simple case of calling DialogBox - which will load the dialog box from your resource file and place it on the screen. The passed in DialogProc will be called with a number of notifications. Typically you would want to return FALSE for everything, but handle WM_INITDIALOG as a place to initialize the edit control with text, and WM_COMMAND will be sent when a button is clicked.
There is nothing like that for pure C++. Basically what you're trying to do can only be achieved by using an API call to the OS or by using some GUI library like Qt (which I recommend cause it's waaaaay easier then calling native APIs and it's also multi-platform)
Using Qt you can show an input dialog pretty much the same way you do it on java:
bool ok;
QString text = QInputDialog::getText(
"MyApp 3000", "Enter your name:", QLineEdit::Normal,
QString::null, &ok, this );
if ( ok && !text.isEmpty() ) {
// user entered something and pressed OK
} else {
// user entered nothing or pressed Cancel
}
You can download the Qt library here: qt.nokia.com/products/developer-tools/
Microsoft doesn't consider your use case to be common enough to optimize for, as with MessageBox. They expect you to lay out a dialog with many controls on it, perhaps with some complex interaction with the controls, and only respond once the dialog is fully filled in. What you're asking for is just the simplified version of that.
The resource editor is the easiest way to create a dialog, but that's not included in the free Express version of Visual Studio. You would design the dialog with a text control for the prompt and an edit control for the user to fill in. You present the dialog with the DialogBox Windows function, and it returns when the user hits the OK button or the X in the corner of the dialog. Microsoft has some documentation for it here.
There are a few platforms available that try to make the process easier, such as MFC, WTL, Qt, and wx, but this is how you'd do it with the pure Windows API.
My answer is based on Stephen Quan's answer to How to load & call a VBScript function from within C++? Added full UTF-8 support, as you can gather from the code comments in the CPP file. Unlike using Microsoft Script Control to create the InputBox, this can be used in x86 and x64 executables, libraries, and controls.
"inputbox.h":
extern "C" char *InputBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
extern "C" char *PasswordBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
"inputbox.cpp":
#include "inputbox.h"
// Windows API
#include <windows.h>
// VBScript InputBox
#include <atlbase.h>
#include <activscp.h>
#include <comdef.h>
// UTF-8 Support
#include <wchar.h>
#include <string>
#include <vector>
using std::string;
using std::wstring;
using std::vector;
static wstring StringWiden(string Str) {
const size_t wchar_tCount = Str.size() + 1;
vector<wchar_t> Buffer(wchar_tCount);
return wstring { Buffer.data(), (size_t)MultiByteToWideChar(CP_UTF8, 0, Str.c_str(), -1, Buffer.data(), wchar_tCount) };
}
static string StringShorten(wstring Str) {
int nBytes = (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), NULL, 0, NULL, NULL);
vector<char> Buffer((size_t)nBytes);
return string { Buffer.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), Buffer.data(), nBytes, NULL, NULL) };
}
static string StringReplaceAll(string Str, string SubStr, string NewStr) {
size_t Position = 0;
const size_t SubLen = SubStr.length(), NewLen = NewStr.length();
while ((Position = Str.find(SubStr, Position)) != string::npos) {
Str.replace(Position, SubLen, NewStr);
Position += NewLen;
}
return Str;
}
static string CPPNewLineToVBSNewLine(string NewLine) {
size_t Position = 0;
while (Position < NewLine.length()) {
if (NewLine[Position] == '\r' || NewLine[Position] == '\n')
NewLine.replace(Position, 2, "\" + vbNewLine + \"");
Position += 1;
}
return NewLine;
}
class CSimpleScriptSite :
public IActiveScriptSite,
public IActiveScriptSiteWindow {
public:
CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { }
// IUnknown
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);
// IActiveScriptSite
STDMETHOD(GetLCID)(LCID* plcid) { *plcid = 0; return S_OK; }
STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti) { return TYPE_E_ELEMENTNOTFOUND; }
STDMETHOD(GetDocVersionString)(BSTR* pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; }
STDMETHOD(OnScriptTerminate)(const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo) { return S_OK; }
STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; }
STDMETHOD(OnScriptError)(IActiveScriptError* pIActiveScriptError) { return S_OK; }
STDMETHOD(OnEnterScript)(void) { return S_OK; }
STDMETHOD(OnLeaveScript)(void) { return S_OK; }
// IActiveScriptSiteWindow
STDMETHOD(GetWindow)(HWND* phWnd) { *phWnd = m_hWnd; return S_OK; }
STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; }
// Miscellaneous
STDMETHOD(SetWindow)(HWND hWnd) { m_hWnd = hWnd; return S_OK; }
public:
LONG m_cRefCount;
HWND m_hWnd;
};
STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef() {
return InterlockedIncrement(&m_cRefCount);
}
STDMETHODIMP_(ULONG) CSimpleScriptSite::Release() {
if (!InterlockedDecrement(&m_cRefCount)) {
delete this;
return 0;
}
return m_cRefCount;
}
STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow) {
*ppvObject = (IActiveScriptSiteWindow*)this;
AddRef();
return NOERROR;
}
if (riid == IID_IActiveScriptSite) {
*ppvObject = (IActiveScriptSite*)this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
static HHOOK hHook = 0;
static bool HideInput = false;
static LRESULT CALLBACK InputBoxProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode < HC_ACTION)
return CallNextHookEx(hHook, nCode, wParam, lParam);
if (nCode = HCBT_ACTIVATE) {
if (HideInput == true) {
HWND TextBox = FindWindowExA((HWND)wParam, NULL, "Edit", NULL);
SendDlgItemMessageW((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, L'\x25cf', 0);
}
}
if (nCode = HCBT_CREATEWND) {
if (!(GetWindowLongPtr((HWND)wParam, GWL_STYLE) & WS_CHILD))
SetWindowLongPtr((HWND)wParam, GWL_EXSTYLE, GetWindowLongPtr((HWND)wParam, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
static char *InputBoxHelper(char *Prompt, char *Title, char *Default) {
// Initialize
HRESULT hr = S_OK;
hr = CoInitialize(NULL);
CSimpleScriptSite* pScriptSite = new CSimpleScriptSite();
CComPtr<IActiveScript> spVBScript;
CComPtr<IActiveScriptParse> spVBScriptParse;
hr = spVBScript.CoCreateInstance(OLESTR("VBScript"));
hr = spVBScript->SetScriptSite(pScriptSite);
hr = spVBScript->QueryInterface(&spVBScriptParse);
hr = spVBScriptParse->InitNew();
// Replace quotes with double quotes
string strPrompt = StringReplaceAll(Prompt, "\"", "\"\"");
string strTitle = StringReplaceAll(Title, "\"", "\"\"");
string strDefault = StringReplaceAll(Default, "\"", "\"\"");
// Create evaluation string
string Evaluation = "InputBox(\"" + strPrompt + "\", \"" + strTitle + "\", \"" + strDefault + "\")";
Evaluation = CPPNewLineToVBSNewLine(Evaluation);
wstring WideEval = StringWiden(Evaluation);
// Run InpuBox
CComVariant result;
EXCEPINFO ei = {};
DWORD ThreadID = GetCurrentThreadId();
HINSTANCE ModHwnd = GetModuleHandle(NULL);
hr = pScriptSite->SetWindow(GetAncestor(GetActiveWindow(), GA_ROOTOWNER));
hHook = SetWindowsHookEx(WH_CBT, &InputBoxProc, ModHwnd, ThreadID);
hr = spVBScriptParse->ParseScriptText(WideEval.c_str(), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei);
UnhookWindowsHookEx(hHook);
// Cleanup
spVBScriptParse = NULL;
spVBScript = NULL;
pScriptSite->Release();
pScriptSite = NULL;
CoUninitialize();
// Result
static string strResult;
_bstr_t bstrResult = (_bstr_t)result;
strResult = StringShorten((wchar_t*)bstrResult);
return (char*)strResult.c_str();
}
char *InputBox(char *Prompt, char *Title, char *Default) {
HideInput = false;
return InputBoxHelper(Prompt, Title, Default);
}
char *PasswordBox(char *Prompt, char *Title, char *Default) {
HideInput = true;
return InputBoxHelper(Prompt, Title, Default);
}
Create the two above files and then add them to your Visual Studio project.
In any file you want the input or password box functions, (found in the header), simply include the header:
#include "inputbox.h"
// use functions here
I also got rid of the default Windows application icon in the title bar of the VBScript InputBox, because a lot of people I've seen complain about how ugly it is to see that there.
Let me know if you have any questions.
I have to admit that I haven't really done much in the way of input boxes in ages, but you basically have to go outside C++ in order to get any kind of graphical input box. There's simply no mechanism built into the language for that kind of stuff for portability reasons. I don't remember if it applied to C++ as well, but C doesn't even assume you have a console. Anyway, your best bet would be something along the lines you were already trying: Win32 API, Qt, etc. If you can use the console, however, feel free to just use the iostream library to get the job done.
Using a console window is better suited to the mode of communication where a program prompts the user, continues, prompts the user again, and so on.
And for that you can use the standard library's facilities like cin and cout.
Unlike Visual Basic and other languages, there is no "built in" Input Box like command in c++. Unlike MessageBox that can be just invoked, InputBox() needs to be written. In fact, I have done so. The following article describes how to implement such InputBox as part of a small Static Library that can be used, with no Resources, from any Win32 c++ program. Source code at Github. It can be used as follow:
LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");
For example:
LPWSTR result = SG_InputBox::GetString(
L"Code Project Demo",
L"What is your name");
try this:
InputBox in c++ vs2010
#include "stdafx.h"
#using <system.windows.forms.dll>
#using <Microsoft.VisualBasic.dll>
using namespace System;
int main(array<System::String ^> ^args)
{
Microsoft::VisualBasic::Interaction::InputBox(L"Hello", L"Title", L"DefResp", 500, 500);
return 0;
}

How to get handles to all windows of another application

in my application i have timer, in TimerProc i want to get handles of all windows(main and child) of the another application that has focus. I have no idea how to do that because i don't understand functions like GetNextWindow or GetParent and Z-oder of windows and i can't find anywhere very detailed explanation of how this functions works(i dont understand explanation on msdn). Please can you give me some advice or block of code which do that? Many thanks for answer.
Use GetForegroundWindow() function - it returns the HWND of the window the user currently is working with.
Then having this handle you can retrieve childs in such a way:
HWND a_hWnd = (HWND)hParent;
HWND a_FirstChild = NULL;
a_FirstChild = ::GetWindow(a_hWnd, GW_CHILD);
if (a_FirstChild != NULL)
{
HWND a_NextChild = NULL;
do
{
a_NextChild = ::GetWindow(a_FirstChild, GW_HWNDNEXT);
if (a_NextChild != NULL)
{
a_FirstChild = a_NextChild;
}
}
while (a_NextChild != NULL);
}
GetForeGroundWindow to get the current foreground window/dialog
GetParent until you get NULL (that gets you to the top level window)**
EnumChildWindows to get to all the dependent windows
** Note that an application can have more than one top level window, though this isn't usual.
Code:
void Ccpp_testDlg::DoWalk ()
{
HWND hCurrent;
HWND hNew;
hCurrent = ::GetForegroundWindow ();
hNew = hCurrent;
while (hNew != NULL)
{
hNew = ::GetParent (hCurrent);
if (hNew != NULL)
{
hCurrent = hNew;
}
}
EnumChildWindows (hCurrent, EnumProc, 0);
}
BOOL CALLBACK EnumProc (HWND hwnd,LPARAM lParam)
{
TCHAR szText [MAX_PATH];
GetWindowText (hwnd, szText, sizeof(szText));
// do something with text
return TRUE;
}

MFC Open Folder Dialog

In MFC, is there an Open Folder Dialog? That is, rather than choosing a filename, it chooses a folder name? Ideally, I'd like it to be the way Visual Studio does it when navigating for a "Project Location" (when creating a new project), which looks very much like a normal file dialog. But I could make do with one of the vertical tree sort of interfaces if the former doesn't exist.
This code will get you a open folder dialog (this was taken from somewhere on the web but I don't really know where).
CString szSelectedFolder = _T("");
// This is the recommended way to select a directory
// in Win95 and NT4.
BROWSEINFO bi;
memset((LPVOID)&bi, 0, sizeof(bi));
TCHAR szDisplayName[_MAX_PATH];
szDisplayName[0] = '\0';
bi.hwndOwner = GetSafeHwnd();
bi.pidlRoot = NULL;
bi.pszDisplayName = szDisplayName;
bi.lpszTitle = _T("Select a folder");
bi.ulFlags = BIF_RETURNONLYFSDIRS;
// Set the callback function
bi.lpfn = BrowseCallbackProc;
LPITEMIDLIST pIIL = ::SHBrowseForFolder(&bi);
TCHAR szReturnedDir[_MAX_PATH];
BOOL bRet = ::SHGetPathFromIDList(pIIL, (TCHAR*)&szReturnedDir);
if (bRet)
{
if (szReturnedDir != _T(""))
{
szSelectedFolder = szReturnedDir;
}
LPMALLOC pMalloc;
HRESULT HR = SHGetMalloc(&pMalloc);
pMalloc->Free(pIIL);
pMalloc->Release();
}
you'll also have to implement this callback function:
TCHAR szInitialDir[_MAX_PATH];
// Set the initial path of the folder browser
int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
// Look for BFFM_INITIALIZED
if (uMsg == BFFM_INITIALIZED)
{
SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)szInitialDir);
}
return 0;
}