1
+ // Copyright (C) Microsoft Corporation. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ #include " stdafx.h"
6
+
7
+ #include " ScenarioSaveAs.h"
8
+
9
+ #include " App.h"
10
+ #include " AppWindow.h"
11
+ #include " CheckFailure.h"
12
+ #include " Shlwapi.h"
13
+ #include " TextInputDialog.h"
14
+ #include " resource.h"
15
+
16
+ using namespace Microsoft ::WRL;
17
+
18
+ ScenarioSaveAs::ScenarioSaveAs (AppWindow* appWindow)
19
+ : m_appWindow(appWindow), m_webView(appWindow->GetWebView ())
20
+ {
21
+ if (m_webView)
22
+ {
23
+ m_webView2Experimental25 = m_webView.try_query <ICoreWebView2Experimental25>();
24
+ }
25
+ }
26
+
27
+ std::initializer_list<COREWEBVIEW2_SAVE_AS_KIND> saveAsKind{
28
+ COREWEBVIEW2_SAVE_AS_KIND_DEFAULT, COREWEBVIEW2_SAVE_AS_KIND_HTML_ONLY,
29
+ COREWEBVIEW2_SAVE_AS_KIND_SINGLE_FILE, COREWEBVIEW2_SAVE_AS_KIND_COMPLETE};
30
+ // Sync with COREWEBVIEW2_SAVE_AS_KIND.
31
+ std::array<std::wstring, 4 > saveAsKindString{
32
+ L" DEFAULT" , L" HTML_ONLY" , L" SIGNLE_FILE" , L" COMPLETE" };
33
+ // Sync with COREWEBVIEW2_SAVE_AS_UI_RESULTS.
34
+ std::array<std::wstring, 5 > saveAsUIResultString{
35
+ L" SUCCESS" , L" INVALID_PATH" , L" FILE_ALREADY_EXISTS" , L" KIND_NOT_SUPPORTED" , L" CANCELLED" };
36
+
37
+ // ! [ToggleSilent]
38
+ // Turn on/off Silent SaveAs, which won't show the system default save as dialog.
39
+ // This example hides the default save as dialog and shows a customized dialog.
40
+ bool ScenarioSaveAs::ToggleSilent ()
41
+ {
42
+ if (!m_webView2Experimental25)
43
+ return false ;
44
+ m_silentSaveAs = !m_silentSaveAs;
45
+ if (m_silentSaveAs && m_saveAsUIShowingToken.value == 0 )
46
+ {
47
+ // Register a handler for the `SaveAsUIShowing` event.
48
+ m_webView2Experimental25->add_SaveAsUIShowing (
49
+ Callback<ICoreWebView2ExperimentalSaveAsUIShowingEventHandler>(
50
+ [this ](
51
+ ICoreWebView2* sender,
52
+ ICoreWebView2ExperimentalSaveAsUIShowingEventArgs* args) -> HRESULT
53
+ {
54
+ // Hide the system default save as dialog.
55
+ CHECK_FAILURE (args->put_SuppressDefaultDialog (TRUE ));
56
+
57
+ auto showCustomizedDialog = [this , args = wil::make_com_ptr (args)]
58
+ {
59
+ // Preview the content mime type, optional.
60
+ wil::unique_cotaskmem_string mimeType;
61
+ CHECK_FAILURE (args->get_ContentMimeType (&mimeType));
62
+
63
+ SaveAsDialog dialog (m_appWindow->GetMainWindow (), saveAsKind);
64
+ if (dialog.confirmed )
65
+ {
66
+ // Set the SaveAsFilePath, Kind, AllowReplace for the event
67
+ // args from this customized dialog inputs, optional. If nothing
68
+ // needs to input, the event args will provide default values.
69
+ CHECK_FAILURE (args->put_SaveAsFilePath (dialog.path .c_str ()));
70
+ CHECK_FAILURE (args->put_Kind (dialog.selectedKind ));
71
+ CHECK_FAILURE (args->put_AllowReplace (dialog.allowReplace ));
72
+
73
+ BOOL allowReplace;
74
+ CHECK_FAILURE (args->get_AllowReplace (&allowReplace));
75
+ wil::unique_cotaskmem_string path;
76
+ CHECK_FAILURE (args->get_SaveAsFilePath (&path));
77
+ COREWEBVIEW2_SAVE_AS_KIND selectedKind;
78
+ CHECK_FAILURE (args->get_Kind (&selectedKind));
79
+
80
+ // Preview silent save as event args inputs, optional.
81
+ MessageBox (
82
+ m_appWindow->GetMainWindow (),
83
+ (std::wstring (L" Content Mime Type: " ) + mimeType.get () + L" \n " +
84
+ L" Fullpath: " + path.get () + L" \n " + L" Allow Replace: " +
85
+ (allowReplace ? L" true" : L" false" ) + L" \n " +
86
+ L" Selected Save As Kind: " + saveAsKindString[selectedKind])
87
+ .c_str (),
88
+ L" Silent Save As Parameters Preview" , MB_OK);
89
+ }
90
+ else
91
+ {
92
+ // Save As cancelled from this customized dialog.
93
+ CHECK_FAILURE (args->put_Cancel (TRUE ));
94
+ }
95
+ };
96
+
97
+ wil::com_ptr<ICoreWebView2Deferral> deferral;
98
+ CHECK_FAILURE (args->GetDeferral (&deferral));
99
+
100
+ m_appWindow->RunAsync (
101
+ [deferral, showCustomizedDialog]()
102
+ {
103
+ showCustomizedDialog ();
104
+ CHECK_FAILURE (deferral->Complete ());
105
+ });
106
+ return S_OK;
107
+ })
108
+ .Get (),
109
+ &m_saveAsUIShowingToken);
110
+ }
111
+ else
112
+ {
113
+ // Unregister the handler for the `SaveAsUIShowing` event.
114
+ m_webView2Experimental25->remove_SaveAsUIShowing (m_saveAsUIShowingToken);
115
+ m_saveAsUIShowingToken.value = 0 ;
116
+ }
117
+ MessageBox (
118
+ m_appWindow->GetMainWindow (),
119
+ (m_silentSaveAs ? L" Silent Save As Enabled" : L" Silent Save As Disabled" ), L" Info" ,
120
+ MB_OK);
121
+ return true ;
122
+ }
123
+ // ! [ToggleSilent]
124
+
125
+ // ! [ProgrammaticSaveAs]
126
+ // Call ShowSaveAsUI method to trigger the programmatic save as.
127
+ bool ScenarioSaveAs::ProgrammaticSaveAs ()
128
+ {
129
+ if (!m_webView2Experimental25)
130
+ return false ;
131
+ m_webView2Experimental25->ShowSaveAsUI (
132
+ Callback<ICoreWebView2ExperimentalShowSaveAsUICompletedHandler>(
133
+ [this ](HRESULT errorCode, COREWEBVIEW2_SAVE_AS_UI_RESULT result) -> HRESULT
134
+ {
135
+ // Show ShowSaveAsUI returned result, optional.
136
+ MessageBox (
137
+ m_appWindow->GetMainWindow (),
138
+ (L" ShowSaveAsUI " + saveAsUIResultString[result]).c_str (), L" Info" , MB_OK);
139
+ return S_OK;
140
+ })
141
+ .Get ());
142
+ return true ;
143
+ }
144
+ // ! [ProgrammaticSaveAs]
145
+
146
+ bool ScenarioSaveAs::HandleWindowMessage (
147
+ HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result)
148
+ {
149
+ if (message == WM_COMMAND)
150
+ {
151
+ switch (LOWORD (wParam))
152
+ {
153
+ case IDM_SCENARIO_SAVE_AS_TOGGLE_SILENT:
154
+ {
155
+ return ToggleSilent ();
156
+ }
157
+ case IDM_SCENARIO_SAVE_AS_PROGRAMMATIC:
158
+ {
159
+ return ProgrammaticSaveAs ();
160
+ }
161
+ }
162
+ }
163
+ return false ;
164
+ }
165
+
166
+ ScenarioSaveAs::~ScenarioSaveAs ()
167
+ {
168
+ if (m_webView2Experimental25)
169
+ {
170
+ m_webView2Experimental25->remove_SaveAsUIShowing (m_saveAsUIShowingToken);
171
+ }
172
+ }
173
+
174
+ static INT_PTR CALLBACK DlgProcStatic (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
175
+ {
176
+ auto self = (SaveAsDialog*)GetWindowLongPtr (hDlg, GWLP_USERDATA);
177
+ switch (message)
178
+ {
179
+ case WM_INITDIALOG:
180
+ {
181
+ self = (SaveAsDialog*)lParam;
182
+ SetWindowLongPtr (hDlg, GWLP_USERDATA, (LONG_PTR)self);
183
+ HWND hwndList = GetDlgItem (hDlg, IDC_SAVE_AS_KIND);
184
+ for (COREWEBVIEW2_SAVE_AS_KIND kind : self->kinds )
185
+ {
186
+ SendMessage (hwndList, CB_ADDSTRING, kind, (LPARAM)saveAsKindString[kind].c_str ());
187
+ SendMessage (hwndList, CB_SETITEMDATA, kind, (LPARAM)kind);
188
+ }
189
+ SendMessage (hwndList, CB_SETCURSEL, 0 , 0 );
190
+ return (INT_PTR)TRUE ;
191
+ }
192
+ case WM_COMMAND:
193
+ {
194
+ if (LOWORD (wParam) == IDOK)
195
+ {
196
+ HWND hwndList = GetDlgItem (hDlg, IDC_SAVE_AS_KIND);
197
+
198
+ wchar_t path[MAX_PATH] = {};
199
+ int length = GetWindowTextLength (GetDlgItem (hDlg, IDC_EDIT_SAVE_AS_DIRECTORY)) +
200
+ GetWindowTextLength (GetDlgItem (hDlg, IDC_EDIT_SAVE_AS_FILENAME));
201
+ wchar_t directory[MAX_PATH] = {};
202
+ GetDlgItemText (hDlg, IDC_EDIT_SAVE_AS_DIRECTORY, directory, length + 1 );
203
+ wchar_t filename[MAX_PATH] = {};
204
+ GetDlgItemText (hDlg, IDC_EDIT_SAVE_AS_FILENAME, filename, length + 1 );
205
+ PathCombineW (path, directory, filename);
206
+ self->path = path;
207
+
208
+ self->allowReplace = IsDlgButtonChecked (hDlg, IDC_CHECK_SAVE_AS_ALLOW_REPLACE);
209
+
210
+ int index = (int )SendMessage (hwndList, CB_GETCURSEL, 0 , 0 );
211
+ self->selectedKind =
212
+ (COREWEBVIEW2_SAVE_AS_KIND)SendMessage (hwndList, CB_GETITEMDATA, index, 0 );
213
+
214
+ self->confirmed = true ;
215
+ }
216
+ if (LOWORD (wParam) == IDOK || LOWORD (wParam) == IDCANCEL)
217
+ {
218
+ EndDialog (hDlg, LOWORD (wParam));
219
+ return (INT_PTR)TRUE ;
220
+ }
221
+ break ;
222
+ }
223
+ case WM_NCDESTROY:
224
+ SetWindowLongPtr (hDlg, GWLP_USERDATA, NULL );
225
+ return (INT_PTR)TRUE ;
226
+ }
227
+ return (INT_PTR)FALSE ;
228
+ }
229
+
230
+ SaveAsDialog::SaveAsDialog (HWND parent, std::initializer_list<COREWEBVIEW2_SAVE_AS_KIND> kinds)
231
+ : kinds(kinds)
232
+ {
233
+ DialogBoxParam (
234
+ g_hInstance, MAKEINTRESOURCE (IDD_SAVE_CONTENT_AS), parent, DlgProcStatic, (LPARAM)this );
235
+ }
0 commit comments