In my C++ Win 32 application, I am making a dialog to select a folder using IFileOpenDialog for this. Please see the code below:
HRESULT DialogService::CreateDialogToPickFolder(HWND hWnd)
{
IFileOpenDialog* pPickFolderDialog = NULL;
IShellItem* pPickedFolder = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pPickFolderDialog));
if (SUCCEEDED(hr))
{
DWORD dialogOptions;
hr = pPickFolderDialog->GetOptions(&dialogOptions);
if (SUCCEEDED(hr))
{
hr = pPickFolderDialog->SetOptions(dialogOptions | FOS_PICKFOLDERS);
if (SUCCEEDED(hr))
{
hr = pPickFolderDialog->Show(hWnd);
if (SUCCEEDED(hr))
{
hr = pPickFolderDialog->GetResult(&pPickedFolder);
if (SUCCEEDED(hr))
{
PWSTR pszFolderPath = NULL;
hr = pPickedFolder->GetDisplayName(SIGDN_FILESYSPATH, &pszFolderPath);
if (SUCCEEDED(hr))
{
// Some code...
}
}
pPickedFolder->Release();
}
}
}
pPickFolderDialog->Release();
}
return hr;
}
I can’t cope with the following problem. If I do not select a folder (the "Folder" field, in the dialog, empty) and click the "Select Folder" button (i.e. OK), the line of code
hr = pPickedFolder->GetDisplayName(SIGDN_FILESYSPATH, &pszFolderPath);
writes the path that was previously selected into pszFolderPath variable and the dialog closes. But I want to ensure that, in this case, the dialog remains on the screen and the value of pszFolderPath remains 0x00000000. Because the dialog should be closed only if the folder was really selected by the user, and the name of the selected folder is displayed in the "Folder" field of the dialog box. (Of course, if, to close the dialog, the user clicked the "Select Folder" button. It goes without saying.) What can I do to prevent the dialog from closing when I click the OK button when the folder is not selected? Help me please.
OnFileOk
event called just before the dialog is about to return with a result. It gives a chance to keep the dialog remain open. If you consider the folder path is invalid return S_FALSE
to prevent the dialog from closing.
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pPickFolderDialog->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// ...
hr = pPickFolderDialog->GetOptions(&dialogOptions);
// ...
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog * pfd)
{
// If the folder field is empty, return S_FALSE, the dialog should remain open.
// Check folder is selected or not here.
//return S_FALSE;
return S_OK;
};
It may require a parsing operation in OnFileOk
method to confirm the "Folder:" field is empty or not.
Refer to "Common Item Dialog".
UPDATE: Add code lines for checking path in the "Folder:" is empty or not. The following is an example using UIAutomation you can refer to.
#include <UIAutomation.h>
IUIAutomation *pClientUIA;
IUIAutomationElement *pRootElement;
BOOL IsPathEmpty(HWND hwnd)
{
HRESULT hr;
hr = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<void**>(&pClientUIA));
if (S_OK != hr)
{
printf("CoCreateInstance error: %d\n", GetLastError());
return FALSE;
}
hr = pClientUIA->ElementFromHandle(hwnd, &pRootElement);
if (S_OK != hr)
{
printf("ElementFromHandle error: %d\n", GetLastError());
return FALSE;
}
BSTR name;
hr = pRootElement->get_CurrentClassName(&name);
if (S_OK != hr)
{
printf("get_CurrentClassName error: %d\n", GetLastError());
return FALSE;
}
wprintf(L"Class Name: %s\n", name);
IUIAutomationCondition *pCondition;
VARIANT varProp;
varProp.vt = VT_I4;
varProp.uintVal = UIA_EditControlTypeId;
hr = pClientUIA->CreatePropertyCondition(UIA_ControlTypePropertyId, varProp, &pCondition);
if (S_OK != hr)
{
printf("CreatePropertyCondition error: %d\n", GetLastError());
return FALSE;
}
IUIAutomationElementArray *pElementFound;
hr = pRootElement->FindAll(TreeScope_Descendants, pCondition, &pElementFound);
if (S_OK != hr)
{
printf("CreatePropertyCondition error: %d\n", GetLastError());
return FALSE;
}
int eleCount;
pElementFound->get_Length(&eleCount);
for (int i = 0; i < eleCount; i++)
{
IUIAutomationElement *pElement;
hr = pElementFound->GetElement(i, &pElement);
if (S_OK != hr)
{
printf("CreatePropertyCondition error: %d\n", GetLastError());
return FALSE;
}
hr = pElement->get_CurrentName(&name);
if (S_OK != hr)
{
printf("CreatePropertyCondition error: %d\n", GetLastError());
return FALSE;
}
wprintf(L"Control Name: %s\n", name);
OutputDebugString(name);
if (0 == wcscmp(name, L"Folder:"))
{
VARIANT varPropText;
hr = pElement->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &varPropText);
if (S_OK != hr)
{
printf("CreatePropertyCondition error: %d\n", GetLastError());
return FALSE;
}
if (0 == wcscmp(varPropText.bstrVal, L""))
{
return TRUE;
}
}
}
return FALSE;
}
The OnFileOk
method can all IsPathEmpty
method like this:
// IFileDialogEvents methods
IFACEMETHODIMP OnFileOk(IFileDialog * pfd)
{
// If the folder field is empty, return S_FALSE, the dialog should remain open.
// Check folder is selected or not here.
//return S_FALSE;
IOleWindow *pWindow;
HRESULT hr = pfd->QueryInterface(IID_PPV_ARGS(&pWindow));
if (SUCCEEDED(hr))
{
HWND hwndDialog;
hr = pWindow->GetWindow(&hwndDialog);
if (SUCCEEDED(hr))
{
if (IsPathEmpty(hwndDialog))
return S_FALSE;
}
pWindow->Release();
}
return S_OK;
};
User contributions licensed under CC BY-SA 3.0