1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
#include "ifile_dialog.h"
#define WIN32_LEAN_AND_MEAN
#include <zen/com_error.h>
#include <zen/com_ptr.h>
#include <Shobjidl.h>
#include <zen/scope_guard.h>
#include <string>
using namespace zen;
namespace
{
bool showFolderPickerImpl(HWND ownerWindow, //throw ComError; return "false" if cancelled by user
const wchar_t* defaultFolder, //optional!
const GUID* persistenceGuid, //
std::wstring& selectedFolder)
{
ComPtr<IFileDialog> fileDlg;
ZEN_COM_CHECK(::CoCreateInstance(CLSID_FileOpenDialog, //throw ComError
nullptr,
CLSCTX_ALL,
IID_PPV_ARGS(fileDlg.init())));
if (persistenceGuid)
ZEN_COM_CHECK(fileDlg->SetClientGuid(*persistenceGuid));
FILEOPENDIALOGOPTIONS dlgOptions = 0;
ZEN_COM_CHECK(fileDlg->GetOptions(&dlgOptions)); //throw ComError
ZEN_COM_CHECK(fileDlg->SetOptions(dlgOptions | FOS_PICKFOLDERS | FOS_NOVALIDATE | FOS_FORCEFILESYSTEM));
if (defaultFolder) //show last selection instead of top level if no default available
{
ComPtr<IShellItem> folderItem;
ZEN_COM_CHECK(::SHCreateItemFromParsingName(defaultFolder,
nullptr,
IID_PPV_ARGS(folderItem.init())));
ZEN_COM_CHECK(fileDlg->SetFolder(folderItem.get()));
}
try
{
ZEN_COM_CHECK(fileDlg->Show(ownerWindow)); //may fail with: HRESULT_FROM_WIN32(ERROR_CANCELLED)
}
catch (const ComError&) { return false; }
ComPtr<IShellItem> folderItem;
ZEN_COM_CHECK(fileDlg->GetResult(folderItem.init()));
LPWSTR folderPath = nullptr;
ZEN_COM_CHECK(folderItem->GetDisplayName(SIGDN_FILESYSPATH, &folderPath));
ZEN_ON_SCOPE_EXIT(::CoTaskMemFree(folderPath));
selectedFolder = folderPath;
return true;
}
wchar_t* allocString(const std::wstring& msg) //ownership passed
{
auto tmp = new wchar_t [msg.size() + 1]; //std::bad_alloc ?
::wmemcpy(tmp, msg.c_str(), msg.size() + 1); //include 0-termination
return tmp;
}
}
//##################################################################################################
void ifile::showFolderPicker(void* ownerWindow,
const wchar_t* defaultFolder,
const GuidProxy* guid,
wchar_t*& selectedFolder,
bool& cancelled,
wchar_t*& errorMsg)
{
selectedFolder = nullptr;
cancelled = false;
errorMsg = nullptr;
try
{
static_assert(sizeof(GuidProxy) == sizeof(GUID), "");
GUID winGuid = {};
if (guid)
::memcpy(&winGuid, guid, sizeof(GUID));
std::wstring folderPath;
if (showFolderPickerImpl(static_cast<HWND>(ownerWindow), defaultFolder, guid ? &winGuid : nullptr, folderPath)) //throw ComError
selectedFolder = allocString(folderPath);
else
cancelled = true;
}
catch (const ComError& e)
{
errorMsg = allocString(e.toString()); //std::bad_alloc ?
}
}
void ifile::freeString(const wchar_t* str)
{
delete [] str;
}
|