summaryrefslogtreecommitdiffstats
path: root/widget/windows/filedialog/WinFileDialogChild.cpp
blob: a41018ff0e0866eb651ad3f6068b270cb89de77c (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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/widget/filedialog/WinFileDialogChild.h"

#include <combaseapi.h>
#include <objbase.h>
#include <shobjidl.h>

#include "mozilla/Assertions.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/widget/filedialog/WinFileDialogCommands.h"
#include "nsPrintfCString.h"

namespace mozilla::widget::filedialog {

/* extern */ mozilla::LazyLogModule sLogFileDialog("FileDialog");

WinFileDialogChild::WinFileDialogChild() {
  MOZ_LOG(sLogFileDialog, LogLevel::Info, ("%s %p", __PRETTY_FUNCTION__, this));
};

WinFileDialogChild::~WinFileDialogChild() {
  MOZ_LOG(sLogFileDialog, LogLevel::Info, ("%s %p", __PRETTY_FUNCTION__, this));
};

#define MOZ_ABORT_IF_ALREADY_USED()                                            \
  do {                                                                         \
    MOZ_RELEASE_ASSERT(                                                        \
        !mUsed, "called Show* twice on a single WinFileDialog instance");      \
    MOZ_LOG(                                                                   \
        sLogFileDialog, LogLevel::Info,                                        \
        ("%s %p: first call to a Show* function", __PRETTY_FUNCTION__, this)); \
    mUsed = true;                                                              \
  } while (0)

template <size_t N>
WinFileDialogChild::IPCResult WinFileDialogChild::MakeIpcFailure(
    HRESULT hr, const char (&what)[N]) {
  CrashReporter::RecordAnnotationU32(
      CrashReporter::Annotation::WindowsFileDialogErrorCode, hr);

  return IPC_FAIL(this, what);
}

#define MOZ_IPC_ENSURE_HRESULT_OK(hr, what)             \
  do {                                                  \
    MOZ_LOG(sLogFileDialog, LogLevel::Verbose,          \
            ("checking HRESULT for %s", what));         \
    HRESULT const _hr_ = (hr);                          \
    if (FAILED(_hr_)) {                                 \
      MOZ_LOG(sLogFileDialog, LogLevel::Error,          \
              ("HRESULT %8lX while %s", (hr), (what))); \
      return MakeIpcFailure(_hr_, (what));              \
    }                                                   \
  } while (0)

WinFileDialogChild::IPCResult WinFileDialogChild::RecvShowFileDialog(
    uintptr_t parentHwnd, FileDialogType type, nsTArray<Command> commands,
    FileResolver&& resolver) {
  MOZ_ABORT_IF_ALREADY_USED();

  SpawnFilePicker(HWND(parentHwnd), type, std::move(commands))
      ->Then(
          GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__,
          [resolver = std::move(resolver)](Maybe<Results> const& res) {
            resolver(res);
          },
          [self = RefPtr(this)](HRESULT hr) {
            // this doesn't need to be returned anywhere; it'll crash the
            // process as a side effect of construction
            self->MakeIpcFailure(hr, "SpawnFilePicker");
          });

  return IPC_OK();
}

WinFileDialogChild::IPCResult WinFileDialogChild::RecvShowFolderDialog(
    uintptr_t parentHwnd, nsTArray<Command> commands,
    FolderResolver&& resolver) {
  MOZ_ABORT_IF_ALREADY_USED();

  SpawnFolderPicker(HWND(parentHwnd), std::move(commands))
      ->Then(
          GetMainThreadSerialEventTarget(), __PRETTY_FUNCTION__,
          [resolver = std::move(resolver)](Maybe<nsString> const& res) {
            resolver(res);
          },
          [self = RefPtr(this), resolver](HRESULT hr) {
            // this doesn't need to be returned anywhere; it'll crash the
            // process as a side effect of construction
            self->MakeIpcFailure(hr, "SpawnFolderPicker");
          });

  return IPC_OK();
}

#undef MOZ_IPC_ENSURE_HRESULT_OK

void WinFileDialogChild::ProcessingError(Result aCode, const char* aReason) {
  detail::LogProcessingError(sLogFileDialog, this, aCode, aReason);
}

}  // namespace mozilla::widget::filedialog