main.cpp (c2c66aff) main.cpp (7b718d36)
1/* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.

--- 6 unchanged lines hidden (view full) ---

15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18#include "shellext.h"
19#include <windows.h>
20#include <commctrl.h>
21#include <strsafe.h>
22#include <stddef.h>
1/* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.

--- 6 unchanged lines hidden (view full) ---

15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18#include "shellext.h"
19#include <windows.h>
20#include <commctrl.h>
21#include <strsafe.h>
22#include <stddef.h>
23#include <stdexcept>
23#include "factory.h"
24#include "resource.h"
25
26static const GUID CLSID_ShellBtrfsIconHandler = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf0 } };
27static const GUID CLSID_ShellBtrfsContextMenu = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf1 } };
28static const GUID CLSID_ShellBtrfsPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf2 } };
29static const GUID CLSID_ShellBtrfsVolPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf3 } };
30

--- 10 unchanged lines hidden (view full) ---

41} PROCESS_DPI_AWARENESS;
42
43typedef ULONG (WINAPI *_RtlNtStatusToDosError)(NTSTATUS Status);
44typedef HRESULT (WINAPI *_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value);
45
46HMODULE module;
47LONG objs_loaded = 0;
48
24#include "factory.h"
25#include "resource.h"
26
27static const GUID CLSID_ShellBtrfsIconHandler = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf0 } };
28static const GUID CLSID_ShellBtrfsContextMenu = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf1 } };
29static const GUID CLSID_ShellBtrfsPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf2 } };
30static const GUID CLSID_ShellBtrfsVolPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf3 } };
31

--- 10 unchanged lines hidden (view full) ---

42} PROCESS_DPI_AWARENESS;
43
44typedef ULONG (WINAPI *_RtlNtStatusToDosError)(NTSTATUS Status);
45typedef HRESULT (WINAPI *_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value);
46
47HMODULE module;
48LONG objs_loaded = 0;
49
49void ShowError(HWND hwnd, ULONG err) {
50 WCHAR* buf;
51
52 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
53 err, 0, (WCHAR*)&buf, 0, NULL) == 0) {
54 MessageBoxW(hwnd, L"FormatMessage failed", L"Error", MB_ICONERROR);
55 return;
56 }
57
58 MessageBoxW(hwnd, buf, L"Error", MB_ICONERROR);
59
60 LocalFree(buf);
61}
62
63void ShowStringError(HWND hwndDlg, int num, ...) {
64 WCHAR title[255], s[1024], t[1024];
65 va_list ap;
66
67 if (!LoadStringW(module, IDS_ERROR, title, sizeof(title) / sizeof(WCHAR))) {
68 ShowError(hwndDlg, GetLastError());
69 return;
70 }
71
72 if (!LoadStringW(module, num, s, sizeof(s) / sizeof(WCHAR))) {
73 ShowError(hwndDlg, GetLastError());
74 return;
75 }
76
77 va_start(ap, num);
78#ifndef __REACTOS__
79 vswprintf(t, sizeof(t) / sizeof(WCHAR), s, ap);
80#else
81 vsnwprintf(t, sizeof(t) / sizeof(WCHAR), s, ap);
82#endif
83
84 MessageBoxW(hwndDlg, t, title, MB_ICONERROR);
85
86 va_end(ap);
87}
88
89void ShowNtStatusError(HWND hwnd, NTSTATUS Status) {
90 _RtlNtStatusToDosError RtlNtStatusToDosError;
91 HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
92
93 if (!ntdll) {
94 MessageBoxW(hwnd, L"Error loading ntdll.dll", L"Error", MB_ICONERROR);
95 return;
96 }
97
98 RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(ntdll, "RtlNtStatusToDosError");
99
100 if (!RtlNtStatusToDosError) {
101 MessageBoxW(hwnd, L"Error loading RtlNtStatusToDosError in ntdll.dll", L"Error", MB_ICONERROR);
102 FreeLibrary(ntdll);
103 return;
104 }
105
106 ShowError(hwnd, RtlNtStatusToDosError(Status));
107
108 FreeLibrary(ntdll);
109}
110
111void set_dpi_aware() {
112 _SetProcessDpiAwareness SetProcessDpiAwareness;
113 HMODULE shcore = LoadLibraryW(L"shcore.dll");
114
115 if (!shcore)
116 return;
117
118 SetProcessDpiAwareness = (_SetProcessDpiAwareness)GetProcAddress(shcore, "SetProcessDpiAwareness");
119
120 if (!SetProcessDpiAwareness)
121 return;
122
123 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
124}
125
50void set_dpi_aware() {
51 _SetProcessDpiAwareness SetProcessDpiAwareness;
52 HMODULE shcore = LoadLibraryW(L"shcore.dll");
53
54 if (!shcore)
55 return;
56
57 SetProcessDpiAwareness = (_SetProcessDpiAwareness)GetProcAddress(shcore, "SetProcessDpiAwareness");
58
59 if (!SetProcessDpiAwareness)
60 return;
61
62 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
63}
64
126void format_size(UINT64 size, WCHAR* s, ULONG len, BOOL show_bytes) {
127 WCHAR nb[255], nb2[255], t[255], bytes[255];
128 WCHAR kb[255];
65void format_size(uint64_t size, wstring& s, bool show_bytes) {
66 wstring t, bytes, kb, nb;
67 WCHAR nb2[255];
129 ULONG sr;
130 float f;
131 NUMBERFMTW fmt;
68 ULONG sr;
69 float f;
70 NUMBERFMTW fmt;
132 WCHAR thou[4], grouping[64], *c;
71 WCHAR dec[2], thou[4], grouping[64], *c;
72#ifdef __REACTOS__
73 WCHAR buffer[64];
74#endif
133
75
134 _i64tow(size, nb, 10);
76#ifndef __REACTOS__
77 nb = to_wstring(size);
78#else
79 swprintf(buffer, L"%I64d", size);
80 nb = wstring(buffer);
81#endif
135
136 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thou, sizeof(thou) / sizeof(WCHAR));
137
82
83 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thou, sizeof(thou) / sizeof(WCHAR));
84
85 dec[0] = '.'; dec[1] = 0; // not used, but silences gcc warning
86
138 fmt.NumDigits = 0;
139 fmt.LeadingZero = 1;
87 fmt.NumDigits = 0;
88 fmt.LeadingZero = 1;
140 fmt.lpDecimalSep = (LPWSTR)L"."; // not used
89 fmt.lpDecimalSep = dec;
141 fmt.lpThousandSep = thou;
142 fmt.NegativeOrder = 0;
143
144 // Grouping code copied from dlls/shlwapi/string.c in Wine - thank you
145
146 fmt.Grouping = 0;
147 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping) / sizeof(WCHAR));
148

--- 7 unchanged lines hidden (view full) ---

156 c++;
157 }
158
159 if (fmt.Grouping % 10 == 0)
160 fmt.Grouping /= 10;
161 else
162 fmt.Grouping *= 10;
163
90 fmt.lpThousandSep = thou;
91 fmt.NegativeOrder = 0;
92
93 // Grouping code copied from dlls/shlwapi/string.c in Wine - thank you
94
95 fmt.Grouping = 0;
96 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, grouping, sizeof(grouping) / sizeof(WCHAR));
97

--- 7 unchanged lines hidden (view full) ---

105 c++;
106 }
107
108 if (fmt.Grouping % 10 == 0)
109 fmt.Grouping /= 10;
110 else
111 fmt.Grouping *= 10;
112
164 GetNumberFormatW(LOCALE_USER_DEFAULT, 0, nb, &fmt, nb2, sizeof(nb2) / sizeof(WCHAR));
113 GetNumberFormatW(LOCALE_USER_DEFAULT, 0, nb.c_str(), &fmt, nb2, sizeof(nb2) / sizeof(WCHAR));
165
166 if (size < 1024) {
114
115 if (size < 1024) {
167 if (!LoadStringW(module, size == 1 ? IDS_SIZE_BYTE : IDS_SIZE_BYTES, t, sizeof(t) / sizeof(WCHAR))) {
168 ShowError(NULL, GetLastError());
169 return;
170 }
116 if (!load_string(module, size == 1 ? IDS_SIZE_BYTE : IDS_SIZE_BYTES, t))
117 throw last_error(GetLastError());
171
118
172 if (StringCchPrintfW(s, len, t, nb2) == STRSAFE_E_INSUFFICIENT_BUFFER) {
173 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
174 return;
175 }
176
119 wstring_sprintf(s, t, nb2);
177 return;
178 }
179
180 if (show_bytes) {
120 return;
121 }
122
123 if (show_bytes) {
181 if (!LoadStringW(module, IDS_SIZE_BYTES, t, sizeof(t) / sizeof(WCHAR))) {
182 ShowError(NULL, GetLastError());
183 return;
184 }
124 if (!load_string(module, IDS_SIZE_BYTES, t))
125 throw last_error(GetLastError());
185
126
186 if (StringCchPrintfW(bytes, sizeof(bytes) / sizeof(WCHAR), t, nb2) == STRSAFE_E_INSUFFICIENT_BUFFER) {
187 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
188 return;
189 }
127 wstring_sprintf(bytes, t, nb2);
190 }
191
192 if (size >= 1152921504606846976) {
193 sr = IDS_SIZE_EB;
194 f = (float)size / 1152921504606846976.0f;
195 } else if (size >= 1125899906842624) {
196 sr = IDS_SIZE_PB;
197 f = (float)size / 1125899906842624.0f;

--- 6 unchanged lines hidden (view full) ---

204 } else if (size >= 1048576) {
205 sr = IDS_SIZE_MB;
206 f = (float)size / 1048576.0f;
207 } else {
208 sr = IDS_SIZE_KB;
209 f = (float)size / 1024.0f;
210 }
211
128 }
129
130 if (size >= 1152921504606846976) {
131 sr = IDS_SIZE_EB;
132 f = (float)size / 1152921504606846976.0f;
133 } else if (size >= 1125899906842624) {
134 sr = IDS_SIZE_PB;
135 f = (float)size / 1125899906842624.0f;

--- 6 unchanged lines hidden (view full) ---

142 } else if (size >= 1048576) {
143 sr = IDS_SIZE_MB;
144 f = (float)size / 1048576.0f;
145 } else {
146 sr = IDS_SIZE_KB;
147 f = (float)size / 1024.0f;
148 }
149
212 if (!LoadStringW(module, sr, t, sizeof(t) / sizeof(WCHAR))) {
213 ShowError(NULL, GetLastError());
214 return;
215 }
150 if (!load_string(module, sr, t))
151 throw last_error(GetLastError());
216
217 if (show_bytes) {
152
153 if (show_bytes) {
218 if (StringCchPrintfW(kb, sizeof(kb) / sizeof(WCHAR), t, f) == STRSAFE_E_INSUFFICIENT_BUFFER) {
219 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
220 return;
221 }
154 wstring_sprintf(kb, t, f);
222
155
223 if (!LoadStringW(module, IDS_SIZE_LARGE, t, sizeof(t) / sizeof(WCHAR))) {
224 ShowError(NULL, GetLastError());
225 return;
226 }
156 if (!load_string(module, IDS_SIZE_LARGE, t))
157 throw last_error(GetLastError());
227
158
228 if (StringCchPrintfW(s, len, t, kb, bytes) == STRSAFE_E_INSUFFICIENT_BUFFER) {
229 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
230 return;
231 }
232 } else {
233 if (StringCchPrintfW(s, len, t, f) == STRSAFE_E_INSUFFICIENT_BUFFER) {
234 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
235 return;
236 }
237 }
159 wstring_sprintf(s, t, kb.c_str(), bytes.c_str());
160 } else
161 wstring_sprintf(s, t, f);
238}
239
162}
163
240std::wstring format_message(ULONG last_error) {
164wstring format_message(ULONG last_error) {
241 WCHAR* buf;
165 WCHAR* buf;
242 std::wstring s;
166 wstring s;
243
167
244 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
245 last_error, 0, (WCHAR*)&buf, 0, NULL) == 0) {
168 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
169 last_error, 0, (WCHAR*)&buf, 0, nullptr) == 0) {
246 return L"(error retrieving message)";
247 }
248
249 s = buf;
250
251 LocalFree(buf);
252
253 // remove trailing newline
254 while (s.length() > 0 && (s.substr(s.length() - 1, 1) == L"\r" || s.substr(s.length() - 1, 1) == L"\n"))
255 s = s.substr(0, s.length() - 1);
256
257 return s;
258}
259
170 return L"(error retrieving message)";
171 }
172
173 s = buf;
174
175 LocalFree(buf);
176
177 // remove trailing newline
178 while (s.length() > 0 && (s.substr(s.length() - 1, 1) == L"\r" || s.substr(s.length() - 1, 1) == L"\n"))
179 s = s.substr(0, s.length() - 1);
180
181 return s;
182}
183
260std::wstring format_ntstatus(NTSTATUS Status) {
184wstring format_ntstatus(NTSTATUS Status) {
261 _RtlNtStatusToDosError RtlNtStatusToDosError;
185 _RtlNtStatusToDosError RtlNtStatusToDosError;
262 std::wstring s;
186 wstring s;
263 HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
264
265 if (!ntdll)
266 return L"(error loading ntdll.dll)";
267
268 RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(ntdll, "RtlNtStatusToDosError");
269
270 if (!RtlNtStatusToDosError) {
271 FreeLibrary(ntdll);
272 return L"(error loading RtlNtStatusToDosError)";
273 }
274
275 s = format_message(RtlNtStatusToDosError(Status));
276
277 FreeLibrary(ntdll);
278
279 return s;
280}
281
187 HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
188
189 if (!ntdll)
190 return L"(error loading ntdll.dll)";
191
192 RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(ntdll, "RtlNtStatusToDosError");
193
194 if (!RtlNtStatusToDosError) {
195 FreeLibrary(ntdll);
196 return L"(error loading RtlNtStatusToDosError)";
197 }
198
199 s = format_message(RtlNtStatusToDosError(Status));
200
201 FreeLibrary(ntdll);
202
203 return s;
204}
205
282#ifdef __cplusplus
283extern "C" {
206bool load_string(HMODULE module, UINT id, wstring& s) {
207 int len;
208 LPWSTR retstr = nullptr;
209
210 len = LoadStringW(module, id, (LPWSTR)&retstr, 0);
211
212 if (len == 0)
213 return false;
214
215 s = wstring(retstr, len);
216
217 return true;
218}
219
220#ifdef _MSC_VER
221#pragma warning(push)
222#pragma warning(disable: 4996)
284#endif
285
223#endif
224
286STDAPI DllCanUnloadNow(void) {
225void wstring_sprintf(wstring& s, wstring fmt, ...) {
226 int len;
227 va_list args;
228
229 va_start(args, fmt);
230 len = _vsnwprintf(nullptr, 0, fmt.c_str(), args);
231
232 if (len == 0)
233 s = L"";
234 else {
235 s.resize(len);
236 _vsnwprintf((wchar_t*)s.c_str(), len, fmt.c_str(), args);
237 }
238
239 va_end(args);
240}
241
242#ifdef _MSC_VER
243#pragma warning(pop)
244#endif
245
246extern "C" STDAPI DllCanUnloadNow(void) {
287 return objs_loaded == 0 ? S_OK : S_FALSE;
288}
289
247 return objs_loaded == 0 ? S_OK : S_FALSE;
248}
249
290STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
250extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
291 if (rclsid == CLSID_ShellBtrfsIconHandler) {
292 Factory* fact = new Factory;
293 if (!fact)
294 return E_OUTOFMEMORY;
295 else {
296 fact->type = FactoryIconHandler;
297
298 return fact->QueryInterface(riid, ppv);

--- 25 unchanged lines hidden (view full) ---

324
325 return fact->QueryInterface(riid, ppv);
326 }
327 }
328
329 return CLASS_E_CLASSNOTAVAILABLE;
330}
331
251 if (rclsid == CLSID_ShellBtrfsIconHandler) {
252 Factory* fact = new Factory;
253 if (!fact)
254 return E_OUTOFMEMORY;
255 else {
256 fact->type = FactoryIconHandler;
257
258 return fact->QueryInterface(riid, ppv);

--- 25 unchanged lines hidden (view full) ---

284
285 return fact->QueryInterface(riid, ppv);
286 }
287 }
288
289 return CLASS_E_CLASSNOTAVAILABLE;
290}
291
332static BOOL write_reg_key(HKEY root, const WCHAR* keyname, const WCHAR* val, DWORD type, const BYTE* data, DWORD datasize) {
292static void write_reg_key(HKEY root, const wstring& keyname, const WCHAR* val, const wstring& data) {
333 LONG l;
334 HKEY hk;
335 DWORD dispos;
336
293 LONG l;
294 HKEY hk;
295 DWORD dispos;
296
337 l = RegCreateKeyExW(root, keyname, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, &dispos);
338 if (l != ERROR_SUCCESS) {
339 WCHAR s[255];
340 wsprintfW(s, L"RegCreateKey returned %08x", l);
341 MessageBoxW(0, s, NULL, MB_ICONERROR);
297 l = RegCreateKeyExW(root, keyname.c_str(), 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hk, &dispos);
298 if (l != ERROR_SUCCESS)
299 throw string_error(IDS_REGCREATEKEY_FAILED, l);
342
300
343 return FALSE;
344 }
301 l = RegSetValueExW(hk, val, 0, REG_SZ, (const BYTE*)data.c_str(), (data.length() + 1) * sizeof(WCHAR));
302 if (l != ERROR_SUCCESS)
303 throw string_error(IDS_REGSETVALUEEX_FAILED, l);
345
304
346 l = RegSetValueExW(hk, val, 0, type, data, datasize);
347 if (l != ERROR_SUCCESS) {
348 WCHAR s[255];
349 wsprintfW(s, L"RegSetValueEx returned %08x", l);
350 MessageBoxW(0, s, NULL, MB_ICONERROR);
351
352 return FALSE;
353 }
354
355 l = RegCloseKey(hk);
305 l = RegCloseKey(hk);
356 if (l != ERROR_SUCCESS) {
357 WCHAR s[255];
358 wsprintfW(s, L"RegCloseKey returned %08x", l);
359 MessageBoxW(0, s, NULL, MB_ICONERROR);
360
361 return FALSE;
362 }
363
364 return TRUE;
306 if (l != ERROR_SUCCESS)
307 throw string_error(IDS_REGCLOSEKEY_FAILED, l);
365}
366
308}
309
367static BOOL register_clsid(const GUID clsid, const WCHAR* description) {
310static void register_clsid(const GUID clsid, const WCHAR* description) {
368 WCHAR* clsidstring;
311 WCHAR* clsidstring;
369 WCHAR inproc[MAX_PATH], progid[MAX_PATH], clsidkeyname[MAX_PATH], dllpath[MAX_PATH];
370 BOOL ret = FALSE;
312 wstring inproc, progid, clsidkeyname;
313 WCHAR dllpath[MAX_PATH];
371
372 StringFromCLSID(clsid, &clsidstring);
373
314
315 StringFromCLSID(clsid, &clsidstring);
316
374 wsprintfW(inproc, L"CLSID\\%s\\InprocServer32", clsidstring);
375 wsprintfW(progid, L"CLSID\\%s\\ProgId", clsidstring);
376 wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring);
317 try {
318#ifndef __REACTOS__
319 inproc = L"CLSID\\"s + clsidstring + L"\\InprocServer32"s;
320 progid = L"CLSID\\"s + clsidstring + L"\\ProgId"s;
321 clsidkeyname = L"CLSID\\"s + clsidstring;
322#else
323 inproc = wstring(L"CLSID\\") + clsidstring + wstring(L"\\InprocServer32");
324 progid = wstring(L"CLSID\\") + clsidstring + wstring(L"\\ProgId");
325 clsidkeyname = wstring(L"CLSID\\") + clsidstring;
326#endif
377
327
378 if (!write_reg_key(HKEY_CLASSES_ROOT, clsidkeyname, NULL, REG_SZ, (BYTE*)description, (wcslen(description) + 1) * sizeof(WCHAR)))
379 goto end;
328 write_reg_key(HKEY_CLASSES_ROOT, clsidkeyname, nullptr, description);
380
329
381 GetModuleFileNameW(module, dllpath, sizeof(dllpath));
330 GetModuleFileNameW(module, dllpath, sizeof(dllpath));
382
331
383 if (!write_reg_key(HKEY_CLASSES_ROOT, inproc, NULL, REG_SZ, (BYTE*)dllpath, (wcslen(dllpath) + 1) * sizeof(WCHAR)))
384 goto end;
332 write_reg_key(HKEY_CLASSES_ROOT, inproc, nullptr, dllpath);
385
333
386 if (!write_reg_key(HKEY_CLASSES_ROOT, inproc, L"ThreadingModel", REG_SZ, (BYTE*)L"Apartment", (wcslen(L"Apartment") + 1) * sizeof(WCHAR)))
387 goto end;
334 write_reg_key(HKEY_CLASSES_ROOT, inproc, L"ThreadingModel", L"Apartment");
335 } catch (...) {
336 CoTaskMemFree(clsidstring);
337 throw;
338 }
388
339
389 ret = TRUE;
390
391end:
392 CoTaskMemFree(clsidstring);
340 CoTaskMemFree(clsidstring);
393
394 return ret;
395}
396
341}
342
397static BOOL unregister_clsid(const GUID clsid) {
343static void unregister_clsid(const GUID clsid) {
398 WCHAR* clsidstring;
344 WCHAR* clsidstring;
399 WCHAR clsidkeyname[MAX_PATH];
400 BOOL ret = FALSE;
401 LONG l;
402
403 StringFromCLSID(clsid, &clsidstring);
345
346 StringFromCLSID(clsid, &clsidstring);
404 wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring);
405
347
406 l = RegDeleteTreeW(HKEY_CLASSES_ROOT, clsidkeyname);
348 try {
349 WCHAR clsidkeyname[MAX_PATH];
407
350
408 if (l != ERROR_SUCCESS) {
409 WCHAR s[255];
410 wsprintfW(s, L"RegDeleteTree returned %08x", l);
411 MessageBoxW(0, s, NULL, MB_ICONERROR);
351 wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring);
412
352
413 ret = FALSE;
414 } else
415 ret = TRUE;
353 LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, clsidkeyname);
416
354
417 CoTaskMemFree(clsidstring);
355 if (l != ERROR_SUCCESS)
356 throw string_error(IDS_REGDELETETREE_FAILED, l);
357 } catch (...) {
358 CoTaskMemFree(clsidstring);
359 throw;
360 }
418
361
419 return ret;
362 CoTaskMemFree(clsidstring);
420}
421
363}
364
422static BOOL reg_icon_overlay(const GUID clsid, const WCHAR* name) {
423 WCHAR path[MAX_PATH];
365static void reg_icon_overlay(const GUID clsid, const wstring& name) {
424 WCHAR* clsidstring;
366 WCHAR* clsidstring;
425 BOOL ret = FALSE;
426
427 StringFromCLSID(clsid, &clsidstring);
428
367
368 StringFromCLSID(clsid, &clsidstring);
369
429 wcscpy(path, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\");
430 wcscat(path, name);
370 try {
371#ifndef __REACTOS__
372 wstring path = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s + name;
373#else
374 wstring path = wstring(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name;
375#endif
431
376
432 if (!write_reg_key(HKEY_LOCAL_MACHINE, path, NULL, REG_SZ, (BYTE*)clsidstring, (wcslen(clsidstring) + 1) * sizeof(WCHAR)))
433 goto end;
377 write_reg_key(HKEY_LOCAL_MACHINE, path, nullptr, clsidstring);
378 } catch (...) {
379 CoTaskMemFree(clsidstring);
380 throw;
381 }
434
382
435 ret = TRUE;
436
437end:
438 CoTaskMemFree(clsidstring);
383 CoTaskMemFree(clsidstring);
439
440 return ret;
441}
442
384}
385
443static BOOL unreg_icon_overlay(const WCHAR* name) {
444 WCHAR path[MAX_PATH];
445 LONG l;
386static void unreg_icon_overlay(const wstring& name) {
387#ifndef __REACTOS__
388 wstring path = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s + name;
389#else
390 wstring path = wstring(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name;
391#endif
446
392
447 wcscpy(path, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\");
448 wcscat(path, name);
393 LONG l = RegDeleteTreeW(HKEY_LOCAL_MACHINE, path.c_str());
449
394
450 l = RegDeleteTreeW(HKEY_LOCAL_MACHINE, path);
451
452 if (l != ERROR_SUCCESS) {
453 WCHAR s[255];
454 wsprintfW(s, L"RegDeleteTree returned %08x", l);
455 MessageBoxW(0, s, NULL, MB_ICONERROR);
456
457 return FALSE;
458 } else
459 return TRUE;
395 if (l != ERROR_SUCCESS)
396 throw string_error(IDS_REGDELETETREE_FAILED, l);
460}
461
397}
398
462static BOOL reg_context_menu_handler(const GUID clsid, const WCHAR* filetype, const WCHAR* name) {
463 WCHAR path[MAX_PATH];
399static void reg_context_menu_handler(const GUID clsid, const wstring& filetype, const wstring& name) {
464 WCHAR* clsidstring;
400 WCHAR* clsidstring;
465 BOOL ret = FALSE;
466
467 StringFromCLSID(clsid, &clsidstring);
468
401
402 StringFromCLSID(clsid, &clsidstring);
403
469 wcscpy(path, filetype);
470 wcscat(path, L"\\ShellEx\\ContextMenuHandlers\\");
471 wcscat(path, name);
404 try {
405#ifndef __REACTOS__
406 wstring path = filetype + L"\\ShellEx\\ContextMenuHandlers\\"s + name;
407#else
408 wstring path = filetype + wstring(L"\\ShellEx\\ContextMenuHandlers\\") + name;
409#endif
472
410
473 if (!write_reg_key(HKEY_CLASSES_ROOT, path, NULL, REG_SZ, (BYTE*)clsidstring, (wcslen(clsidstring) + 1) * sizeof(WCHAR)))
474 goto end;
475
476 ret = TRUE;
477
478end:
479 CoTaskMemFree(clsidstring);
480
481 return ret;
411 write_reg_key(HKEY_CLASSES_ROOT, path, nullptr, clsidstring);
412 } catch (...) {
413 CoTaskMemFree(clsidstring);
414 throw;
415 }
482}
483
416}
417
484static BOOL unreg_context_menu_handler(const WCHAR* filetype, const WCHAR* name) {
485 WCHAR path[MAX_PATH];
486 LONG l;
418static void unreg_context_menu_handler(const wstring& filetype, const wstring& name) {
419#ifndef __REACTOS__
420 wstring path = filetype + L"\\ShellEx\\ContextMenuHandlers\\"s + name;
421#else
422 wstring path = filetype + wstring(L"\\ShellEx\\ContextMenuHandlers\\") + name;
423#endif
487
424
488 wcscpy(path, filetype);
489 wcscat(path, L"\\ShellEx\\ContextMenuHandlers\\");
490 wcscat(path, name);
425 LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path.c_str());
491
426
492 l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path);
493
494 if (l != ERROR_SUCCESS) {
495 WCHAR s[255];
496 wsprintfW(s, L"RegDeleteTree returned %08x", l);
497 MessageBoxW(0, s, NULL, MB_ICONERROR);
498
499 return FALSE;
500 } else
501 return TRUE;
427 if (l != ERROR_SUCCESS)
428 throw string_error(IDS_REGDELETETREE_FAILED, l);
502}
503
429}
430
504static BOOL reg_prop_sheet_handler(const GUID clsid, const WCHAR* filetype, const WCHAR* name) {
505 WCHAR path[MAX_PATH];
431static void reg_prop_sheet_handler(const GUID clsid, const wstring& filetype, const wstring& name) {
506 WCHAR* clsidstring;
432 WCHAR* clsidstring;
507 BOOL ret = FALSE;
508
509 StringFromCLSID(clsid, &clsidstring);
510
433
434 StringFromCLSID(clsid, &clsidstring);
435
511 wcscpy(path, filetype);
512 wcscat(path, L"\\ShellEx\\PropertySheetHandlers\\");
513 wcscat(path, name);
436 try {
437#ifndef __REACTOS__
438 wstring path = filetype + L"\\ShellEx\\PropertySheetHandlers\\"s + name;
439#else
440 wstring path = filetype + wstring(L"\\ShellEx\\PropertySheetHandlers\\") + name;
441#endif
514
442
515 if (!write_reg_key(HKEY_CLASSES_ROOT, path, NULL, REG_SZ, (BYTE*)clsidstring, (wcslen(clsidstring) + 1) * sizeof(WCHAR)))
516 goto end;
517
518 ret = TRUE;
519
520end:
521 CoTaskMemFree(clsidstring);
522
523 return ret;
443 write_reg_key(HKEY_CLASSES_ROOT, path, nullptr, clsidstring);
444 } catch (...) {
445 CoTaskMemFree(clsidstring);
446 throw;
447 }
524}
525
448}
449
526static BOOL unreg_prop_sheet_handler(const WCHAR* filetype, const WCHAR* name) {
527 WCHAR path[MAX_PATH];
528 LONG l;
450static void unreg_prop_sheet_handler(const wstring& filetype, const wstring& name) {
451#ifndef __REACTOS__
452 wstring path = filetype + L"\\ShellEx\\PropertySheetHandlers\\"s + name;
453#else
454 wstring path = filetype + wstring(L"\\ShellEx\\PropertySheetHandlers\\") + name;
455#endif
529
456
530 wcscpy(path, filetype);
531 wcscat(path, L"\\ShellEx\\PropertySheetHandlers\\");
532 wcscat(path, name);
457 LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path.c_str());
533
458
534 l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path);
535
536 if (l != ERROR_SUCCESS) {
537 WCHAR s[255];
538 wsprintfW(s, L"RegDeleteTree returned %08x", l);
539 MessageBoxW(0, s, NULL, MB_ICONERROR);
540
541 return FALSE;
542 } else
543 return TRUE;
459 if (l != ERROR_SUCCESS)
460 throw string_error(IDS_REGDELETETREE_FAILED, l);
544}
545
461}
462
546STDAPI DllRegisterServer(void) {
547 if (!register_clsid(CLSID_ShellBtrfsIconHandler, COM_DESCRIPTION_ICON_HANDLER))
548 return E_FAIL;
463extern "C" STDAPI DllRegisterServer(void) {
464 try {
465 register_clsid(CLSID_ShellBtrfsIconHandler, COM_DESCRIPTION_ICON_HANDLER);
466 register_clsid(CLSID_ShellBtrfsContextMenu, COM_DESCRIPTION_CONTEXT_MENU);
467 register_clsid(CLSID_ShellBtrfsPropSheet, COM_DESCRIPTION_PROP_SHEET);
468 register_clsid(CLSID_ShellBtrfsVolPropSheet, COM_DESCRIPTION_VOL_PROP_SHEET);
549
469
550 if (!register_clsid(CLSID_ShellBtrfsContextMenu, COM_DESCRIPTION_CONTEXT_MENU))
551 return E_FAIL;
470 reg_icon_overlay(CLSID_ShellBtrfsIconHandler, ICON_OVERLAY_NAME);
552
471
553 if (!register_clsid(CLSID_ShellBtrfsPropSheet, COM_DESCRIPTION_PROP_SHEET))
554 return E_FAIL;
472 reg_context_menu_handler(CLSID_ShellBtrfsContextMenu, L"Directory\\Background", ICON_OVERLAY_NAME);
473 reg_context_menu_handler(CLSID_ShellBtrfsContextMenu, L"Folder", ICON_OVERLAY_NAME);
555
474
556 if (!register_clsid(CLSID_ShellBtrfsVolPropSheet, COM_DESCRIPTION_VOL_PROP_SHEET))
475 reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet, L"Folder", ICON_OVERLAY_NAME);
476 reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet, L"*", ICON_OVERLAY_NAME);
477 reg_prop_sheet_handler(CLSID_ShellBtrfsVolPropSheet, L"Drive", ICON_OVERLAY_NAME);
478 } catch (const exception& e) {
479 error_message(nullptr, e.what());
557 return E_FAIL;
480 return E_FAIL;
558
559 if (!reg_icon_overlay(CLSID_ShellBtrfsIconHandler, ICON_OVERLAY_NAME)) {
560 MessageBoxW(0, L"Failed to register icon overlay.", NULL, MB_ICONERROR);
561 return E_FAIL;
562 }
563
481 }
482
564 if (!reg_context_menu_handler(CLSID_ShellBtrfsContextMenu, L"Directory\\Background", ICON_OVERLAY_NAME)) {
565 MessageBoxW(0, L"Failed to register context menu handler.", NULL, MB_ICONERROR);
566 return E_FAIL;
567 }
568
569 if (!reg_context_menu_handler(CLSID_ShellBtrfsContextMenu, L"Folder", ICON_OVERLAY_NAME)) {
570 MessageBoxW(0, L"Failed to register context menu handler.", NULL, MB_ICONERROR);
571 return E_FAIL;
572 }
573
574 if (!reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet, L"Folder", ICON_OVERLAY_NAME)) {
575 MessageBoxW(0, L"Failed to register property sheet handler.", NULL, MB_ICONERROR);
576 return E_FAIL;
577 }
578
579 if (!reg_prop_sheet_handler(CLSID_ShellBtrfsPropSheet, L"*", ICON_OVERLAY_NAME)) {
580 MessageBoxW(0, L"Failed to register property sheet handler.", NULL, MB_ICONERROR);
581 return E_FAIL;
582 }
583
584 if (!reg_prop_sheet_handler(CLSID_ShellBtrfsVolPropSheet, L"Drive", ICON_OVERLAY_NAME)) {
585 MessageBoxW(0, L"Failed to register volume property sheet handler.", NULL, MB_ICONERROR);
586 return E_FAIL;
587 }
588
589 return S_OK;
590}
591
483 return S_OK;
484}
485
592STDAPI DllUnregisterServer(void) {
593 unreg_prop_sheet_handler(L"Folder", ICON_OVERLAY_NAME);
594 unreg_prop_sheet_handler(L"*", ICON_OVERLAY_NAME);
595 unreg_prop_sheet_handler(L"Drive", ICON_OVERLAY_NAME);
596 unreg_context_menu_handler(L"Folder", ICON_OVERLAY_NAME);
597 unreg_context_menu_handler(L"Directory\\Background", ICON_OVERLAY_NAME);
598 unreg_icon_overlay(ICON_OVERLAY_NAME);
486extern "C" STDAPI DllUnregisterServer(void) {
487 try {
488 unreg_prop_sheet_handler(L"Folder", ICON_OVERLAY_NAME);
489 unreg_prop_sheet_handler(L"*", ICON_OVERLAY_NAME);
490 unreg_prop_sheet_handler(L"Drive", ICON_OVERLAY_NAME);
491 unreg_context_menu_handler(L"Folder", ICON_OVERLAY_NAME);
492 unreg_context_menu_handler(L"Directory\\Background", ICON_OVERLAY_NAME);
493 unreg_icon_overlay(ICON_OVERLAY_NAME);
599
494
600 if (!unregister_clsid(CLSID_ShellBtrfsVolPropSheet))
495 unregister_clsid(CLSID_ShellBtrfsVolPropSheet);
496 unregister_clsid(CLSID_ShellBtrfsPropSheet);
497 unregister_clsid(CLSID_ShellBtrfsContextMenu);
498 unregister_clsid(CLSID_ShellBtrfsIconHandler);
499 } catch (const exception& e) {
500 error_message(nullptr, e.what());
601 return E_FAIL;
501 return E_FAIL;
502 }
602
503
603 if (!unregister_clsid(CLSID_ShellBtrfsPropSheet))
604 return E_FAIL;
605
606 if (!unregister_clsid(CLSID_ShellBtrfsContextMenu))
607 return E_FAIL;
608
609 if (!unregister_clsid(CLSID_ShellBtrfsIconHandler))
610 return E_FAIL;
611
612 return S_OK;
613}
614
504 return S_OK;
505}
506
615STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) {
507extern "C" STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) {
616 if (bInstall)
617 return DllRegisterServer();
618 else
619 return DllUnregisterServer();
620}
621
508 if (bInstall)
509 return DllRegisterServer();
510 else
511 return DllUnregisterServer();
512}
513
622BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {
514extern "C" BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {
623 if (dwReason == DLL_PROCESS_ATTACH)
624 module = (HMODULE)hModule;
625
515 if (dwReason == DLL_PROCESS_ATTACH)
516 module = (HMODULE)hModule;
517
626 return TRUE;
518 return true;
627}
628
519}
520
629static void create_subvol(std::wstring fn) {
521static void create_subvol(const wstring& fn) {
630 size_t found = fn.rfind(L"\\");
522 size_t found = fn.rfind(L"\\");
631 std::wstring path, file;
632 HANDLE h;
523 wstring path, file;
524 win_handle h;
633 ULONG bcslen;
634 btrfs_create_subvol* bcs;
635 IO_STATUS_BLOCK iosb;
636
525 ULONG bcslen;
526 btrfs_create_subvol* bcs;
527 IO_STATUS_BLOCK iosb;
528
637 if (found == std::wstring::npos) {
529 if (found == wstring::npos) {
638 path = L"";
639 file = fn;
640 } else {
641 path = fn.substr(0, found);
642 file = fn.substr(found + 1);
643 }
644 path += L"\\";
645
530 path = L"";
531 file = fn;
532 } else {
533 path = fn.substr(0, found);
534 file = fn.substr(found + 1);
535 }
536 path += L"\\";
537
646 h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
538 h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
647
648 if (h == INVALID_HANDLE_VALUE)
649 return;
650
651 bcslen = offsetof(btrfs_create_subvol, name[0]) + (file.length() * sizeof(WCHAR));
652 bcs = (btrfs_create_subvol*)malloc(bcslen);
653
539
540 if (h == INVALID_HANDLE_VALUE)
541 return;
542
543 bcslen = offsetof(btrfs_create_subvol, name[0]) + (file.length() * sizeof(WCHAR));
544 bcs = (btrfs_create_subvol*)malloc(bcslen);
545
654 bcs->readonly = FALSE;
655 bcs->posix = FALSE;
656 bcs->namelen = file.length() * sizeof(WCHAR);
546 bcs->readonly = false;
547 bcs->posix = false;
548 bcs->namelen = (uint16_t)(file.length() * sizeof(WCHAR));
657 memcpy(bcs->name, file.c_str(), bcs->namelen);
658
549 memcpy(bcs->name, file.c_str(), bcs->namelen);
550
659 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, NULL, 0);
660
661 CloseHandle(h);
551 NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, nullptr, 0);
662}
663
552}
553
664void CALLBACK CreateSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
665 LPWSTR* args;
666 int num_args;
554extern "C" void CALLBACK CreateSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
555 vector<wstring> args;
667
556
668 args = CommandLineToArgvW(lpszCmdLine, &num_args);
557 command_line_to_args(lpszCmdLine, args);
669
558
670 if (!args)
671 return;
672
673 if (num_args >= 1)
559 if (args.size() >= 1)
674 create_subvol(args[0]);
560 create_subvol(args[0]);
675
676 LocalFree(args);
677}
678
561}
562
679static void create_snapshot2(std::wstring source, std::wstring fn) {
563static void create_snapshot2(const wstring& source, const wstring& fn) {
680 size_t found = fn.rfind(L"\\");
564 size_t found = fn.rfind(L"\\");
681 std::wstring path, file;
682 HANDLE h, src;
565 wstring path, file;
566 win_handle h, src;
683 ULONG bcslen;
684 btrfs_create_snapshot* bcs;
685 IO_STATUS_BLOCK iosb;
686
567 ULONG bcslen;
568 btrfs_create_snapshot* bcs;
569 IO_STATUS_BLOCK iosb;
570
687 if (found == std::wstring::npos) {
571 if (found == wstring::npos) {
688 path = L"";
689 file = fn;
690 } else {
691 path = fn.substr(0, found);
692 file = fn.substr(found + 1);
693 }
694 path += L"\\";
695
572 path = L"";
573 file = fn;
574 } else {
575 path = fn.substr(0, found);
576 file = fn.substr(found + 1);
577 }
578 path += L"\\";
579
696 src = CreateFileW(source.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
580 src = CreateFileW(source.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
697 if (src == INVALID_HANDLE_VALUE)
698 return;
699
581 if (src == INVALID_HANDLE_VALUE)
582 return;
583
700 h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
584 h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
701
585
702 if (h == INVALID_HANDLE_VALUE) {
703 CloseHandle(src);
586 if (h == INVALID_HANDLE_VALUE)
704 return;
587 return;
705 }
706
707 bcslen = offsetof(btrfs_create_snapshot, name[0]) + (file.length() * sizeof(WCHAR));
708 bcs = (btrfs_create_snapshot*)malloc(bcslen);
709
588
589 bcslen = offsetof(btrfs_create_snapshot, name[0]) + (file.length() * sizeof(WCHAR));
590 bcs = (btrfs_create_snapshot*)malloc(bcslen);
591
710 bcs->readonly = FALSE;
711 bcs->posix = FALSE;
712 bcs->namelen = file.length() * sizeof(WCHAR);
592 bcs->readonly = false;
593 bcs->posix = false;
594 bcs->namelen = (uint16_t)(file.length() * sizeof(WCHAR));
713 memcpy(bcs->name, file.c_str(), bcs->namelen);
714 bcs->subvol = src;
715
595 memcpy(bcs->name, file.c_str(), bcs->namelen);
596 bcs->subvol = src;
597
716 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, NULL, 0);
598 NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, nullptr, 0);
599}
717
600
718 CloseHandle(h);
719 CloseHandle(src);
601extern "C" void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
602 vector<wstring> args;
603
604 command_line_to_args(lpszCmdLine, args);
605
606 if (args.size() >= 2)
607 create_snapshot2(args[0], args[1]);
720}
721
608}
609
722void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
723 LPWSTR* args;
610void command_line_to_args(LPWSTR cmdline, vector<wstring> args) {
611 LPWSTR* l;
724 int num_args;
725
612 int num_args;
613
726 args = CommandLineToArgvW(lpszCmdLine, &num_args);
614 args.clear();
727
615
728 if (!args)
616 l = CommandLineToArgvW(cmdline, &num_args);
617
618 if (!l)
729 return;
730
619 return;
620
731 if (num_args >= 2)
732 create_snapshot2(args[0], args[1]);
621 try {
622 args.reserve(num_args);
733
623
734 LocalFree(args);
624 for (unsigned int i = 0; i < (unsigned int)num_args; i++) {
625 args.push_back(l[i]);
626 }
627 } catch (...) {
628 LocalFree(l);
629 throw;
630 }
631
632 LocalFree(l);
735}
736
633}
634
737#ifdef __cplusplus
635#ifdef _MSC_VER
636#pragma warning(push)
637#pragma warning(disable: 4996)
638#endif
639
640string_error::string_error(int resno, ...) {
641 wstring fmt, s;
642 int len;
643 va_list args;
644
645 if (!load_string(module, resno, fmt))
646 throw runtime_error("LoadString failed."); // FIXME
647
648 va_start(args, resno);
649 len = _vsnwprintf(nullptr, 0, fmt.c_str(), args);
650
651 if (len == 0)
652 s = L"";
653 else {
654 s.resize(len);
655 _vsnwprintf((wchar_t*)s.c_str(), len, fmt.c_str(), args);
656 }
657
658 va_end(args);
659
660 utf16_to_utf8(s, msg);
738}
661}
662
663#ifdef _MSC_VER
664#pragma warning(pop)
739#endif
665#endif
666
667void utf8_to_utf16(const string& utf8, wstring& utf16) {
668 NTSTATUS Status;
669 ULONG utf16len;
670 WCHAR* buf;
671
672 Status = RtlUTF8ToUnicodeN(nullptr, 0, &utf16len, utf8.c_str(), utf8.length());
673 if (!NT_SUCCESS(Status))
674 throw string_error(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str());
675
676 buf = (WCHAR*)malloc(utf16len + sizeof(WCHAR));
677
678 if (!buf)
679 throw string_error(IDS_OUT_OF_MEMORY);
680
681 Status = RtlUTF8ToUnicodeN(buf, utf16len, &utf16len, utf8.c_str(), utf8.length());
682 if (!NT_SUCCESS(Status)) {
683 free(buf);
684 throw string_error(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str());
685 }
686
687 buf[utf16len / sizeof(WCHAR)] = 0;
688
689 utf16 = buf;
690
691 free(buf);
692}
693
694void utf16_to_utf8(const wstring& utf16, string& utf8) {
695 NTSTATUS Status;
696 ULONG utf8len;
697 char* buf;
698
699 Status = RtlUnicodeToUTF8N(nullptr, 0, &utf8len, utf16.c_str(), utf16.length() * sizeof(WCHAR));
700 if (!NT_SUCCESS(Status))
701 throw string_error(IDS_RECV_RTLUNICODETOUTF8N_FAILED, Status, format_ntstatus(Status).c_str());
702
703 buf = (char*)malloc(utf8len + sizeof(char));
704
705 if (!buf)
706 throw string_error(IDS_OUT_OF_MEMORY);
707
708 Status = RtlUnicodeToUTF8N(buf, utf8len, &utf8len, utf16.c_str(), utf16.length() * sizeof(WCHAR));
709 if (!NT_SUCCESS(Status)) {
710 free(buf);
711 throw string_error(IDS_RECV_RTLUNICODETOUTF8N_FAILED, Status, format_ntstatus(Status).c_str());
712 }
713
714 buf[utf8len] = 0;
715
716 utf8 = buf;
717
718 free(buf);
719}
720
721last_error::last_error(DWORD errnum) {
722 WCHAR* buf;
723
724 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
725 errnum, 0, (WCHAR*)&buf, 0, nullptr) == 0)
726 throw runtime_error("FormatMessage failed");
727
728 try {
729 utf16_to_utf8(buf, msg);
730 } catch (...) {
731 LocalFree(buf);
732 throw;
733 }
734
735 LocalFree(buf);
736}
737
738void error_message(HWND hwnd, const char* msg) {
739 wstring title, wmsg;
740
741 load_string(module, IDS_ERROR, title);
742
743 utf8_to_utf16(msg, wmsg);
744
745 MessageBoxW(hwnd, wmsg.c_str(), title.c_str(), MB_ICONERROR);
746}
747
748ntstatus_error::ntstatus_error(NTSTATUS Status) {
749 _RtlNtStatusToDosError RtlNtStatusToDosError;
750 HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
751 WCHAR* buf;
752
753 if (!ntdll)
754 throw runtime_error("Error loading ntdll.dll.");
755
756 try {
757 RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(ntdll, "RtlNtStatusToDosError");
758
759 if (!RtlNtStatusToDosError)
760 throw runtime_error("Error loading RtlNtStatusToDosError in ntdll.dll.");
761
762 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
763 RtlNtStatusToDosError(Status), 0, (WCHAR*)&buf, 0, nullptr) == 0)
764 throw runtime_error("FormatMessage failed");
765
766 try {
767 utf16_to_utf8(buf, msg);
768 } catch (...) {
769 LocalFree(buf);
770 throw;
771 }
772
773 LocalFree(buf);
774 } catch (...) {
775 FreeLibrary(ntdll);
776 throw;
777 }
778
779 FreeLibrary(ntdll);
780}
781
782#ifdef __REACTOS__
783NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
784 ULONG *utf8_bytes_written,
785 const WCHAR *uni_src, ULONG uni_bytes)
786{
787 NTSTATUS status;
788 ULONG i;
789 ULONG written;
790 ULONG ch;
791 BYTE utf8_ch[4];
792 ULONG utf8_ch_len;
793
794 if (!uni_src)
795 return STATUS_INVALID_PARAMETER_4;
796 if (!utf8_bytes_written)
797 return STATUS_INVALID_PARAMETER;
798 if (utf8_dest && uni_bytes % sizeof(WCHAR))
799 return STATUS_INVALID_PARAMETER_5;
800
801 written = 0;
802 status = STATUS_SUCCESS;
803
804 for (i = 0; i < uni_bytes / sizeof(WCHAR); i++)
805 {
806 /* decode UTF-16 into ch */
807 ch = uni_src[i];
808 if (ch >= 0xdc00 && ch <= 0xdfff)
809 {
810 ch = 0xfffd;
811 status = STATUS_SOME_NOT_MAPPED;
812 }
813 else if (ch >= 0xd800 && ch <= 0xdbff)
814 {
815 if (i + 1 < uni_bytes / sizeof(WCHAR))
816 {
817 ch -= 0xd800;
818 ch <<= 10;
819 if (uni_src[i + 1] >= 0xdc00 && uni_src[i + 1] <= 0xdfff)
820 {
821 ch |= uni_src[i + 1] - 0xdc00;
822 ch += 0x010000;
823 i++;
824 }
825 else
826 {
827 ch = 0xfffd;
828 status = STATUS_SOME_NOT_MAPPED;
829 }
830 }
831 else
832 {
833 ch = 0xfffd;
834 status = STATUS_SOME_NOT_MAPPED;
835 }
836 }
837
838 /* encode ch as UTF-8 */
839 ASSERT(ch <= 0x10ffff);
840 if (ch < 0x80)
841 {
842 utf8_ch[0] = ch & 0x7f;
843 utf8_ch_len = 1;
844 }
845 else if (ch < 0x800)
846 {
847 utf8_ch[0] = 0xc0 | (ch >> 6 & 0x1f);
848 utf8_ch[1] = 0x80 | (ch >> 0 & 0x3f);
849 utf8_ch_len = 2;
850 }
851 else if (ch < 0x10000)
852 {
853 utf8_ch[0] = 0xe0 | (ch >> 12 & 0x0f);
854 utf8_ch[1] = 0x80 | (ch >> 6 & 0x3f);
855 utf8_ch[2] = 0x80 | (ch >> 0 & 0x3f);
856 utf8_ch_len = 3;
857 }
858 else if (ch < 0x200000)
859 {
860 utf8_ch[0] = 0xf0 | (ch >> 18 & 0x07);
861 utf8_ch[1] = 0x80 | (ch >> 12 & 0x3f);
862 utf8_ch[2] = 0x80 | (ch >> 6 & 0x3f);
863 utf8_ch[3] = 0x80 | (ch >> 0 & 0x3f);
864 utf8_ch_len = 4;
865 }
866
867 if (!utf8_dest)
868 {
869 written += utf8_ch_len;
870 continue;
871 }
872
873 if (utf8_bytes_max >= utf8_ch_len)
874 {
875 memcpy(utf8_dest, utf8_ch, utf8_ch_len);
876 utf8_dest += utf8_ch_len;
877 utf8_bytes_max -= utf8_ch_len;
878 written += utf8_ch_len;
879 }
880 else
881 {
882 utf8_bytes_max = 0;
883 status = STATUS_BUFFER_TOO_SMALL;
884 }
885 }
886
887 *utf8_bytes_written = written;
888 return status;
889}
890#endif