summaryrefslogtreecommitdiff
path: root/ui/IFileDialog_Vista/ifile_dialog.cpp
blob: 19dcbc5d112529f5bb6e98ff316b34717e1b1da0 (plain)
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;
}
bgstack15