main
cpp 363 lines 10.9 KB
Raw
1 // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3 #include "precomp.h"
4
5
6 // Exit macros
7 #define WnduExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
8 #define WnduExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
9 #define WnduExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
10 #define WnduExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
11 #define WnduExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
12 #define WnduExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_WNDUTIL, x, e, s, __VA_ARGS__)
13 #define WnduExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
14 #define WnduExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_WNDUTIL, p, x, e, s, __VA_ARGS__)
15 #define WnduExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, p, x, s, __VA_ARGS__)
16 #define WnduExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_WNDUTIL, p, x, e, s, __VA_ARGS__)
17 #define WnduExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, p, x, s, __VA_ARGS__)
18 #define WnduExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_WNDUTIL, e, x, s, __VA_ARGS__)
19 #define WnduExitOnOptionalXmlQueryFailure(x, b, s, ...) ExitOnOptionalXmlQueryFailureSource(DUTIL_SOURCE_WNDUTIL, x, b, s, __VA_ARGS__)
20 #define WnduExitOnRequiredXmlQueryFailure(x, s, ...) ExitOnRequiredXmlQueryFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
21 #define WnduExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_WNDUTIL, g, x, s, __VA_ARGS__)
22
23 struct MEMBUFFER_FOR_RICHEDIT
24 {
25 BYTE* rgbData;
26 DWORD cbData;
27
28 DWORD iData;
29 };
30
31 const DWORD GROW_WINDOW_TEXT = 250;
32
33
34 // prototypes
35 static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
36 __in DWORD_PTR dwCookie,
37 __in_bcount(cb) LPBYTE pbBuff,
38 __in LONG cb,
39 __in LONG *pcb
40 );
41 static DWORD CALLBACK RichEditStreamFromMemoryCallback(
42 __in DWORD_PTR dwCookie,
43 __in_bcount(cb) LPBYTE pbBuff,
44 __in LONG cb,
45 __in LONG *pcb
46 );
47
48
49 DAPI_(HRESULT) WnduLoadRichEditFromFile(
50 __in HWND hWnd,
51 __in_z LPCWSTR wzFileName,
52 __in HMODULE hModule
53 )
54 {
55 HRESULT hr = S_OK;
56 LPWSTR sczFile = NULL;
57 HANDLE hFile = INVALID_HANDLE_VALUE;
58
59 hr = PathRelativeToModule(&sczFile, wzFileName, hModule);
60 WnduExitOnFailure(hr, "Failed to read resource data.");
61
62 hFile = ::CreateFileW(sczFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
63 if (INVALID_HANDLE_VALUE == hFile)
64 {
65 WnduExitWithLastError(hr, "Failed to open RTF file.");
66 }
67 else
68 {
69 LONGLONG llRtfSize;
70 hr = FileSizeByHandle(hFile, &llRtfSize);
71 if (SUCCEEDED(hr))
72 {
73 ::SendMessageW(hWnd, EM_EXLIMITTEXT, 0, static_cast<LPARAM>(llRtfSize));
74 }
75
76 EDITSTREAM es = { };
77 es.pfnCallback = RichEditStreamFromFileHandleCallback;
78 es.dwCookie = reinterpret_cast<DWORD_PTR>(hFile);
79
80 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es));
81 hr = es.dwError;
82 WnduExitOnFailure(hr, "Failed to update RTF stream.");
83 }
84
85 LExit:
86 ReleaseStr(sczFile);
87 ReleaseFile(hFile);
88
89 return hr;
90 }
91
92 DAPI_(HRESULT) WnduLoadRichEditFromResource(
93 __in HWND hWnd,
94 __in_z LPCSTR szResourceName,
95 __in HMODULE hModule
96 )
97 {
98 HRESULT hr = S_OK;
99 MEMBUFFER_FOR_RICHEDIT buffer = { };
100 EDITSTREAM es = { };
101
102 hr = ResReadData(hModule, szResourceName, reinterpret_cast<LPVOID*>(&buffer.rgbData), &buffer.cbData);
103 WnduExitOnFailure(hr, "Failed to read resource data.");
104
105 es.pfnCallback = RichEditStreamFromMemoryCallback;
106 es.dwCookie = reinterpret_cast<DWORD_PTR>(&buffer);
107
108 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es));
109 hr = es.dwError;
110 WnduExitOnFailure(hr, "Failed to update RTF stream.");
111
112 LExit:
113 return hr;
114 }
115
116
117 DAPI_(HRESULT) WnduGetControlText(
118 __in HWND hWnd,
119 __inout_z LPWSTR* psczText
120 )
121 {
122 HRESULT hr = S_OK;
123 SIZE_T cbSize = 0;
124 DWORD cchText = 0;
125 DWORD cchTextRead = 0;
126
127 // Ensure the string has room for at least one character.
128 hr = StrMaxLength(*psczText, &cbSize);
129 WnduExitOnFailure(hr, "Failed to get text buffer length.");
130
131 cchText = (DWORD)min(DWORD_MAX, cbSize);
132
133 if (!cchText)
134 {
135 cchText = GROW_WINDOW_TEXT;
136
137 hr = StrAlloc(psczText, cchText);
138 WnduExitOnFailure(hr, "Failed to grow text buffer.");
139 }
140
141 // Read (and keep growing buffer) until we finally read less than there
142 // is room in the buffer.
143 for (;;)
144 {
145 cchTextRead = ::GetWindowTextW(hWnd, *psczText, cchText);
146 if (cchTextRead + 1 < cchText)
147 {
148 break;
149 }
150 else
151 {
152 cchText = cchTextRead + GROW_WINDOW_TEXT;
153
154 hr = StrAlloc(psczText, cchText);
155 WnduExitOnFailure(hr, "Failed to grow text buffer again.");
156 }
157 }
158
159 LExit:
160 return hr;
161 }
162
163
164 DAPI_(HRESULT) WnduShowOpenFileDialog(
165 __in_opt HWND hwndParent,
166 __in BOOL fForcePathExists,
167 __in BOOL fForceFileExists,
168 __in_opt LPCWSTR wzTitle,
169 __in COMDLG_FILTERSPEC* rgFilters,
170 __in DWORD cFilters,
171 __in DWORD dwDefaultFilter,
172 __in_opt LPCWSTR wzDefaultPath,
173 __inout LPWSTR* psczPath
174 )
175 {
176 HRESULT hr = S_OK;
177 IFileOpenDialog* pFileOpenDialog = NULL;
178 FILEOPENDIALOGOPTIONS fos = 0;
179 FILEOPENDIALOGOPTIONS additionalFlags = FOS_NOCHANGEDIR;
180 IShellItem* psi = NULL;
181 LPWSTR sczDefaultDirectory = NULL;
182 LPWSTR sczPath = NULL;
183
184 hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog));
185 WnduExitOnFailure(hr, "Failed to create FileOpenDialog object.");
186
187 hr = pFileOpenDialog->SetTitle(wzTitle);
188 WnduExitOnFailure(hr, "Failed to set FileOpenDialog title.");
189
190 hr = pFileOpenDialog->GetOptions(&fos);
191 WnduExitOnFailure(hr, "Failed to get FileOpenDialog options.");
192
193 if (fForcePathExists)
194 {
195 additionalFlags |= FOS_PATHMUSTEXIST;
196 }
197
198 if (fForceFileExists)
199 {
200 additionalFlags |= FOS_FILEMUSTEXIST;
201 }
202
203 hr = pFileOpenDialog->SetOptions(fos | additionalFlags);
204 WnduExitOnFailure(hr, "Failed to set FileOpenDialog options.");
205
206 hr = pFileOpenDialog->SetFileTypes(cFilters, rgFilters);
207 WnduExitOnFailure(hr, "Failed to set FileOpenDialog file types.");
208
209 hr = pFileOpenDialog->SetFileTypeIndex(dwDefaultFilter);
210 WnduExitOnFailure(hr, "Failed to set FileOpenDialog default file type.");
211
212 if (wzDefaultPath && *wzDefaultPath)
213 {
214 hr = PathGetDirectory(wzDefaultPath, &sczDefaultDirectory);
215 if (SUCCEEDED(hr))
216 {
217 hr = ::SHCreateItemFromParsingName(sczDefaultDirectory, NULL, IID_PPV_ARGS(&psi));
218 if (SUCCEEDED(hr))
219 {
220 hr = pFileOpenDialog->SetFolder(psi);
221 WnduExitOnFailure(hr, "Failed to set FileOpenDialog folder.");
222 }
223
224 ReleaseNullObject(psi);
225 }
226
227 hr = pFileOpenDialog->SetFileName(wzDefaultPath);
228 WnduExitOnFailure(hr, "Failed to set FileOpenDialog file name.");
229 }
230
231 hr = pFileOpenDialog->Show(hwndParent);
232 if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr)
233 {
234 ExitFunction();
235 }
236 WnduExitOnFailure(hr, "Failed to show FileOpenDialog for file.");
237
238 hr = pFileOpenDialog->GetResult(&psi);
239 WnduExitOnFailure(hr, "Failed to get FileOpenDialog result.");
240
241 hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath);
242 WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path.");
243
244 hr = StrAllocString(psczPath, sczPath, 0);
245 WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path.");
246
247 LExit:
248 if (sczPath)
249 {
250 ::CoTaskMemFree(sczPath);
251 }
252
253 ReleaseStr(sczDefaultDirectory);
254 ReleaseObject(psi);
255 ReleaseObject(pFileOpenDialog);
256
257 return hr;
258 }
259
260
261 DAPI_(HRESULT) WnduShowOpenFolderDialog(
262 __in_opt HWND hwndParent,
263 __in BOOL fForceFileSystem,
264 __in_opt LPCWSTR wzTitle,
265 __inout LPWSTR* psczPath
266 )
267 {
268 HRESULT hr = S_OK;
269 IFileOpenDialog* pFileOpenDialog = NULL;
270 FILEOPENDIALOGOPTIONS fos = 0;
271 FILEOPENDIALOGOPTIONS additionalFlags = FOS_PICKFOLDERS | FOS_NOCHANGEDIR;
272 IShellItem* psi = NULL;
273 LPWSTR sczPath = NULL;
274
275 hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpenDialog));
276 WnduExitOnFailure(hr, "Failed to create FileOpenDialog object.");
277
278 hr = pFileOpenDialog->SetTitle(wzTitle);
279 WnduExitOnFailure(hr, "Failed to set FileOpenDialog title.");
280
281 hr = pFileOpenDialog->GetOptions(&fos);
282 WnduExitOnFailure(hr, "Failed to get FileOpenDialog options.");
283
284 if (fForceFileSystem)
285 {
286 additionalFlags |= FOS_FORCEFILESYSTEM;
287 }
288
289 hr = pFileOpenDialog->SetOptions(fos | additionalFlags);
290 WnduExitOnFailure(hr, "Failed to set FileOpenDialog options.");
291
292 hr = pFileOpenDialog->Show(hwndParent);
293 if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr)
294 {
295 ExitFunction();
296 }
297 WnduExitOnFailure(hr, "Failed to show FileOpenDialog for folder.");
298
299 hr = pFileOpenDialog->GetResult(&psi);
300 WnduExitOnFailure(hr, "Failed to get FileOpenDialog result.");
301
302 hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &sczPath);
303 WnduExitOnFailure(hr, "Failed to get FileOpenDialog result path.");
304
305 hr = StrAllocString(psczPath, sczPath, 0);
306 WnduExitOnFailure(hr, "Failed to copy FileOpenDialog result path.");
307
308 LExit:
309 if (sczPath)
310 {
311 ::CoTaskMemFree(sczPath);
312 }
313
314 ReleaseObject(psi);
315 ReleaseObject(pFileOpenDialog);
316
317 return hr;
318 }
319
320
321 static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
322 __in DWORD_PTR dwCookie,
323 __in_bcount(cb) LPBYTE pbBuff,
324 __in LONG cb,
325 __in LONG* pcb
326 )
327 {
328 HRESULT hr = S_OK;
329 HANDLE hFile = reinterpret_cast<HANDLE>(dwCookie);
330
331 if (!::ReadFile(hFile, pbBuff, cb, reinterpret_cast<DWORD*>(pcb), NULL))
332 {
333 WnduExitWithLastError(hr, "Failed to read file");
334 }
335
336 LExit:
337 return hr;
338 }
339
340
341 static DWORD CALLBACK RichEditStreamFromMemoryCallback(
342 __in DWORD_PTR dwCookie,
343 __in_bcount(cb) LPBYTE pbBuff,
344 __in LONG cb,
345 __in LONG* pcb
346 )
347 {
348 HRESULT hr = S_OK;
349 MEMBUFFER_FOR_RICHEDIT* pBuffer = reinterpret_cast<MEMBUFFER_FOR_RICHEDIT*>(dwCookie);
350 DWORD cbCopy = 0;
351
352 if (pBuffer->iData < pBuffer->cbData)
353 {
354 cbCopy = min(static_cast<DWORD>(cb), pBuffer->cbData - pBuffer->iData);
355 memcpy(pbBuff, pBuffer->rgbData + pBuffer->iData, cbCopy);
356
357 pBuffer->iData += cbCopy;
358 Assert(pBuffer->iData <= pBuffer->cbData);
359 }
360
361 *pcb = cbCopy;
362 return hr;
363 }