[NTOBJSHEX] Change Turkish translation.
[reactos.git] / dll / shellext / shellbtrfs / main.cpp
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.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
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 "factory.h"
24 #include "resource.h"
25
26 static const GUID CLSID_ShellBtrfsIconHandler = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf0 } };
27 static const GUID CLSID_ShellBtrfsContextMenu = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf1 } };
28 static const GUID CLSID_ShellBtrfsPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf2 } };
29 static const GUID CLSID_ShellBtrfsVolPropSheet = { 0x2690b74f, 0xf353, 0x422d, { 0xbb, 0x12, 0x40, 0x15, 0x81, 0xee, 0xf8, 0xf3 } };
30
31 #define COM_DESCRIPTION_ICON_HANDLER L"WinBtrfs shell extension (icon handler)"
32 #define COM_DESCRIPTION_CONTEXT_MENU L"WinBtrfs shell extension (context menu)"
33 #define COM_DESCRIPTION_PROP_SHEET L"WinBtrfs shell extension (property sheet)"
34 #define COM_DESCRIPTION_VOL_PROP_SHEET L"WinBtrfs shell extension (volume property sheet)"
35 #define ICON_OVERLAY_NAME L"WinBtrfs"
36
37 typedef enum _PROCESS_DPI_AWARENESS {
38 PROCESS_DPI_UNAWARE,
39 PROCESS_SYSTEM_DPI_AWARE,
40 PROCESS_PER_MONITOR_DPI_AWARE
41 } PROCESS_DPI_AWARENESS;
42
43 typedef ULONG (WINAPI *_RtlNtStatusToDosError)(NTSTATUS Status);
44 typedef HRESULT (WINAPI *_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value);
45
46 HMODULE module;
47 LONG objs_loaded = 0;
48
49 void 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
63 void 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
89 void 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
111 void 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
126 void 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];
129 ULONG sr;
130 float f;
131 NUMBERFMTW fmt;
132 WCHAR thou[4], grouping[64], *c;
133
134 _i64tow(size, nb, 10);
135
136 GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, thou, sizeof(thou) / sizeof(WCHAR));
137
138 fmt.NumDigits = 0;
139 fmt.LeadingZero = 1;
140 fmt.lpDecimalSep = (LPWSTR)L"."; // not used
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
149 c = grouping;
150 while (*c) {
151 if (*c >= '0' && *c < '9') {
152 fmt.Grouping *= 10;
153 fmt.Grouping += *c - '0';
154 }
155
156 c++;
157 }
158
159 if (fmt.Grouping % 10 == 0)
160 fmt.Grouping /= 10;
161 else
162 fmt.Grouping *= 10;
163
164 GetNumberFormatW(LOCALE_USER_DEFAULT, 0, nb, &fmt, nb2, sizeof(nb2) / sizeof(WCHAR));
165
166 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 }
171
172 if (StringCchPrintfW(s, len, t, nb2) == STRSAFE_E_INSUFFICIENT_BUFFER) {
173 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
174 return;
175 }
176
177 return;
178 }
179
180 if (show_bytes) {
181 if (!LoadStringW(module, IDS_SIZE_BYTES, t, sizeof(t) / sizeof(WCHAR))) {
182 ShowError(NULL, GetLastError());
183 return;
184 }
185
186 if (StringCchPrintfW(bytes, sizeof(bytes) / sizeof(WCHAR), t, nb2) == STRSAFE_E_INSUFFICIENT_BUFFER) {
187 ShowError(NULL, ERROR_INSUFFICIENT_BUFFER);
188 return;
189 }
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;
198 } else if (size >= 1099511627776) {
199 sr = IDS_SIZE_TB;
200 f = (float)size / 1099511627776.0f;
201 } else if (size >= 1073741824) {
202 sr = IDS_SIZE_GB;
203 f = (float)size / 1073741824.0f;
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
212 if (!LoadStringW(module, sr, t, sizeof(t) / sizeof(WCHAR))) {
213 ShowError(NULL, GetLastError());
214 return;
215 }
216
217 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 }
222
223 if (!LoadStringW(module, IDS_SIZE_LARGE, t, sizeof(t) / sizeof(WCHAR))) {
224 ShowError(NULL, GetLastError());
225 return;
226 }
227
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 }
238 }
239
240 std::wstring format_message(ULONG last_error) {
241 WCHAR* buf;
242 std::wstring s;
243
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) {
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
260 std::wstring format_ntstatus(NTSTATUS Status) {
261 _RtlNtStatusToDosError RtlNtStatusToDosError;
262 std::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
282 #ifdef __cplusplus
283 extern "C" {
284 #endif
285
286 STDAPI DllCanUnloadNow(void) {
287 return objs_loaded == 0 ? S_OK : S_FALSE;
288 }
289
290 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);
299 }
300 } else if (rclsid == CLSID_ShellBtrfsContextMenu) {
301 Factory* fact = new Factory;
302 if (!fact)
303 return E_OUTOFMEMORY;
304 else {
305 fact->type = FactoryContextMenu;
306
307 return fact->QueryInterface(riid, ppv);
308 }
309 } else if (rclsid == CLSID_ShellBtrfsPropSheet) {
310 Factory* fact = new Factory;
311 if (!fact)
312 return E_OUTOFMEMORY;
313 else {
314 fact->type = FactoryPropSheet;
315
316 return fact->QueryInterface(riid, ppv);
317 }
318 } else if (rclsid == CLSID_ShellBtrfsVolPropSheet) {
319 Factory* fact = new Factory;
320 if (!fact)
321 return E_OUTOFMEMORY;
322 else {
323 fact->type = FactoryVolPropSheet;
324
325 return fact->QueryInterface(riid, ppv);
326 }
327 }
328
329 return CLASS_E_CLASSNOTAVAILABLE;
330 }
331
332 static BOOL write_reg_key(HKEY root, const WCHAR* keyname, const WCHAR* val, DWORD type, const BYTE* data, DWORD datasize) {
333 LONG l;
334 HKEY hk;
335 DWORD dispos;
336
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);
342
343 return FALSE;
344 }
345
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);
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;
365 }
366
367 static BOOL register_clsid(const GUID clsid, const WCHAR* description) {
368 WCHAR* clsidstring;
369 WCHAR inproc[MAX_PATH], progid[MAX_PATH], clsidkeyname[MAX_PATH], dllpath[MAX_PATH];
370 BOOL ret = FALSE;
371
372 StringFromCLSID(clsid, &clsidstring);
373
374 wsprintfW(inproc, L"CLSID\\%s\\InprocServer32", clsidstring);
375 wsprintfW(progid, L"CLSID\\%s\\ProgId", clsidstring);
376 wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring);
377
378 if (!write_reg_key(HKEY_CLASSES_ROOT, clsidkeyname, NULL, REG_SZ, (BYTE*)description, (wcslen(description) + 1) * sizeof(WCHAR)))
379 goto end;
380
381 GetModuleFileNameW(module, dllpath, sizeof(dllpath));
382
383 if (!write_reg_key(HKEY_CLASSES_ROOT, inproc, NULL, REG_SZ, (BYTE*)dllpath, (wcslen(dllpath) + 1) * sizeof(WCHAR)))
384 goto end;
385
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;
388
389 ret = TRUE;
390
391 end:
392 CoTaskMemFree(clsidstring);
393
394 return ret;
395 }
396
397 static BOOL unregister_clsid(const GUID clsid) {
398 WCHAR* clsidstring;
399 WCHAR clsidkeyname[MAX_PATH];
400 BOOL ret = FALSE;
401 LONG l;
402
403 StringFromCLSID(clsid, &clsidstring);
404 wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring);
405
406 l = RegDeleteTreeW(HKEY_CLASSES_ROOT, clsidkeyname);
407
408 if (l != ERROR_SUCCESS) {
409 WCHAR s[255];
410 wsprintfW(s, L"RegDeleteTree returned %08x", l);
411 MessageBoxW(0, s, NULL, MB_ICONERROR);
412
413 ret = FALSE;
414 } else
415 ret = TRUE;
416
417 CoTaskMemFree(clsidstring);
418
419 return ret;
420 }
421
422 static BOOL reg_icon_overlay(const GUID clsid, const WCHAR* name) {
423 WCHAR path[MAX_PATH];
424 WCHAR* clsidstring;
425 BOOL ret = FALSE;
426
427 StringFromCLSID(clsid, &clsidstring);
428
429 wcscpy(path, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\");
430 wcscat(path, name);
431
432 if (!write_reg_key(HKEY_LOCAL_MACHINE, path, NULL, REG_SZ, (BYTE*)clsidstring, (wcslen(clsidstring) + 1) * sizeof(WCHAR)))
433 goto end;
434
435 ret = TRUE;
436
437 end:
438 CoTaskMemFree(clsidstring);
439
440 return ret;
441 }
442
443 static BOOL unreg_icon_overlay(const WCHAR* name) {
444 WCHAR path[MAX_PATH];
445 LONG l;
446
447 wcscpy(path, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\");
448 wcscat(path, name);
449
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;
460 }
461
462 static BOOL reg_context_menu_handler(const GUID clsid, const WCHAR* filetype, const WCHAR* name) {
463 WCHAR path[MAX_PATH];
464 WCHAR* clsidstring;
465 BOOL ret = FALSE;
466
467 StringFromCLSID(clsid, &clsidstring);
468
469 wcscpy(path, filetype);
470 wcscat(path, L"\\ShellEx\\ContextMenuHandlers\\");
471 wcscat(path, name);
472
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
478 end:
479 CoTaskMemFree(clsidstring);
480
481 return ret;
482 }
483
484 static BOOL unreg_context_menu_handler(const WCHAR* filetype, const WCHAR* name) {
485 WCHAR path[MAX_PATH];
486 LONG l;
487
488 wcscpy(path, filetype);
489 wcscat(path, L"\\ShellEx\\ContextMenuHandlers\\");
490 wcscat(path, name);
491
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;
502 }
503
504 static BOOL reg_prop_sheet_handler(const GUID clsid, const WCHAR* filetype, const WCHAR* name) {
505 WCHAR path[MAX_PATH];
506 WCHAR* clsidstring;
507 BOOL ret = FALSE;
508
509 StringFromCLSID(clsid, &clsidstring);
510
511 wcscpy(path, filetype);
512 wcscat(path, L"\\ShellEx\\PropertySheetHandlers\\");
513 wcscat(path, name);
514
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
520 end:
521 CoTaskMemFree(clsidstring);
522
523 return ret;
524 }
525
526 static BOOL unreg_prop_sheet_handler(const WCHAR* filetype, const WCHAR* name) {
527 WCHAR path[MAX_PATH];
528 LONG l;
529
530 wcscpy(path, filetype);
531 wcscat(path, L"\\ShellEx\\PropertySheetHandlers\\");
532 wcscat(path, name);
533
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;
544 }
545
546 STDAPI DllRegisterServer(void) {
547 if (!register_clsid(CLSID_ShellBtrfsIconHandler, COM_DESCRIPTION_ICON_HANDLER))
548 return E_FAIL;
549
550 if (!register_clsid(CLSID_ShellBtrfsContextMenu, COM_DESCRIPTION_CONTEXT_MENU))
551 return E_FAIL;
552
553 if (!register_clsid(CLSID_ShellBtrfsPropSheet, COM_DESCRIPTION_PROP_SHEET))
554 return E_FAIL;
555
556 if (!register_clsid(CLSID_ShellBtrfsVolPropSheet, COM_DESCRIPTION_VOL_PROP_SHEET))
557 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
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
592 STDAPI 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);
599
600 if (!unregister_clsid(CLSID_ShellBtrfsVolPropSheet))
601 return E_FAIL;
602
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
615 STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) {
616 if (bInstall)
617 return DllRegisterServer();
618 else
619 return DllUnregisterServer();
620 }
621
622 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {
623 if (dwReason == DLL_PROCESS_ATTACH)
624 module = (HMODULE)hModule;
625
626 return TRUE;
627 }
628
629 static void create_subvol(std::wstring fn) {
630 size_t found = fn.rfind(L"\\");
631 std::wstring path, file;
632 HANDLE h;
633 ULONG bcslen;
634 btrfs_create_subvol* bcs;
635 IO_STATUS_BLOCK iosb;
636
637 if (found == std::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
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);
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
654 bcs->readonly = FALSE;
655 bcs->posix = FALSE;
656 bcs->namelen = file.length() * sizeof(WCHAR);
657 memcpy(bcs->name, file.c_str(), bcs->namelen);
658
659 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, NULL, 0);
660
661 CloseHandle(h);
662 }
663
664 void CALLBACK CreateSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
665 LPWSTR* args;
666 int num_args;
667
668 args = CommandLineToArgvW(lpszCmdLine, &num_args);
669
670 if (!args)
671 return;
672
673 if (num_args >= 1)
674 create_subvol(args[0]);
675
676 LocalFree(args);
677 }
678
679 static void create_snapshot2(std::wstring source, std::wstring fn) {
680 size_t found = fn.rfind(L"\\");
681 std::wstring path, file;
682 HANDLE h, src;
683 ULONG bcslen;
684 btrfs_create_snapshot* bcs;
685 IO_STATUS_BLOCK iosb;
686
687 if (found == std::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
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);
697 if (src == INVALID_HANDLE_VALUE)
698 return;
699
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);
701
702 if (h == INVALID_HANDLE_VALUE) {
703 CloseHandle(src);
704 return;
705 }
706
707 bcslen = offsetof(btrfs_create_snapshot, name[0]) + (file.length() * sizeof(WCHAR));
708 bcs = (btrfs_create_snapshot*)malloc(bcslen);
709
710 bcs->readonly = FALSE;
711 bcs->posix = FALSE;
712 bcs->namelen = file.length() * sizeof(WCHAR);
713 memcpy(bcs->name, file.c_str(), bcs->namelen);
714 bcs->subvol = src;
715
716 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, NULL, 0);
717
718 CloseHandle(h);
719 CloseHandle(src);
720 }
721
722 void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
723 LPWSTR* args;
724 int num_args;
725
726 args = CommandLineToArgvW(lpszCmdLine, &num_args);
727
728 if (!args)
729 return;
730
731 if (num_args >= 2)
732 create_snapshot2(args[0], args[1]);
733
734 LocalFree(args);
735 }
736
737 #ifdef __cplusplus
738 }
739 #endif